VTK基礎概念

東靈工作室出品的系列教程,看完這一章感覺入門了。底部有系列教程的鏈接,建議自己逐行把代碼敲進去


3、VTK基礎概念

在第2章裏,我們已經接觸了一個簡單的VTK工程,也掌握了怎麼使用CMake來構建VTK工程的步驟,本書後續章節的所有例子都是採用第2章介紹的步驟來構建VTK的工程。

本章我們先在第2章TestVTKInstall的基礎上作一些更改,演示一個能夠交互的VTK應用程序。與前面的風格類似,我們先是讓你“知其然”,然後再慢慢地讓你“知其所以然”。

3.1 一個稍微複雜的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調試運行(這些快捷鍵可能不同版本的VS不太一樣,也可以用菜單來操作,這個步驟在本書後續章節將不再贅述),程序運行結果如圖3.1所示。


圖3.1 示例3.1.1_RenderCylinder的運行結果

可以使用鼠標與柱體(圖3.1)交互,比如用鼠標滾輪可以對柱體放大、縮小;按下鼠標左鍵不放,然後移動鼠標,可以轉動柱體;按下鼠標左鍵,同時按下Shift鍵,移動鼠標,可以移動整個柱體,等等。其他的功能你也可以試着摸索一下,比如按下Ctrl鍵時再按鼠標左鍵;鼠標停留在柱體上,然後按下P鍵;試着按一下字母E呢?

接下來我們詳細解釋一下示例3.1.1_RenderCylinder裏每行代碼的含義以及所用到的VTK的類。從包含的頭文件可以看出,除了vtkSmartPointer和vtkRenderWindow在第2章已經介紹過,其他6個類都是新加入的。

(1)   vtkCylinderSource:(第12-16行),派生自vtkPolyDataAlgorithm。顧名思義,vtkCylinderSource生成的數據類型就是PolyData(vtkPolyData)的,它主要是生成一箇中心在渲染場景原點的柱體,柱體的長軸沿着Y軸,柱體的高度、截面半徑等都可以任意指定。

vtkCylinderSource::SetHeight() ——設置柱體的高。

vtkCylinderSource::SetRadius() ——設置柱體橫截面的半徑。

vtkCylinderSource::SetResolution() ——設置柱體橫截面的等邊多邊形的邊數。轉動一下柱體,然後數數柱體橫截面有多少條邊,應該就能明白這個參數表示什麼意思。

(2)  vtkPolyDataMapper:(第18-20行),渲染多邊形幾何數據(vtkPolyData),派生自類vtkMapper,將輸入的數據轉換爲幾何圖元(點、線、多邊形)進行渲染。

vtkPolyDataMapper::SetInputConnection() —— VTK可視化管線的輸入數據接口,對應的可視化管線輸出數據的接口爲GetOutputPort();VTK5.0之前的版本使用SetInput()和GetOutput()作爲輸入輸出接口,VTK 5.0以後版本保留了對這兩個接口的支持。關於這兩者的區別,後續內容會詳細介紹。

(3)   vtkActor:(第22-24行),派生自vtkProp類,渲染場景中數據的可視化表達是通過vtkProp的子類負責的。比如,本例要渲染一個柱體,柱體的數據類型是vtkPolyData,數據要在場景中渲染時,不是直接把數據加入渲染場景就可以,待渲染的數據是以vtkProp的形式存在於渲染場景中。三維空間中渲染對象最常用的vtkProp子類是vtkActor(表達場景中的幾何數據)和vtkVolume(表達場景中的體數據);二維空間中的數據則是用vtkActor2D表達。vtkProp子類負責確定渲染場景中對象的位置、大小和方向信息。Prop依賴於兩個對象(Prop一詞來源於戲劇裏的“道具”,在VTK裏表示的是渲染場景中可以看得到的對象。),一個是Mapper(vtkMapper)對象,負責存放數據和渲染信息,另一個是屬性(vtkProperty)對象,負責控制顏色、不透明度等參數。

VTK中定義了大量(超過50個)的Prop類,如vtkImageActor(負責圖像顯示)和vtkPieChartActor(用於創建數組數據的餅圖可視化表達)。其中的一些Prop內部直接包括了控制顯示的參數和待渲染數據的索引,因此並不需要額外的Property和Mapper對象。vtkActor的子類vtkFollower可以自動的更新方向信息以保持始終面向一個特定的相機。這樣無論怎樣旋轉,三維場景中的廣告板(Billboards)或者文本都是可見的。vtkActor的子類vtkLODActor可以自動改變自身的幾何表達來實現需要達到的交互幀率。vtkProp3D的子類vtkLODProp3D則是通過從許多Mapper(可以是體數據的Mapper和幾何數據的Mapper集合)中進行選擇來實現交互。vtkAssembly建立Actor的等級結構以便在整個結構平移、旋轉或者縮放時能夠更合理的控制變換。

vtkActor::SetMapper()——設置生成幾何圖元的Mapper。即連接一個Actor到可視化管線的末端(可視化管線的末端就是Mapper)

(4)   vtkRenderWindow:(第31-34行),將操作系統與VTK渲染引擎連接到一起。不同平臺下的vtkRenderWindow子類負責本地計算機系統中窗口創建和渲染過程管理。當使用VTK開發應用程序時,你只需要使用平臺無關的vtkRendererWindow類,運行時,系統會自動替換爲平臺相關的vtkRendererWindow子類。比如,Windows下運行上述的VTK程序,實際創建的是vtkWin32OpenGLRenderWindow(vtkRenderWindow的子類)對象。vtkRenderWindow中包含了vtkRenderer集合、渲染參數,如立體顯示(Stereo),反走樣,運動模糊(Motion Blur)和焦點深度(Focal Depth)等。

vtkRenderWindow::AddRenderer() ——加入vtkRenderer對象。

vtkRenderWindow::SetSize() ——該方法是從vtkRenderWindow的父類vtkWindow繼承過來的,用於設置窗口的大小,以像素爲單位。

(5)   vtkRenderer:(第26-29行),負責管理場景的渲染過程。組成場景的所有對象包括Prop,照相機(Camera)和光照(Light)都被集中在一個vtkRenderer對象中。一個vtkRenderWindow中可以有多個vtkRenderer對象,而這些vtkRenderer可以渲染在窗口中不同的矩形區域中(即視口),或者覆蓋整個窗口區域。

vtkRenderer::AddActor() ——添加vtkProp類型的對象到渲染場景中。

vtkRenderer::SetBackground() ——該方法是從vtkRenderer的父類vtkViewport繼承的,用於設置渲染場景的背景顏色,用R、G、B的格式設置,三個分量的取值爲0.0~ 1.0。(0.0,0.0, 0.0)爲黑色,(1.0,1.0, 1.0)爲白色。除了可以設置單一的背景顏色之外,還可以設置漸變的背景顏色,vtkViewport::SetBackground2()用於設置漸變的另外一種顏色,但是要使背景顏色漸變生效或者關閉,必須調用以下的方法:

vtkViewport::SetGradientBackground(bool) ——參數爲0是關閉,反之,打開。

vtkViewport::GradientBackgroundOn()—— 打開背景顏色漸變效果,相當於調用方法SetGradientBackground(1)。

vtkViewport::GradientBackgroundOff() ——關閉背景顏色漸變效果。相當於調用方法SetGradientBackground(0)。

(6)   vtkRenderWindowInteractor:(第36-38行),提供平臺獨立的響應鼠標、鍵盤和時鐘事件的交互機制,通過VTK的Command/Observer設計模式將監聽到的特定平臺的鼠標、鍵盤和時鐘事件交由vtkInteractorObserver或其子類,如vtkInteractorStyle進行處理。vtkInteractorStyle等監聽這些消息並進行處理以完成旋轉、拉伸和放縮等運動控制。vtkRenderWindowInteractor自動建立一個默認的3D場景交互器樣式(Interactor Style):vtkInteractorStyleSwitch,當然你也可以選擇其他的交互器樣式,或者是創建自己的交互器樣式。在本例中,我們就是選擇了其他的交互器樣式來替代默認的:vtkInteractorStyleTrackballCamera。

vtkRenderWindowInteractor::SetRenderWindow()——設置渲染窗口,消息是通過渲染窗口捕獲到的,所以必須要給交互器對象設置渲染窗口。

vtkRenderWindowInteractor::SetInteractorStyle()——定義交互器樣式,默認的交互樣式爲vtkInteractorStyleSwitch。

vtkRenderWindowInteractor::Initialize() ——爲處理窗口事件做準備,交互器工作之前必須先調用這個方法進行初始化。

vtkRenderWindowInteractor::Start() ——開始進入事件響應循環,交互器處於等待狀態,等待用戶交互事件的發生。進入事件響應循環之前必須先調用Initialize()方法。

(7)   vtkInteractorStyleTrackballCamera:(第40-41行),交互器樣式的一種,該樣式下,用戶是通過控制相機對物體作旋轉、放大、縮小等操作。做個類比:我們在照相的時候如果要想物體看起來顯得大一些,我們可以採取兩種做法,第一種做法是相機不動,讓我們要拍的物體靠近我們;第二種做法是物體不要動,我們把相機靠近物體,這樣物體看起來也是大一些。第二種做法就是vtkInteractorStyleTrackballCamera的風格。其父類爲vtkInteractorStyle,除了vtkInteractorStyleTrackballCamera之外,VTK還定義了其他多種交互器樣式,如vtkInteractorStyleImage,主要用於顯示二維圖像時的交互。

以上內容我們是逐行代碼進行解釋,並稍微做了擴展。可能你看了以後會覺得比較零散,還是不夠系統、全面。下面我們就從稍微宏觀的角度重新看看這個例子的代碼。繼續下面的內容之前,我們先來看一個類比,可能沒有你想的形象,但它對我們理解例子的代碼還是會有幫助的。

當我們去看舞臺劇的時候,我們坐在臺下,展現在我們面前的是一個舞臺,舞臺上有各式的燈光,各樣的演員。演員出場的時候肯定是會先化妝,有些演員可能會打扮成高富帥,有些演員可能會化妝成白富美。觀衆有時還會與臺上的演員有一定的互動。

整個劇院就好比VTK程序的渲染窗口(vtkRenderWindow);舞臺就相當於渲染場景(vtkRenderer);而那些高富帥、白富美就是我們程序中的Actor(有些文獻翻譯成“演員”,有些翻譯成“角色”,這裏我們不作翻譯);臺上的演員與臺下觀衆的互動可以看成是程序的交互(vtkRenderWindowInteractor);演員與觀衆的互動方式有很多種,現場的觀衆可以直接上臺跟演員們握手擁抱,電視機前的可以發短信,電腦、移動終端用戶等可以微博關注、加粉等等,這就好比我們程序裏的交互器樣式(vtkInteractorStyle);舞臺上的演員我們都能一一分辨出來,不會把高富帥弄混淆,是因爲他們化的妝、穿的服飾都不一樣,這就相當於我們程序裏vtkActor的不同屬性(vtkProperty);臺下觀衆的眼睛可以看作是vtkCamera,前排的觀衆因爲離得近,看臺上演員會顯得比較高大,而後排的觀衆看到的會顯得小點,每個觀衆看到的東西在他的世界裏都是唯一的,所以渲染場景Renderer裏的vtkCamera對象也是隻有一個;舞臺上的燈光可以有多個,所以渲染場景裏的vtkLight也存在多個。可以參考一下圖3.2,加深理解。


圖3.2VTK渲染場景以及各主要對象

3.2 vtkActor及相關屬性

由前面的內容我們知道,數據渲染時不是直接加入渲染場景,而是以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內部用一個4×4的矩陣來表示。默認構造的vtkProp3D對象原點爲(0,0,0),放置的位置爲(0,0,0),放置的方向爲(0,0,0),用戶自定義的矩陣或者變換爲空。以下是vtkProp3D定義的用於放置vtkProp3D對象的方法:

l  SetScale (double) / GetScale ():設置/獲取各向同性的縮放比例。

l  SetScale (double, double,double) / GetScale (double):設置/獲取各同異性的縮放比例。

l  RotateX (double) / RotateY (double) / RotateZ (double):分別繞X、Y、Z軸旋轉指定角度。

l  RotateWXYZ (double, double,double, double):繞指定的方向旋轉指定的角度,第一個參數表示旋轉角度,後三個參數確定一個方向。GetOrientationWXYZ()用於獲取對應的數據。

l  SetOrientation (double, double,double) / GetOrientation ():設置vtkProp3D對象的方向。先繞Z軸旋轉,然後繞X軸,最後繞Y軸旋轉,從而確定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 ():設置/獲取vtkProp3D對象的原點。

3.2.2vtkActor及其屬性

前面的內容已經提到:Prop依賴於兩個對象,一個是Mapper(vtkMapper)對象,負責存放數據和渲染信息,另一個是屬性(vtkProperty)對象,負責控制顏色、不透明度等參數。對應的這兩個方法就是在類vtkActor裏定義的:

l  SetMapper (vtkMapper *):設置定義Actor幾何形狀的Mapper。

l  SetProperty (vtkProperty *):設置Actor的屬性,包括表面屬性,如環境光(Ambient)、散射光(Diffuse)、鏡面光(Specular)、顏色、透明度等;紋理映射;點的大小,線的寬度設置等。每一個Actor都有一個屬性對象(vtkProperty的實例)與之相關聯,如果沒有給Acttor指定相應的屬性(3.1.1的例子就沒有指定),VTK會指定默認的屬性對象。多個Actor可以共享一個屬性對象。請看以下的代碼:

 

//控制Actor屬性方法一:先獲取Actor的Property對象,然後設置對應的參數。

//調用以下方法時,應該先包括頭文件:#include“vtkProperty.h”

//改變cylinderActor顏色爲紅色,可以直接調用SetColor(),也可調用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的屬性,第一種方法相對來說比較簡單,直接設置即可,第二種方法則需要先實例化一個vtkProperty對象,但第二種方法比較靈活,而且如果想把多個Actor設置成同一屬性時,所需的代碼是最少的。

接着,我們看看怎麼使用vtkProperty給Actor貼紋理圖(與紋理圖相關的類:vtkTexture),我們在以上例子的基礎上作一下修改,在柱體上貼一個圖。

//在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對象以後,調用以下代碼

cylinderActor->SetTexture(texture);

 

程序運行結果如圖3.4所示:


圖3.4 使用vtkProperty和vtkTexture給Actor貼紋理圖


==========歡迎轉載,轉載時請保留該聲明信息==========

版權歸@東靈工作室所有,更多信息請訪問東靈工作室


教程系列導航:http://blog.csdn.net/www_doling_net/article/details/8763686

================================================


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章