【D3D11遊戲程式設計】學習筆記七:3D渲染管線

Brother灬Nam發表於2012-12-15

      

       (注:【D3D11遊戲程式設計】學習筆記系列由CSDN作者BonChoix所寫,轉載請註明出處:http://blog.csdn.net/BonChoix,謝謝~)

 

       3D圖形學研究的基本內容,即給定場景的描述,包括各個物體的材質、紋理、座標等,照相機的位置及朝向,光源等資訊,計算其最終在二維的光柵化顯示器上對應的顯示結果。從最初的場景描述到最終的顯示結果,這整個過程就是在3D渲染管線中完成的。
       這裡的“管線”即我們通常意義上的流水線,與工業上的生產流水線,或者是CPU指令執行的流水線具有相似的意義。如果對“流水線”概念有所瞭解,就會明白其直接目的就是提高執行的效率。假如沒有流水線,所有的處理都放到單獨一個階段執行,那麼一個頂點從開始被處理到最終處理完畢的過程中,後面的頂點只能處於等待狀態。假設整個處理過程時間為T,那麼系統的吞吐量就相當於1/T。 如果把整個處理過程合理地分成不同的階段,我們假設平均分成了5個階段(P1,P2,P3,P4,P5,且每個階段執行時間為T/5),各個階段可以互不影響地獨立工作,即一個頂點在執行完P1進入P2階段後下一個頂點馬上可以進入P1階段開始執行。這種情況下在任意時刻,五個階段就可以同時工作,效率自然會大大提高。此時的吞吐量為5/T這個事實就是證明。當然,真正的管線不同的階段執行時間一般不可能完全一樣的,這時整個管線的效率瓶頸取決於時間最長的那個,假設為Tmax,則整個管線的吞吐量為1/Tmax。
 在D3D11中,整個渲染管線可以分成如下幾個主要階段:

       從最開始的Input Assembler階段到最終的Output Merger階段,每個階段處理完的輸出,傳遞給下一個階段,作為其輸入。
       下面針對各個階段逐個進行介紹:
1. Input Assembler Stage
       這個階段的主要目的是根據使用者提供的頂點及索引資訊,構建多邊形,主要有點、線段、三角形。給定頂點和索引,構建多邊形的方法取決於所使用的基本圖元的拓撲型別(Primitive Topology)。D3D11中常見的拓撲型別有以下幾種:
   1. Point List:定義的每一個頂點作為一個單獨的點進行繪製,如圖:
  

  2. Line Strip:所有的頂點按順序逐個連線成線段,如圖:
 
   3. Line List:所有的頂點按順序兩兩配對連線成線段,如圖:
 
   4. Triangle Strip:所有的頂點按順序組成三角形,前三個頂點為第一個三角形,從第四個開始每個頂點與位於其前面的兩個頂點組成一個三角形,如圖:
 
   5. Triangle List:類似於Line List,按順序三三配對組成三角形,如圖:
 
        舉個例子,對於下圖,9個頂點及拓撲型別Triangle List,對應索引:[0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,7, 0,7,8]。
 
        Input Assembler會三個三個地讀取索引組成三角形,形成圖中的七個三角形。
        對於另一個圖,4個頂點及拓撲型別Triangle Strip,對應索引:[1,2,0,3]。
 
        此時,GPU讀取[1,2,0]組成第一個三角形,[0,2,3]組成第二個三角形。
      【注意】:從上面可以看出,對於奇數序號三角形和偶數序號三角形,讀取索引順序是不一樣的。偶數三角形三個頂點索引順序跟使用者指定的一致([1,2,0]),奇數三角形前兩個索引順序與使用者指定的相反([0,2,3]中的0和2與使用者指定索引2,0反序)。這是由GPU自動完成的,以保證所有的三角形頂點順序一致地按照順時針(或逆時針)排列。
        此外,三角形的奇、偶是以0為基準的。

        除此之外還有Control Point PatchList型別,由於其主要用於Tessellation階段作為控制點使用,這裡不多作介紹,在後面學習到曲面細分技術時再來了解它。

2. Vertex Shader Stage
        這是一個完全可程式設計的階段,即完全由程式設計師自己來實現。該階段的核心為模型頂點的各種空間變化。3D圖形學定義了以下幾種座標系空間:
        1. 模型空間:Model Space,也叫Local Space
        直觀的講,這個座標系一般以模型中心為原點,所有的模型在建模的時候給定的模型頂點座標都以這個座標系為基準,使用者最開始所指定的頂點座標也是位於該空間。
        給出模型空間的好處在於方便建模,以及單個模型的重重利用。因為一個物體可被放置到場景的多個地方,這時每個物體的頂點座標顯然是不一樣的,但可以共享同一個模型。
        2. 世界空間:World Space
        這個座標系即3D場景給各個物體指定座標的基準。場景有不同的物體具有不同的世界座標。
        3. 視角空間:View Space
        這個座標是以照相機為基準的,以照相機位置為原點,照相機朝向z軸正方向,右邊為x軸正方向,上邊為y軸正方向。之所以設定這個座標系,主要是為了主便接下來的投影及裁剪操作。如果直接在世界空間下進行,由於照相機位置、朝向靈活多變,計算將會十分複雜。有了視角空間,一切計算以原點為基準,會大大方便計算。
        4. 投影、裁剪空間:Projection Clip Space
        這個空間即世界空間的物體被投影到相應的投影面上之後,繼而進行裁剪操作所在的空間。

        使用者指定的所有頂點都是基於模型空間的,在Vertex Shader階段,每個頂點要依次經歷所有這些空間,最終轉換為螢幕上對應的二維座標,不同空間之間的切換稱為“空間變換”,實現空間變換的基本工作即矩陣。
        I. 模型、世界空間變換
        從模型空間到世界的變換主要包括:縮放、旋轉和平移。縮放和旋轉操作通過3X3矩陣及可實現,為了實現平移操作,則需要4X4型矩陣,因此所有的空間變換統一採用4X4矩陣,且頂點座標也採用相應的[x,y,z,w]型。大多數情況下,w=1,[x,y,z]與頂點本身座標保持一致。此外,多出的w在投影變換中發揮了至關重要的作用。
        II. 世界、視角空間變換
        從世界空間到視角空間通過相應的“視角矩陣”實現。為了更好的理解視角矩陣的作用,可以這樣理解:

       在任意時刻,相機在世界空間都有一個位置座標[Px,Py,Pz],同時也有相應的朝向,我們可以用三個座標軸來確定其朝向,即U,V,W,U指向相機右側,V指定相機上側,W為相機注視方向。那麼視角矩陣的作用,即把相機位置移回到世界座標系原點,且三個座標軸U,V,W與世界座標系的X,Y,Z分別重合。這就是視角矩陣的目的!理解這一點對於自己來實現靈活的照相機非常重要,因為實現照相機最重要的一點即根據任意時刻相機的位置、朝向來計算其視角矩陣。
        III. 視角、投影空間變換
        從視角空間到投影、裁剪空間依靠“投影矩陣”來實現。投影有兩種:正交投影和透明投影,大多數情況下,比如遊戲中,用到的投影為透視投影,因為這種投影方式與人觀察物體的方式是一樣的。
 要計算投影矩陣,首先要確定照相機的幾項基本引數:近、遠平面(n,f),投影平面的寬、高比(r),以及上、下視野角度大小(a)。近、遠平面規定照相機能看到的最近和最遠的距離。有了這些引數,所有能投影到螢幕上的點組成了如下所示的多面體:
 
        即一個被切掉頂部的金字塔。
        投影變換的效果即把這個多面體轉換成長方體,長、寬分別位於[-1,1]之間,z位於[0,1]之間。真正的裁剪操作就是在這個長方體中進行的,因此將大大簡化裁剪的計算。
        關於投影變換,要注意一點的是,很多人誤以為投影即把三維頂點投影到二維平面 上,投影變換後頂點的z座標即被拋棄,只剩下x,y座標用於後面的螢幕變換。實際上,投影變換後z座標並沒有消失,位於[0,1]之間。螢幕座標的變換不再使用z座標,但z座標在後面的Output Merger階段用於深度比較時發揮的關鍵作用。

       整個頂點著色階段到此結束。

3. Hull Shader Stage、Tessellation Stage、Domain Shader Stage
        這三個階段其實共屬於Tessellation Stage,即曲面細分階段,可選階段。這個是D3D11中剛加入的一個高階特性,主要用於如LOD(Level of Detail)技術中。
        該階段主要的好處即在執行期可利用顯示卡動態的增加模型多邊形的細節。例如在地形渲染中,根據距離照相機距離的遠近程式採用不同的細節等級,近距離的部分採用高精度的多邊形,遠距離的部分採用低精度的多邊形,以同時滿足視覺上的要求又優化了渲染。 另一個利用曲面細分的典型例子是Displacement Mapping,這個在後面學習法線對映時會介紹。

4. Geometry Shader Stage
        這個也是D3D11中加入的新特性,為可選階段。在這個階段中,輸入為一個完整的多邊形,點、線段或三角形。這個階段直接對輸入的多邊形進行操作,可以把其消滅,不再往下一個階段傳輸;也可以衍生出新的多邊形出來。總之,該階段操作的物件是完整的多邊形,相比於頂點著色階段,其操作的物件是單個的頂點。

5. Rasterizer Stage
        這個階段屬於不可程式設計階段,即完全由硬體實現,主要包括:
        1. 視口變換
        即把投影變換後得到的頂點的x,y座標,根據使用者設定的視口引數,變換到螢幕上對應的座標。
        2. 隱藏面消除(Backface Culling)
        即使經過了裁剪操作,對於每一個物體,照相機只能看到其正對著相機的一面,對背對著相機的一面是看不到的。這一步的任務即是把看不到的這一面消除掉,以免繼續對其進行處理影響效率。
        為了確定一個多邊形是正對著相機還是背對著相機,就要用到我們在Input Assembler Stage指定多邊形(三角形)時的頂點順序了。預設情況下,D3D規定按順時針順序指定的三角形屬於正面,逆時針為背面。如果V0,V1,V2按順時針排序,則該三角形為正面,將通過這一步的檢測,如果為逆時針,則被拋棄。
        確定順時針還是逆時針,可以用如下方法:
        給出兩個向量:E0 = V1-V0 E1 = V2-V0對E0和E1進行叉乘操作N = E0 X E1。如果N指向相機,則為正面,否則為背面。
        3. 頂點屬性的插值計算
        在Input Assembler Stage中,使用者指定的僅僅是一系列的多邊形,以三角形為合例,每個三角形由三個頂點組成,每個頂點包含一系列的屬性,如座標、法線、紋理座標等等。在經過頂點著色階段、視口變換後,這三個頂點在螢幕上都有對應的座標。但為了顯示該三角形,僅僅三個頂點顯然是不夠的,為了計算該三角形所覆蓋的螢幕上每個畫素處的屬性,要進行正確的插值計算。
 注意,插值計算的要求是,在世界空間中保證以三個頂點為基準進行線性計算,在二維螢幕上,以相應的投影后的三個頂點進行插值時不再是線性。插值方法如下圖所示:
 
        不過,這一點了解一下就夠了,畢竟這一步插值計算是完全由硬體完成的。如果想有興趣瞭解的更多一點,可以參考《Mathematics for 3D Game Programming and Computer Graphics》,針對這個有詳細講解。

6. Pixel Shader Stage
        這個階段也是完全可程式設計的一個階段,也是跟頂點著色器階段一樣十分重要的階段。因為在D3D11中,頂點著色器和畫素著色器是程式設計師實現的兩個最基本的階段。
        畫素著色器,從名字上也很容易看出,是在畫素級別上進行的計算。對於三維空間中投影到螢幕上的每一個多邊形,針對其在螢幕上所覆蓋的每一個畫素,逐個進行畫素著色計算。這一階段接受的資料是經過插值計算後的頂點屬性。輸出的是顏色值,以提供給下一階段處理。
        畫素著色器給程式設計師提供了相當多的靈活性和自由度,通過各種不同的演算法來計算片段顏色以實現各種特效。

 

7. Output Merger Stage
        這個階段即輸出片段的混合階段。該階段不可程式設計,但是高度可調節。程式設計師可以靈活地調整管線的狀態來實現不同的特效。比如針對深度緩衝區、模板緩衝區,混合等可以有各種不同的狀態。利用它們來實現各種特效後面也有特別詳細的介紹。


        D3D11整個渲染管線到這一步就結束了,小結一下:
        3D渲染管線的作用就是,給定場景描述:頂點屬性、索引、照相機、光源、材質等資訊,計算其在光柵顯示器螢幕上對應的顯示結果。其主要階段包括:Input Assembler Stage、Vertex Shader Stage、Tessellation Stage(包括三個子階段:Hull Shader Stage、Tessellator、Domain Shader Stage)、Geometry Shader Stage、Rasterizer Stage、Pixel Shader Stage、Output Merger Stage。
 
        3D渲染管線對於學習3D圖形學還是D3D API,都相當重要。因此,請務必花時間深刻理解之,否則是不可能靈活地寫Shader的。

相關文章