天天看點

Shader和渲染管線

什麼是Shader

Shader,中文翻譯即着色器,是一種較為短小的程式片段,用于告訴圖形硬體如何計算和輸出圖像,過去由彙編語言來編寫,現在也可以使用進階語言來編寫。一句話概括:

  • Shader是可程式設計圖形管線的算法片段。

它主要可以分成以下兩類:

  • Vertex Shader
  • Fragment Shader

什麼是渲染管線

渲染管線也稱為渲染流水線,是顯示晶片内部處理圖形信号互相獨立的并行處理單元。一個流水線是一序列可以并行和按照固定順序進行的階段。就像一個在同一時間内,不同階段不同的汽車一起制造的裝配線,傳統的圖形硬體流水線以流水的方式處理大量的頂點、幾何圖元和片段。

注意了解的是這裡有一個前後關系,前一個階段的輸入會到後一個階段去輸出。比如在頂點程式當中,頂點程式計算的資料就會作為片段程式再進一步加工的材料。

為了更形象地了解渲染管線:

Shader和渲染管線

最上面的是:

  • 【3D應用或者遊戲】

    3D應用或者遊戲會直接調用 【3D應用接口】,也就是OpenGL或者DirectX等。OpenGL和DirectX是友善應用程式去進行硬體通路和調用的中間層。如果沒有他們,我們就需要為硬體去編寫一個非常複雜的專門針對硬體的驅動程式。

再往下,則是:

  • 【CPU和GPU的分界線】

    在此之上都是CPU的操作,一下進行GPU的運算。

GPU的運算是 從左往右進行的,最開始是 【GPU前段子產品】 到 【圖元裝配】 這中間如果在過去T&L流水線的過程當中是由硬體設計好的運算過程,也就是內建的,它不能夠進行程式設計控制。

當圖形硬體有了可程式設計能力之後,我們就可以在這個階段使用 【頂點着色器】 進行編寫運算邏輯,用于取代過于直接內建在硬體中的運算。在這個階段完成之後,會到**【光栅化以及插值】**階段。

光栅化就是把計算機顯示卡當中運算的資料進行一個細分,用于去适配螢幕上具體的每一個像素的顯示,但是光栅化并不等同于像素顯示,像素顯示最終反映的是顔色,而光栅化過後得到的結果是 【幀緩存】,在這個過程當中,我們可以插入 【片段着色器】,這個部分就可以使用可程式設計化運算。是以 【片段着色器】 的目标是為螢幕上最終要顯示的每一個像素去計算它最後需要什麼樣的顔色。

對于Unity而言,上面的流程可以由下面的圖表示:

Shader和渲染管線

最上面 【Geometry】 是幾何模型,幾何模型進入 【Unity】,可以了解為把幾何模型Mesh、網格等資料交給Unity,Unity導入後就通過Unity引擎去調用 【Grphics APU】 圖形API,調用圖形API的過程就是在驅動GPU進行處理運算。

進入GPU運算首先進行的是 【Vertex Processor】 頂點處理器,這個部分就需要我們使用 【Vertex Shader】 頂點着色器,頂點着色器運算的結果會交給 【Pixel Processor】 像素處理器,也就是片段處理器,在這個部分我需要為像素處理編寫 【Pixel Shader】 像素着色器程式,這部分計算完後就輸出了最終我們可以用于在螢幕上的顔色資訊,我們把它叫做 【Frame Buffer】 幀緩沖。幀緩沖存儲的是計算機依次顯示所要的資料,但也不僅僅是這些資料,它還有其他的附加資訊,比如深度值等。

下面是Unity官方手冊中的一張渲染管線圖示。

Shader和渲染管線

渲染管道線中最左邊的這個部分中Transform指的是模型的空間變換,主要針對的是頂點的空間幾何變換;TexGen即Texture Generator,表示的是紋理坐标的生成,主要用于在頂點當中去取得紋理坐标,再轉換為UV取值的範圍;Lighting指的是光照。是以這個部分就是過去就是T&L幾何變換光照流水線,當圖形硬體具有了可程式設計能力後,這個固定的子產品就被 【Vertex Shader】 頂點着色器代替了。

在頂點着色器處理過後,Unity就進入 【Culling & Depth Test】 裁剪和深度測試過程。裁剪和深度測試描述的是如果一個物體在錄影機前展示,它向着錄影機的面會被觀察到,它背對着錄影機的面不會被觀察到,在這樣的情況下,為了減少GPU處理資料量就進行了一個裁剪(Culling),把看不見的面直接剔除,不需要去處理的這些面所涉及的頂點資料,進而加速圖形處理。第二個方面深度測試(Depth Test),指的是錄影機有一個特性,在計算機當中沒有無限這個概念,計算機處理的資料都是離散化的,它有一個範圍,當超過最近和最遠這個範圍的這部分會被剔除。

接下來就進入到紋理采樣(Texturing)和霧化處理(Fog)階段。在這階段實際上就是在進行光栅化處理,描述的就是如何在螢幕上顯示每一個像素的顔色。這裡需要去紋理采樣,一張貼圖有很多資料,我們去采集紋理上某一點的顔色值,這個就叫做紋理采樣。霧化就是根據最後計算的資料後需不需要進行一個霧化處理,近處的很清晰,遠處的有種朦胧感,這個部分就是片段着色器可程式設計的能力範圍。

之後還需要 【Alpha Test】,指的是去繪制那些半透明的或全透明的物體。經過【Alpha Test】之後還需要進行 【Blending】 處理,這階段會混合最終的圖像。

以上介紹的是渲染管線的流程,要把握的主要的過程就是我們可程式設計能力是兩個部分,一個就是幾何變換和光照使用的頂點着色器部分,另一個就是關于如何去采樣,去計算顔色以及霧化處理等使用的片段着色器部分。

這裡需要注意的是Unity優化當中有一個主要部分就是減少Draw Call的調用,Draw Call就指的是應用程式去調用圖形硬體GPU去進行渲染的排程過程。應用程式需要準備很多的資料,包括頂點資料、矩陣、向量等資料,都需要通過應用程式傳遞給GPU,這樣個排程過程CPU必須要去收集資料以後才産生一個API的調用,這個過程的消耗是高昂的,如果反複地啟動這個調用,那麼就僅僅收集和傳遞參數這樣的過程相當耗時耗力,就會造成了應用程式或遊戲運作的瓶頸。是以要盡量減少Draw Call,盡量減少CPU對GPU這樣的調用。

Shader和材質、貼圖的關系

Shader(着色器)實際上就是一小段程式,它負責将輸入的頂點資料以指定的方式和輸入的貼圖或者顔色等組合起來,然後輸出。繪圖單元可以依據這個輸出來将圖像繪制到螢幕上。輸入的貼圖或者顔色等,加上對應的Shader,以及對Shader的特定的參數設定,将這些内容(Shader及輸入參數)打包存儲在一起,得到的就是一個Material(材質),之後,我們便可以将材質賦予三維物體來進行渲染(輸出)了。

材質好比引擎最終使用的商品,Shader好比是生産這種商品的加工方法,而貼圖就是原材料。

小結

  • Shader是圖形可程式設計方案的程式片段。主要分為頂點着色器和片段着色器。
  • 渲染管線是一種計算機從資料到最終圖形成像的形象描述。
  • 材質可以了解為商品,Shader是加工這種商品的方法,而貼圖是加工過程中需要的材料。

參考文章:

shader和渲染管線

繼續閱讀