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…...
7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器
拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件: 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
9-Oracle 23 ai Vector Search 特性 知识准备
很多小伙伴是不是参加了 免费认证课程(限时至2025/5/15) Oracle AI Vector Search 1Z0-184-25考试,都顺利拿到certified了没。 各行各业的AI 大模型的到来,传统的数据库中的SQL还能不能打,结构化和非结构的话数据如何和…...
Qt的学习(一)
1.什么是Qt Qt特指用来进行桌面应用开发(电脑上写的程序)涉及到的一套技术Qt无法开发网页前端,也不能开发移动应用。 客户端开发的重要任务:编写和用户交互的界面。一般来说和用户交互的界面,有两种典型风格&…...
goreplay
1.github地址 https://github.com/buger/goreplay 2.简单介绍 GoReplay 是一个开源的网络监控工具,可以记录用户的实时流量并将其用于镜像、负载测试、监控和详细分析。 3.出现背景 随着应用程序的增长,测试它所需的工作量也会呈指数级增长。GoRepl…...
32位寻址与64位寻址
32位寻址与64位寻址 32位寻址是什么? 32位寻址是指计算机的CPU、内存或总线系统使用32位二进制数来标识和访问内存中的存储单元(地址),其核心含义与能力如下: 1. 核心定义 地址位宽:CPU或内存控制器用32位…...
