在這一小節,主要學習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日
廣州