一个稍微复杂的VTK程序
3、VTK基礎(chǔ)概念
在第2章里,我們已經(jīng)接觸了一個簡單的VTK工程,也掌握了怎么使用CMake來構(gòu)建VTK工程的步驟,本書后續(xù)章節(jié)的所有例子都是采用第2章介紹的步驟來構(gòu)建VTK的工程。
本章我們先在第2章TestVTKInstall的基礎(chǔ)上作一些更改,演示一個能夠交互的VTK應(yīng)用程序。與前面的風格類似,我們先是讓你“知其然”,然后再慢慢地讓你“知其所以然”。
3.1 一個稍微復(fù)雜的VTK程序
首先當然是寫一個CMakeLists.txt文件。在D:\Toolkits\VTK\Examples\下新建一個文件夾,名為3.1.1_RenderCylinder,在該目錄下新建CMakeLists.txt和RenderCylinder.cpp文件。
?
| 示例3.1.1_RenderCylinder的CMakeLists.txt |
?? 1:?cmake_minimum_required(VERSION 2.8)
?? 2:?project(RenderCylinder)
?? 3:?find_package(VTK REQUIRED)
?? 4:?include(${VTK_USE_FILE})
?? 5:?add_executable(${PROJECT_NAME} RenderCylinder.cpp)
?? 6:?target_link_libraries(${PROJECT_NAME} ${VTK_LIBRARIES})
?
| 示例3.1.1_RenderCylinder |
1:? #include "vtkSmartPointer.h"
?? 2:?#include "vtkRenderWindow.h"
?? 3:?#include "vtkRenderer.h"
?? 4:?#include "vtkRenderWindowInteractor.h"
?? 5:?#include "vtkInteractorStyleTrackballCamera.h"
?? 6:?#include "vtkCylinderSource.h"
?? 7:?#include "vtkPolyDataMapper.h"
?? 8:?#include "vtkActor.h"
?? 9:??
? 10:?int ??main()
? 11:? {
? 12:???vtkSmartPointer<vtkCylinderSource> cylinder =
? 13:?????vtkSmartPointer<vtkCylinderSource>::New();
? 14:???cylinder->SetHeight( 3.0 );
? 15:???cylinder->SetRadius( 1.0 );
? 16:???cylinder->SetResolution( 10 );
? 17:???
? 18:???vtkSmartPointer<vtkPolyDataMapper> cylinderMapper =
? 19:?????vtkSmartPointer<vtkPolyDataMapper>::New();
? 20:???cylinderMapper->SetInputConnection( cylinder->GetOutputPort() );
? 21:??
? 22:???vtkSmartPointer<vtkActor> cylinderActor =
? 23:?????vtkSmartPointer<vtkActor>::New();
? 24:???cylinderActor->SetMapper( cylinderMapper );
? 25:??
? 26:???vtkSmartPointer<vtkRenderer> renderer =
? 27:?????vtkSmartPointer<vtkRenderer>::New();
? 28:???renderer->AddActor( cylinderActor );
? 29:???renderer->SetBackground( 0.1, 0.2, 0.4 );
? 30:??
? 31:???vtkSmartPointer<vtkRenderWindow> renWin =
? 32:?????vtkSmartPointer<vtkRenderWindow>::New();
? 33:???renWin->AddRenderer( renderer );
? 34:???renWin->SetSize( 300, 300 );
? 35:??
? 36:???vtkSmartPointer<vtkRenderWindowInteractor> iren =
? 37:?????vtkSmartPointer<vtkRenderWindowInteractor>::New();
? 38:???iren->SetRenderWindow(renWin);
? 39:??
? 40:???vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
? 41:?????vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
? 42:???iren->SetInteractorStyle(style);
? 43:??
? 44:???iren->Initialize();
? 45:???iren->Start();
? 46:??
? 47:???return 0;
? 48:? }
?
跟上一章的步驟一樣,運行CMake –> Configure –> Generate。接著打開生成的RenderCylinder.sln文件,F7編譯,F5調(diào)試運行(這些快捷鍵可能不同版本的VS不太一樣,也可以用菜單來操作,這個步驟在本書后續(xù)章節(jié)將不再贅述),程序運行結(jié)果如圖3.1所示。
圖3.1 示例3.1.1_RenderCylinder的運行結(jié)果
可以使用鼠標與柱體(圖3.1)交互,比如用鼠標滾輪可以對柱體放大、縮小;按下鼠標左鍵不放,然后移動鼠標,可以轉(zhuǎn)動柱體;按下鼠標左鍵,同時按下Shift鍵,移動鼠標,可以移動整個柱體,等等。其他的功能你也可以試著摸索一下,比如按下Ctrl鍵時再按鼠標左鍵;鼠標停留在柱體上,然后按下P鍵;試著按一下字母E呢?
接下來我們詳細解釋一下示例3.1.1_RenderCylinder里每行代碼的含義以及所用到的VTK的類。從包含的頭文件可以看出,除了vtkSmartPointer和vtkRenderWindow在第2章已經(jīng)介紹過,其他6個類都是新加入的。
(1)???vtkCylinderSource:(第12-16行),派生自vtkPolyDataAlgorithm。顧名思義,vtkCylinderSource生成的數(shù)據(jù)類型就是PolyData(vtkPolyData)的,它主要是生成一個中心在渲染場景原點的柱體,柱體的長軸沿著Y軸,柱體的高度、截面半徑等都可以任意指定。
vtkCylinderSource::SetHeight() ——設(shè)置柱體的高。
vtkCylinderSource::SetRadius() ——設(shè)置柱體橫截面的半徑。
vtkCylinderSource::SetResolution() ——設(shè)置柱體橫截面的等邊多邊形的邊數(shù)。轉(zhuǎn)動一下柱體,然后數(shù)數(shù)柱體橫截面有多少條邊,應(yīng)該就能明白這個參數(shù)表示什么意思。
(2)??vtkPolyDataMapper:(第18-20行),渲染多邊形幾何數(shù)據(jù)(vtkPolyData),派生自類vtkMapper,將輸入的數(shù)據(jù)轉(zhuǎn)換為幾何圖元(點、線、多邊形)進行渲染。
vtkPolyDataMapper::SetInputConnection() —— VTK可視化管線的輸入數(shù)據(jù)接口,對應(yīng)的可視化管線輸出數(shù)據(jù)的接口為GetOutputPort();VTK5.0之前的版本使用SetInput()和GetOutput()作為輸入輸出接口,VTK 5.0以后版本保留了對這兩個接口的支持。關(guān)于這兩者的區(qū)別,后續(xù)內(nèi)容會詳細介紹。
(3)???vtkActor:(第22-24行),派生自vtkProp類,渲染場景中數(shù)據(jù)的可視化表達是通過vtkProp的子類負責的。比如,本例要渲染一個柱體,柱體的數(shù)據(jù)類型是vtkPolyData,數(shù)據(jù)要在場景中渲染時,不是直接把數(shù)據(jù)加入渲染場景就可以,待渲染的數(shù)據(jù)是以vtkProp的形式存在于渲染場景中。三維空間中渲染對象最常用的vtkProp子類是vtkActor(表達場景中的幾何數(shù)據(jù))和vtkVolume(表達場景中的體數(shù)據(jù));二維空間中的數(shù)據(jù)則是用vtkActor2D表達。vtkProp子類負責確定渲染場景中對象的位置、大小和方向信息。Prop依賴于兩個對象(Prop一詞來源于戲劇里的“道具”,在VTK里表示的是渲染場景中可以看得到的對象。),一個是Mapper(vtkMapper)對象,負責存放數(shù)據(jù)和渲染信息,另一個是屬性(vtkProperty)對象,負責控制顏色、不透明度等參數(shù)。
VTK中定義了大量(超過50個)的Prop類,如vtkImageActor(負責圖像顯示)和vtkPieChartActor(用于創(chuàng)建數(shù)組數(shù)據(jù)的餅圖可視化表達)。其中的一些Prop內(nèi)部直接包括了控制顯示的參數(shù)和待渲染數(shù)據(jù)的索引,因此并不需要額外的Property和Mapper對象。vtkActor的子類vtkFollower可以自動的更新方向信息以保持始終面向一個特定的相機。這樣無論怎樣旋轉(zhuǎn),三維場景中的廣告板(Billboards)或者文本都是可見的。vtkActor的子類vtkLODActor可以自動改變自身的幾何表達來實現(xiàn)需要達到的交互幀率。vtkProp3D的子類vtkLODProp3D則是通過從許多Mapper(可以是體數(shù)據(jù)的Mapper和幾何數(shù)據(jù)的Mapper集合)中進行選擇來實現(xiàn)交互。vtkAssembly建立Actor的等級結(jié)構(gòu)以便在整個結(jié)構(gòu)平移、旋轉(zhuǎn)或者縮放時能夠更合理的控制變換。
vtkActor::SetMapper()——設(shè)置生成幾何圖元的Mapper。即連接一個Actor到可視化管線的末端(可視化管線的末端就是Mapper)。
(4)???vtkRenderWindow:(第31-34行),將操作系統(tǒng)與VTK渲染引擎連接到一起。不同平臺下的vtkRenderWindow子類負責本地計算機系統(tǒng)中窗口創(chuàng)建和渲染過程管理。當使用VTK開發(fā)應(yīng)用程序時,你只需要使用平臺無關(guān)的vtkRendererWindow類,運行時,系統(tǒng)會自動替換為平臺相關(guān)的vtkRendererWindow子類。比如,Windows下運行上述的VTK程序,實際創(chuàng)建的是vtkWin32OpenGLRenderWindow(vtkRenderWindow的子類)對象。vtkRenderWindow中包含了vtkRenderer集合、渲染參數(shù),如立體顯示(Stereo),反走樣,運動模糊(Motion Blur)和焦點深度(Focal Depth)等。
vtkRenderWindow::AddRenderer() ——加入vtkRenderer對象。
vtkRenderWindow::SetSize() ——該方法是從vtkRenderWindow的父類vtkWindow繼承過來的,用于設(shè)置窗口的大小,以像素為單位。
(5)???vtkRenderer:(第26-29行),負責管理場景的渲染過程。組成場景的所有對象包括Prop,照相機(Camera)和光照(Light)都被集中在一個vtkRenderer對象中。一個vtkRenderWindow中可以有多個vtkRenderer對象,而這些vtkRenderer可以渲染在窗口中不同的矩形區(qū)域中(即視口),或者覆蓋整個窗口區(qū)域。
vtkRenderer::AddActor() ——添加vtkProp類型的對象到渲染場景中。
vtkRenderer::SetBackground() ——該方法是從vtkRenderer的父類vtkViewport繼承的,用于設(shè)置渲染場景的背景顏色,用R、G、B的格式設(shè)置,三個分量的取值為0.0~ 1.0。(0.0,0.0, 0.0)為黑色,(1.0,1.0, 1.0)為白色。除了可以設(shè)置單一的背景顏色之外,還可以設(shè)置漸變的背景顏色,vtkViewport::SetBackground2()用于設(shè)置漸變的另外一種顏色,但是要使背景顏色漸變生效或者關(guān)閉,必須調(diào)用以下的方法:
vtkViewport::SetGradientBackground(bool) ——參數(shù)為0是關(guān)閉,反之,打開。
vtkViewport::GradientBackgroundOn()—— 打開背景顏色漸變效果,相當于調(diào)用方法SetGradientBackground(1)。
vtkViewport::GradientBackgroundOff() ——關(guān)閉背景顏色漸變效果。相當于調(diào)用方法SetGradientBackground(0)。
(6)???vtkRenderWindowInteractor:(第36-38行),提供平臺獨立的響應(yīng)鼠標、鍵盤和時鐘事件的交互機制,通過VTK的Command/Observer設(shè)計模式將監(jiān)聽到的特定平臺的鼠標、鍵盤和時鐘事件交由vtkInteractorObserver或其子類,如vtkInteractorStyle進行處理。vtkInteractorStyle等監(jiān)聽這些消息并進行處理以完成旋轉(zhuǎn)、拉伸和放縮等運動控制。vtkRenderWindowInteractor自動建立一個默認的3D場景交互器樣式(Interactor Style):vtkInteractorStyleSwitch,當然你也可以選擇其他的交互器樣式,或者是創(chuàng)建自己的交互器樣式。在本例中,我們就是選擇了其他的交互器樣式來替代默認的:vtkInteractorStyleTrackballCamera。
vtkRenderWindowInteractor::SetRenderWindow()——設(shè)置渲染窗口,消息是通過渲染窗口捕獲到的,所以必須要給交互器對象設(shè)置渲染窗口。
vtkRenderWindowInteractor::SetInteractorStyle()——定義交互器樣式,默認的交互樣式為vtkInteractorStyleSwitch。
vtkRenderWindowInteractor::Initialize() ——為處理窗口事件做準備,交互器工作之前必須先調(diào)用這個方法進行初始化。
vtkRenderWindowInteractor::Start() ——開始進入事件響應(yīng)循環(huán),交互器處于等待狀態(tài),等待用戶交互事件的發(fā)生。進入事件響應(yīng)循環(huán)之前必須先調(diào)用Initialize()方法。
(7)???vtkInteractorStyleTrackballCamera:(第40-41行),交互器樣式的一種,該樣式下,用戶是通過控制相機對物體作旋轉(zhuǎn)、放大、縮小等操作。做個類比:我們在照相的時候如果要想物體看起來顯得大一些,我們可以采取兩種做法,第一種做法是相機不動,讓我們要拍的物體靠近我們;第二種做法是物體不要動,我們把相機靠近物體,這樣物體看起來也是大一些。第二種做法就是vtkInteractorStyleTrackballCamera的風格。其父類為vtkInteractorStyle,除了vtkInteractorStyleTrackballCamera之外,VTK還定義了其他多種交互器樣式,如vtkInteractorStyleImage,主要用于顯示二維圖像時的交互。
以上內(nèi)容我們是逐行代碼進行解釋,并稍微做了擴展。可能你看了以后會覺得比較零散,還是不夠系統(tǒng)、全面。下面我們就從稍微宏觀的角度重新看看這個例子的代碼。繼續(xù)下面的內(nèi)容之前,我們先來看一個類比,可能沒有你想的形象,但它對我們理解例子的代碼還是會有幫助的。
當我們?nèi)タ次枧_劇的時候,我們坐在臺下,展現(xiàn)在我們面前的是一個舞臺,舞臺上有各式的燈光,各樣的演員。演員出場的時候肯定是會先化妝,有些演員可能會打扮成高富帥,有些演員可能會化妝成白富美。觀眾有時還會與臺上的演員有一定的互動。
整個劇院就好比VTK程序的渲染窗口(vtkRenderWindow);舞臺就相當于渲染場景(vtkRenderer);而那些高富帥、白富美就是我們程序中的Actor(有些文獻翻譯成“演員”,有些翻譯成“角色”,這里我們不作翻譯);臺上的演員與臺下觀眾的互動可以看成是程序的交互(vtkRenderWindowInteractor);演員與觀眾的互動方式有很多種,現(xiàn)場的觀眾可以直接上臺跟演員們握手擁抱,電視機前的可以發(fā)短信,電腦、移動終端用戶等可以微博關(guān)注、加粉等等,這就好比我們程序里的交互器樣式(vtkInteractorStyle);舞臺上的演員我們都能一一分辨出來,不會把高富帥弄混淆,是因為他們化的妝、穿的服飾都不一樣,這就相當于我們程序里vtkActor的不同屬性(vtkProperty);臺下觀眾的眼睛可以看作是vtkCamera,前排的觀眾因為離得近,看臺上演員會顯得比較高大,而后排的觀眾看到的會顯得小點,每個觀眾看到的東西在他的世界里都是唯一的,所以渲染場景Renderer里的vtkCamera對象也是只有一個;舞臺上的燈光可以有多個,所以渲染場景里的vtkLight也存在多個。可以參考一下圖3.2,加深理解。
圖3.2VTK渲染場景以及各主要對象
3.2 vtkActor及相關(guān)屬性
由前面的內(nèi)容我們知道,數(shù)據(jù)渲染時不是直接加入渲染場景,而是以vtkProp的形式存在的,因此有必要再詳細討論一下vtkProp及其子類,圖3.3為vtkProp類的繼承圖。
圖3.3 類vtkProp的繼承圖
3.2.1vtkProp和vtkProp3D
vtkProp是任何存在于渲染窗口的對象的父類,包括二維或者三維的對象。換言之,在渲染窗口里能夠看得到的對象(這些對象都稱作Prop),都是從vtkProp繼承過來的。在這個類里定義了用于拾取(Picking)、LOD(Level-Of-Detail)操作的方法,同時也定義了確定Prop是否可見、可否被拾取以及可否被拖動等的變量。即:
?
SetVisibility(int) / GetVisibility () /VisibilityOn () /VisibilityOff ()
Pick () / SetPickable (int) / GetPickable () / PickableOn() / PickableOff ()
SetDragable (int) / GetDragable () / DragableOn () /DragableOff()
?
vtkProp3D從vtkProp直接派生,是對象在三維渲染場景中的表達形式。把一個對象放置在三維場景時,首先要考慮的是這個對象到底要放在場景中的哪個位置,擺放的方向如何等等,這些信息在vtkProp3D內(nèi)部用一個4×4的矩陣來表示。默認構(gòu)造的vtkProp3D對象原點為(0,0,0),放置的位置為(0,0,0),放置的方向為(0,0,0),用戶自定義的矩陣或者變換為空。以下是vtkProp3D定義的用于放置vtkProp3D對象的方法:
l? SetScale (double) / GetScale ():設(shè)置/獲取各向同性的縮放比例。
l? SetScale (double, double,double) / GetScale (double):設(shè)置/獲取各同異性的縮放比例。
l? RotateX (double) / RotateY (double) / RotateZ (double):分別繞X、Y、Z軸旋轉(zhuǎn)指定角度。
l? RotateWXYZ (double, double,double, double):繞指定的方向旋轉(zhuǎn)指定的角度,第一個參數(shù)表示旋轉(zhuǎn)角度,后三個參數(shù)確定一個方向。GetOrientationWXYZ()用于獲取對應(yīng)的數(shù)據(jù)。
l? SetOrientation (double, double,double) / GetOrientation ():設(shè)置vtkProp3D對象的方向。先繞Z軸旋轉(zhuǎn),然后繞X軸,最后繞Y軸旋轉(zhuǎn),從而確定vtkProp3D對象的方向。
l? AddOrientation (double, double,double):在vtkProp3D對象的當前方向增加一個給
定的偏移。
l? SetPosition (double, double,double) / GetPosition ():在世界坐標系下,指定/獲取vtkProp3D對象的位置。
l? AddPosition (double, double,double):在vtkProp3D對象的當前位置增加一個偏移。
l? SetOrigin (double, double,double ) / GetOrigin ():設(shè)置/獲取vtkProp3D對象的原點。
3.2.2vtkActor及其屬性
前面的內(nèi)容已經(jīng)提到:Prop依賴于兩個對象,一個是Mapper(vtkMapper)對象,負責存放數(shù)據(jù)和渲染信息,另一個是屬性(vtkProperty)對象,負責控制顏色、不透明度等參數(shù)。對應(yīng)的這兩個方法就是在類vtkActor里定義的:
l? SetMapper (vtkMapper *):設(shè)置定義Actor幾何形狀的Mapper。
l? SetProperty (vtkProperty *):設(shè)置Actor的屬性,包括表面屬性,如環(huán)境光(Ambient)、散射光(Diffuse)、鏡面光(Specular)、顏色、透明度等;紋理映射;點的大小,線的寬度設(shè)置等。每一個Actor都有一個屬性對象(vtkProperty的實例)與之相關(guān)聯(lián),如果沒有給Acttor指定相應(yīng)的屬性(3.1.1的例子就沒有指定),VTK會指定默認的屬性對象。多個Actor可以共享一個屬性對象。請看以下的代碼:
?
//控制Actor屬性方法一:先獲取Actor的Property對象,然后設(shè)置對應(yīng)的參數(shù)。
//調(diào)用以下方法時,應(yīng)該先包括頭文件:#include“vtkProperty.h”
//改變cylinderActor顏色為紅色,可以直接調(diào)用SetColor(),也可調(diào)用SetDiffuseColor()。
cylinderActor->GetProperty()->SetColor(1.0,0.0,0.0);
//cylinderActor->GetProperty()->SetDiffuseColor(1.0,0.0,0.0);
?
//控制Actor屬性的方法二:先實例化vtkProperty對象,然后加入到Actor里。
vtkSmartPointer<vtkProperty>cylinderProperty = vtkSmartPointer<vtkProperty>::New();
cylinderProperty->SetColor(1.0,0.0,0.0);
cylinderActor->SetProperty(cylinderProperty);
?
以上兩種方法都可以改變一個Actor的屬性,第一種方法相對來說比較簡單,直接設(shè)置即可,第二種方法則需要先實例化一個vtkProperty對象,但第二種方法比較靈活,而且如果想把多個Actor設(shè)置成同一屬性時,所需的代碼是最少的。
接著,我們看看怎么使用vtkProperty給Actor貼紋理圖(與紋理圖相關(guān)的類:vtkTexture),我們在以上例子的基礎(chǔ)上作一下修改,在柱體上貼一個圖。
//在3.1.1_RenderCylinder程序的最開始加入下列的代碼
vtkSmartPointer<vtkBMPReader>bmpReader = vtkSmartPointer<vtkBMPReader>::New();
bmpReader->SetFileName("doling.bmp");
?
vtkSmartPointer<vtkTexture>texture = vtkSmartPointer<vtkTexture>::New();
texture->SetInputConnection(bmpReader->GetOutputPort());
texture->InterpolateOn();
//實例化cylinderActor對象以后,調(diào)用以下代碼
cylinderActor->SetTexture(texture);
?
程序運行結(jié)果如圖3.4所示:
圖3.4 使用vtkProperty和vtkTexture給Actor貼紋理圖
==========歡迎轉(zhuǎn)載,轉(zhuǎn)載時請保留該聲明信息==========
版權(quán)歸@東靈工作室所有,更多信息請訪問東靈工作室
教程系列導(dǎo)航:http://blog.csdn.net/www_doling_net/article/details/8763686
================================================
總結(jié)
以上是生活随笔為你收集整理的一个稍微复杂的VTK程序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python:No module nam
- 下一篇: 国家粮食与物资储备局揭示中国稻谷产毒真菌