標籤:
3.3 光照
劇場裡有各式各樣的燈光,三維渲染情境中也一樣,可以有多個光照存在。光照和相機是三維渲染情境必備的因素,如果沒有指定(像3.1.1_RenderCylinder例子,我們沒有給Renderer指定相機和光照),vtkRenderer會自動地建立預設的光照和相機。VTK裡用類vtkLight來表示渲染情境中的光照。與現實中的燈光類似,VTK中的vtkLight執行個體也可以開啟、關閉,設定光照的顏色,照射位置(即焦點),光照所在的位置,強度等等。
vtkLight可以分為位置光照(Positional Light,即聚光燈)和方向光照(Direction Light)。位置光照是光源位置在渲染情境中的某個位置,可以指定光照的衰減值、錐角等;方向光照即光源位置在無窮遠,光線可以認為是平行的,比如自然界中的太陽光。光源的位置和焦點的連線定義光線的方向,預設的vtkLight即為方向光照。
vtkLight常的方法有:
SetColor() — 設定光照的顏色,以RGB的形式指定顏色。
SetPosition() — 設定光照位置。
SetFocalPoint() — 設定光照焦點。
SetIntensity() — 設定光照的強度。
SetSwitch() / SwitchOn()/ SwitchOff()— 開啟或關閉對應的光照。
我們在講vtkProp的時候,該類有方法SetVisibility (int) / GetVisibility() /VisibilityOn() /VisibilityOff()等來控制vtkProp對象的可見與不可見的屬性。同樣,vtkLight裡也有類似命名風格的方法:SetSwitch() /GetSwitch()/SwitchOn()/ SwitchOff()。不難發現,在VTK裡,某個屬性的設定都是採取這一類方法,以vtkLight為例,SwitchOn()跟SetSwitch(1)實現的效果是一樣,SwitchOff()則與SetSwitch(0)是一樣的,GetSwitch()則是用於擷取vtkLight對象關閉或開啟這個屬性的值。如果某個類有提供SetXXX()方法,一般也會提供GetXXX()方法來擷取相應的值,這個我們在前面的內容也已經有一些瞭解。再比如,vtkLight還提供:SetPositional() / GetPositional()/ PositionalOn()/PositionalOff()一類方法來設定位置光照。
在類vtkLight的標頭檔vtkLight.h裡,找不到類似SetSwitch()/GetSwitch()等方法的原型,但是可以看到以下幾行:
vtkSetMacro(Switch,int);
vtkGetMacro(Switch,int);
vtkBooleanMacro(Switch,int);
顧名思義,vtkSetMacro/vtkGetMacro/vtkBooleanMacro都是宏,展開這幾個宏以後就是以上函數的原型。為了保證代碼的整潔與複用性,VTK在檔案vtkSetGet.h裡定義了大量了宏,當你找不到某個函數的原型時,可能這些函數就是由宏展開以後所定義的,所以,在閱讀VTK源碼的時候,不妨多右擊一下某個函數或者關鍵字,然後點擊快顯功能表中的“Go to Definition…”,也就一目瞭然了。
光照vtkLight的使用方法(程式執行結果3.5所示):
vtkSmartPointer<vtkLight> myLight= vtkSmartPointer<vtkLight>::New();
myLight->SetColor(0,1,0);
myLight->SetPosition(0,0,1);
myLight->SetFocalPoint(renderer->GetActiveCamera()->GetFocalPoint());
renderer->AddLight(myLight);
vtkSmartPointer<vtkLight> myLight2= vtkSmartPointer<vtkLight>::New();
myLight2->SetColor(0,0,1);
myLight2->SetPosition(0,0,-1);
myLight2->SetFocalPoint(renderer->GetActiveCamera()->GetFocalPoint());
renderer->AddLight(myLight2);
上述定義了兩個vtkLight對象,一個為綠色光,位置在(0,0,1),焦點對著相機的焦點;另一個為藍色光,位置在(0,0,-1),焦點也是對著相機的焦點,最後兩個光照調用vtkRenderer的方法AddLight()加入到渲染情境中,因為Renderer裡可以有多個燈照,所以,VTK提供的介面是AddLight()而不是SetLight()。
圖3.5例3.1.1_RenderCylinder加入綠色和藍色光照的效果
3.4 相機
觀眾的眼睛就好比三維渲染情境中的相機,VTK則是用vtkCamera類來表示三維渲染情境中的相機。vtkCamera負責把三維情境投影到二維平面,如螢幕、映像等。圖3.6為相機投影。
從圖3.6可以看出與相機投影相關的因素主要有:
l 相機位置:即相機所在的位置,用方法vtkCamera::SetPosition()設定。
l 相機焦點:用方法vtkCamera::SetFocusPoint()設定,預設的焦點位置在全局座標系的原點。
l 朝上方向:即哪個方向為相機朝上的方向。就好比我們直立看東西,方向為頭朝上,看到的東西也是直立的,如果我們倒立看某個東西,這時方向為頭朝下,看到的東西當然就是倒立的。相機位置、相機焦點和朝上方向三個因素確定了相機的實際方向,即確定相機的視圖。
圖3.6相機vtkCamera投影
l 投影方向:相機位置到相機焦點的向量方向即為投影方向。
l 投影方法:確定Actor是如何映射到像平面的。vtkCamera定義了兩種投影方法,一種是正交投影(OrthographicProjection),也叫平行投影(Parallel Projection),即進入相機的光線與投影方向是平行的。另一種是透視投影(PerspectiveProjection),即所有的光線相交於一點。
l 視角:透視投影時需要指定相機的視角(View Angle),預設的視角大小為30º,可以用方法vtkCamera::SetViewAngle()設定。
l 前後裁剪平面:裁剪平面與投影方向相交,一般與投影方向也是垂直的。裁剪平面主要用於評估Actor與相機距離的遠近,只有在前後裁剪平面之間的Actor才是可見的。裁剪平面的位置可以用方法vtkCamera::SetClippingRange()設定。
如果你想擷取vtkRenderer裡預設的相機,可以用方法vtkRenderer::GetActiveCamera()。
相機vtkCamera的使用方法:
vtkSmartPointer<vtkCamera>myCamera = vtkSmartPointer<vtkCamera>::New();
myCamera->SetClippingRange(0.0475,2.3786); //這些值隨便設定的,為了示範用法而已
myCamera->SetFocalPoint(0.0573,-0.2134, -0.0523);
myCamera->SetPosition(0.3245,-0.1139, -0.2932);
myCamera->ComputeViewPlaneNormal();
myCamera->SetViewUp(-0.2234,0.9983, 0.0345);
renderer->SetActiveCamera(myCamera);
上述我們用SetClippingRange();SetFocalPoint();SetPosition()分別設定相機的前後裁剪平面,焦點和位置。ComputeViewPlaneNormal()方法是根據設定的相機位置、焦點等資訊,重新計算視平面(View Plane)的法向量。一般該法向量與視平面是垂直的,如果不是垂直的話,Actor等看起來會有一些特殊的效果,如錯切。SetViewUp()方法用於設定相機朝上方向。最後用方法vtkRenderer::SetActiveCamera()把相機設定到渲染情境中。
vtkCamera除了提供設定與相機投影因素相關的方法之外,還提供了大量的控制相機運動的方法,如:vtkCamera::Dolly(),vtkCamera::Roll(),vtkCamera::Azimuth(),vtkCamera::Yaw(),vtkCamera::Elevation(),vtkCamera::Pitch(),vtkCamera::Zoom()。這些方法具體表示相機是怎麼運動,以及相對哪個位置或者方向運動,請參考圖3.7或者關於類vtkCamera的文檔說明。
圖3.7 相機運動方向
圖3.7是指令檔camera.tcl(在VTK的源碼目錄裡:VTK\Hybrid\Testing\Tcl\camera.tcl)和camera2.tcl的執行結果。第1章裡,我們提到過Tcl指令檔,當時建議大家安裝vtk-5.10.0-win32-x86.exe這個程式,如果你安裝了這個程式的話,現在就可以執行圖3.7的指令碼了。
有兩種方法可以運行tcl指令碼。第一種是從Windows開始菜單裡開啟VTK的Tcl指令碼程式,出現圖3.8所示的介面。
圖3.8 vtk-5.10.0-win32-x86程式運行介面
接著,在“%”後面輸入“source XXXX.tcl”,然後斷行符號,即可執行對應的tcl指令檔。XXXX.tcl如果輸入的是絕對路徑時,要注意路徑裡的斜杠是“/”,而不是“\”,如果路徑帶有空格,需要用英文的雙引號把整個路徑括起來。
比如:source “D:/ProgramFiles/VTK/camera.tcl” (然後斷行符號,即可運行tcl指令碼)
第二種方法是:安裝完vtk-5.10.0-win32-x86.exe程式後,把vtk.exe所在的路徑加入到Path環境變數,然後開啟cmd視窗,在cmd視窗裡直接輸入:vtk XXXX.tcl,斷行符號,同樣可以執行tcl指令檔。*.tcl檔案可以用記事本開啟。
3.5 顏色
前面的內容我們提到Actor的屬性,顏色是Actor比較重要的屬性之一。VTK採用RGB和HSV兩種顏色系統來描述顏色。
RGB顏色系統就是由三個顏色分量:紅色(R)、綠色(G)和藍色(B)的組合表示,在VTK裡這三個分量的取值都是從0到1,(0, 0, 0)表示黑色,(1, 1, 1)表示白色。vtkProperty::SetColor(r,g, b)採用的就是RGB顏色系統設定顏色屬性值。
HSV顏色系統同樣也是由三個分量來決定顏色,分別是:色相(Hue),是顏色的基本屬性,就是我們平常所說的顏色名稱,如紅色、黃色等;飽和度(Saturation),是指顏色的純度,其值越高則越純;值(Value,也就是強度Intensity或者亮度Bright),值為0通常表示的是黑色,值為1表示的是最亮的顏色。這三個分量的取值範圍也是0到1。類vtkLookupTable提供了HSV顏色系統設定的方法。
表3.1列出了常用顏色RGB和HSV值的對照。
顏色 |
RGB |
HSV |
黑色Black |
0, 0, 0 |
*, *, 0 |
白色White |
1, 1, 1 |
*, 0, 1 |
紅色Red |
1, 0, 0 |
0, 1, 1 |
綠色Green |
0, 1, 0 |
1/3, 1, 1 |
藍色Blue |
0, 0, 1 |
2/3, 1, 1 |
黃色Yellow |
1, 1, 0 |
1/6, 1, 1 |
藍綠色Cyan |
0, 1, 1 |
1/2, 1, 1 |
品紅色Magenta |
1, 0, 1 |
5/6, 1, 1 |
天藍色Sky blue |
1/2, 1/2, 1 |
2/3, 1/2, 1 |
表3.1 常用顏色RGB和HSV值的對照
與顏色設定相關的VTK類除了vtkProperty,vtkLookupTable之外,還有vtkColorTransferFunction。vtkLookupTable和vtkColorTransferFunction都派生自vtkScalarsToColors。
3.6 座標系統及空間變換3.6.1座標系統
電腦圖形學裡常用的座標系統主要有四種,分別是:Model座標系統、World座標系統、View座標系統和Display座標系統,以及兩種表示座標點的方式:以螢幕像素值為單位和歸一化座標值(各座標軸取值都為[-1, 1])。它們之間的關係3.9所示。
Model座標系統是定義模型時所採用的座標系統,通常是局部的笛卡爾座標系。例如,我們要定義一個表示球體的Actor,一般的做法是將該球體定義在一個柱座標系統裡。
World座標系統是放置Actor的三維空間座標系,Actor其中的一個功能就是負責將模型從Model座標系統變換到World座標系統。每一個模型可以定義有自己的Model座標系統,但World座標系只有一個,每一個Actor必須通過放縮、旋轉、平移等操作將Model座標系變換到World座標系。World座標系同時也是相機和光照所在的座標系統。
View座標系統表示的是相機所看見的座標系統。X、Y、Z軸取值為[-1, 1],X、Y值表示像平面上的位置,Z值表示到相機的距離。相機負責將World座標系變換到View座標系。
圖3.9Model、World、View和Display座標系統
Display座標系統跟View座標系統類似,但是各座標軸的取值不是[-1, 1],而是使用螢幕像素值。螢幕上顯示的不同視窗的大小會影響View座標系的座標值[-1, 1]到Display座標系的映射。可以把不同的渲染情境放在同一個視窗進行顯示,例如,在一個視窗裡,分為左右兩個渲染情境,這左右的渲染情境(vtkRenderer)就是不同的視口(Viewport)。例子3.6.1_Viewport示範了把一個視窗分為四個視口,用vtkRenderer::SetViewport()來設定視口的範圍(取值為[0, 1]):
renderer1->SetViewport(0.0,0.0,0.5,0.5);
renderer2->SetViewport(0.5,0.0,1.0,0.5);
renderer3->SetViewport(0.0,0.5,0.5,1.0);
renderer4->SetViewport(0.5,0.5,1.0,1.0);
程式執行結果3.10所示。
在VTK裡,Model座標系統用得比較少,其他三種座標系統經常使用。它們之間的變換則是由類vtkCoordinate進行管理的。根據座標點單位、取值範圍等不同,可以將座標系統分為:
l DISPLAY — X、Y軸的座標取值為渲染視窗的像素值。座標原點位於渲染視窗的左下角,這個對於VTK裡所有的二維座標系統都是一樣的,且VTK裡的座標系統都是採用右手座標系。
l NORMALIZEDDISPLAY — X、Y軸座標取值範圍為[0, 1],跟DISPLAY一樣,也是定義在渲染視窗裡的。
l VIEWPORT— X、Y的座標值定義在視口或者渲染器(Renderer)裡。
l NORMALIZEDVIEWPORT — X、Y座標值定義在視口或渲染器裡,取值範圍為[0, 1]。
l VIEW— X、Y、Z座標值定義在相機所在的座標系統裡,取值範圍為[-1, 1],Z值表示深度資訊。
l WORLD — X、Y、Z座標值定義在全局座標系統,參考圖3.9。
l USERDEFINED— 使用者自訂座標系統。
vtkCoordinate類提供的設定以上座標系統的方法是:
SetCoordinateSystemToDisplay ()
SetCoordinateSystemToNormalizedDisplay ()
SetCoordinateSystemToViewport ()
SetCoordinateSystemToNormalizedViewport ()
SetCoordinateSystemToView ()
SetCoordinateSystemToWorld ()
圖3.10 例3.6.1_Viewport執行結果
3.6.2空間變換
我們在三維空間裡定義的3D 模型,最後顯示的時候都是投影到二維平面,比如在螢幕上顯示,產生二維映像等等。三維到二維的投影包括透視投影(PerspectiveProjection)和正交投影(Orthogonal Projection,正交投影也叫平行投影)。
不管是透視投影還是正交投影,變換的基本元素都是三維座標點,在電腦圖形學裡,三維座標點通常用齊次座標來表示。例如,三維空間裡有一個座標點(x,y,z),用齊次座標表示為(xh,yh,zh,wh),其中,
式 3-1
如果wh = 0,則表示無窮遠的點。
利用齊次座標,可以將空間變換用4×4的矩陣來表示。例如,平移、旋轉、縮放等仿射變換都可以用矩陣相乘的形式表示:
l 平移。設笛卡爾座標系下的點(x, y, z),求經平移向量(tx, ty,tz)變換後的結果(x’,y’,z’)。
首先,先構造平移矩陣TT:
式3-2
得平移結果為:
式3-3
如果用笛卡爾座標系表達為:
式3-4
l 縮放。同理,我們也可以構造出縮放矩陣TS。
式3-5
其中Sx, Sy, Sz分別為X、Y、Z軸的縮放因子。
l 旋轉。設繞X、Y、Z軸旋轉角度分別為α,β,γ,則旋轉矩陣分別為:
式3-6
VTK裡與空間變換相關的類有:vtkTransform2D,vtkTransform,vtkPerspectiveTransform,vtkGeneralTransform,vtkTransformFilter,vtkMatrix4x4等。
3.7 本章小結
本章從一個稍微複雜的VTK程式裡出發,深入瞭解VTK的一些基本概念。
首先我們從vtkCylinderSource學會了一組VTK類:vtkXXXSource。這一組類派生自vtkPolyDataAlgorithm,它們輸出的資料類型都是vtkPolyData,都些類都是VTK預定義好的圖形模型。
接著,我們把vtkXXXSource的輸出作為vtkPolyDataMapper的輸入,Mapper的作用是將輸入的資料轉換為幾何圖元(點、線、多邊形)進行渲染。
然後,我們執行個體化一個Actor對象,因為我們知道,VTK渲染情境中資料的可視化表達是通過vtkProp的子類負責的。通過Actor的方法SetMapper()可以設定對應的Mapper。
緊接著,我們又執行個體化了渲染視窗、渲染器、互動器、互動類型等對象,並逐個地加以介紹。於是我們明白了渲染視窗就是我們看到的那個VTK視窗;渲染器Renderer可以通過渲染視窗的方法AddRenderer()加入的渲染視窗裡;互動器則是用方法SetRenderWindow()給它指定互動的視窗;互動風格與互動器是用方法SetInteractorStyle()關聯在一起;若干個Actor對象可以用方法AddActor()加入到渲染器裡渲染。綜合起來可以用圖3.11來理清它們之間簡單而複雜的關係。(可以發現:這些對象之間頭尾相接,可以連成一條線結構,這就是VTK裡非常重要的概念:VTK管線結構。)
圖3.11 例3.1.1_RenderCylinder各對象之間的關係
然後我們又看了渲染情境裡光照和相機等對象,明白了渲染情境裡可以有多個光照,但只能有一個相機;以及瞭解了設定光照和相機的方法。
介紹vtkActor時,我們通過vtkProperty對象來改變Actor的顏色,於是我們順便介紹了VTK所用到的顏色模型,分別是RGB顏色模型和HSV顏色模型。
最後我們又講了似乎跟前面的內容並不搭邊的“座標系統及空間變換”,明白VTK裡用到Model、World、View和Display等座標系統,它們之間可以變換通過類vtkCoordinate來實現。然後介紹了VTK裡使用齊次座標做空間變換的概念,列出了平移、縮放和旋轉等變換矩陣。其實這部分內容跟前面介紹的是息息相關的,比如,渲染情境裡的Actor通過相機投影到像平面時,就用到了這些內容。vtkRenderer裡的方法ViewToWorld()和WorldToView()等,裡面也會用到空間變換。
本章的內容是VTK最最基礎的東西,可以毫不誇張地說,後續三維方面的例子基本都會用到本章所介紹的概念,所以,掌握本章內容的重要性可想而知。
3.8 本章參考資料
[1] 《VTK User’s Guide (11th Edition)》
[2] 《The Visualization Toolkit – AnObject-Oriented Approach To 3D Graphics (4th Edition)》
==========歡迎轉載,轉載時請保留該聲明資訊==========著作權歸@東靈工作室所有,更多資訊請訪問東靈工作室
03-VTK基礎概念(2)