VTK修炼之道60:体绘制_体绘制管线&图形渲染管线

1.几何渲染与体绘制

1.1 几何渲染

前面练习的渲染技术都是几何渲染技术。所谓的几何渲染技术,就是通过绘制几何图元(顶点、线段、面片等)来渲染数据,例如:绘制图像需要在空间中建立一个四边形图元,然后以纹理映射的方式将该图像贴图到该图元上进行渲染;而三维模型的绘制通常会分解为一系列的多边形面片进行绘制。这种通过生成中间几何图元来进行渲染的方法称为几何渲染。
几何渲染的速度比较快,但是不能显示体数据的内部细节。例如:在渲染人的三维CT体数据时,通过几何渲染只能在切片图像之间进行切换,而不能对体数据内部细节进行立体观察。

1.2 体绘制

体绘制技术,更多的时候,我们把它称为三维重建(区别于投影图像的三维重建),是一种直接利用体数据来生成二维图像的绘制技术。与面绘制不同,体绘制不需要提取体数据内部的等值面,它是对三维体数据进行采样和合成的过程。体数据能过通过设置不透明度值来显示体数据内部的不同成分和细节,例如显示人体CT图像的不同器官和组织。

2.图形渲染管线

在进行体绘制管线学习之前,很有必要回顾一下前面的VTK可视化管线的基本组成。
我习惯把渲染窗口vtkRenderWindow看做一个剧院,剧院中一般需要灯光(vtkLight)、相机(vtkCamera)和舞台(vtkRenderer)来呈现精彩的演出。
舞台上负责表演的自然就是演员(vtkActor),而且演员往往不止一个,可以根据需要为舞台加入更多的演员(vtkActor)。
每个演员又各具特色,而用来表示其特色的则是vtkProperty(负责控制值颜色、材质和不透明度等)
每个vtkActor的数据和渲染信息存储在一个vtkMapper对象中,负责将原始数据转换为渲染所需要的图元数据

3.体绘制管线

从可视化管线的组成上来讲,体绘制的渲染管线与几何渲染管线基本一致,先通过一个实例进行初步认识:
#include 
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL); //错误:no override found for 'vtkRayCastImageDisplayHelper'.
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkInteractionStyle);

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char *argv[])
{
	vtkSmartPointer reader =
		vtkSmartPointer::New();
	reader->SetFileName("mummy.128.vtk");
	reader->Update();


	vtkSmartPointer volumeMapper =
		vtkSmartPointer::New();
	volumeMapper->SetInputData(reader->GetOutput());

	//设置光线采样距离
	//volumeMapper->SetSampleDistance(volumeMapper->GetSampleDistance()*4);
	//设置图像采样步长
	//volumeMapper->SetAutoAdjustSampleDistances(0);
	//volumeMapper->SetImageSampleDistance(4);
	/*************************************************************************/
	vtkSmartPointer volumeProperty =
		vtkSmartPointer::New();
	volumeProperty->SetInterpolationTypeToLinear();
	volumeProperty->ShadeOn();  //打开或者关闭阴影测试
	volumeProperty->SetAmbient(0.4);
	volumeProperty->SetDiffuse(0.6);  //漫反射
	volumeProperty->SetSpecular(0.2); //镜面反射
	//设置不透明度
	vtkSmartPointer compositeOpacity =
		vtkSmartPointer::New();
	compositeOpacity->AddPoint(70, 0.00);
	compositeOpacity->AddPoint(90, 0.40);
	compositeOpacity->AddPoint(180, 0.60);
	volumeProperty->SetScalarOpacity(compositeOpacity); //设置不透明度传输函数
	//compositeOpacity->AddPoint(120,  0.00);//测试隐藏部分数据,对比不同的设置
	//compositeOpacity->AddPoint(180,  0.60);
	//volumeProperty->SetScalarOpacity(compositeOpacity);
	//设置梯度不透明属性
	vtkSmartPointer volumeGradientOpacity =
		vtkSmartPointer::New();
	volumeGradientOpacity->AddPoint(10, 0.0);
	volumeGradientOpacity->AddPoint(90, 0.5);
	volumeGradientOpacity->AddPoint(100, 1.0);
	volumeProperty->SetGradientOpacity(volumeGradientOpacity);//设置梯度不透明度效果对比
	//设置颜色属性
	vtkSmartPointer color =
		vtkSmartPointer::New();
	color->AddRGBPoint(0.000, 0.00, 0.00, 0.00);
	color->AddRGBPoint(64.00, 1.00, 0.52, 0.30);
	color->AddRGBPoint(190.0, 1.00, 1.00, 1.00);
	color->AddRGBPoint(220.0, 0.20, 0.20, 0.20);
	volumeProperty->SetColor(color);
	/********************************************************************************/
	vtkSmartPointer volume =
		vtkSmartPointer::New();
	volume->SetMapper(volumeMapper);
	volume->SetProperty(volumeProperty);

	vtkSmartPointer ren = vtkSmartPointer::New();
	ren->SetBackground(0, 1, 0);
	ren->AddVolume(volume);

	vtkSmartPointer rw = vtkSmartPointer::New();
	rw->AddRenderer(ren);
	rw->SetSize(640, 480);
	rw->Render();
	rw->SetWindowName("VolumeRendering PipeLine");

	vtkSmartPointer rwi =
		vtkSmartPointer::New();
	rwi->SetRenderWindow(rw);
	/********************************************************************************/
	//vtkSmartPointer axes = vtkSmartPointer::New();
	//axes->SetScale(10);
	//vtkSmartPointer widget =
	//	vtkSmartPointer::New();
	//widget->SetOutlineColor(1, 1, 1);
	//widget->SetViewport(0, 0, 0.2, 0.2);
	//widget->SetOrientationMarker(axes);
	//widget->SetInteractor(rwi);
	//widget->SetEnabled(1);
	//widget->InteractiveOn();

	ren->ResetCamera();
	rw->Render();
	rwi->Start();

	return 0;
}

#vtkVolumeRayCastMapper:
vtkVolumeRayCastMapper定义了一个光线投影体绘制Mapper,其主要接受如下两个输入。
SetInputData(vtkImageData*):该函数用于设置输入图像数据。
SetVolumeRayCastFunction(vtkVolumeRayCastFunction*):该函数用于设置光线透射函数类型。
vtkVolumeRayCastCompositeFunction是vtkVolumeRayCastFunction的子类,定义了光线经过体数据后的颜色计算方式。
需要注意的是,这个类备受很多科研人员职责,在VTK7.0.0之后会被移除。
这里我采用vtkFixedPointVolumeRayCastMapper以避免如下错误:

#vtkVolumeProperty:
该类定义了体绘制属性,设置标量不透明度传输函数梯度不透明度函数颜色传输函数阴影
vtkVolumeProperty用于设置体绘制的属性,决定体绘制的渲染效果,其中:
  • SetScalarOpacity(vtkPiecewiseFunction* function):该类用于设置灰度不透明度函数。
  • SetColor(vtkColorTransferFunction *function):该类用于设置颜色传输函数。
#vtkVolume:
vtkVolume与几何渲染中的vtkActor作用一致,需要设置如下两个输入:
  • void SetMapper(vtkAbstractVolumeMapper* mapper):该函数用于设置Mapper对象。
  • void SetProperty(vtkVolumeProperty* property):该函数用于设置属性对象。
#定义vtkRenderer、vtkRenderWindow、vtkRenderWindowInteractor对象,建立可视化管线。
体绘制渲染结果如下:
VTK修炼之道60:体绘制_体绘制管线&图形渲染管线_第1张图片

4.图形渲染管线与体绘制渲染管线对比

通过上面代码可以看出,体绘制渲染管线与几何渲染管线的组成是比较一致的,都需要vtkRenderWindow、vtkRenderer、vtkActor/vtkVolume、vtkMapper等对象。
它们不同之处在于:
  • 几何渲染中,通常使用vtkActor来渲染几何图像数据,使用vtkImageActor来渲染图像数据;而在体绘制中,则使用vtkVolume渲染数据。
  • 在几何渲染中,通常采用vtkPolyDataMapper实现输入数据向图元数据的转换;在体绘制中,则采用vtkVolumeRayCastMapper,要切记的是,这个类是与体绘制的算法相关的,不同的体绘制算法会有不同的Mapper类。
更一般的,几何图像渲染管线与体绘制的渲染管线对比图如下:
VTK修炼之道60:体绘制_体绘制管线&图形渲染管线_第2张图片
虚线部分表示两者不同之处,从上图我们能够看出来,两种渲染方式不同点主要在Mapper和Actor对象上。

5.no override found for 'vtkRayCastImageDisplayHelper'修订

体绘制过程中,出现如下错误:

这也是一个初始化的问题,解决办法如下:
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL);  

6.参看资料

1.《C++ primer》
2.《The VTK User’s Guide – 11thEdition》
3.  张晓东, 罗火灵. VTK图形图像开发进阶[M]. 机械工业出版社, 2015.

你可能感兴趣的:(VTK修炼之道,VTK,三维数据渲染进阶)