OpenGL Shading Language GLSL作爲一種着色語言是純粹的和GPU打交道的計算機語言。因爲GPU是多線程並行處理器,所以GLSL直接面向SIMD模型的多線程計算。GLSL編寫的着色器函數是對每個數據同時執行的。每個頂點都會由頂點着色器中的算法處理,每個像素也都會由片段着色器中的算法處理。因此,初學者在編寫自己的着色器時,需要考慮到SIMD的併發特定,並用並行計算的思路來思考問題
最常見的用法是在頂點着色器生成所需要的值,然後傳遞給片段着色器使用。
GLSL能做什麼?
- 日益逼真的材質 – 金屬、岩石、木頭、油漆等。
- 日益逼真的光照效果 – 區域光和軟陰影。
- 非現實材質 – 美術效果、鋼筆畫、水墨畫和對插畫技術的模擬。
- 針對紋理內存的新用途。
- 更少的紋理訪問。
- 圖形處理 – 選擇、邊緣鈍化遮蔽和複雜混合。
- 動畫效果 – 關鍵幀插值、粒子系統。
- 用戶可編程的反走樣方法。
GLSL注意
- GLSL支持函數重載
- GLSL不存在數據類型的自動提升,類型必須嚴格保持一致。
- GLSL不支持指針、字符串、字符,它基本上是一種處理數字數據的語言。
- GLSL不支持聯合、枚舉類型、結構體位字段及按位運算符。
數據類型
GLSL有三種基本數據類型:float,int和bool,以及這些數據類型組成的數組和結構體。
需要注意的是:GLSL並不支持指針。與C/C++不同的是,GLSL將向量和矩陣作爲基本數據類型。
注意:GLSL不存在數據類型的自動提升,類型必須嚴格保持一致。
標量
- float
- int
- bool
42 // 十進制
042 // 八進制
0x2A // 十六進制
GLSL不存在數據類型的自動轉換,必須嚴格保持一致
矢量
矢量可以和標量甚至矩陣做加減乘除(必須符合規則)
vec2, vec3, vec4 // 包含2/3/4個浮點數的矢量
ivec2, ivec3, ivec4 // 包含2/3/4個整數的矢量
bvec2, bvec3, bvec4 // 包含2/3/4個布爾值的矢量
聲明:
vec3 v; //聲明三維浮點型向量v
v[1]=3.0; //給向量v的第二個元素賦值
// 下面兩種等價
vec3 v = vec3(0.6);
vec3 v = vec3(0.6, 0.6, 0.6);
注意:除了用索引的方式外,還可以用選擇運算符的方式來使用向量。選擇運算符是對於向量的各個元素(最多爲4個)約定俗稱的名稱,用一個小寫拉丁字母來表示。根據向量表示對象的意義不同,可以使用以下選擇運算符:
- 表示頂點可以用(x、y、z、w)。
- 表示顏色可以用(r、g、b、a)。
- 表示紋理座標用(s、t、r、q)。
用戶可以選擇其中任意一種選擇運算符,它們的作用是等效的。
也即是說,如果v是一個向量,那麼v[0]、v.r、v.x和v.s都是指向量v的第一個元素。例如:
vec4 v1=vec4(1.0, 2.0, 3.0, 4.0); //用構造函數的方式聲明並初始化四維浮點型
vec4 v2;
v2.xy=v1.yz; //將v1的第二個和第三個元素複製到v2的第一個和第二個元素
v2.z=2.0; //給v2的第三個元素賦值
v2.xy=v1.yx; //將v1的頭兩個元素互換,再複製到v2的頭兩個元素中
矩陣
mat2,mat3,mat4 – 2x2/3x3/4x4 的矩陣
矩陣式按列順序組織的,先列後行。
例如:
mat4 m; //聲明四維浮點型方陣m
m[2][3]=2.0; //給方陣的第三列、第四行元素賦值
// 下面兩種等價,初始化矩陣對角
mat2 m = mat2(1.0)
mat2 m = mat2(1.0, 0.0, 0.0, 1.0);
取樣器(Sampler)
紋理查找需要指定哪個紋理或者紋理單元將指定查找。
sampler1D // 訪問一個一維紋理
sampler2D // 訪問一個二維紋理
sampler3D // 訪問一個三維紋理
samplerCube // 訪問一個立方貼圖紋理
sampler1DShadow // 訪問一個帶對比的一維深度紋理
sampler2DShadow // 訪問一個帶對比的二維深度紋理
uniform sampler2D grass;
vcc2 coord = vec2(100, 100);
vec4 color = texture2D(grass, coord);
如果一個着色器要在程序裏結合多個紋理,可以使用取樣器數組
const int tex_nums = 4;
uniform sampler2D textures[tex_nums];
for(int i = 0; i < tex_nums; ++i) {
sampler2D tex = textures[i];
// todo ...
}
結構體
這是唯一的用戶定義類型
struct light
{
vec3 position;
vec3 color;
};
light ceiling_light;
數組
數組索引是從0開始的,而沒有指針概念
// 創建一個10個元素的數組
vec4 points[10];
// 創建一個不指定大小的數組
vec4 points[];
points[2] = vec4(1.0); // points現在大小爲3
points[7] = vec4(2.0); // points現在大小爲8
void
只能用於聲明函數返回值
類型轉換
必須明確地進行類型轉換,不會自動轉換提升。
float f = 2.3;
bool b = bool(f); // b is true
限定符
GLSL中有4個限定符(varable qualifiers)可供使用,它們限定了被標記的變量不能被更改的“範圍”。
- const
- attribute
- uniform
- varying
const
const和C++裏差不多,定義不可變常量,表示限定的變量在編譯時不可被修改。
attribute
attribute是應用程序傳給頂點着色器用的。不允許生命時初始化,attribute限定符標記的是一種全局變量,該變量在頂點着色器中是隻讀(read-only)的,該變量被用作從OpenGL應用程序向頂點着色器中傳遞參數,因此該限定符僅能用於頂點着色器。
uniform
uniform一般是應用程序用於設定頂點着色器和片段着色器相關初始化值。不允許聲明時初始化,uniform限定符標記的是一種全局變量,該變量對於一個圖元(primitivie)來說是不可更改的,它可以從OpengGL應用程序中接受傳遞來的參數。
varying
varying用於傳遞頂點着色器的值給片段着色器。不允許聲明時初始化,它提供了從頂點着色器向片段着色器傳遞數據的方法,varying限定符可以再頂點着色器中定義變量,然後再傳遞給光柵化器,光柵化器對數據插值後,再將每個片段的的值交給片段着色器。
限制
- 不能再if-else中生命變量
- 用於判斷的條件必須是bool類型(if,while,for…)
- (?:)操作符後兩個參數必須類型相同
- 不支持switch語句
vec4 toonify(in float intensify)
{
vec4 color;
color = vec4(0.8,0.8,0.8,0.8)
return color;
}
discard
discard關鍵字可以避免片段更新幀緩衝區,當流控制遇到這個關鍵字時,正在處理的片段就會被標記位丟
函數
- 函數名可以通過參數類型重載,但是和返回類型值無關
- 所有參數必須完全匹配,參數不會自動
- 函數不能被遞歸調用
- 函數返回值不能是數組
hanshu參數標示符
in:進複製到函數中,但不返回的參數(默認)
out:不將參數複製到函數中,單返回參數
inout:複製到函數中並返回
混合操作
通過選擇器(.)後列出各分量名,就可以選擇這些分量
vec4 v4;
v4.rgba; // 得到vec4
v4.rgb; // 得到vec3
v4.b; // 得到float
v4.xy; // 得到vec2
v4.xgba; // 錯誤!分量名不是同一類
v4.wxyz; // 打亂原有分量順序
v4.xxyy; // 重複分量