Unity&Shader基礎篇-可程式設計GPU圖形繪製管線
Cg是最早的為可程式設計圖形硬體設計的高階程式語言。它是英偉達和微軟公司一起合作開發出來了語言,如果你非常熟悉C語言或者其他的程式語言,如C++、C#或者Java等,那對於Cg語言你將會非常容易掌握。Cg程式通常都比較的小,結構也非常的簡單,儘管如此,不瞭解基本的Cg語言的語法和它的執行機制也是很難理解一段Cg程式到底做了什麼以及要怎麼控制它到達預期的效果
1.1、可程式設計GPU圖形繪製管線
所謂可程式設計圖形繪製管線,就是給定虛擬攝像機、模型、光源等元素輸出一副電腦螢幕顯示的二維影象。《實時計算機圖形學》的書中概況圖形繪製管線為三個主要的階段:應用程式階段、幾何階段和光柵階段。
應用程式階段,是使用高階語言進行開發,主要和CPU進行交流,如我們熟知的碰撞檢測就是在此階段執行的。基於此特點開發者能夠對該階段進行完全的控制,因此可以通過一些演算法的應用來提高效能。
幾何階段,主要負責頂點變換、光照、裁剪、投影以及螢幕對映。該階段是在GPU中執行的,考慮到要將三維模型最終顯示在一個二維的螢幕上,因此該階段最重要就是頂點座標空間的轉換。值得注意的是光照計算也是在幾何階段被處理。
光柵化階段,決定哪些畫素最終顯示在螢幕上的過程,霧化和透明度處理都是在這個階段被處理。
GPU是高度並行的處理器,實際上它包含兩種並行機制:縱向並行和橫向並行。可以這樣去理解,想象一個工廠的工人在一個流水線上同時工作,這個就是縱向並行,而一個國家的相同工廠在同時工作,這就叫縱向並行。在OpenGL ES 1.X、核心OpenGL 1.X以及Direct3D 7.x中的管線都是配置了固定功能的管線,這個管線中都不能通過程式進行控制。而在OpenGL(ES)、WebGL和Direct3D8.0中上述兩個並行處理管線是可程式設計的,即稱為可程式設計圖形繪製管線,Cg程式就是在這個階段被執行。如圖所示虛框部分為可程式設計階段,塗黑框部分為圖元資料,其他部分為固定功能階段。
其中頂點著色器和片段著色器會在接下來的章節中具體講述,也是本書的重點。
1.1.1、頂點座標空間的轉換
在可程式設計圖形繪製管線中頂點著色器最重要的任務就是將圖元頂點的從模型區域性座標空間轉換到螢幕座標空間。雖然可程式設計頂點著色器允許頂點變換的方法很多,但是有些變換過程還是發生在之後的固定功能階段。當編寫頂點著色器程式的時候,理解那些過程各自發生在哪個階段是非常重要的。如圖1.2所示
為具體的轉換過程,前三個過程都發生在頂點著色器中,透視剔除和視口轉換髮生在固定功能階段,在該階段都被自動執行並且不能對其進行任何控制。
模型座標轉換:將模型座標或者區域性座標轉換到常見的世界座標。模型座標通常都是美術通過模型工具,如maya或者3D Max等工具指定。世界座標是場景中所有物件共用的座標系,這些物件如光源、3D音效和所有3D模型。視點轉換:將世界座標轉換成視點座標,視點就相當於Unity的虛擬攝像機,視點座標系就以虛擬攝像機為原點的座標系。如圖所示
視點轉換就是將模型的世界座標轉換成視點所在的座標系。而通常Unity中所說的攝像機的視場角就是在座標軸方向上所展開的角度,如1.3圖中的 角。
投影轉換和裁剪剔除:投影分為正交投影和透視投影,圖1.3所示為透視投影,正交投影即近裁剪面和遠裁剪面一樣大。它們的區別就是正交投影投出來的影象沒有遠近之分,而透視投影有;它們之間的聯絡就是都要進行裁剪剔除。實際上,投影轉換就是將視點座標系轉換成裁剪座標系,所有處於近、遠裁剪面的梯形體外的部分都將被裁剪掉。最後這些轉換後的裁剪座標進行歸一化設定,使得所有的座標值都在-1到1的範圍內,在這個階段座標仍然是三維的。
視口轉換:將歸一化後的座標對映到螢幕上進行繪製,這個過程是發生在GPU的固定功能階段,被GPU自動執行。螢幕對映會進行平移,x.y座標會被改變,新的x和y座標被稱為螢幕座標,將與z座標一起進入光柵階段。
1.1.2、圖元裝配和光柵化階段
圖元裝配:前面經過頂點變換後得到都只是單個的頂點資訊,在圖元裝配階段會根據頂點的序列和分類資訊將頂點裝配成幾何圖元。最後會產生一序列的三角形、線段和點。如圖1.4所示的片段紋理對映和著色,最後到光柵化的階段。光柵化其實就是一個決定哪些畫素被幾何圖元覆蓋的過程,螢幕在重新整理的過程其實就是畫素不停的被覆蓋的過程。光柵化後,一個圖元擁有的頂點數目和產生的片段之間沒有任何關係。例如,一個由頂點組成的三角形可以佔據整個螢幕而需要生產上百萬個片段。
片段和畫素的區別:在光柵化階段會把每個幾何圖元(如三角形)所覆蓋的畫素分解成畫素大小的片段。而畫素代表幀緩衝中某個指定位置的內容,如顏色、深度和其他與這個位置相關聯的值;片段即是經過各種光柵化測試之後得到的將更新一個特定畫素的潛在狀態。
光柵化操作:將螢幕空間的二維頂點轉換為螢幕上的畫素。這個階段會根據許多測試來檢查每個片段,這些測試包括剪下、透明度混合、模板和深度等測試。這些測試過程會決定最後畫素的位置、顏色的值,所以,如果任何一項測試不通過這個片段就會被丟棄掉。
雙緩衝機制:為了避免出現閃屏或卡幀的現象,GPU都採用了雙緩衝機制,一旦螢幕在後置緩衝器中繪製,後置緩衝器中的內容就會不斷與顯示在螢幕上的前置緩衝器的內容進行交換。
Z緩衝器:也稱為深度緩衝器,前面提到的深度測試的過程也即是Z緩衝器的處理過程。每個畫素都儲存著一個z值,這個z值是圖元到虛擬相機之間的距離。當將一個圖元繪製成畫素的時候,需要將畫素位置處圖元z值與處在Z緩衝器裡的同一畫素的z值進行比較。如果新得到的z值遠遠小於Z緩衝器中的z值,就說明這個圖元距離相機更近,因此需要使用新得到的畫素去更新當前圖元的資訊。反之,則圖元資訊不變。注意這裡提到的是畫素的z值,不是模型距離攝像機的距離z,畫素有可能是前面的模型也有可能是後面的模型進行覆蓋後的畫素。
當圖元經過以上這些變化之後,就可以在螢幕上看到影象。Z緩衝之所以重要,是因為z值決定了物體之間的相互遮擋關係,如果沒有足夠的精度,則兩個相距很近的物體就會出現隨機遮擋的現象。
透明度混合:為了繪製透明物體,通常需要對物體進行排序。首先,繪製不透明的物體;然後,在不透明物體的後面,對透明物體按照由後到前的順序進行混合處理。實時繪製中對於透明度的混合有一定的侷限性,如,因為透明度的厚度導致管線的逐步弱化和光線在物體內的折射效果。如果按照任意序列會產生嚴重的失真,因此對於排序會使用Z緩衝。關於透明度混合的相關技術可以參考《實時計算機圖形學(第二版)》第四章4.5節(59頁)。
模板緩衝:如果一個畫素的模板緩衝中存放了1,則表示該畫素對應的空間處於陰影體中。所有模板緩衝通常都是處理陰影效果的。