vtkVolumeMapper的不同混合模式
不同的模式下会呈现出不同的渲染效果。注意vtkGPUVolumeRayCastMapper和vtkFixedPointVolumeRayCastMapper支持的模式不同。
例如:
-
Composite混合模式:
- 默认模式,通过体积采样并使用alpha混合算法从前到后合成标量值。
- 使用颜色传输函数和不透明度传输函数确定最终的颜色和不透明度。
-
Maximum混合模式:
- 使用采样光线上的最大标量值。
- 通过颜色传输函数和不透明度传输函数确定最终的颜色和不透明度。
-
Minimum混合模式:
- 使用采样光线上的最小标量值。
- 通过颜色传输函数和不透明度传输函数确定最终的颜色和不透明度。
-
Additive混合模式:
- 累积标量值,将每个值通过不透明度传输函数,并将值乘以其不透明度进行相加。
- 结果图像始终是灰度的,即聚合的值不经过颜色传输函数。
- 最终的值是通过不透明度传输函数和累积计算得到的。
-
Average intensity混合模式:
- 类似于Additive混合模式,但是在求和之前将标量值乘以从不透明度传输函数计算得到的不透明度,并在求和后除以通过体积采样的数量。
- 可通过设置AverageIPScalarRange来控制标量范围。
- 最终的图像始终是灰度的,即聚合的值不经过颜色传输函数。
-
IsoSurface混合模式:(vtkFixedPointVolumeRayCastMapper不支持)
- 使用用户定义的等值面值,在光线穿过等值面时显示标量值。
- 支持与Composite混合模式相同的不透明度处理方式。
数据特点
数据文件(txt)举例:
3 6 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1
格式说明:
这样的一串数字,3 6 3分别表示z,y,x方向格点数,后面的3*6*3个数字就是从第0层开始每个点的属性值。
注意:
是 z * y * x ;
这里的0、1、2代表不同的材料,0为空气,1为硅基底,2为多晶硅;
3 6 3 之后的数字是按照 x轴,y轴,z轴,逐个、逐行、逐层的顺序存储。
算法
光线投射体绘制算法:一种基于图像序列的直接体绘制方法,其基本原理是从投影图像平面的每个像素沿着视线方向发射一条穿过体数据的射线,然后在射线上按照一定的步长进行等距采样,对每个采样点采用插值技术计算其体素值,根据颜色传输函数和不透明度传输函数来获取相应的颜色值和不透明度,最后利用光线吸收模型将颜色值进行累加,直至光线穿过体数据,即可得到当前平面像素的渲染颜色,生成最终显示图像。
两个重要函数(颜色传输函数、不透明度传输函数):
// 设置颜色
vtkSmartPointer<vtkColorTransferFunction> colorFunction = vtkSmartPointer<vtkColorTransferFunction>::New();
// 设置透明度
vtkSmartPointer<vtkPiecewiseFunction> opacityFunction = vtkSmartPointer<vtkPiecewiseFunction>::New();
volumeProperty->SetInterpolationTypeToLinear();
使用线性插值计算比较符合我们的显示需求。
全部代码
这里使用的是默认模式。
int maxPointsX, maxPointsY, maxPointsZ;
std::vector<int> datas;
readFile(datas, maxPointsZ, maxPointsY, maxPointsX);
vtkSmartPointer<vtkImageData> imageData = vtkSmartPointer<vtkImageData>::New();
imageData->SetDimensions(maxPointsX, maxPointsY, maxPointsZ);//设置网格的尺寸
imageData->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
imageData->SetSpacing(1.0, 1.0, 1.0);//设置间距
unsigned char* voxelData = static_cast<unsigned char*>(imageData->GetScalarPointer());
int k = 0;
for (int i = 0; i < maxPointsZ; ++i) {
for (int j = 0; j < maxPointsY; ++j) {
for (int l = 0; l < maxPointsX; ++l) {
voxelData[k] = datas[k];
k++;
}
}
}
vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper =
vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
volumeMapper->SetInputData(imageData);
//volumeMapper->SetBlendModeToAverageIntensity();
//volumeMapper->SetBlendModeToMinimumIntensity();
vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
// 设置透明度
vtkSmartPointer<vtkPiecewiseFunction> opacityFunction = vtkSmartPointer<vtkPiecewiseFunction>::New();
opacityFunction->AddPoint(0, 0.0);
opacityFunction->AddPoint(1, 1.0);
opacityFunction->AddPoint(2, 1.0);
volumeProperty->SetScalarOpacity(opacityFunction);
// 设置颜色
vtkSmartPointer<vtkColorTransferFunction> colorFunction = vtkSmartPointer<vtkColorTransferFunction>::New();
colorFunction->AddRGBPoint(0, 0.0, 0.0, 0.0);
colorFunction->AddRGBPoint(1, 1, 0, 0);
colorFunction->AddRGBPoint(2, 0, 1, 0);
volumeProperty->SetColor(colorFunction);
volumeProperty->SetInterpolationTypeToLinear();
volumeProperty->SetScalarOpacityUnitDistance(1);
vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
vtkSmartPointer<vtkRenderer> ren = vtkSmartPointer<vtkRenderer>::New();
ren->SetBackground(0, 0, 0);
ren->AddVolume(volume);
vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(ren);
rw->SetSize(640, 480);
rw->Render();
rw->SetWindowName("VolumeRendering PipeLine");
vtkSmartPointer<vtkRenderWindowInteractor> rwi =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(rw);
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
rwi->SetInteractorStyle(style);
rw->Render();
rwi->Start();
return 0;
效果图
在不同的光照角度下,会呈现不同的效果。这一点并不是很符合要求。可以尝试soSurface混合模式,使用等值面法进行渲染。