管道
如前所屬,本書講解的API版本是OpenGL ES 3.0。本書的目標是,深刻講解OpenGL ES 3.0的技術細節,給出具體的例子來講明如何使用某個特性,而且討論了各類性能優化技術。當您讀完這本書,您應該能夠對OpenGL ES 3.0API有一個很好的把握。您將能夠輕鬆的寫出讓人新服的OpenGL ES 3.0的應用程序,而且您沒必要經過閱讀多種OpenGL ES的規範來搞懂某個特性是如何工做的。
OpenGL ES 3.0實現了可編程着色圖形管道。OpenGL ES 3.0規範包含兩部分:OpenGL ES 3.0 API的規範和OpenGL ES 3.0 着色語言規範(OpenGL ES SL)。
下圖1-1描述了OpenGL ES 3.0的圖形管道。圖中有陰影的模塊表明OpenGL ES 3.0圖形管道中可變成的階段。下面將逐個介紹OpenGL ES 3.0圖形管道的各個階段。
頂點着色器(Vertex Shader)
本節將給出頂點着色器的一個高層次的概述。頂點着色器(Vertex Shader)和片斷着色器(Fragment Shader)將在之後的章節中作詳細的介紹。頂點着色器實現了一套用來操做頂點的通用的方法。
頂點着色器的輸入以下:
- 着色器程序(Shader Program) —— 用來對頂點進行操做的頂點着色程序源代碼或者可執行程序。
- Attribute —— 由頂點列表提供的每一個頂點的數據。
- Uniform —— 頂點着色器(或者片斷着色器)使用的常亮。
- Sampler(採樣器) —— 一種特殊類型的Uniform,它表明了每一個頂點着色器使用的紋理。
在OpenGL ES 2.0中頂點着色器的輸出被乘坐Varying變量,可是在OpenGL ES3.0中被重命名爲「頂點着色器輸出變量(vertex shader output variables )」。在原始光柵化階段,每一個生成片斷的頂點着色輸出值被計算出來,這些被計算出的值將會被做爲片斷着色器的輸入。用來計算每一個片斷上頂點着色輸出值的機制被乘坐「差值(
interpolation )」。此外,OpenGL還提供一個一個新的功能,叫作變換反饋(
transform feedback )。變幻反饋容許將頂點着色器的輸出值有選擇的寫入輸出緩存中。例如,在第14章中,有一個在頂點着色器中實現粒子系統的程序實例。在這個程序中,變換反饋就被輸出到了一個緩存對象中。頂點着色器的輸入和輸出以下圖所示。
頂點着色器能夠用於傳統的基於頂點的操做,如經過矩陣變換位置,計算光線方程來產生每頂點顏色,紋理座標生成或轉換。另外,因爲頂點着色器能夠由應用程序指定,因此能夠在頂點着色器中使用自定義的數學方法,來實現傳統固定管道中沒法實現的新的變換,光照以及基於定點處理的特殊效果。
Example 1-1 展現了一個用OpenGL ES着色語言實現的頂點着色器。本書之後的章節中將很是消息的介紹頂點着色器,而此處給出這個例子,只是想讓讀者瞭解頂點着色器大概是個什麼樣子。在Example1-1的頂點着色器中,將位置(position)和顏色(color)做爲輸入,使用一個4*4的矩陣對位置作變換,而後輸入變換後的位置和顏色。
着色器程序的第一行,提供了着色語言的版本。版本信息必須出如今着色器的第一行。本例子中的「#version 300 es」 表示OpenGL ES着色語言的版本是v3.00 。第二行,描述了一個Uniform變量u_mvpMatrix,他保存了模型視圖和投影矩陣。第七和第八行描述了頂點着色器的輸入。其中a_position是頂點的位置屬性,a_color是頂點的顏色屬性。第十二行,聲明瞭一個輸出變量v_color。這個變量做爲頂點着色器的輸出之一,保存了每一個頂點的顏色。gl_Position是一個內建變量,它找着色器中被自定生命,而且,OpenGL ES要求頂點着色器必須將變換以後的頂點位置賦值給這個變量。一個頂點着色器(或者片斷着色器)有惟一的一個程序入口叫作main方法。第13行到第17行描述了頂點着色器的main方法。第15行,咱們從定點輸入屬性a_color讀取丁點的顏色值,而後將它做爲頂點着色器輸出的顏色,保存在v_color中。第16行,將變幻以後的頂點位置保存在頂點着色器輸出gl_Position中。
圖元裝配(Primitive Assembly )
OpenGL ES 3.0圖形渲染管道中,在定點着色器以後的一個階段是圖元裝配。圖元指的是一個幾何對象,例如三角形,直線或者點精靈。圖元的每一個頂點數據被髮送給頂點着色器的不一樣copy。在圖元組裝階段,這些被處理過的頂點數據又被傳回給圖元。
對於每一個圖元,必需要肯定其是否處在透視錐內部(透視錐就是3D空間中在屏幕上可見的部分)。若是某個圖元不是徹底被包含在透視錐的內部,這個圖元就須要被透視錐切割。若是圖元是徹底處在透視錐之外,那麼這個圖元將被拋棄。在透視錐對圖元進行切割以後,頂點的座標被轉換成屏幕座標。也能夠根據指定渲染的方式是正面(face forward)仍是反面(backward),捨棄不須要被渲染的部分圖元。這個操做被稱做消隱(Culling)。在完成了切割和消隱以後,圖元被傳送給渲染管道的下一個階段——光柵化階段。
光柵化(Rasterization)
下一個階段,如Figure1-3所示,是光柵化階段。在這個階段相關的圖元(如點精靈、直線和三角形)將被描繪。光柵化過程是要完成將圖元轉化成一組能夠在以後的片斷着色器上被處理的二維片斷的過程。這些片斷表明着能夠被花到屏幕上的像素點。
片斷着色器(Fragment Shader)
片斷着色器實現了一套操做片斷的通用的編程方法。如Figure1-4所示,片斷着色器是用來處理每個在光柵化階段生成的片斷的。片斷着色器的輸入以下:
- 着色器程序(Shader Program)—— 片斷着色器的源代碼或者可執行程序。它描述了着色器將對片斷執行那些操做。
- 輸入變量——頂點着色器的輸出變量,在光柵化階段經過插值方法獲得的每一個插值單元,在此處被做爲片斷着色器的輸入。
- Uniform——片斷着色器中須要使用的常量。
- 採樣(Samples)——特殊類型的Uniform,表明着片斷着色器使用的紋理。
片斷着色器能夠拋棄片斷,或者生成一個或多個被做爲片斷着色器輸出的顏色值。
一般狀況下,片斷着色器只會產生一個顏色值,除非是須要向多個渲染目標進行渲染操做(參考第11章的多目標渲染相關的章節)。對於多目標渲染的狀況,輸出的每個顏色值對應一個渲染目標。在OpenGL ES 3.0的圖形渲染管道中,顏色、深度、模板、以及在光柵化階段中生成的屏幕座標被做爲每一個片斷操做的輸入。
Exeample1-2描述了一個簡單的片斷着色器。Exeample1-2的片斷着色器和Exeample1-1的頂點着色器組合起來,就能夠畫出一個高氏着色(Gouraud-shaded)三角形。一樣,咱們會在本書的後面章節詳細介紹片斷着色器。咱們此處給出找個例子只是讓讀者對片斷着色器有個基本的瞭解。
就像前面介紹的頂點着色器同樣,第一行,給出了找色語言的版本,這個版本信息必須出如今着色器代碼的第一行(#version 300 表示對應的OpenGL ES找色語言版本是v3.00)。第二行,設置了默認的精度限制符。精度限制符會在第四章「着色器和着色程序」中詳細介紹。第四行描述了片斷着色器的輸入。OpenGL ES 要求頂點着色器中必須輸出相同的一組變量,以後這組變量的值會在片斷着色器中會被讀入。第六行聲明瞭片斷着色器的輸出變量。這個輸出的顏色值會做爲下一個階段的輸入。第七行至第十行,描述了片斷着色器的main方法。此處,輸出的顏色值被賦值爲輸入的顏色值。片斷着色器的輸入是在光柵化過程當中被插值的數據,而後這些數據被傳送給片斷着色器。
逐個片斷的處理(Per-Fragment Operations)
在片斷着色器以後,是逐個片斷的處理。光柵化過程當中生成的座標爲(x,y)的片斷,只能修改幀緩存(framebuffer)中座標爲(x,y)位置的想素。Figure1-5描述了OpenGL ES 3.0中逐個片斷操做階段。
如Figure1-5所示,逐個片斷處理階段對每一個片斷執行的操做以下:
- 像素歸屬測試(Pixel ownership test)—— 這個測試過程將決定幀緩存中位置爲(x,y)的像素當前是否歸OpenGL ES全部。這個測試中容許窗口系統來決定幀緩存中的像素是否屬於當前OpenGL ES上下文。例如,若是用來顯示OpenGL ES幀緩存的窗口被另外一個窗口遮住了,窗口系統就能夠決定被遮住的像素不屬於OpenGL ES上下文。這樣,這些遮住的像素就不會被顯示。儘管像素所屬測試是屬於OpenGL ES的一部分,它倒是OpenGL內部機制來實現的,而不是由開發者來控制的。
- 剪裁測試(Scissor test)—— 剪裁測試用來肯定座標爲(x,y)的點是否落在OpenGL ES的部分狀態肯定出的剪裁矩形內部。若是片斷是在剪裁區域的外部,這個片斷就會被丟棄。
- 模板和深度測試(Stencil and depth測試)—— 模板和深度測試分表做用在片斷的模板和深度值上。經過這些測試,能夠肯定是否要丟棄當前片斷。
- 混合(Blending)—— 混合是根據片斷的顏色值和幀緩存中對應位置的顏色值進行混合,生成新的顏色的操做。
- 抖動(Dithering)—— 經過使用抖動,能夠最小化因爲在幀緩存中使用有限精度致使的圖像上的瑕疵。
逐個片斷處理階段最終操做,是在幀緩衝取(x,y)座標肯定的位置上寫入該片斷的顏色值、深度值、模板值,或者將該片斷丟棄掉。若是在各類測試以後,沒有丟棄該片斷,那麼,無論顏色、深度、模板相關的寫入掩模(write mask)有沒有被啓用,對這些值的寫入操做都會被執行。寫入掩模能夠更好的控制寫入相關緩存的顏色、深度和模板值。例如,針對顏色緩存的寫入掩模能夠被設置成只有紅色值能夠寫入到顏色緩存中。此外,OpenGL ES 3.0提供了一個從緩存區中讀取像素值的接口。
注意:
alpha測試和「邏輯操做」不在包含在逐個片斷處理階段中。在OpenGL ES 2.0和OpenGL ES 1.x中,這兩個操做曾經是支持的。片斷着色器能夠丟棄片斷,alpha測試等價的操做能夠在頂點着色器中完成,因此alpha測試就沒有存在的必要了。對於邏輯操做,在應用開發中是不多使用的,並且OpenGL ES的工做組也沒有收到獨立應用開發者針對OpenGL ES 2.0 中支持邏輯操做的需求。因此,這個功能也在OpenGL中被放棄了。