VTK编程指南<六>:VTK可视化管线与渲染详解
1、VTK渲染引擎
回顾前几章节的RenderCylinder示例 可以找到以下的类:
vtkProp;
ytkAbstractMapper;
vtkProperty;
vtkCamera;
vtkLight;
vtkRenderer;
vtkRenderWindow;
vtkRenderWindowInteractor
vtkTransform;
vtkLookupTable;
可以发现这些类都是与数据显示或渲染相关的。用计算机图形学的专业词汇来说,就是它们构成了VTK的渲染引擎(Rendering Engine)。渲染引擎主要负责数据的可视化表达,是VTK里的两个重要概念之一,而另一个重要概念就是可视化管线(Visualization Pipeline)。
可视化管线是指用于获取或创建数据、处理数据以及把数据写入文件或者把数据传递给渲染引擎进行显示,这样的一种结构在VTK里就称为可视化管线。数据对象(Data Object)、处理对象(Process Object)和数据流方向(Direction of Data Flow)是可视化管线的三个基本要素。每个VTK程序都会有可视化管线存在,比如示例2.1RenderCylinder,其可视化管线可以简单地表示成如图所示的连接关系。
示例RenderCylinder 的可视化管线非常简单,先是创建一个柱体数据,接着经 Mapper后生成的图元直接送入渲染引擎渲染,创建的数据没有经过任何处理。再看一个稍微复杂的可视化管线。在该示例中,先读入一个后缀为vtk的文件(head.vtk),然后用移动立方体法(vtkMarchingCubes)提取等值面,最后把等值面数据经 Mapper 送往渲染引擎进行显示,示例代码如下:
#include <iostream>#include <vtkSmartPointer.h>
#include <vtkStructuredPointsReader.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkImageDataGeometryFilter.h>
#include <vtkMarchingCubes.h>
#include <vtkPolyDataMapper.h>
#include <vtkPolyDataReader.h>
#include <vtkActor.h>#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);// VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);//测试文件:data/head.vtk
int main(int argc, char* argv[])
{std::string sFilePath = "D:\\VTK_Learn\\Examples\\Chap02\\data\\head.vtk";//读入Structured_Points类型的vtk文件。vtkSmartPointer<vtkStructuredPointsReader> reader =vtkSmartPointer<vtkStructuredPointsReader>::New();reader->SetFileName(sFilePath.c_str());//用移动立方体法提取等值面。vtkSmartPointer<vtkMarchingCubes> marchingCubes =vtkSmartPointer<vtkMarchingCubes>::New();marchingCubes->SetInputConnection(reader->GetOutputPort());marchingCubes->SetValue(0, 550);//将生成的等值面数据进行MappervtkSmartPointer<vtkPolyDataMapper> mapper =vtkSmartPointer<vtkPolyDataMapper>::New();mapper->SetInputConnection(marchingCubes->GetOutputPort());//把Mapper的输出送入渲染引擎进行显示vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();actor->SetMapper(mapper);vtkSmartPointer<vtkRenderer> renderer =vtkSmartPointer<vtkRenderer>::New();renderer->AddActor(actor);renderer->SetBackground(1.0, 1.0, 0.0);vtkSmartPointer<vtkRenderWindow> renWin =vtkSmartPointer<vtkRenderWindow>::New();renWin->AddRenderer(renderer);renWin->SetSize(640, 480);renWin->Render();renWin->SetWindowName("vtkPipelineDemo");vtkSmartPointer<vtkRenderWindowInteractor> interactor =vtkSmartPointer<vtkRenderWindowInteractor>::New();interactor->SetRenderWindow(renWin);interactor->Initialize();interactor->Start();return EXIT_SUCCESS;
}
2、VTK可视化管线
比较代码可以看出多了一个vtkMarchingCubes用于处理读入的数据。VTK 中把与类似 vtkMarchingCubes 对数据做处理的类称为 Filter。
Source 是指用于创建数据(如vtkCylinderSource)或者读取数据(如 vtkBMPReader、vtkStructuredPointsReader 等)类的统称,即 VTK 的数据源。Source 输出的数据作为 Filter 的输入,经Filter 处理以后(可以经多个 Filter 处理),生成新的数据。Filter 的输出可以直接写入文件,或者经 Mapper 变换后传入渲染引擎进行渲染、显示,结束可视化管线。
图 2-12 所示的箭头方向即为VTK里数据流流动的方向。可视化管线的三要素分别是数据对象、处理对象和数据流方向,Source、Filter 和 Mapper一起构成了处理对象,它们的区别是基于数据流的初始化、维持和终止。根据数据的生成方式,Source 可以分为程序源对象(Procedural,如vtkCylinderSource,通过程序代码生成相关的数据)和读取源对象(Reader,如 vtkBMPReader,从外部文件中导入数据)。
关于 Source、Filter 和 Mapper 的区别,可以简单地通过图 2-13 所示的示意图进行表示。Source 没有输入,但至少有一个输出;Filter 可以有一个或多个输入,产生一个或多个输出;Mapper 接受一个或多个输入,但没有输出,写文件的Writer(如 vtkBMPWriter)可以看作Mapper,负责把数据写入文件或者流(Stream)中,因此,Mapper 是可视化管线的终点,同时也是可视化管线和渲染引擎(有时也称之为图形管线)的桥梁。
2.1、可视化管线的连接
由示例可知,可视化管线里各个模块的连接是通过接口SetInputConnection()和 GetOutputPort()来完成的。VTK 5.0 版本之前,可视化管线之间的连接使用 SetInput()和 GetOutput(),VTK 5.0 版本的可视化管线使用 SetInputConnection()和GetOutputPort()连接,同时也保留了对旧版本的支持。
marchingCubes->SetInputConnection(reader->GetOutputPort));
vtkMarchingCubes作为 Filter 只接受一个输入,Filter 概括起来有以下三种类型(见图2-14):单个输入,产生单个输出;多个输入,产生单个输出,但输出的数据可有多种用途,比如,读入数据后,可以对其作等值面提取,另外还可以针对读入的数据生成轮廓线(Outline);单个输入,产生多个输出。
使用 SetInputConnection()和 GetOutputPort()连接可视化管线时,还要求连接的两部分之间的数据类型必须一致。由于管线是运行时才执行的,如果连接的两部分类型不匹配,程序运行时就会报错。比如,vtkMarchingCubes 要求输入的是 vtkImageData 类型的数据,如果给它输入的是vtkPolyData类型的,程序运行时就会报如下的错误:
ERROR:In ..L.lVTK-5.10\FilteringlvtkDemandDrivenPipeline.cxx,line 827
vtkStreamingDemandDrivenPipeline (0000000000BAAB90):Input for connection index 0 on input port index 0 for algorithm vtkMarchingCubes(0000000000BA9590) is of type vtkPolyData,but a vtkImageData is required.
2.2、可视化管线的执行
可视化管线连接完成后,必须有一种机制来控制管线的执行。有时,对某一部分数据做了改变,只希望改变的这部分数据在可视化管线里做更新,而不要影响其他没做改变的数据。如图2-15 所示,假如 Filter D的输入发生了变化,E和 F是依赖于 D的输入的,所以虚线框内的部分是需要重新执行的管线,而 C和 G是另外一个分支,D输入的改变不影响 C和 G,所以,为了节省运行时间,C和 G是不需要重新执行的。毕竟对于三维的应用程序来说,处理的数据量一般都是比较大的,如果真能这样做,有利于提高程序的运行效率。
VTK采用一种叫作“惰性赋值”(LazyEvaluation)的方案来控制管线的执行,惰性赋值是指根据每个对象的内部修改时间来决定什么时候执行管线,只有当用户或者程序发出“请求数据”时,管线才会被执行。
vtkObject 类里有一个重要的成员变量 MTime,管线里的每个从vtkObject 派生的类的对象都会跟踪自己的内部修改时间,当遇到“请求数据”时,该对象会比较这个修改时间,如果发现修改时间发生了改变,对象就会执行。换言之,VTK是采用命令驱动(Demand Driven)的方法来控制管线的执行,这种方法的好处是,当对数据对象作了更改时,不必立即做计算,只有当发出请求时才开始处理,这样能最小化计算所需的时间,以便更流畅地与数据进行交互。
vtkSmartPointer<vtkBMPReader> reader = vtkSmartPointer<vtkBMPReader>::New();std::cout<<"Modification Time of reader (After New()): "<<reader->GetMTime()<<std::endl;reader->SetFileName(argv[1]);std::cout<<"Modification Time of reader (After SetFileName()): "<<reader->GetMTime()<<std::endl;vtkImageData* imageData = reader->GetOutput();std::cout<<"Modification Time of reader (After GetOutput()): "<<reader->GetMTime()<<std::endl;reader->Update();std::cout<<"Modification Time of reader (After Update()): "<<reader->GetMTime()<<std::endl;int extent[6];imageData->GetWholeExtent(extent);std::cout<<"Extent of image: "<<extent[0]<<" "<<extent[1]<<" "<<extent[2]<<" "<<extent[3]<<" "<<extent[4]<<" "<<extent[5]<<" "<<std::endl;
该例先读入一幅 BMP图像,然后把 reader 的输出值赋给 imageData,接着需要获取读入图像的大小,调用 vtkImageData::GetWholeExtent()方法后,输出为“Extent of image: 0-1 0 -1 0 -1”。该结果显然是错误的,所读图像实际大小为300X246 像素,这就是因为没有“请求数据(RequestData())。
只有在 reader->GetOutput()之前,调用 reader->Update(),才会迫使管线的执行,即 reader 从磁盘中读取数据,然后才可获得 imageData 的正确信息。通常,程序不用显式地调用 Update()函数,因为在渲染引擎的最后,当调用 Render()函数时,Actor 就会收到渲染请求,接着 Actor 会请求 Mapper 给它发送数据,而 Mapper 又会请求上一层的 Filter 的数据,Filter 最后请求 Source 给它数据,于是,整条管线就被执行。除非像以上代码所列,读入数据以后,中间需要输出某些信息,在得到这些信息之前,就应该显式地调用 Update()函数。管线的执行过程大致如图 2-16 所示。
相关文章:

VTK编程指南<六>:VTK可视化管线与渲染详解
1、VTK渲染引擎 回顾前几章节的RenderCylinder示例 可以找到以下的类: vtkProp; ytkAbstractMapper; vtkProperty; vtkCamera; vtkLight; vtkRenderer; vtkRenderWindow; vtkRenderWindowInteractor vtkTransform; vtkLookupTable;可以发现这些类都是与数据显示或渲染相关的。…...

基于STM32的智能计步器
引言 随着健康意识的提高,计步器逐渐成为人们日常生活中重要的健康管理工具。本文将指导你如何使用STM32微控制器制作一个智能计步器。该计步器通过加速度传感器检测步伐,并使用OLED显示屏显示步数。通过这个项目,你将学习到STM32开发的基本流…...
VB.NET 从入门到精通:开启编程进阶之路
摘要: 本文全面深入地阐述了 VB.NET 的学习路径,从基础的环境搭建与语法入门开始,逐步深入到面向对象编程、图形用户界面设计、数据访问、异常处理、多线程编程以及与其他技术的集成等核心领域,通过详细的代码示例与理论讲解&…...
射频电路屏蔽简略
电磁波的干扰是每个射频设备的自带属性,不管是内部还是外部,怎样去更好的抑制掉干扰,关系到射频设备的工作状态,而能够找到产生干扰的来源就是重中之重,电磁波的干扰与其产生的源密不可分,而源就离不开所需…...

基础算法——搜索与图论
搜索与图论 图的存储方式2、最短路问题2.1、Dijkstra算法(朴素版)2.2、Dijkstra算法(堆优化版)2.3、Bellman-Ford算法2.4、SPFA求最短路2.5、SPFA判负环2.6、Floyd算法 图的存储方式 2、最短路问题 最短路问题可以分为单源最短路…...

redis优化编码之字符串
redis 优化编码之字符串 ### 字符串优化 字符串对象是redis内部最常用的数据类型。 所有的键是字符串对象值对象除了整数之外都是使用字符串存储lpush cache:type "redis" "tair" "memcache" "leveldb"创建如上一个链表 需要创建一…...

Python特定版本的安装/卸载/环境配置,Spyder安装教程
目录 1.Python安装 1.1 Python下载 1.2 下载特定版本 1.3 安装Python 1.4 修改安装 1.5 环境配置 1.6 卸载Python 2.Spyder安装使用 2.1 Spyder下载 2.1.1 官网下载Spyder 2.2.2 Github下载Spyder 2.2 安装 参考资料:网盘 1.Python安装 1.1 Python下载…...

全局搜索正则表达式(grep)
一.grep简介 grep 全程Globally search a Regular Expression and Print,是一种强大的文本搜索工具,它能使用特定模式匹配(包括正则表达式)搜索文本,并默认输出匹配行。Unix的grep家族包括grep和egrep 二.grep的工作…...

linux-12 关于shell(十一)ls
登录系统输入用户名和密码以后,会显示给我们一个命令提示符,就意味着我们在这里就可以输入命令了,给一个命令,这个命令必须要可执行,那问题是我的命令怎么去使用,命令格式有印象吗?在命令提示符…...
编写指针函数使向右循环移动m个位置
题目描述:有n个整数,要求你编写一个函数使其向右循环移动m个位置 请仔细阅读右侧代码,结合相关知识,在Begin-End区域内进行代码补充。 输入 输入n m表示有n个整数,移动m位 输出 输出移动后的数组 样例输入: 10 5 1 2 3…...
xvisor调试记录
Xvisor是一种开源hypervisor,旨在提供完整、轻量、移植且灵活的虚拟化解决方案,属于type-1类型的虚拟机,可以直接在裸机上启动。 启动xvisor步骤: 1、搭建riscv编译环境 首先从github上下载riscv-gnu-toolchain很费劲,建议直接从国内的源下载 git clone https://gitee…...

MongoDB-ObjectID 生成器
前言 MongoDB中一个非常关键的概念就是 ObjectID,它是 MongoDB 中每个文档的默认唯一标识符。了解 ObjectID 的生成机制不仅有助于开发人员优化数据库性能,还能帮助更好地理解 MongoDB 的设计理念。 什么是 MongoDB ObjectID? 在 MongoDB …...

CUDA 计时功能,记录GPU程序/函数耗时,cudaEventCreate,cudaEventRecord,cudaEventElapsedTime
为了测试GPU函数的耗时,可以使用 CUDA 提供的计时功能:cudaEventCreate, cudaEventRecord, 和 cudaEventElapsedTime。这些函数可以帮助你测量某个 CUDA 操作(如设置设备)所花费的时间。 一、记录耗时案例 以下是一个示例程序&a…...

PDF 文件如何转为 CAD 图纸?PDF2CAD 使用教程
在工程设计和建筑行业中,PDF 文件常常被用来分享和存档图纸。然而,当需要对这些图纸进行编辑或进一步开发时,静态的 PDF 格式就显得力不从心了。这时候,将 PDF 文件转换为可编辑的 CAD(计算机辅助设计)格式…...

【YashanDB知识库】php查询超过256长度字符串,数据被截断的问题
本文内容来自YashanDB官网,原文内容请见:https://www.yashandb.com/newsinfo/7488290.html?templateId1718516 问题现象 如下图,php使用odbc数据源,查询表数据,mysql可以显示出来,yashan显示数据被截断。…...

暴雨AI加速计算服务器新品X8840上市
用户输入简短的文字,大模型可以自动生成创意文本或图像;金融机构的风险评估和预测,大模型通过对金融数据的分析,可以识别异常交易行为;15秒内完成中英文作文的批改和评分,并提供针对性的改进建议࿰…...
在多个分布式机器间设置和使用 NFS(Network File System)共享目录的步骤如下:
在多个分布式机器间设置和使用 NFS(Network File System)共享目录的步骤如下: 1. 准备工作 确保所有参与的机器都在同一个网络中,并安装了 NFS 软件包。 在 Linux 系统上: sudo apt update && sudo apt install nfs-kernel-server -y # Ubuntu/Debian sudo yu…...

机器学习中的 Transformer 简介(第 1 部分)
目录 一、说明 二、为什么是 Transformer? 三、什么是 Transformer? 3.1 译者的类比 四、编码器部分 4.1 、从文本输入到输入嵌入 4.2 词嵌入 4.2 N倍编码器段 4.4 多头注意力机制 4.5 添加残差和层归一化 4.6 添加残差和层归一化 五、总结 一、说明 西如…...

D3实现站点路线图demo分享
分享一下通过D3实现的站点路线分布图,这是一个demo。效果图如下: 源码如下: <template><div class"map-test" ref"d3Chart"><div class"tooltip" id"popup-element"><span>…...

非文件形式的内存动态函数库调用接口
使用memfd的系统调用接口将动态库加载到proc虚拟文件系统,提供的fd为进程持有的句柄,通过dlopen的path指向此句柄,即可实现非文件系统加载动态链接库。 文章目录 一、memfd_create二、dl_open三、示例参考 一、memfd_create 接口名称int mem…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...

VB.net复制Ntag213卡写入UID
本示例使用的发卡器:https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...

【汇编逆向系列】六、函数调用包含多个参数之多个整型-参数压栈顺序,rcx,rdx,r8,r9寄存器
从本章节开始,进入到函数有多个参数的情况,前面几个章节中介绍了整型和浮点型使用了不同的寄存器在进行函数传参,ECX是整型的第一个参数的寄存器,那么多个参数的情况下函数如何传参,下面展开介绍参数为整型时候的几种情…...
IP选择注意事项
IP选择注意事项 MTP、FTP、EFUSE、EMEMORY选择时,需要考虑以下参数,然后确定后选择IP。 容量工作电压范围温度范围擦除、烧写速度/耗时读取所有bit的时间待机功耗擦写、烧写功耗面积所需要的mask layer...