OpenGL 圖形渲染流程入門

1、什麼是 shader

shader 中文名爲着色器,全稱爲着色器程序,是專門用來渲染圖形的一種技術。通過 shader,我們可以自定義顯卡渲染畫面的算法,使畫面達到我們想要的效果。小到每一個像素點,大到整個屏幕。通常來說,程序是運行在 CPU 中的,但是着色器程序比較特殊,它是運行在 GPU 中的,所以當我們在編寫 shader 程序的時候,實際上也是在編寫 GPU 程序。在 OpenGL 中,對應的着色器語言是 GLSL(OpenGL Shading Language)。通過 shader 編程,我們可以實現很多渲染風格,如馬賽克效果、素描風格等。

2、OpenGL 圖形渲染流程

當我們使用 OpenGL 時,都是基於 3D 空間去編程的,但是最終呈現到屏幕或者窗口時卻是二維的像素數組,所以簡單來說 OpenGL 的渲染流程其實就是將 3D 座標轉換成適配屏幕的 2D 像素,而這個過程實際上是由 OpenGL 的圖形渲染管線管理的,大致可以劃分成兩步:

  1. 將 3D 座標轉換成 2D 座標。

  2. 將 2D 座標轉換成實際有顏色的像素。

如下圖所示,圖形渲染管線可以被劃分爲頂點着色器、圖元裝配、幾何着色器、光柵化、片段着色器和測試混合六個階段,每一個階段將會把前一個階段的輸出作爲輸入。所有這些階段都是高度專門化的(它們都有一個特定的函數),並且很容易並行執行。正是由於它們具有並行執行的特性,當今大多數顯卡都有成千上萬的小處理核心,它們在 GPU 上爲每一個(渲染管線)階段運行各自的小程序,從而在圖形渲染管線中快速處理你的數據。這些小程序就是 shader。

2.1. 頂點着色器

3D 圖形都是由一個個三角面片組成的,頂點着色器就是計算每個三角面片上的頂點,併爲最終像素渲染做準備。在頂點着色器中,可以訪問到頂點的三維位置、顏色、法向量等信息。可以通過修改這些值,或者將其傳遞到片元着色器中,實現特定的渲染效果。

可以作爲頂點着色器的輸入有:

頂點着色器常見的輸出有:

在頂點着色器進行的業務處理有:

2.2. 圖元裝配

圖元裝配,即將從頂點着色器中輸出的頂點根據 primitive (原始的連接關係)還原成網格結構。網格由頂點和索引組成,在這個階段是根據索引將頂點連接在一起,組成線、面單元。之後就是對超出屏幕外的三角形進行裁剪。

這裏的裁剪怎麼理解呢?假設有一個三角形,三角形的一個頂點在屏幕外,兩個頂點在屏幕內,這個時候就需要將超出屏幕外的三角形裁剪掉,所以我們能看到的其實是一個四邊形,然後再將這個四邊形的頂點裝配成兩個三角形圖元的形狀。

同時在圖元裝配這個階段還需要根據三角形面片的頂點順序 —— 也就是三角形的法向量朝向來判斷是否要進行去除操作。一般頂點按照逆時針排序,根據右手定則來決定三角面片的法向量,如果該法向量朝向視點(法向量與到視點的方向的點積爲正),該面是正面。如果該面是反面,則進行背面去除操作。

這裏注意:在這個階段進行的所有裁剪剔除計算都是爲了減少需要繪製的頂點個數。

2.3. 幾何着色器

幾何着色器位於頂點和片段着色器之間,如果沒有使用時,則頂點着色器輸出到片元着色器,在使用幾何着色器後,頂點着色器輸出組成一個基礎圖元的頂點信息到幾何着色器,經過幾何着色器處理後,再輸出到片元着色器。幾何着色器能夠產生 0 個以上的基礎圖元 (primitive),它能起到一定的裁剪作用、同時也能產生比頂點着色器輸入更多的基礎圖元。

幾何着色器在啓用後,它將獲得頂點着色器以組成一個基礎圖元爲一組的頂點輸入,通過對輸入的頂點進行處理,幾何着色器將決定輸出的圖元類型和個數。當輸出的圖元減少或者不輸出時,實際上起到了裁剪圖形的作用,當輸出的圖元類型改變或者輸出更多圖元時起到了產生和改變圖元的作用。

2.4. 光柵化

光柵化階段會接收來自幾何着色器的圖元數據輸出。在這個階段會把圖元映射爲最終屏幕上相應的像素,生成供片段着色器 (Fragment Shader) 使用的片段 (Fragment)。在片段着色器運行之前會執行裁切 (Clipping)。裁切會丟棄超出你的視圖以外的所有像素,用來提升執行效率。光柵化分爲三角形設置與三角形遍歷兩個階段:

這一步的輸出就是得到一個片元序列。需要注意的是,一個片元並不是真正意義上的像素,而是包含了很多狀態的集合,這些狀態用於計算每個像素的最終顏色。這些狀態包括了 (但不限於) 它的屏幕座標、深度信息,以及其他從幾何階段輸出的頂點信息,例如法線、紋理座標等。

2.5. 片段着色器

在片段着色器階段的主要目的是計算一個像素的最終顏色,這也是所有 OpenGL 高級效果產生的地方。通常,片段着色器包含 3D 場景的數據(比如光照、陰影、光的顏色等等),這些數據可以被用來計算最終像素的顏色。

這裏注意:光柵化階段後得到的是一個個 “片元”。片元和像素已經非常接近了,但兩者仍是有區別的。用一種通俗的說法來解釋的話,就是比如三維空間內有兩個從攝像機角度看過去一前一後的三角形,它們重疊部分的顯示區域,每個像素對應兩個片元;不重疊的部分,像素和片元一一對應。當然,這個例子是簡化過的,真實的對應關係可能更復雜一些。片段着色器也是我們能夠在圖形渲染過程中進行編程的一個階段。

2.6. Alpha 測試和混合

Alpha test 是一種類似 depth test 一般的存在,簡單粗暴,通過多個條件來判斷當前的片元是否通過測試,只要有一個條件不通過,即被捨棄而不會對後續渲染產生任何影響。當前片元的透明度是其中一個重要的指標,通常我們設定一個閾值,如果透明度小於這個閾值,那麼就會被直接捨棄,相當於這個片元透明到 "看不到"、"消失" 了一般;而高於這個閾值的面片則會被當作不透明的物體來進行處理。這種簡單粗暴的方法無法實現真正透明的效果。

Alpha blending 則能夠真正實現透明的效果。它將當前面片的 alpha 通道值(透明度)作爲混合因子,參與該面片本身的顏色與顏色緩衝區中本身顏色的混合。需要注意的是,alpha 混合過程中需要關閉深度寫入,但不關閉深度測試。不關閉深度測試意味着,當一個不透明的物體在另一個物體前面的時候,能夠通過深度測試正常渲染更近的不透明的物體。

所以,即使在片段着色器中計算出來了一個像素輸出的顏色,在渲染多個三角形的時候最後的像素顏色也可能完全不同。

3、參考文章

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/bw7GQDJhirVoddiBeErSlA