1、vtkGPUVolumeRayCastMapper
1)概述
vkGPUVolumeRayCastMapper实现了基于GPU 加速的光线投射体绘制算法。该类的使用方法与 vtkVolumeRayCastMapper 基本一致,使用时将 vkVolimeRayCastMapper 对象替换为 vtkGPUVolumeRayCastMapper,并可以利用下面的函数设置光线采样步长、图像采样距离是否自动调节图像采样距离等。
void SetSampleDistance (float)。
void SetlmageSampleDistance (float).
void SetAutoAdjustSampleDistances (int).
2)代码
vtkGPUVolumeRayCastMapper texMapper = vtkGPUVolumeRayCastMapper.New();texMapper.SetInputConnection(reader.GetOutputPort());texMapper.SetSampleDistance(0.5f);texMapper.SetImageSampleDistance(0.5f);texMapper.SetAutoAdjustSampleDistances(1);
2、纹理映射体绘制
1)概述
基于软件实现的光线投射体绘制算法计算量非常大,不利于进行实时染。因此,目前体绘制经常会使用图形硬件利用纹理映射来加速。其主要原理是将三维体数据作为纹理装载入图像硬件缓存中,利用硬件来实现插值以及图像合成的操作,以提高绘制效率。
基于图形硬件三维纹理功能的体绘制技术,主要利用硬件的三线性过滤插值能力,通过渲染多个与视线垂直的面片来重建整个三维结构。每个面片利用三维纹理来决定颜色与透明度。这种方法得到的效果从本质上讲与光线投射的效果相同。最新的方法可以直接利用三维纹理在图形硬件上实现光线投射的算法。
2)二维纹理映射
早期受到硬件技术的限制,显卡只能支持二维纹理映射。其基本思路是将每个坐标轴方向的切片图像作为二维纹理保存至图形硬件缓存中,在光线投射时,选择与当前视线方向重直的一组纹理图像,在硬件中进行插值和合成运算以实现体绘制。VTK的tkVolumeTextureMapper2D 类可用于实现基于二维纹理映射的体绘制方法。
3)三维纹理映射
目前多数显卡已经能够支持三维纹理映射。利用三维纹理映射,将体数据映射至一组与视图平面平行的多边形,避免了二维纹理映射方法中因为纹理图像的切换产生的瑕疵现象。VTK 中三维纹理映射体绘制方法是由vtkVolumeTextureMapper3D类实现,其使用方法与vtkVolumeTextureMapper2D 类似。
4)说明
3、裁剪
1)概述
对于一些体积比较大、结构比较复杂的体数据进行体绘制的渲染效果难以展示其内部细节,需要用到裁剪技术来渲染部分数据。vtkVolumeMapper类中提供了两种裁剪技术,分别是 Cropping 和 Clipping。
2)Cropping 技术
①概述
Cropping 技术只支持 vtkImageData 数据的裁剪。该方法在每个坐标轴上定义两个裁剪面,共6个裁剪平面(xmimn, xmax, ymin, ymax,zmin, zmx)将三维空间分割为 27 个可视区域。这些裁剪面仅与数据的原点和像素尺寸有关,而不依赖于数据的任何坐标变换,因此可以使用一个 27位数字来定义这些区域,每一位代表一个区域。当某位上数字为1时,说明显示其对应的区域。在这些区域中,小于(xmi,yi,)的区域为第一位,然后根据先X轴方向,再Y轴方向,最后Z轴方向的顺序来定义每个区域的位号。例如当只显示中间区域时,其对应的27位数字为 0x0002000。
vtkVolumeMapper 中定义了 Cropping方法的接口函数。
②代码
private void TestCroppingVolume(){vtkStructuredPointsReader reader = vtkStructuredPointsReader.New();reader.SetFileName("F:\\code\\VTK\\TestActiViz\\data\\mummy.128.vtk");reader.Update();vtkFixedPointVolumeRayCastMapper volumeMApper = vtkFixedPointVolumeRayCastMapper.New();volumeMApper.SetInputData(reader.GetOutput());volumeMApper.SetCropping(1);volumeMApper.SetCroppingRegionPlanes(100, 200, 100, 200, 100, 200);volumeMApper.SetCroppingRegionFlags(0x0002000);vtkVolumeProperty volumeProperty = vtkVolumeProperty.New();volumeProperty.SetInterpolationTypeToLinear();volumeProperty.ShadeOn(); //打开或者关闭阴影测试volumeProperty.SetAmbient(0.4);volumeProperty.SetDiffuse(0.6);volumeProperty.SetSpecular(0.2);vtkPiecewiseFunction compositeOpacity = vtkPiecewiseFunction.New();compositeOpacity.AddPoint(70, 0.0);compositeOpacity.AddPoint(90, 0.4);compositeOpacity.AddPoint(180, 0.6);//volumeProperty.SetScalarOpacity(compositeOpacity);vtkPiecewiseFunction volumeGradientOpacity = vtkPiecewiseFunction.New();volumeGradientOpacity.AddPoint(10, 0);volumeGradientOpacity.AddPoint(90, 0.5);volumeGradientOpacity.AddPoint(100, 1.0);volumeProperty.SetGradientOpacity(volumeGradientOpacity); //设置梯度不透明度效果对比vtkColorTransferFunction color = vtkColorTransferFunction.New();color.AddRGBPoint(0, 0, 0, 0);color.AddRGBPoint(64, 1.0, 0.52, 0.3);color.AddRGBPoint(190, 1.0, 1.0, 1.0);color.AddRGBPoint(220, 0.2, 0.2, 0.2);volumeProperty.SetColor(color);vtkVolume vol = vtkVolume.New();vol.SetMapper(volumeMApper);vol.SetProperty(volumeProperty);vtkRenderer render = vtkRenderer.New();render.AddVolume(vol);render.SetBackground(1, 1, 1);vtkRenderWindow renWin = renderWindowControl.RenderWindow;renWin.AddRenderer(render);renWin.Render();}
③效果
④说明
vtkVolumeMapperSetCropping()是设置 Cropping 打开的函数;
vtkVolumeMapper::SeCroppingRegionPlanes()函数用于设置三个坐标轴上6个裁剪面位置;
vtkVolumeMapper:SetCroppingRegionFlags()函数用于设置显示区域标记。
另外,还提供了如下几个常用的显示区域设置函数,避免自行计算显示区域标记。
- void SetCroppingRegionFlagsToSubVolume()。
- void SetCroppingRegionFlagsToFence().
- void SetCroppingRegionFlagsToInvertedFence().
- void SetCroppingRegionFlagsToCross(。
- void SetCroppingRegionFlagsTolnvertedCross().
3)Cliping 技术
①概述
Clipping 技术支持 vtkImageData 和 vtkUnstructuredGrid 数据类型。该功能由 vtkAbstractMapper3D类提供,对于那些使用基于OpengGL,的硬件裁剪技术的Mapper类,如vkPolyDataMapper、vtkVolumeTextureMapper2D、vtkProjectedTetrahedraMapper 等,当设置的裁剪面个数超出 OpenG 支持的个数(一般为6)时,VTK 会反馈一个错误;而对于基于软件的裁剪技术的 Mapper 类,如 vtkVolumeRayCastMapper 则没有此限制,可以支持任意多个裁剪面。使用 Clipping 技术,可以沿着任意方向将图像切开,便于观察体数据内部细节。
②代码
private void TestClippingVolume(){vtkStructuredPointsReader reader = vtkStructuredPointsReader.New();reader.SetFileName("F:\\code\\VTK\\TestActiViz\\data\\mummy.128.vtk");reader.Update();vtkFixedPointVolumeRayCastMapper volumeMApper = vtkFixedPointVolumeRayCastMapper.New();volumeMApper.SetInputData(reader.GetOutput());//clippingvtkPlane plane = vtkPlane.New();plane.SetOrigin(100, 100, 0);plane.SetNormal(1, 1, 0);volumeMApper.AddClippingPlane(plane);vtkVolumeProperty volumeProperty = vtkVolumeProperty.New();volumeProperty.SetInterpolationTypeToLinear();volumeProperty.ShadeOn(); //打开或者关闭阴影测试 默认是关闭阴影效果volumeProperty.SetAmbient(0.4); //环境光系数0.4volumeProperty.SetDiffuse(0.6); //散射光系数0.6volumeProperty.SetSpecular(0.2); //反射光系数0.2vtkPiecewiseFunction compositeOpacity = vtkPiecewiseFunction.New();compositeOpacity.AddPoint(70, 0.0); //当灰度值小于70时,不透明度值映射为0;compositeOpacity.AddPoint(90, 0.4); //当灰度值 介于70~90时,通过线性映射到0~0.4的一个值compositeOpacity.AddPoint(180, 0.6); //当灰度值介于90~180时,线性映射至0.4~0.6;大于180时,不透明度映射到0.6~1.0.//volumeProperty.SetScalarOpacity(compositeOpacity);vtkPiecewiseFunction volumeGradientOpacity = vtkPiecewiseFunction.New();volumeGradientOpacity.AddPoint(10, 0);volumeGradientOpacity.AddPoint(90, 0.5);volumeGradientOpacity.AddPoint(100, 1.0);// 梯度小于10的点的不透明度乘子设置为0,即完全透明。// 当梯度大小为10时,不透明度乘子为0;// 梯度大小为90时,不透明度乘子为0.5;// 而梯度大小在10~90时,通过线性映射到0~0.5之间;// 梯度大小在90~100时,通过线性映射至0.5~1.0之间。// 梯度值大于100时,其不透明度乘子为1.0.volumeProperty.SetGradientOpacity(volumeGradientOpacity); //设置梯度不透明度效果对比vtkColorTransferFunction color = vtkColorTransferFunction.New();color.AddRGBPoint(0, 0, 0, 0);color.AddRGBPoint(64, 1.0, 0.52, 0.3);color.AddRGBPoint(190, 1.0, 1.0, 1.0);color.AddRGBPoint(220, 0.2, 0.2, 0.2);volumeProperty.SetColor(color);vtkVolume vol = vtkVolume.New();vol.SetMapper(volumeMApper);vol.SetProperty(volumeProperty);vtkRenderer render = vtkRenderer.New();render.AddVolume(vol);render.SetBackground(1, 1, 1);vtkRenderWindow renWin = renderWindowControl.RenderWindow;renWin.AddRenderer(render);renWin.Render();}
③效果
④说明
只需定义一个 vtkPlane 类型的裁剪平面对象,然后通过 vtkAbstractMapper3D::AddClippingPlane()函数将该平面添加至Mapper对象中即可。
4、法向量编码
在体绘制阴影渲染中,计算漫反射和镜面反射依赖于表面法向。vtkImageData数据体绘制过程中,一个数据点的法向为其梯度方向的反方向。通常采用有限差分技术来计算梯度,但是如果每个采样点都要计算一次梯度,无疑会带来巨大的计算量,影响体绘制的渲染速度一个解决方案是在体绘制前预先计算图像所有点的法向。这样每个点的法向和模值的存储需要使用4个浮点型数据来存储。对于一个大的体数据来讲,这将会带来非常大的内存消耗因此,这里需要通过法向编码减少内存存储量。
在 vtkmageData 的部分体绘制 Mapper 对象中,可以使用法向编码来减少存储量。法向采用 2Byte 存储,模值采用 1Byte 存储。法向计算使用的是 vtkEncodedGradientEstimater 的子类 vtkFiniteDifferenceGradientEstimater 类,而法向的编码则是利用 vtkDirectionEncoder 的子类vtkRecursiveSphereDirectionEncoder 和 vtkSphericalDirectionEncoder 类。对于使用法向编码的体绘制 mapper 类如 vtkVolumeRayCastMapper 和 vtkVolumeTextureMapper2D,其内部自动生成相应的编码类对象,因此用户不必考虑。而对于同一个数据,当有多个 Mapper 对象进行渲染时,一个比较好的方法是先生成一个梯度计算类对象,然后传给每个Mapper 对象使用,这样有利于节省空间和提高渲染速度。