1.从图形着色开始
拜森是上一个实验中显示的图像,图形颜色和vtkPolyData属性数据密切相关。默认显示为白色,因为没有指定任何颜色和属性数据。 属性数据包括点属性和单元属性。vtkPolyData的点数据和单元数据分别指定属性数据。属性数据可以是标量,如点的曲率;可以是向量,如点火者法向量;也可以是张量,主要在流畅中比较常见。颜色可以直接作为一种标量属性数据,设置到相应的点或者单元数据中,这也是最直接的一种图形着色方式。
以下代码继承了上一节的代码VTKPolyData数据。定义了vtkUnsingedCharArray对象ptColor和cellColor,颜色数据分别设置为点和单元。vtkUnsingedCharArray其实对象是一个Unsinged char类型数组。SetNumberOfComponents()函数指定了数组中每个元组的大小。因为每种颜色RGB由三种颜色组成。因此,将元祖大小设置为3.InsertNextValue()元组数据可以顺序插入函数。 因为要为点集设置颜色,所以颜色的数量要和点的数量一致。单元的颜色设置也是如此。 设置点颜色时,需要通过GetPointData()函数获取VTKPointData数据指针的类型,然后通过SetScalar()函数设置颜色数据。
代码
错误原因:VTK版本6具有InsertNextTuplevalue,但是新版本的名称已经改变了. This is according to https://www.vtk.org/doc/nightly/html/VTK-7-1-Changes.html which says: The old and new method names are listed below: GetTupleValue is now GetTypedTuple SetTupleValue is now SetTypedTuple InsertTupleValue is now InsertTypedTuple InsertNextTupleValue is now InsertNextTypedTuple
#include <vtkAutoInit.h> VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle); #include <vtkSmartPointer.h> #include <vtkPoints.h> #include <vtkPolygon.h> #include <vtkTriangle.h> #include <vtkCellArray.h> #include <vtkPolyData.h> #include <vtkUnsignedCharArray.h> //Attribution #include <vtkPointData.h> #include <vtkCellData.h> /// #include <vtkPolyDataMapper.h> #include <vtkActor.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h>/span> int main() {
//几何结构数据:点集 vtkSmartPointer<vtkPoints> pts = vtkSmartPointer<vtkPoints>::New(); pts->InsertNextPoint(0.0, 0.0, 0.0); pts->InsertNextPoint(1.0, 0.0, 0.0); pts->InsertNextPoint(1.0, 1.0, 0.0); pts->InsertNextPoint(0.0, 1.0, 0.0); pts->InsertNextPoint(2.0, 0.0, 0.0); //拓扑结构数据:正四边形 vtkSmartPointer<vtkPolygon> polygon = vtkSmartPointer<vtkPolygon>::New(); polygon->GetPointIds()->SetNumberOfIds(4); polygon->GetPointIds()->SetId(0, 0); polygon->GetPointIds()->SetId(1, 1); polygon->GetPointIds()->SetId(2, 2); polygon->GetPointIds()->SetId(3, 3); //拓扑结构数据:三角形 vtkSmartPointer<vtkTriangle> triangle = vtkSmartPointer<vtkTriangle>::New(); triangle->GetPointIds()->SetId(0, 1); triangle->GetPointIds()->SetId(1, 2); triangle->GetPointIds()->SetId(2, 4); //构成拓扑结构集合 vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New(); cells->InsertNextCell(polygon); cells->InsertNextCell(triangle); //合成几何拓扑结构用于显示 vtkSmartPointer<vtkPolyData> polygonPolyData = vtkSmartPointer<vtkPolyData>::New(); polygonPolyData->SetPoints(pts); polygonPolyData->SetPolys(cells); //添加属性结构 unsigned char red[3] = {
255, 0, 0 }; unsigned char green[3] = {
0, 255, 0 }; unsigned char blue[3] = {
0, 0, 255 }; vtkSmartPointer<vtkUnsignedCharArray> ptColor = vtkSmartPointer<vtkUnsignedCharArray>::New(); ptColor->SetNumberOfComponents(3); ptColor->InsertNextTypedTuple(red); ptColor->InsertNextTypedTuple(green); ptColor->InsertNextTypedTuple(blue); ptColor->InsertNextTypedTuple(red); ptColor->InsertNextTypedTuple(green); polygonPolyData->GetPointData()->SetScalars(ptColor); vtkSmartPointer<vtkUnsignedCharArray> cellColor = vtkSmartPointer<vtkUnsignedCharArray>::New(); cellColor->SetNumberOfComponents(3); cellColor->InsertNextTypedTuple(blue); cellColor->InsertNextTypedTuple(red); polygonPolyData->GetCellData()->SetScalars(cellColor); vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputData(polygonPolyData); vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); actor->SetMapper(mapper); vtkSmartPointer<vtkRenderer> render = vtkSmartPointer<vtkRenderer>::New(); render->AddActor(actor); render->SetBackground(0.0, 0.0, 0.0); vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New(); rw->AddRenderer(render); rw->SetSize(320, 240); rw->SetWindowName("Creating PolyData Structure"); vtkSmartPointer<vtkRenderWindowInteractor> rwi = vtkSmartPointer<vtkRenderWindowInteractor>::New(); rwi->SetRenderWindow(rw); rwi->Render(); rwi->Start(); return 0; }
运行截图
标量数据和向量数据的区别
向量数据具有方向和模;而标量数据不具有。如果一个数据(可以是但组分、也可以是多组分)经过一个集合变换后保持不变,那么数据是一个标量,例如我们所说的颜色属性。然而,对于法向量,该数据同样有三个组分,却是一个矢量数据,因为法向量经过集合变换后(如图形的旋转)会发生变化。因此不能简单的通过组分的个数来区分标量数据或矢量数据。在对属性数据进行赋值时,也要分清数据还是矢量数据,不能将两者混淆,例如将颜色数据设置为矢量数据,那么在对图像数据进行几何变换后,颜色数据会发生变化。
2.单元的标量数据和矢量属性数据设置
默认情况下,VTKPolyDataMapper会使用一个Unsinged char类型的三元组作为颜色值进行渲染。但很多情况下,模型颜色是通过属性数据获取的,比如根据标量数据在颜色查找表中获取相应的颜色。 实例:主要演示怎样添加单元的标量数据和向量属性数据。 vtkPlaneSource定义一个3*3的网格数据。cellScalar定义了vtkFloatArray类型的标量数据,默认情况下其元组的大小为1,因此不需要显示指定其大小;cellVetor则定义了vtkFloatArray类型的矢量数据,通过SetNumberOfComponents()指定向量维数为3,并通过InsertNextTuple3()方便地插入向量数据。 定义完毕后,VTKPolyData的单元数据(VTKCellData)调用函数SetScalars()和SetVetors()设置相应的属性数据和标量数据。 为了演示利用标量数据进行颜色映射,定义了一个具有10个颜色的颜色映射表。利用vtkPolyDataMapper类的SetLookupTable()函数设定的颜色映射表。另外,需要注意的是,SetScalarRange()指定颜色映射范围的最小值和最大值,当标量值大于最大值时,按定义最大值获取颜色。当小于最小值时,按照指定的最小值获取颜色。这样做的一个好处,可以在一个小的标量范围内显示更所的颜色。
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkPlaneSource.h>
#include <vtkPolyData.h>
#include <vtkFloatArray.h>
#include <vtkCellData.h>
#include <vtkLookupTable.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
int main()
{
//定义一个3*3的网格数据
vtkSmartPointer<vtkPlaneSource> gridSource =
vtkSmartPointer<vtkPlaneSource>::New();
gridSource->SetXResolution(3);
gridSource->SetYResolution(3);
gridSource->Update();
vtkSmartPointer<vtkPolyData> grid = gridSource->GetOutput();
//标量属性
vtkSmartPointer<vtkFloatArray> cellScalars =
vtkSmartPointer<vtkFloatArray>::New();
//矢量属性
vtkSmartPointer<vtkFloatArray> cellVector =
vtkSmartPointer<vtkFloatArray>::New();
cellVector->SetNumberOfComponents(3);//指定向量的维数为3
//设置属性
for (int i = 0; i < 9; i++)
{
cellScalars->InsertNextValue(i + 1); //九个索引
cellVector->InsertNextTuple3(0.0, 0.0, 1.0);
}
grid->GetCellData()->SetScalars(cellScalars);
grid->GetCellData()->SetVectors(cellVector);
vtkSmartPointer<vtkLookupTable> lut =
vtkSmartPointer<vtkLookupTable>::New();
lut->SetNumberOfTableValues(10);
lut->Build();
lut->SetTableValue(0, 0, 0, 0, 1);
lut->SetTableValue(1, 0.8900, 0.8100, 0.3400, 1);
lut->SetTableValue(2, 1.0000, 0.3882, 0.2784, 1);
lut->SetTableValue(3, 0.9608, 0.8706, 0.7020, 1);
lut->SetTableValue(4, 0.9020, 0.9020, 0.9804, 1);
lut->SetTableValue(5, 1.0000, 0.4900, 0.2500, 1);
lut->SetTableValue(6, 0.5300, 0.1500, 0.3400, 1);
lut->SetTableValue(7, 0.9804, 0.5020, 0.4471, 1);
lut->SetTableValue(8, 0.7400, 0.9900, 0.7900, 1);
lut->SetTableValue(9, 0.2000, 0.6300, 0.7900, 1);
//
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(grid);
mapper->SetScalarRange(0, 9);
mapper->SetLookupTable(lut);
//
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkRenderer> render =
vtkSmartPointer<vtkRenderer>::New();
render->AddActor(actor);
render->SetBackground(0.0, 0.0, 0.0);
vtkSmartPointer<vtkRenderWindow> rw =
vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(render);
rw->SetSize(320, 320);
rw->SetWindowName("Setting Attribution of Vectors and Scalars");
vtkSmartPointer<vtkRenderWindowInteractor> rwi =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(rw);
rwi->Start();
return 0;
}