1. 程式人生 > >學習shader之前必須知道的東西之計算機圖形學(一)渲染...

學習shader之前必須知道的東西之計算機圖形學(一)渲染...

shader到底是幹什麼用的?shader的工作原理是什麼? 
        其實當我們對這個問題還很懵懂的時候,就已經開始急不可耐的要四處搜尋有關shader的資料,恨不得立刻上手寫一個出來。但看了一些資料甚至看了不少cg的語法之後,我們還是很迷茫,UNITY_MATRIX_MVP到底是個什麼矩陣?它和v.vertex相乘出來的又是什麼玩意?當這些問題困擾我們很久之後,我們才發現,原來我們是站在浮沙上築高臺,根基都沒有打牢當然不可能蓋得起高樓大廈了。 該文章來自
那根基是什麼呢?大牛曰,計算機圖形學。 
        shader中文名叫著色器,顧名思義,它的作用可以先簡單理解為給螢幕上的物體畫上顏色。而什麼東西負責給螢幕上畫顏色?當然是GPU,所以我們寫shader的目的就是告訴GPU往螢幕哪裡畫、怎麼畫。說到這其實大家應該很明白了,如果我們連GPU的工作原理都不知道,何談指揮它? 

說到計算機圖形學,包括我在內很多同學都非常害怕它,因為裡面包含了各種艱深的理論、變換,大量的公式什麼的。其實我們大可不必一開始就嚇倒自己,先從基本概念開始,慢慢來,總有一天我們也會成為大牛~! 
        最後,這篇文章不算是原創,最多算是摘要+讀後感,很多概念性文字都是我從書裡搬過來後再加上自己的理解,算是和大家一起學習,有理解不當之處還請多多指教。 
        廢話不多說,讓我們來進入第一章的學習,GPU的渲染管線。 

        所謂GPU的渲染管線,聽起來好像很高深的樣子,其實我們可以把它理解為一個流程,就是我們告訴GPU一堆資料,最後得出來一副二維影象,而這些資料就包括了”視點、三維物體、光源、照明模型、紋理”等元素。 

       在各種圖形學的書中,渲染管線主要分為三個階段:應用程式階段、幾何階段、光柵階段。 
1,應用程式階段。 
       這個階段相對比較好理解,就比如我們在Unity裡開發了一個遊戲,其實很多底層的東西Unity都幫我們實現好了,例如碰撞檢測、視錐剪裁等等,這個階段主要是和CPU、記憶體打交道,在把該計算的都計算完以後,在這個階段的末端,這些計算好的資料(頂點座標、法向量、紋理座標、紋理)就會通過資料匯流排傳給圖形硬體,作為我們進一步處理的源資料。 
2,幾何階段。 
       主要負責頂點座標變換、光照、裁剪、投影以及螢幕對映,改階段基於GPU進行運算,在該階段的末端得到了經過變換和投影之後的頂點座標、顏色、以及紋理座標。簡而言之,幾何階段的主要工作就是“變換三維頂點座標”和“光照計算”。


       問題隨之而來,為什麼要變換頂點座標?我是這麼理解的,比如你有一個三維遊戲場景,場景中的每個模型都可以用一個向量來確定它的位置,但如何讓計算機根據這些座標把模型正確的、有層次的畫在螢幕上?這就是我們需要變換三維頂點座標的原因,最終目的就是讓GPU可以將這些三維資料繪製到二維螢幕上。 
       根據頂點座標變換的先後順序,主要有如下幾個座標空間:Object space,模型座標空間;World space,世界座標空間;Eye space,觀察座標空間;Clip and Project space,螢幕座標空間。下圖就是GPU的整個處理流程,深色區域就是頂點座標空間的變換流程,大家瞭解一下即可,我們需要關注的是每個座標空間的具體含義和座標空間之間轉換的方法。


 

2.1,從object space到world space  
       object space有兩層核心含義,第一,object space中的座標值就是模型檔案中的頂點值,這些值是在建立模型時得到的,例如一個.max檔案,裡面包含的資料就是object space的座標。第二,object space的座標與其他物體沒有任何參照關係,這是object space和world space區分的關鍵。world space座標的實際意義就有有一個座標原點,物體跟座標原點相比較才能知道自己的確切位置。例如在unity中,我們將一個模型匯入到場景中以後,它的transform就是世界座標。

2.2,從world space到eye space 

       所謂eye space,就是以攝像機為原點,由視線方向、視角和遠近平面,共同組成的一個梯形體,如下圖,稱之為視錐(viewing frustum)。近平面,是梯形體較小的矩形面,也是靠近攝像機的平面,遠平面就是梯形體較大的矩形,作為投影平面。在這個梯形體的內的資料是可見的,超出的部分會被視點去除,也叫視錐剪裁。 
       例如在遊戲中的漫遊功能,螢幕的內容隨攝像機的移動而變化,這是因為GPU將物體的頂點座標從world space轉換到了eye space。 


 
2.3,從eye space到project and clip space 
       eye space座標轉換到project and clip space座標的過程其實就是一個投影、剪裁、對映的過程。因為在不規則的視錐體內剪裁是一件非常困難的事,所以前人們將剪裁安排到一個單位立方體中進行,這個立方體被稱為規範立方體(CCV),CVV的近平面(對應視錐體的近平面)的x、y座標對應螢幕畫素座標(左下角0、0),z代表畫面畫素深度。所以這個轉換過程事實上由三步組成: 
(1),用透視變換矩陣把頂點從視錐體變換到CVV中; 
(2),在CVV內進行剪裁; 
(3),螢幕對映:將經過前兩步得到的座標對映到螢幕座標系上。 

2.4,primitive assembly(圖元裝配)和triangle setup(三角形處理) 

       到目前為止我們得到了一堆頂點的資料,這一步就是根據這些頂點的原始連線關係還原出網格結構。網格由頂點和索引組成,這個階段就是根據索引將頂點連結到一起,組成線、面單元,然後進行剪裁,如果一個三角形超出螢幕以外,例如兩個頂點在螢幕內,一個頂點在螢幕外,這時我們在螢幕上看到的就是一個四邊形,然後把這個四邊形切成兩個小的三角形。

       現在我們得到了一堆在螢幕座標上的三角形面片,這些面片是用於光柵化的。 

3,光柵化階段。 

       經過上面的步驟之後,我們得到了每個點的螢幕座標值,和我們需要繪製的圖元,但此時還有兩個問題: 
     (1)螢幕座標是浮點數,但畫素是用整數來表示的,如何確定螢幕座標值所對應的畫素? 
     (2)如何根據已確定位置的點,在螢幕上畫出線段或者三角形? 
       對於問題1,繪製的位置只能接近兩指定端點間的實際線段位置,例如,一條線段的位置是(10.48, 20.51),轉換為畫素位置就是(10,21)。 
       問題2,涉及到具體的畫線和填充演算法,有興趣的話可以研究。 
       這個過程結束後,頂點和圖元已經對應到畫素,之後的流程就是如何處理畫素,即給畫素賦予顏色值。 
       給畫素賦予顏色的階段稱為Pixel Operation,是在更新幀快取之前,執行最後一系列針對每個片段的操作,其目的是計算出每個畫素的顏色值。在這個階段,被遮擋的面通過一個被稱為深度測試的過程消除。 
       pixel operation包含下面這些流程: 
      (1)消除遮擋面; 
      (2)Texture operation,紋理操作,根據畫素的紋理座標,查詢對應的紋理值; 
      (3)Blending,通常稱為alpha blending,根據目前已經畫好的顏色,與正在計算的顏色的alpha值混合,形成新的顏色。 
      (4)Filtering,將正在計算的顏色經過某種濾鏡後輸出。 
       該階段之後,畫素的顏色值被寫入幀快取中。