【OPENGL】第三篇 着色器基礎(二)

 


 

在這一小節,主要學習GLSL的基本數據類型以及控制結構。GLSL具有了C++和Java的不少特性,咱們會先了解全部着色階段共有的特性,再瞭解各個着色器的專屬特性。數組

 


 

一、着色器的基本結構緩存

一個着色器程序和一個C程序相似,都是從main()函數開始執行的。一樣支持單行註釋//以及多行註釋/**/函數

#version 330 core
void main(){
    // add test code
}

 

 二、着色器的數據類型學習

GLSL是一種強類型的語言,全部變量使用前的必須聲明。可用字母、數字、以及下劃線字符來組成變量名字。可是數字或者下劃線字符不能做爲變量名的第一個字符,也不能使用連續下劃線。ui

全部變量都必須在聲明的同時進行初始化。atom

類型透明:基本數據類型(float、double、int、uint、bool)以及聚合類型(所謂聚合類型就是基本類型的合併)spa

類型不透明:採樣器(sampler)、圖像(Image)、原子計數器(atomic counter)。翻譯

 

前面提到的聚合類型,每一個基本類型都有對應的聚合類型,以int爲例,有2D向量(vec2)、3D向量(vec3)、4D向量(vec4)以及矩陣(mat二、mat4)等類型。指針

須要注意的是對於矩陣類型好比mat4×3,其中第一個值表示列數,第二個值表示行數。此外,矩陣的指定須要遵循主序的原則。也就是說,傳入的數據將先填充列,而後填充行。code

 

向量與矩陣中的元素是能夠單獨訪問和設置的。下面主要說三種比較特殊的份量

(x,y,z,w) 與位置相關的份量

(r,g,b,a)  與顏色相關的份量

(s,t,p,q)  與紋理座標相關的份量

 

此外,還有數組類型,一個大小爲n的數組的元素範圍是0到n-1。

float coeff[3];
float[3] coeff;
int indices[];

相似其餘語言好比C++/Java。  

數組擁有構造函數 float coeff[3] = float[3](2.38, 3.14, 42.0)

GLSL的數組能夠獲取數組的長度 length() 該函數返回元素的個數。由於長度值在編譯時就是已知的,因此length()方法會返回一個編譯時常量。

 

 三、着色器的存儲限制符(Storage Qualifiers)

數據類型能夠經過一些修飾符來改變本身的行爲。GLSL中一共定義了4種全局範圍內的修飾符。

一、const 將一個變量定義爲只讀形式,能夠理解爲常量的意思

二、in 設置爲着色器階段的輸入變量

三、out 設置爲着色器階段的輸出變量

四、uniform 表示惟一,對全部幾何圖元的值都是一致的,除非應用程序對它執行了更新,不然着色器是並不會影響它的值的變化的。

五、buffer 設置應用程序共享的愉快可讀寫的內存

六、shared  只能用於用於計算着色器當中,它能夠創建本地工做組內共享的內存。

 

四、邏輯語句

與其餘語言相似GLSL提供了大量的操做符以及控制語句執行流程的邏輯操做

包括算術運算符、操做符、ifels、while、for、break、continue、return等,

這裏有個特殊的關鍵字 discard 它只能用於片元着色器中,用於丟棄當前的片元、終止着色器的運行,不過這也得取決於具體的硬件實現。

 

另外函數的聲明以及定義和C/C++相似,而且使用函數以前必須先聲明,不然會產生錯誤。可是,須要特別注意的是,GLSL中沒有指針或者引用的概念,

所以,GLSL提供了參數限制符,來代表其參數時候能夠修改或者拷貝到函數等等,類型以下:

一、in 將數據拷貝到函數中(默認)

二、const in 將只讀數據拷貝到函數中

三、out 從函數中獲取數值

四、inout 將數據拷貝到函數中,而且返回函數中修改的數據

 


 

以上大概瞭解了GLSL的數據類型以及語句,下面是一些零散的知識點,先看看,之後用到時再從新回顧。


 

一、計算的不變性

GLSL沒法保證在不一樣的着色器中,兩個徹底相同的計算公式會獲得徹底同樣的結果。所以GLSL提供了invariant和precise關鍵字來保持着色器之間的計算不變性。

關於這個知識點,暫時沒法理解,之後再回顧。

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

二、着色器的預處理器(跳過)

三、數據塊接口(Interface Blocks)

着色器與應用程序之間,或者着色器階段之間共享的變量能夠組織爲變量塊的形式,而且有的時候必須採用這種形式

例如 uniform塊、in塊、out塊、buffer塊等等。

寫法有點類型結構體的寫法:

下面以uniform爲例
uniform b{   vec4 v1;   bool v2; };
一個uniform塊中只能夠包含透明類型的變量,並且uniform塊必須在全局做用域內聲明。

注意:着色器中的數據類型有兩種:不透明以及透明的。上文有說起。

四、從應用程序中訪問uniform塊

uniform變量是着色器與應用程序之間共享數據的橋樑,所以若是着色器中的uniform變量是定義在命名的uniform塊中,那麼就有必要找到不一樣變量的偏移值。

五、Buffer塊

GLSL中的buffer塊,或者對於應用程序而言,就是着色器的存儲緩存對象(shader storage buffe object)

與uniform塊相似,可是buffer塊更爲強大。若是不須要寫入緩存,那麼能夠直接使用uniform塊,而且硬件設備自己可能也沒有足夠的資源空間來支持buffer塊,

可是uniform塊一般是足夠的。

六、in/out塊


 

 

關於着色器的編譯

 

OpenGL着色器程序的編寫與C語言等基於編譯器的語言很是相似。

咱們使用編譯器來解析程序,檢查是否存在錯誤,而後將它翻譯爲目標代碼obj。而後,在鏈接過程當中將一系列目標文件合併,併產生最終的可執行程序。

在程序中使用GLSL着色器的過程與之相似,只不過編譯器和鏈接器都是OpenGL API的一部分而已。

 

常規步驟:

對於每個着色器對象:

  一、建立一個着色器對象

  二、將着色器源代碼編譯爲對象

  三、驗證着色器的編譯是否成功

將後須要將多個着色器對象連接爲一個着色器程序,包括:

  一、建立一個着色器程序

  二、將着色器對象關聯到着色器程序

  三、鏈接着色器程序。

  四、判斷着色器的鏈接過程是否成功完成

  五、使用着色器來處理頂點和片元

相關OpenGL函數

  一、建立着色器對象  glCreateShader(GLenum type)

     type必須是  GL_VERTEX_SHADER、GL_FFRAGMENT_SHADER、

              GL_TESS_CONTROL_SHADER、GL_TESS_EVALUATION_SHADER、GL_GEOMETRY_SHADER

     中的一個。

  二、將着色器的源代碼關聯到這個對象上。  glShaderSource(...)

  三、編譯着色器對象的源代碼       glCompileShader()

  四、將着色器對象shader關聯到着色器程序program中    glAttachShader()

and so on...


 

 

不知不覺明天就是11月份了。一份小記拖了將近2個月,我也是醉了。

最近發現了DOOM3源碼,如獲至寶。之後有時間會研究下約翰卡馬克大神的這個引擎。

 

10月31日

廣州

相關文章
相關標籤/搜索