今天講述渲染管道的一些基本概念,希望對初學者能提供一定的幫助;如有錯誤請大蝦指正。。。
1,頂點格式
一個場景是由物體或者模型組成,物體可以通過三角形網格進行近似的描述。網格中的三角形是物體的組成部分,通常下列屬於都是描述網格中三角形:多邊形,圖元,網格幾何體。我們可以通過指定三角形的三個頂點來描述三角形。
另外在DX中頂點還可以有顏色屬性以及法線向量屬性;D3D為用戶提供了構建頂點格式的靈活性,換句話說就是用戶可以設置頂點的組成屬性。
創建一個自定義的頂點格式,首先需要創建一個頂點數據結構,用於保存頂點數據。舉個例子,下面兩個不同的頂點格式,一種頂點格式保存了位置和顏色信息。一種保存了位置和法向量和紋理坐標信息。
struct ColorVertex
{
float _x,_y,_z;//位置
DWORD _color;//顏色
}
struct ColorVertex
{
float _x,_y,_z;//位置
float _nx,_ny,_nz;//法向量
float _u,_v;//紋理坐標
}
定義完頂點結構后,需要使用靈活頂點格式(FVF)標志來描述頂點的組成格式,例如對於前面定義的頂點結構可以通過如下的靈活格式進行描述。
1)要描述包含位置屬性和散射(diffuse)顏色屬性的頂點結構時,靈活頂點格式標志為:
#define FVF_COLOR (D3DFVF_XYZ|D3DFVF_DIFFUSE)
2) 描述包含位置,法向量,紋理的頂點結構時,標志為:
#define FVF_NORMAL_TEX1 (D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1)
有一個必須要考慮的限制是:在定義靈活頂點格式標志中,方案與屬性的描述順序必須與頂點數據結構中屬性描述的順序相同。
2,三角形:
三角形是構成三維某型的基本元素,通過創建三角形的李彪愛描述物體的形狀和輪廓來創建一個物體。
三角形李彪中包含了每個需要渲染的三角形的數據。
例如,如果需要構建一個矩形,可以將矩形分成兩個矩形,並且指定所有三角形的頂點。
Vertex rect[6]={v0,v1,v2,//三角形0
v0,v2,v3};//三角形1
3,索引:通常組成三維物體的三角形都會使用許多相同的頂點,在矩形中雖然只重復使用了兩個頂點,但是被重復使用的頂點數將隨着模型的細節程度以及復雜度的增加而增加。
為了解決這個問題,就引入了索引的概念,索引的工作原理是:在創建一個頂點坐標的同時創建一個索引列表。頂點列表中存儲了所有獨立頂點的數據,索引列表中存儲所有三角形的頂點對應獨立頂點數據在頂點列表中的索引。
對於上一個例子通過不同的索引來定義頂點如何組合以組成三角形:注意類型。
WORD indexList[6]={0,1,2,//三角形0;
0,2,3}//三角形1;
4,虛擬攝像機:
攝像機決定觀察者可以看到的三維世界的范圍,即決定了要把三維世界的哪些部分變成一個二維的圖片。攝像機可以具有不同的位置和方向。通過改變攝像機的狀態可以決定三角形的可見范圍。
攝像機的可見體積范圍是一個平截台體,有視角范圍,近平面,遠平面來決定,只所以使用平截台體來描述攝像機的可見范圍,主要是因為顯式器的屏幕是矩形的,不在攝像機可見范圍內的物體將不可見,要進行更多的處理來去除這些物體,這種去除不可見物體的過程被稱為“裁剪”。
投影窗口是一個二維區域,平截台體內的三維幾何體都將投影到這個二維窗口上,從而生成一個代表三維世界的二維圖像。投影窗口被定義在最小為(-1,-1)到最大值(1,1)
的范圍之間,這一點非常重要。
為了簡化圖像渲染的難度,我們假設近平面和投影平面(投影窗口所在的平面)是一個平面。同時,需要注意在D3D中將z=1的平面設置為投影平面。
5,渲染管道:
在三維場景中建立三維世界的幾何描述,並且設置好了攝像機的位置,接下來的任務就是生成用於在顯示器上顯式的二維場景圖像,為了是完成這一功能而完成的一系列必要操作被稱為渲染管道。
渲染管道中的很多步驟中,都要將幾何物體從一個坐標系中變換到另一個坐標系中去。D3D(Driect3D)提供了矩陣變換的計算功能,這樣做的好處是非常明顯的,如果硬件提供了對這些計算功能的支持。就可以講這些變換操作交給圖形硬件來完成。
主要步驟:本地坐標->世界坐標->視圖坐標->背面裁剪->光照->裁剪->投影->視圖變換->光柵化。
在使用D3D來進行變換時,用戶只需要提供描述系統變換的完整的變換矩陣。可以通過IDirect3DDevice->SetTransform方法設置Direct3D需要變換矩陣,該方法接受兩個參數,一個用於描述變換的類型,一個用於提供變換的矩陣,舉個例子:假如需要設置從本地矩陣到世界矩陣轉換,可以進行如下設置:
Device->SetTransform(D3DTS_WORLD,&worldMatrax);
下面對每個步驟做具體介紹:
5.1 本地空間:
或者成為模型空間,指定義組成物體的三角形列表是所使用的坐標系統,本地空間在簡化模型處理工作上是相當有用的,在模型的本地空間中創建模型比在世界空間坐標中創建模型要簡單些,比如,本地空間中創建空間時,不需要考慮物體的位置,大小以及與世界空間中其他物體的關系。
5.2 世界空間:
在完成個模型的創建后,所有的物體都只在相應的本地空間中,需要把這些模型組合到一個統一的世界空間中來構造一個場景,這杯稱為世界變換。這些變換包括評議操作,旋轉操作以及縮放操作,分別用於設置模型在世界坐標系中的威化紙,方向以及大小。世界變換完成世界空間中所有物體位置,包括大小,方向以及相互之間關系的設置。
世界變換用矩陣來表示,在D3D中,用IDirect3DDevice->SetTransform方法來設置世界變換矩陣,調用此方法是需要設置參數1的變換類型為D3DTS_WORLD。
例如,如果想在(-3,2,6)處放一個立方體,在位置(5,0,-2)處放置一個球體,程序將書寫如下:
//創建立方體的世界矩陣,它只是表示一個平移變換:
D3DXMATRIX cubeWorldMatrix;
D3DXMatrixTranlation(&cubeWorldMatrix,-3.0f,2.0f.6.0f);
//創建球體世界矩陣,它也只包含一個平移變換。
D3DMATRIX sphereWorldMatrix;
D3DMatrixTranslation(&sphereWorldMatrix,5.0f,0.0,-2.0f);
//進行立方體變換
Device->SetTransform(D3DTS_WORLD,&cubeWorldMatrix);
drawcube();//畫出立方體
5.3 視圖空間
在世界空間中,幾何物體和攝像機都是相對於世界坐標系來定義的,但是如果將攝像機放置在世界空間中的任意位置和方向,那么投影操作以及其他操作就會變得相當困難並且效率低下,為了簡化操作,攝像機將被放置到世界坐標系的原點。並指向z軸的正方向,這是世界空間中的所有幾何體都和攝像機進行了相投個變換,所以通過攝像機看到的世界並沒有發上改變,這種在射界坐標系中移動攝像機的變換被稱為試圖空間變換,在這個變換之后幾何物體就就位於試圖空間中。
視圖空間變換矩陣可以通過以下的D3DX函數來計算:
D3DMATRIX* D3DMAtrixLookAtLH(
D3DMATRIX *pOut;//指向視圖矩陣的指針
CONST D3DXVECTOR3 *pEye;//攝像機在世界坐標系中的位置。
CONST D3DXVECTOR3 *pAt;//攝像機的觀察點。
CONST D3DXVECTOR3 *pUp;//攝像機的向上向量;通常就是Y軸;
)
例如,如果需要將攝像機放在位置(5,3,-10)並且設置攝像機看向世界空間的中心點(0,0,0),可以像下面這樣構造視圖變換矩陣:
D3DXVECTOR3 position(5.0f,3.0f,-10.0f);
D3DXVECTOR3 targetpoint(0.0f,0.0f,0.0f);
D3DXVECTOR3 worldUp(0.0f,1.0f,0.0f);
D3DMATRIX V;
D3DMatrixLookAtLH(&V,position,targetPoint,worldUp);
Device->SetTransform(D3DTS_VIEW,&V);
5.4 背面裁剪:
根據朝向的不同,可以認為多邊形具有兩個面,其中一個為前表面,一個為后表面,一般來說多邊形的背面是不可見的。場景中大部分物體都是閉合的,由於攝像機不可能進入這些物體的內部,因此也看不見組成這些物體的背面,如果循序多邊形背面可見,就不需要使用背面裁剪了。
當然,為了使背面裁剪能夠正確的工作,D3D就需要知道哪些多邊形是前向多邊形,哪些是背向多邊形;
默認情況下,定義頂點按照順時針方式排列(在視圖空間)的三角形為前向多邊形;
如果因為某些原因需要不使用默認裁剪方法。就可以通過改變D3DRS_CULLMODE渲染狀態來改變裁剪方法:
Devive->SetRenderState(D3DRS_CULLMODE,Value);
這里的參數Value可以為以下值:
D3DCULL_NONE;//不進行背面裁剪
D3DCULL_CW;//順時針方式
D3DCULL_CCW;//逆時針方式
5.5 關照
光源是在世界空間中定義的,但是經過視圖變換后,光源就變換到視圖空間中了,在視圖空間中,光源可以照亮場景中的物體,這樣場景看起來就更加真實。
5.6 裁剪
到了這一步需要剔除可視范圍以外的物體,這種操作叫做裁剪;
5.7投影:
在視圖空間中,要使用二維的形式來描述三維場景,將n維變換成n-1維的過程就稱為投影。
有很多種投影的方法,在這樣只討論透視投影,其實質就是按照近大遠小的原則進行投影,也就是說對於相同大小的物體,離攝像機遠的物體顯式的就小。
投影矩陣相當復雜,在這里不進行投影矩陣的推導,在D3D中使用下面的函數,就可以得到一個使用平截台體進行描述投影矩陣。
D3DMATRIX* D3DMatrixPerspectiveFovLH(
D3DMATRIX* pOut;//返回投影矩陣;
FLOAT fovY;//垂直方向的視角,用弧度表示
FLOAT Aspect//寬高比
FLOAT zn;//與近面的距離
FLOAT ZF//與遠面的距離
)
其中需要詳細說明的是寬高比參數。投影窗口中的幾何體最終將變換到屏幕空間中,因為投影窗口時正方形的,而屏幕是矩形的,他們之間的變換會造成拉伸失真;所以寬高比可以簡單地設置為顯式屏幕的寬高比;從而可以正確地實現投影窗口屏幕空間的映射;
舉個例子:
D3DMATRIX V;
D3DMatrixPerspectiveFovLH(&V,pI*0.5f,(float)width/(float)height,1.0,1000.0f);
Device->SetTransform(D3DTS_PROJECTION,&V);
5.8視口變換
視口變換負責將視口空間轉換到屏幕空間。這個屏幕空間區域就是視口,在游戲中,視口經常是整個屏幕,但是視口也可能是屏幕的一部分或者是出於窗口模式下窗口的客戶區。視口語氣所在的窗口相關並且通過所在窗口的相對坐標來進行描述。
在D3D中,使用D3DVIEWPORT9結構來描述視口,該結構定義如下:
typedef struct _D3DVIWPORT9{
DWORD X;//
DWORD Y;
DWORD WIDTH;
DWORD Height;
DWORD Minz;//深度緩沖區的最小值
DWORD MAXZ;//深度緩沖的最大值
}D3DVIEWPORT9;
前四個參數描述視口相對於所在窗口的位置。深度緩沖區值的范圍0-1;除非用戶因為需要實現某個特殊的效果而更改深度緩沖區的范圍,否則必須設置在這個范圍內。
舉個例子:
D3DVIEWPORT9 VP(0,0,640,480,0,1);
Device->setViewport(&vp);
5.9光柵化:
當所有頂點都變換到屏幕坐標系的時候,就有了一個三維形式的三角形列表。光柵化所做的工作就是計算每個獨立像素點的顏色值。
光柵化會消耗大量的計算,因此需要專門的圖形設備來完成,光柵化后就得到了一張在顯式器上顯式的二維圖片。
總結:
三維物體使用三角形網格進行描述,三角形網格是一個三角形的列表這些三角形組成一個與原來物體形狀輪廓相似的三維圖形。
虛擬相機的可是范圍被設置為一個平截台體,它的范圍就是攝像機的可視范圍。
三維物體在本地坐標系中定義在進行變換時,集合物體首先被變換到一個世界空間中,為了方便進行攝影,裁剪以及其他操作,物體將被變換到視圖空間中。視圖空間中攝像機處於坐標系的原點,觀察方向為z軸的正方向,幾何物體被變換到視圖空間后,物體將再次被變換到投影窗口中,最后,視口變換敬愛幾何物體從投影窗口變換到視口中,最后通過光柵化,計算是所有獨立像素點的顏色值,得到一張描述三維世界的二維圖片。
明天給大家展示一個簡單的較為完整的渲染管道的例子。各位晚安~~~~
