3.vtk学习——vtkPolyData
vtk数据集(vtkDataSet)
vtkDataSet 是 VTK 中描述三维对象的核心数据结构,由三部分组成:
- 几何结构:定义空间位置,如顶点坐标。
- 拓扑结构:定义几何元素连接关系,如顶点构成面的规则。
- 属性数据(可选):附加描述信息,如面的面积、点的温度。
关键规则:完整数据集必须包含几何与拓扑结构,才能进行显示。属性数据为信息补充。
示例:创建三角形时,三顶点坐标是几何结构,顶点连接顺序是拓扑结构,添加的三角形面积则是属性数据。
不要局限于只能使用面积去描述三角形的面积,我们还可以为每个点添加一个属性(颜色等),这样几何结构也拥有了属性数据。

Cell(单元)
一系列点的点按照特定顺序连接起来就形成了Cell。也就是上面提到的拓扑结构。在vtk中拓扑结构使用cell(单元)来表示,一个数据集由一个或者多个cell组成。
属性数据
此处不对这个做细致解释,先说明以下内容。
- 属性数据分为标量数据和矢量数据
- 属性数据可以添加在cell上也可以添加在point上。
- 数据与元素通过Id实现一一对应绑定。
什么是vtkPolyData
该数据类型是vtk中最为常用的数据类型,也是我在进行点云三维可视化时主要使用的。属于上面介绍的vtkDataSet的一种子类。

vtkPolyData 主要由几何结构数据、拓扑结构数据和属性数据组成。 几何结构数据主要是组成模型的点集;拓扑结构数据则是由这些点根据一定的连接关系组成的单元数据,表明了几何点集之间的拓扑关系;而属性数据与几何结构数据和拓扑结构数据相关联,属性数据可以是标量、向量或者张量。比如可以为 vtkPolyData 中的每个点定义曲率属性数据,也可以为其中的每个单元定义一个法向量属性数据。在 vtkPolyData 可视化中会利用这些属性数据直接或者间接计算单元或点的颜色。
vtkPolyData的数据创建
结合我们的应用场景,我们不太需要使用vtk自带的数据源(自带几何结构和拓扑结构),而是去自己创建我们需要的数据(几何结合和拓扑数据)。下面介绍如何创建。
- 在vtk中我们使用vtkPoints这个类为我们添加点集。
- 使用vtk提供的单元类型,把我们的点生成对应的cell。
- 进行可视化。
点击查看代码
private void PolyDataTest()
{
vtkPoints vtkPoints = new vtkPoints();
vtkPoints.InsertNextPoint(0.0, 0.0, 0.0);
vtkPoints.InsertNextPoint(1.0, 0.0, 0.0);
vtkPoints.InsertNextPoint(1.0, 1.0, 0.0);
vtkPoints.InsertNextPoint(0.0, 1.0, 0.0);
vtkPoints.InsertNextPoint(2.0, 0.0, 0.0);
vtkPolygon vtkPolygon1 = new vtkPolygon();
//声明当前多边形有4个点
vtkPolygon1.GetPointIds().SetNumberOfIds(4);
//将当前多边形的点通过Id与上面咱们创建的点对应起来
vtkPolygon1.GetPointIds().SetId(0, 0);//多边形的第一个点对应我们vtkPoints中第一个点,以此类推。
vtkPolygon1.GetPointIds().SetId(1, 1);
vtkPolygon1.GetPointIds().SetId(2, 2);
vtkPolygon1.GetPointIds().SetId(3, 3);
vtkTriangle triangle = new vtkTriangle();
//同理,只不过这里是三角形。我们没必要再声明3个点。
triangle.GetPointIds().SetId(0, 1);//三角形的第一个点对应我们vtkPoints中第二个点,以此类推。
triangle.GetPointIds().SetId(1, 2);
triangle.GetPointIds().SetId(2, 4);
vtkCellArray cells = new vtkCellArray();
cells.InsertNextCell(vtkPolygon1);
cells.InsertNextCell(triangle);
vtkPolyData polyData = new vtkPolyData();
//添加几何结构和拓扑结构
polyData.SetPoints(vtkPoints);
polyData.SetPolys(cells);
//可视化
vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
mapper.SetInput(polyData);
vtkActor actor = new vtkActor();
actor.SetMapper(mapper);
renderer = vtkRenderer.New();
renderer.AddActor(actor);
renderWindow.AddRenderer(renderer);
renderWindow.Render();
}

对应的显示效果如下。

vtkPolyData的属性数据
vtk中的属性数据分类标量数据和向量数据。对于标量数据往往对着与几何变换无关的值,向量数据则会根据几何变换发生改变(如法向量的值)。
上面可视化后的图形,只有默认的白色。如果我们想实现更加高级的效果,例如让颜色跟随某一个值的大小进行改变。这就需要为我们创建的图形对象添加属性数据。此处,我们将颜色作为标量数据进行演示。
图形着色
使用vtkUnsignedCharArray数据进行着色
想为我们创建的点和单元进行颜色(标量)的设置。在vtk中,vtkUnsignedCharArray类来实现RGB颜色的设置,在C#中该类对应着一个byte数组。对于RGB颜色,我们可以通过3个字节去描述对应的颜色。更棒的是,我们使用vtkPolyDataMapper类进行映射时,该类会自动的找到vtkUnsignedCharArray类型的数据来实现这种图形着色功能。
非常重要的一点是,我们设置的颜色数据的数量一定要和我们想要赋值的数据的数量的个数一致。例如9个点,我们必须定义9个属性数据才能着色。
点击查看代码
private void PolyDataTest()
{
//添加颜色
vtkUnsignedCharArray colorArray = new vtkUnsignedCharArray();
colorArray.SetNumberOfComponents(3);
colorArray.InsertNextTuple3(255, 0, 0);
colorArray.InsertNextTuple3(0, 255, 0);
colorArray.InsertNextTuple3(0, 0, 255);
colorArray.InsertNextTuple3(255, 255, 0);
colorArray.InsertNextTuple3(255, 0, 255);
vtkPoints vtkPoints = new vtkPoints();
vtkPoints.InsertNextPoint(0.0, 0.0, 0.0);
vtkPoints.InsertNextPoint(1.0, 0.0, 0.0);
vtkPoints.InsertNextPoint(1.0, 1.0, 0.0);
vtkPoints.InsertNextPoint(0.0, 1.0, 0.0);
vtkPoints.InsertNextPoint(2.0, 0.0, 0.0);
vtkPolygon vtkPolygon1 = new vtkPolygon();
//声明当前多边形有4个点
vtkPolygon1.GetPointIds().SetNumberOfIds(4);
//将当前多边形的点通过Id与上面咱们创建的点对应起来
vtkPolygon1.GetPointIds().SetId(0, 0);
vtkPolygon1.GetPointIds().SetId(1, 1);
vtkPolygon1.GetPointIds().SetId(2, 2);
vtkPolygon1.GetPointIds().SetId(3, 3);
vtkTriangle triangle = new vtkTriangle();
//同理,只不过这里是三角形。我们没必要再声明3个点。
triangle.GetPointIds().SetId(0, 1);
triangle.GetPointIds().SetId(1, 2);
triangle.GetPointIds().SetId(2, 4);
vtkCellArray cells = new vtkCellArray();
cells.InsertNextCell(vtkPolygon1);
cells.InsertNextCell(triangle);
vtkPolyData polyData = new vtkPolyData();
//添加几何结构和拓扑结构
polyData.GetPointData().SetScalars(colorArray);
polyData.SetPoints(vtkPoints);
polyData.SetPolys(cells);
//可视化
vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
mapper.SetInput(polyData);
vtkActor actor = new vtkActor();
actor.SetMapper(mapper);
renderer = vtkRenderer.New();
renderer.AddActor(actor);
renderWindow.AddRenderer(renderer);
renderWindow.Render();
}
上述代码与初始版本差异不大,核心需关注两部分:一是颜色数据的定义方式,二是其添加至 polyData 的过程。
如前所述,因颜色数据对应 3 字节(RGB 模式),我们需将 vtkUnsignedCharArray 的每个元素设置为 3 字节大小,再向其中填充颜色值。最后通过 GetPointData () 方法获取点数据指针,调用 SetScalars () 即可完成颜色标量值的设置。

使用其他类型数据进行着色
上面提到vtkPolyDataMapper类能够自动根据vtkUnsignedCharArray类型的数据进行着色,该模式称为 mapper.SetColorModeToDefault();,但在其他情况下,我们可能希望使用其他的属性数据对颜色进行渲染,该种模式称为mapper.SetColorModeToMapScalars();,该模式下我们不需要考虑特定的颜色类型。当数据的组分大于1时,会自动使用第一组分的值进行颜色映射。下面演示如何对指定的数据进行颜色映射。
点击查看代码
private void ColorSet()
{
vtkPlaneSource gridSource= new vtkPlaneSource();
gridSource.SetXResolution(3);
gridSource.SetYResolution(3);
gridSource.Update();
vtkPolyData grid = gridSource.GetOutput();
//vtkFloatArray默认组分大小为1,因此标量没有专门设置。
vtkFloatArray cellScalars=new vtkFloatArray();
vtkFloatArray cellVectors=new vtkFloatArray();
cellVectors.SetNumberOfComponents(3);
for(int i = 0; i < 9; i++)
{
cellScalars.InsertNextValue(i);
cellVectors.InsertNextTuple3(0.0, 0.0, 1.0);
}
grid.GetCellData().SetScalars(cellScalars);
grid.GetCellData().SetVectors(cellVectors);
vtkLookupTable vtkLookupTable = new vtkLookupTable();
vtkLookupTable.SetNumberOfTableValues(10);
vtkLookupTable.Build();
vtkLookupTable.SetTableValue(0, 0, 0, 0, 1);
vtkLookupTable.SetTableValue(1, 0.8900, 0.8100, 0.3400, 1);
vtkLookupTable.SetTableValue(2, 1.0000, 0.3882, 0.2784, 1);
vtkLookupTable.SetTableValue(3, 0.9608, 0.8706, 0.7020, 1);
vtkLookupTable.SetTableValue(4, 0.9020, 0.9020, 0.9804, 1);
vtkLookupTable.SetTableValue(5, 1.0000, 0.4900, 0.2500, 1);
vtkLookupTable.SetTableValue(6, 0.5300, 0.1500, 0.3400, 1);
vtkLookupTable.SetTableValue(7, 0.9804, 0.5020, 0.4471, 1);
vtkLookupTable.SetTableValue(8, 0.7400, 0.9900, 0.7900, 1);
vtkLookupTable.SetTableValue(9, 0.2000, 0.6300, 0.7900, 1);
vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
mapper.SetInput(grid);
mapper.SetScalarRange(0, 9);
mapper.SetLookupTable(vtkLookupTable);
vtkActor actor = new vtkActor();
actor.SetMapper(mapper);
renderer = vtkRenderer.New();
renderer.AddActor(actor);
renderWindow.AddRenderer(renderer);
renderWindow.Render();
在上述代码中,我们首先通过 VTK 提供的数据源创建平面网格,接着分别创建 vtkFloatArray 类型的标量与向量并完成赋值,随后获取 vtkPolyData 中的单元数据,通过对应方法将标量数据和向量数据设置其中。
之后,我们创建了 vtkLookupTable 以定义颜色映射关系(若不手动创建,会默认使用 mapper 中的 LookupTable),并通过 SetScalarRange 指定标量的颜色映射范围 —— 超出该范围的数值按最大值映射颜色,低于该范围的数值则按最小值映射颜色。
补充说明两点:
- 代码中未显式调用 mapper.SetColorModeToMapScalars(),原因是未添加 vtkUnsignedCharArray 时,mapper 会自动基于标量进行颜色映射。
- 未指定使用点数据还是单元数据进行颜色映射,这是由于 mapper 有默认逻辑:优先选择点的标量数据进行映射,若不存在则选择单元的标量数据。

选择着色数据
在mapper中提供以下方法帮助我们决定使用单元数据还是点数据进行着色。

自定义场数据进行着色
vtkIntArray array = new vtkIntArray();
array.SetName("MyArray");
array.SetNumberOfComponents(3);
array.InsertNextTuple3(0, 2, 3);
vtkPolyDataMapper mapper1 = vtkPolyDataMapper.New();
mapper1.SetScalarModeToUsePointFieldData();
mapper1.SelectColorArray("MyArray");
//使用MyArray每个元素的第一组分进行着色
mapper1.ColorByArrayComponent("MyArray", 0);
单元数据和点数据的相互转换

点击查看代码
vtkCellDataToPointData convert = new vtkCellDataToPointData();
convert.SetPassCellData(1);
convert.SetInput(grid);
convert.Update();
mapper.SetInputConnection(convert.GetOutputPort());
mapper.SetScalarRange(0, 9);
mapper.SetLookupTable(vtkLookupTable);


浙公网安备 33010602011771号