Shader學習-渲染流水線


簡單記錄了關於學習《Unity Shader 入門精要》的一些內容。

什麼是渲染流水線

渲染流水線的工作是從一個三維場景出發,生成一張二維圖片。《Real-Time Rendering,The Edition》一書中將渲染流程分爲3個階段:
應用階段幾何階段光柵化階段

應用階段

渲染流水線的起點是CPU,即是應用階段。在應用階段開發者需要準備好場景數據,例如攝像機位置,光源,場景中的模型等;其次可以進行粗粒度剔除工作,以把那些不可見的物體剔除出去,這樣就不需要再移交給幾何階段進行處理;最後需要設置好渲染狀態。應用階段最重要的輸出就是渲染圖元。應用階段可分3個 階段:

  1. 加載數據到顯存中。 渲染所需要的數據都需要從硬盤中加載到內存(RAM),然後網格紋理等渲染所需要的信息又被加載到顯存(VRAM)中。
  2. 設置渲染狀態。 渲染狀態定義了場景中的網格怎樣被渲染的。例如,使用哪個頂點着色器、片元着色器、光源屬性、材質等。如果沒有定義渲染狀態,那麼所有網格都會使用同一種渲染狀態。
  3. 調用Draw Call 。 準備好上述所有工作後,CPU就需要調用渲染命令來告知GPU可以開始渲染了。Draw Call實際上就是一個命令,由CPU發起,GPU接收,命令指向一個需要被渲染的圖元列表。當給定了一個Draw Call時,GPU就會根據渲染狀態(材質、紋理、着色器等) 和所有輸入的頂點數據來計算,最終完成屏幕顯示。

GPU流水線

幾何階段和光柵化階段的實現載體是GPU,開發者無法擁有絕對的控制權,幾何階段和光柵化階段可以分成若干個更小的流水線階段,每個階段GPU提供了不同的可配置性和可編程性。

綠色表示完全可編程控制,實線表示該Shader必須由開發者編程實線,虛線是可選的。
黃色表示可配置但不可編程。
藍色表示由CPU固定實現,開發者沒有任何控制權。

GPU的渲染流水線實現

頂點着色器

頂點着色器處理單位是頂點,即輸入進來的每個頂點都會調用一次頂點着色器。頂點着色器的任務主要是:頂點變換和逐頂點光照。

  • 座標變換。頂點着色器必須完成的工作是把頂點座標從模型空間轉換到齊次裁剪空間,接着由硬件設備做透視除法後,得到歸一化的設備座標(NDC)。 頂點着色器可以在這一步中改變頂點的位置,實現類似水面流動的頂點動畫。

裁剪

不在攝像機視野範圍內的物體將不會被處理,完全在和完全不在攝像機視野範圍內的很好理解。跟範圍邊界有交叉情況時,會在線段和邊界生成新的頂點,外部的則被裁剪掉。

屏幕映射

把每個圖元的x,y座標轉換到屏幕座標系。屏幕座標是二維座標系,所以最終會是一個從[-1,1]到窗口座標x1,y1,x2,y2縮放的過程。輸入的z會與屏幕座標系一起構成窗口座標系傳入光柵化階段。

三角形設置和三角形遍歷

計算一個三角形網格所需要的信息。從上一階段傳入都是網格的頂點信息,爲了得到整個三角網格的覆蓋情況,必須知道每條邊上的像素座標。
三角形遍歷會檢查每個像素是否被一個三角形網格所覆蓋,如果被覆蓋該像素就會生成一個片元(fragment)。這一步的輸出就是一個片元序列。片元並不是真正意義上的像素,它還包含了很多狀態的集合,這些集合用於計算每個像素最終顯示出來的顏色。這些狀態包括了(屏幕座標、深度信息、法線、紋理座標)等。

片元着色器

片元着色器輸出是一個或多個顏色值。這一階段可以完成很多重要的渲染技術,其中最重要的技術之一是紋理採樣。爲了在片元着色器中進行紋理採樣,我們通常會在頂點着色器階段輸出每個頂點所對應的紋理座標,然後通過光柵化階段對三角網格的三個頂點對應的紋理座標進行插值後,就可以得到其覆蓋的片元的紋理座標。
除最後一個階段的逐片元操作會對像素產生影響外,光柵化的前幾個階段都不會影響屏幕像素的顏色值,而是會產生一系列的數據信息。

逐片元操作

最後一個階段在OpenGL中叫做逐片元操作,在DirectX中,叫做輸出合併階段。這一階段的主要任務有:

  • 決定每個片元的可見性。這涉及了很多測試工作。例如深度測試,模板測試等。
  • 如果一個片元通過測試後,會將這個片元的顏色和已經存在在顏色緩存區的顏色進行混合。

片元 → 模板測試 → 深度測試 → 混合 → 顏色緩衝區
逐片元操作階段所做的操作。
只有通過所有測試後,新生成的片元才能和顏色緩衝區中已經存在的像素顏色進行混合,最後再寫入顏色緩
衝區。

  • 模板測試(Stencil Test)。與之相關的是模板緩衝,如果開啓了模板測試,GPU會首先讀取(使用讀取掩碼?)模板緩衝區中該片元位置的模板值,然後進行比較,比較函數可以自定義,片元沒有通過測試將會被捨棄掉。無論片元有沒有通過模板測試,我們都可以根據與模板測試和深度測試結果來修改模板緩衝區(??這裏不太明白)。模板測試通常用於限制渲染的區域。模板測試還用於更高級的用法,如渲染陰影、輪廓渲染等。
  • 深度測試。如果一個片元通過模板測試,接下來便是深度測試。如果開啓了深度測試。GPU會把該片元的深度與已經存在於深度緩衝區的中的深度進行對比,比較函數可以設置。如果一個片元沒有通過深度測試,會被捨棄,同時沒有權力改寫深度緩衝區。如果通過測試開發者可以通過是否開啓深度寫入來限制該片元是否能夠覆蓋緩衝區的值。
  • 合併。當一個片元通過所有操作,將會進行合併操作。完全用新的顏色覆蓋原有顏色還是與原有顏色混合是合併操作需要決定的事情。對於不透明物體可以選擇關閉 混合(Blend) 操作,直接覆蓋,而對於半透明物體,我們需要使用混合操作來達到所需效果。如果開啓了混合,GPU會取出源顏色(片元着色器得到的顏色)和目標顏色(存在於顏色緩衝區中的顏色)進行混合。這裏需要一個混合函數,函數與透明通道息息相關。例如根據透明通道進行相加、相減、相乘等。

上面給的測試順序並不是唯一的,雖然從邏輯上來說這些測試在片元 着色器之後進行,但對於大多數GPU,都會盡可能在執行片元着色器之前就進行這些測試,片元着色器階段花費很多算出片元的顏色,卻因爲沒有通過測試,片元被捨棄到,那計算成本將全部浪費掉。但是這種Early-Z技術有可能會跟片元着色器中的操作相沖突,例如在片元着色器中進行了透明度測試,會手動捨棄掉不滿足測試的片元。那麼GPU就不能進行提前測試。現代GPU會判斷片元着色器中的操作是否與提前測試相沖突,如果衝突,會禁用掉提前測試,這樣會造成性能上的下降。

避免我們看到正在進行光柵化的圖元,GPU會使用雙重緩衝策略,場景的渲染在幕後發生,即後置緩衝中,一旦渲染完成,就會交換前置緩衝和後置緩衝,保證看到的圖像都是連續的。

問題

關於Draw Call

Draw Call 是CPU向GPU發起的一個渲染命令。CPU和GPU通過命令緩衝區實現並行工作,CPU向命令緩衝區添加命令,GPU從緩衝區中讀取命令,添加和讀取操作相互獨立。命令緩衝區中命令有很多,Draw Call 只是其中一種,其他還有改變渲染狀態等(改變使用的shader,使用不同的紋理等,改變渲染狀態更加耗時)
Draw Call 多了會影響幀率。 CPU每次調用Draw Call之前,都會向GPU發送很多內容,包括數據、狀態和命令等,CPU需要完成很多操作,CPU完成這些準備工作後,GPU就可以開始本次渲染,GPU的渲染速度是往往快於CPU提交命令的速度的,Draw Call過多時,CPU會把大量時間花費在提交Draw Call上,造成CPU過載。。
減少Draw Call。 批處理。批處理需要在CPU在內存中合併網格,更適用於靜態物體。

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