渲染會將抽象幾何轉換為像素。GPU 管線會取得頂點、轉換它們、裁切它們、光柵化可見形狀,並對產生的片段進行著色。
管線 #
典型的渲染管線包含以下階段:
- 頂點處理;
- 基元組裝;
- 裁切與視埠轉換;
- 光柵化;
- 片段著色;
- 深度與混合;
- 畫格緩衝區寫回。
這個順序很重要,因為每個階段都會將問題從幾何逐步縮小到像素。
頂點資料 #
輸入通常從頂點清單與索引緩衝區開始。
- 頂點包含位置,以及色彩、法線或紋理座標等選用屬性;
- 索引會在三角形之間重複使用頂點;
- 基元通常是三角形,因為三角形總是共平面。
頂點著色器會在每個頂點執行一次。它的工作是將位置轉換到裁切空間,並將每個頂點的資料傳遞到後續階段。傳統轉換會將每個物件空間位置乘以模型、視圖與投影矩陣:
clip_position = projection * view * model * object_position模型矩陣將物件放置到世界空間,視圖矩陣表達相對於攝影機的世界,投影矩陣則將攝影機空間的視錐映射到齊次裁切空間。矩陣順序取決於 API 與向量慣例;著色器與主機程式碼必須一致。
裁切空間與裁切 #
裁切空間外的幾何會在光柵化前被裁切。在 OpenGL 與 WebGL 中,當 -w <= x, y, z <= w 時,裁切空間頂點位於內部。若三角形跨越邊界,GPU 會建立可見多邊形並捨棄外部部分。
裁切後,透視除法會將正規化裝置座標(NDC)計算為 (x/w, y/w, z/w)。接著視埠轉換會將 NDC 映射到視窗座標。透視相依屬性的插值會使用齊次 w 值,因此紋理座標不會像仿射螢幕空間值那樣失真。
光柵化 #
光柵化會將三角形轉換為片段,也就是候選像素。光柵器會決定哪些取樣位置位於三角形內,並在表面上插值屬性。
插值值包括:
- 色彩;
- 深度;
- 紋理座標;
- 法線或其他 varying。
即使輸入只在角落指定值,這項插值也能讓三角形呈現漸層。
片段著色 #
片段著色器會在每個片段執行一次,並計算最終色彩或捨棄決策。
典型的片段工作包括:
- 紋理取樣;
- 光照近似;
- alpha 測試或捨棄;
- 色彩校正;
- 程序式圖樣。
許多視覺上重要的效果都發生在這個階段,因為著色器可以將插值屬性與紋理及 uniform 結合。
深度、混合與畫格緩衝區 #
深度緩衝區會解決重疊基元之間的可見性。若一個片段比另一個更接近,通常會保留較近的片段。
混合會組合半透明表面的來源與目的地色彩。它對透明度、粒子與 UI 效果很有用,但取決於繪製順序。通常會先啟用深度寫入繪製不透明幾何,再使用仔細選取的混合因子,由後往前繪製半透明幾何。
最終色彩會寫入畫格緩衝區,接著呈現到螢幕或影像目標。
WebGL 視角 #
WebGL 透過 JavaScript 暴露這條管線。canvas 提供繪製表面,著色器以來源字串提供,瀏覽器將工作交給 GPU。WebGL 繼承 OpenGL ES 的裁切空間慣例:NDC 在三個軸上都涵蓋 [-1, 1],而視窗座標將視埠原點放在左下角。瀏覽器影像來源通常是由上而下,因此紋理上傳或座標可能需要明確垂直翻轉。
心智模型仍然相同:
- 上傳緩衝區;
- 設定頂點屬性;
- 編譯著色器;
- 綁定程式、畫格緩衝區與其他必要狀態;
- 繪製三角形;
- 呈現產生的畫格。
實務規則 #
WebGL 是狀態機。繪製呼叫會使用目前綁定的程式、頂點陣列與緩衝區繫結、紋理、畫格緩衝區、視埠、深度狀態與混合狀態。當輸出錯誤時,應檢查繪製呼叫時的完整狀態,而不只是著色器來源。
評論
在 GitHub 上閱讀或評論(發表評論需要登入)