1. 程式人生 > 其它 >Chapter 1 The Graphics Rendering Pipeline

Chapter 1 The Graphics Rendering Pipeline

歡迎來到萬惡之源——渲染管線,這是一切罪惡的開始

這玩意的主要功能就是決定在給定虛擬相機、三維物體、光源、照明模式,以及紋理等諸多條件的情況下,生成或繪製一幅二維影象的過程

(二向箔打擊懂不懂啊)

1.1 Architecture

在rtr4中,是將圖形渲染管線分成了四個階段,(而在rtr3和入門精要中之分成了三個階段)

• 應用程式階段

• 幾何階段

• 光柵化階段

• 逐片元階段

幾個要點:

每個階段本身也可能是一條管線,如圖中的幾何階段所示。此外,還可以對有的階段進行全部或者部分的並行化處理,如圖中的光柵化階段。應用程式階段雖然是一個單獨的過程,但是依然可以對之進行管線化或者並行化處理。

• 最慢的管線階段決定繪製速度,即影象的更新速度,這種速度一般用 FPS 來表示,也就是每秒繪製的影象數量,或者用 Hz 來表示。 

1.2 The Application Stage

 應用程式階段是通過軟體方式來實現的階段,開發者能夠對該階段發生的情況進行完全控制,可以改變實際效能。正因應用程式階段是軟體方式實現,因此不能像幾何和光柵化階段那樣繼續分為若干個子階段。但為了提高效能,該階段還是可以在幾個並行處理器上同時執行。在 CPU 設計上,稱這種形式為超標量體系(superscalar)結構,因為它可以在同一階段同一時間做不同的幾件事情。

應用階段大致可分為三個階段(CPU->GPU):

  1. 把資料載入在視訊記憶體(CPU ->RAM-> VRAM)

   2.設定渲染狀態

    3.呼叫Draw Call

  • CPU通過呼叫Draw Call 來告訴GPU開始進行一個渲染過程,一個Draw Call 會指向本次呼叫需要渲染的圖元列表(DC就是一個命令,CPU是發起方,GPU是接收方)

 1.2.1什麼是Draw Call

  ①就是 CPU呼叫圖形API

  ②深入理解Draw Call的一些問題

  (a).問題一: CPU GPU 是如何實現並行工作的?

    解決方法就是使用命令緩衝區 (Command Buffer)

       

   (b).問題二:為什麼 Draw Call 多了會影響幀率?

    如果 Draw Call 的數批太多, CPU 就會把大獻時間花費在提交 Draw Call 上,造成 CPU 的過載。

     

  (c).問題三:如何減少 Draw Call?

    有很多方法。其中一個:批處理

      把很多小的 DrawCall 合併成一個大的Draw Call, 這就是批處理的思想。如圖

      

1.2.2什麼是OpenGL、DirectX

API(Application Programming Interface,應用程式介面)是一些預先定義的介面(如函式、HTTP介面),或指軟體系統不同組成部分銜接的約定。 用來提供應用程式與開發人員基於某軟體或硬體得以訪問的一組例程,而又無需訪問原始碼,或理解內部工作機制的細節

① API (Application Programming Interface) :應用程式設計介面

【應用程式設計介面】是指電腦作業系統或程式庫提供給應用程式呼叫使用的程式碼,其主要目的是讓應用程式開發人員得以呼叫一組例程功能,而無須考慮其底層的原始碼為何、或理解其內部工作機制的細節。

②兩者都是圖形API,要開發者直接訪問 GPU 件非常麻煩的事情,我們可能需要和各種暫存器、視訊記憶體打交道,而圖形API在這些硬體的基礎上實現了一層抽象。

//渲染命令即Draw Call

通常視線的方法有碰撞檢測,加速演算法,輸入檢測,動畫,力反饋以及紋理動畫,變換模擬,幾何變形,以及一些不在其他階段執行的計算,如層次視錐剪裁等加速演算法就可以在這裡實現

主要任務:在應用程式階段的末端,將需要在螢幕上(具體形式取決於具體輸入裝置)顯示出來繪製的幾何體(也就是繪製圖元,rendering primitives,如點、線、矩形等)輸入到繪製管線的下一個階段。

總結:將需要繪製圖元輸入到繪製管線的下一個階段,以及實現一些軟體方式來實現的階段

1.3 The Geometry Processing Stage

幾何階段主要負責大部分多邊形操作和頂點操作

1.模型視點變換 Model and View Transform

在顯示過程中,模型通常需要變換到若干不同的空間或座標系中,目的是從模型座標變換到世界空間座標,讓所有模型都位於同一個空間中。為了便於後續投影和剪裁,這一步必須對相機和所有模型進行視點變換,變換目的就是要把相機放在原點,然後進行試點校準,變換後實際位置和方向就依賴於當前的API,我們稱之為相機空間或觀察空間

 

【總結】模型和檢視變換階段分為模型變換和檢視變換。模型變換的目的是將模型變換到適合渲染的空間當中,而檢視變換的目的是將攝像機放置於座標原點,方便後續步驟的操作。

2 頂點著色 Vertex Shading

確定材質上的光照效果的這種操作被稱為著色,著色過程涉及在物件上的各個點處計算著色方程,而一部分計算是在模型頂點上執行的,而其他計算可以在每畫素光柵化期間執行。可以在每個頂點處儲存各種材料資料,結算完成後,會被髮送到光柵化階段進行插值操作

【總結】頂點著色階段的目的在於確定模型上頂點處材質的光照效果。這裡引入頂點著色器(Vertex Shader),頂點資料來自於CPU,主要工作是將:頂點座標從模型空間轉換到齊次空間,逐頂點光照

o.pos = mul(UNITY_MVP,v.position)

GPU在每個輸入的網格頂點上都會呼叫頂點著色器,頂點著色器必須進行頂點的座標變換,同時還可以計算和輸出頂點的顏色

 

頂點著色器會將模型頂點的位置變換到其次裁剪座標空間下,進行輸出後再由硬體做透視除法得到NDC空間下的座標

 在齊次裁剪空間的基礎上進行透視除法(perspective division)或稱齊次除法(homogeneous division),得到的座標叫做NDC空間座標。

補充渲染流水線:

模型資料-頂點著色 - 曲面細分 - 幾何著色器 - 裁剪 - NDC空間 - 螢幕空間 - 光柵階段 - 幀快取

其中曲面細分和幾何著色器是可選項,而從裁剪空間---NDC空間---螢幕空間一般由底層幫我們自動完成。我們的頂點著色器只需要把頂點轉換到齊次裁剪空間就可(就是一般所說的輸出的positionCS)空間。

透視除法:就是將齊次裁剪空間座標positionCS的X,Y,Z分量都除以W分量。

我們假設在NDC空間中,經過透視除法後的點為:那麼x’,y’,z’的取值範圍則在【-1,1】區間內。反推會齊次裁剪空間的公式:NDC空間到螢幕空間:頂點著色器我們的輸出在齊次裁剪,那麼片段著色器的輸入是什麼呢?不是齊次裁剪空間,也不是NDC空間,而是螢幕空間。在Unity中螢幕左下角畫素座標為(0,0),右上角畫素座標為(pixelWidth,pixelHeight),由於當前x,y的座標範圍為【-1,1】,因此是一個縮放的過程,可以用下面公式變換:

ScreenX = NDCx * pixelWidth/2 + pixelWidth/2;

ScreenY = NDCy * pixelWidth/2 + pixelWidth/2;

ScreenZ的值通常為Clipz/Clipw,存入深度緩衝,但也不是必須。

注意上面所說的螢幕空間和使用unity內建函式o.screenPos = ComputeScreenPos(o.vertex)不同,內建函式直接從齊次裁剪空間轉換,沒有經過透視除法轉換到NDC空間的過程,所以如果使用內建函式,需要自己在片段著色器中不上透視除法。

如果需要從螢幕空間轉換到NDC空間,可以使用內建函式ComputeScreenPos(o.vertex),求得ScreenPos後進行下面公式轉換:

float4 ndcPos = (o.screenPos / o.screenPos.w) * 2 - 1;

3 投影 Projection

在光照處理之後,渲染系統就會開始進行投影操作,將視體變換到一個對角頂點分別是(-1,-1,-1)和(1,1,1)單位立方體,目前,主要由兩種投影方法:正交投影,透視投影

兩種投影方式的主要異同點:

• 正交投影。正交投影的可視體通常是一個矩形,正交投影可以把這個視體變換為單位立方體。正交投影的主要特性是平行線在變換之後彼此之間仍然保持平行,這種變換是平移與縮放的組合。

• 透視投影。相比之下,透視投影比正交投影複雜一些。在這種投影中,越遠離攝像機的物體,它在投影后看起來越小。更進一步來說,平行線將在地平線處會聚。透視投影的變換其實就是模擬人類感知物體的方式。

• 正交投影和透視投影都可以通過 4 x 4 的矩陣來實現,在任何一種變換之後,都可以認為模型位於歸一化處理之後的裝置座標系中。

【總結】投影階段就是將模型從三維空間投射到了二維的空間中的過程。

4 裁剪 Clipping

主要工作:裁剪掉那些不在攝像機視野範圍的物體(不需要被處理)

 

只有在單位立方體的圖元才需要被繼續處理。因此,完全在單位立方體外部的圖元(紅色三角形)被捨棄,完全在單位立方體內部的圖元(綠色三角形)將被保留。和單位立方體相交的圖元(黃色三角形)會被裁剪,新的頂點會被生成,原來在外部的頂點會被捨棄

【總結】裁剪階段的目的,就是對部分位於視體內部的圖元進行裁剪操作。

5 螢幕對映 Screen Mapping

主要工作:把每個圖元的座標轉換到螢幕座標系 (Screen Coordinates) 下

1.4 光柵化階段The Rasterizer Stage

光柵化階段即從二維頂點所處的螢幕空間(都包含深度值及各種與相關的著色資訊)到螢幕上的畫素的轉化。

把一堆三角形變成真正的圖(打散成畫素)

 

1.4.1三角形設定 Triangle Setup

來源:三角網格的頂點資料

主要工作:計算三角網格表示的資料

1.4.2三角形遍歷(Triangle Traversal)

主要工作:檢查每個畫素是否被一個三角網格所覆蓋。如果被覆蓋的話,就會生成一個片元 (fragment) 。 而這樣一個找到哪些畫素被三角網格覆蓋的過程就 是三角形遍歷,這個階段也被稱為掃描變換

 

三角形遍歷的過程。根據幾何階段輸出的頂點資訊,最終得到該三角網格覆蓋的畫素位置。對應畫素會生成一個片元,而片元中的狀態是對三個頂點的資訊進行插值得到的。例如,對圖中三個頂點的深度進行插值得到其重心位置對應的片元的深度值為-10.0

【總結】找到哪些取樣點或畫素在三角形中的過程通常叫三角形遍歷(TriangleTraversal)或 掃描轉換(scan conversion)。

1.4.3片元著色器(Fragment Shader)

//DirectX中叫作畫素著色器(Pixel Shader)

輸入:輸入是上一個階段對頂點資訊插值得到的結果

輸出:是一個或者多個顏色值

 

根據上一步插值後的片元資訊,片元著色器計算該片元的輸出顏色

畫素著色階段是在可程式設計 GPU 內執行的,在這一階段有大量的技術可以使用,其中最常見, 最重要的技術之一就是紋理貼圖(Texturing)

1.4.4 融合Merging/逐片元操作 Per-Fragment Operations

主要工作: a.決定每個片元的可見性

      b.如果一個片元通過了所有的測試 就需要把這個片元的顏色值和已經儲存在顏色緩衝區顏色進行合併(混合)。

 

這個階段還負責可見性問題的處理。這意味著當繪製完整場景的時候,顏色緩衝器中 應該還包含從相機視點處可以觀察到的場景圖元。對於大多數圖形硬體來說,這個過程是通 過 Z 緩衝(也稱深度緩衝器)演算法來實現的。Z 緩衝演算法非常簡單,具有 O(n)複雜度(n 是需要繪製的畫素數量),只要對每個圖元計算出相應的畫素 z 值,就可以使用這種方法:

Z 緩衝器和顏色緩衝器形狀大小一樣,每個畫素都儲存著一個 z 值,這個 z 值是從相機到最近圖元之間的距離。每次將一個圖元繪製為相應畫素時,需要計算畫素位置處圖元的 z 值,並 與同一畫素處的 z 緩衝器內容進行比較。如果新計算出的 z 值,遠遠小於 z 緩衝器中的 z 值, 那麼說明即將繪製的圖元與相機的距離比原來距離相機最近的圖元還要近。這樣,畫素的 z 值和顏色就由當前圖元對應的值和顏色進行更新。反之,若計算出的 z 值遠遠大於 z 緩衝器 中的 z 值,那麼 z 緩衝器和顏色緩衝器中的值就無需改變。

//對於不透明物體,開發者可以關閉混合(blend)操作,這樣片元著色器計算得到的顏色值會直接覆蓋掉顏色緩衝區的畫素區。但對於半透明物體,我們就需要用混合操作來讓這個物體看起來是透明的

而當圖元通過光柵化階段之後,從相機視點處看到的東西就可以在熒幕上顯示出來。為了避 免觀察者體驗到對圖元進行處理併發送到螢幕的過程,圖形系統一般使用了雙緩衝(double buffering)機制,這意味著螢幕繪製是在一個後置緩衝器(backbuffer)中以離屏的方式進行 的。一旦螢幕已在後置緩衝器中繪製,後置緩衝器中的內容就不斷與已經在螢幕上顯示過的前置緩衝器中的內容進行交換。注意,只有當不影響顯示的時候,才進行交換。

【總結】主要任務是合成當前儲存於緩衝器的由之前的畫素著色階段產生的片段顏色,還負責可見性問題的處理

 

Unity中不透明物體的渲染順序:從前往後

也就是說深度小的先渲染,其次再渲染深度大的

Unity中透明物體的渲染順序:從後往前(類似畫家演算法,會造成 OverDraw)