1.從圖形着色說起
前一個實驗顯示結果中的圖像是白色的,而圖形顏色與vtkPolyData屬性數據息息相關。由於並未指定任何顏色和屬性數據,因此在顯示時默認以白色顯示。屬性數據包括點屬性和單元屬性。可以為vtkPolyData的點數據和單元數據分別指定屬性數據。屬性數據可以是標量,如點的曲率;可以是向量,如點或者單元的法向量;也可以是張量,主要在流場中較為常見。顏色可以直接作為一種標量屬性數據,設置到相應的點或者單元數據中,這也是最直接的一種圖形着色方式。下面的實例代碼僅是對上例圖形進行着色:1 #include <vtkAutoInit.h> 2 VTK_MODULE_INIT(vtkRenderingOpenGL); 3 4 #include <vtkSmartPointer.h> 5 #include <vtkPoints.h> 6 #include <vtkPolygon.h> 7 #include <vtkTriangle.h> 8 #include <vtkCellArray.h> 9 #include <vtkPolyData.h> 10 #include <vtkUnsignedCharArray.h> //Attribution 11 #include <vtkPointData.h> 12 #include <vtkCellData.h> 13 /// 14 #include <vtkPolyDataMapper.h> 15 #include <vtkActor.h> 16 #include <vtkRenderer.h> 17 #include <vtkRenderWindow.h> 18 #include <vtkRenderWindowInteractor.h> 19 20 int main() 21 { 22 //幾何結構數據:點集 23 vtkSmartPointer<vtkPoints> pts = 24 vtkSmartPointer<vtkPoints>::New(); 25 pts->InsertNextPoint(0.0, 0.0, 0.0); 26 pts->InsertNextPoint(1.0, 0.0, 0.0); 27 pts->InsertNextPoint(1.0, 1.0, 0.0); 28 pts->InsertNextPoint(0.0, 1.0, 0.0); 29 pts->InsertNextPoint(2.0, 0.0, 0.0); 30 //拓撲結構數據:正四邊形 31 vtkSmartPointer<vtkPolygon> polygon = 32 vtkSmartPointer<vtkPolygon>::New(); 33 polygon->GetPointIds()->SetNumberOfIds(4); 34 polygon->GetPointIds()->SetId(0, 0); 35 polygon->GetPointIds()->SetId(1, 1); 36 polygon->GetPointIds()->SetId(2, 2); 37 polygon->GetPointIds()->SetId(3, 3); 38 //拓撲結構數據:三角形 39 vtkSmartPointer<vtkTriangle> triangle = 40 vtkSmartPointer<vtkTriangle>::New(); 41 triangle->GetPointIds()->SetId(0, 1); 42 triangle->GetPointIds()->SetId(1, 2); 43 triangle->GetPointIds()->SetId(2, 4); 44 //構成拓撲結構集合 45 vtkSmartPointer<vtkCellArray> cells = 46 vtkSmartPointer<vtkCellArray>::New(); 47 cells->InsertNextCell(polygon); 48 cells->InsertNextCell(triangle); 49 //合成幾何拓撲結構用於顯示 50 vtkSmartPointer<vtkPolyData> polygonPolyData = 51 vtkSmartPointer<vtkPolyData>::New(); 52 polygonPolyData->SetPoints(pts); 53 polygonPolyData->SetPolys(cells); 54 55 //添加屬性結構 56 unsigned char red[3] = { 255, 0, 0 }; 57 unsigned char green[3] = { 0, 255, 0 }; 58 unsigned char blue[3] = { 0, 0, 255 }; 59 vtkSmartPointer<vtkUnsignedCharArray> ptColor = 60 vtkSmartPointer<vtkUnsignedCharArray>::New(); 61 ptColor->SetNumberOfComponents(3); 62 ptColor->InsertNextTupleValue(red); 63 ptColor->InsertNextTupleValue(green); 64 ptColor->InsertNextTupleValue(blue); 65 ptColor->InsertNextTupleValue(red); 66 ptColor->InsertNextTupleValue(green); 67 polygonPolyData->GetPointData()->SetScalars(ptColor); 68 69 vtkSmartPointer<vtkUnsignedCharArray> cellColor = 70 vtkSmartPointer<vtkUnsignedCharArray>::New(); 71 cellColor->SetNumberOfComponents(3); 72 cellColor->InsertNextTupleValue(blue); 73 cellColor->InsertNextTupleValue(red); 74 polygonPolyData->GetCellData()->SetScalars(cellColor); 75 76 vtkSmartPointer<vtkPolyDataMapper> mapper = 77 vtkSmartPointer<vtkPolyDataMapper>::New(); 78 mapper->SetInputData(polygonPolyData); 79 80 vtkSmartPointer<vtkActor> actor = 81 vtkSmartPointer<vtkActor>::New(); 82 actor->SetMapper(mapper); 83 84 vtkSmartPointer<vtkRenderer> render = 85 vtkSmartPointer<vtkRenderer>::New(); 86 render->AddActor(actor); 87 render->SetBackground(0.0, 0.0, 0.0); 88 89 vtkSmartPointer<vtkRenderWindow> rw = 90 vtkSmartPointer<vtkRenderWindow>::New(); 91 rw->AddRenderer(render); 92 rw->SetSize(320, 240); 93 rw->SetWindowName("Creating PolyData Structure"); 94 95 vtkSmartPointer<vtkRenderWindowInteractor> rwi = 96 vtkSmartPointer<vtkRenderWindowInteractor>::New(); 97 rwi->SetRenderWindow(rw); 98 rwi->Render(); 99 rwi->Start(); 100 101 return 0; 102 }
該示例代碼繼承了上一節中的vtkPolyData數據。定義了兩個vtkUnsignedCharArray對象ptColor和cellColor,分別為點和單元設置顏色數據。vtkUnsignedCharArray對象實際上為一個Unsigned char類型的數組。SetNumberOfComponents()函數指定了該數組中每個元組的大小。由於每個顏色是由RGB三個顏色分量組成。因此設置元組大小為3。InsertNextTupleValue()函數可以順序插入元組數據。由於要為點集設置顏色,因此顏色數目要與點數保持一致。對於單元的顏色數據設置同樣需要注意,有多少個單元,就要設置多少個顏色。設置點的顏色時,需要通過GetPointData()函數獲取vtkPointData類型的點數據指針,然后通過SetScalar()函數設置顏色數據。顯示結果如下所示,從圖中可以看出,在進行顏色渲染時,使用的是點的顏色,而不是單元的顏色!
根據之前的內容,我們知道:點數據和單元的屬性數據是分別存儲在VTKPointData和VTKCellData中的。在這里,我們還是要着重區分一下標量屬性數據和向量屬性數據的區別:向量數據具有方向和模;而標量數據不具有。如果一個數據(可以是單組分、也可以是多組分)經過一個幾何變換后保持不變,那么該數據是一個標量,例如我們說的顏色屬性。然而,對於法向量,該數據同樣有三個組分,卻是一個矢量屬性,因為法向量經過幾何變換后(如圖像旋轉)會發生改變。因此不能簡單滴通過組分的個數來區分標量數據或者矢量數據。在對屬性數據進行賦值時,也要分清標量數據還是矢量數據,不能將兩者混淆,例如將顏色數據設置為矢量數據,那么在對圖像數據進行幾何變換后,顏色數據會發生改變。
2. 單元的標量屬性和矢量屬性數據設置
默認情況下,vtkPolyDataMapper會使用一個unsigned char類型的三元數組作為顏色值進行渲染。但是在很多情況下,模型顏色是通過屬性數據獲取的,比如根據標量數據在顏色查找表中獲取相應的顏色。1 #include <vtkAutoInit.h> 2 VTK_MODULE_INIT(vtkRenderingOpenGL); 3 4 #include <vtkSmartPointer.h> 5 #include <vtkPlaneSource.h> 6 #include <vtkPolyData.h> 7 #include <vtkFloatArray.h> 8 #include <vtkCellData.h> 9 #include <vtkLookupTable.h> 10 #include <vtkPolyDataMapper.h> 11 #include <vtkActor.h> 12 #include <vtkRenderer.h> 13 #include <vtkRenderWindow.h> 14 #include <vtkRenderWindowInteractor.h> 15 16 int main() 17 { 18 vtkSmartPointer<vtkPlaneSource> gridSource = 19 vtkSmartPointer<vtkPlaneSource>::New(); 20 gridSource->SetXResolution(3); 21 gridSource->SetYResolution(3); 22 gridSource->Update(); 23 24 vtkSmartPointer<vtkPolyData> grid = gridSource->GetOutput(); 25 //標量屬性 26 vtkSmartPointer<vtkFloatArray> cellScalars = 27 vtkSmartPointer<vtkFloatArray>::New(); 28 //矢量屬性 29 vtkSmartPointer<vtkFloatArray> cellVector = 30 vtkSmartPointer<vtkFloatArray>::New(); 31 cellVector->SetNumberOfComponents(3); 32 //設置屬性 33 for (int i = 0; i < 9; i++) 34 { 35 cellScalars->InsertNextValue(i + 1); //九個索引 36 cellVector->InsertNextTuple3(0.0, 0.0, 1.0); 37 } 38 39 grid->GetCellData()->SetScalars(cellScalars); 40 grid->GetCellData()->SetVectors(cellVector); 41 42 vtkSmartPointer<vtkLookupTable> lut = 43 vtkSmartPointer<vtkLookupTable>::New(); 44 lut->SetNumberOfTableValues(10); 45 lut->Build(); 46 lut->SetTableValue(0, 0, 0, 0, 1); 47 lut->SetTableValue(1, 0.8900, 0.8100, 0.3400, 1); 48 lut->SetTableValue(2, 1.0000, 0.3882, 0.2784, 1); 49 lut->SetTableValue(3, 0.9608, 0.8706, 0.7020, 1); 50 lut->SetTableValue(4, 0.9020, 0.9020, 0.9804, 1); 51 lut->SetTableValue(5, 1.0000, 0.4900, 0.2500, 1); 52 lut->SetTableValue(6, 0.5300, 0.1500, 0.3400, 1); 53 lut->SetTableValue(7, 0.9804, 0.5020, 0.4471, 1); 54 lut->SetTableValue(8, 0.7400, 0.9900, 0.7900, 1); 55 lut->SetTableValue(9, 0.2000, 0.6300, 0.7900, 1); 56 // 57 vtkSmartPointer<vtkPolyDataMapper> mapper = 58 vtkSmartPointer<vtkPolyDataMapper>::New(); 59 mapper->SetInputData(grid); 60 mapper->SetScalarRange(0, 9); 61 mapper->SetLookupTable(lut); 62 // 63 vtkSmartPointer<vtkActor> actor = 64 vtkSmartPointer<vtkActor>::New(); 65 actor->SetMapper(mapper); 66 67 vtkSmartPointer<vtkRenderer> render = 68 vtkSmartPointer<vtkRenderer>::New(); 69 render->AddActor(actor); 70 render->SetBackground(0.0, 0.0, 0.0); 71 72 vtkSmartPointer<vtkRenderWindow> rw = 73 vtkSmartPointer<vtkRenderWindow>::New(); 74 rw->AddRenderer(render); 75 rw->SetSize(320, 320); 76 rw->SetWindowName("Setting Attribution of Vectors and Scalars"); 77 78 vtkSmartPointer<vtkRenderWindowInteractor> rwi = 79 vtkSmartPointer<vtkRenderWindowInteractor>::New(); 80 rwi->SetRenderWindow(rw); 81 rwi->Start(); 82 83 return 0; 84 }
這個實例主要演示了怎樣添加單元的標量屬性數據和向量屬性數據。VTKPlaneSource定義了一個3*3的網格數據。cellScalars定義了vtkFloatArray類型的標量屬性數據,默認情況下其元組大小為1,因此不需要顯示指定其大小;cellVectors則定義了vtkFloatArray類型的矢量屬性數組,通過SetNumberOfComponents()指定向量維數為3,並通過InsertNextTuple3()可以方便地插入向量數據。定義完畢后,vtkPolyData的單元數據(VTKCellData)通過調用函數SetScalars()和SetVectors()設置相應的屬性數據和標量數據。為了進一步演示利用標量數據進行顏色映射,定義了一個具有10個顏色的顏色映射表。利用vtkPolyDataMapper類的SetLookupTable()函數設置定義的顏色映射表。另外,需要注意的是,SetScalarRange()指定了顏色映射范圍的最小值和最大值,當標量值大於最大值時,按定義最大值獲取顏色;當小魚最小值時,按照指定的最小值獲取顏色。這樣做的一個好處是,可以在一個小的標量范圍內顯示更多的顏色!!!該例的輸出結果為:
![]()