GLSL基礎
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、p、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個限定符(variable qualifiers)可供使用,它們限定了被標記的變量不能被更改的"范圍"。
- const
- attribute
- uniform
- varying
const
const和C++里差不多,定義不可變常量
表示限定的變量在編譯時不可被修改
attribute
attribute是應用程序傳給頂點着色器用的
不允許聲明時初始化
attribute限定符標記的是一種全局變量,該變量在頂點着色器中是只讀(read-only)的,該變量被用作從OpenGL應用程序向頂點着色器中傳遞參數,因此該限定符僅能用於頂點着色器。
uniform
unifrom一般是應用程序用於設定頂點着色器和片斷着色器相關初始化值。
不允許聲明時初始化
uniform限定符標記的是一種全局變量,該變量對於一個圖元(primitive)來說是不可更改的 它可以從OpenGL應用程序中接收傳遞來的參數。
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關鍵字可以避免片段更新幀緩沖區,當流控制遇到這個關鍵字時,正在處理的片段就會被標記為丟
函數
- 函數名可以通過參數類型重載,但是和返回值類型無關
- 所有參數必須完全匹配,參數不會自動
- 函數不能被遞歸調用
- 函數返回值不能是數組
函數參數標示符
in: 進復制到函數中,但不返回的參數(默認)
out: 不將參數復制到函數中,但返回參數
inout: 復制到函數中並返回
混合操作
通過在選擇器(.)后列出各分量名,就可以選擇這些分量
vec4 v4; v4.rgba; // 得到vec4 v4.rgb; // 得到vec3 v4.b; // 得到float v4.xy; // 得到vec2 v4.xgba; // 錯誤!分量名不是同一類 v4.wxyz; // 打亂原有分量順序 v4.xxyy; // 重復分量
最后推薦一個GLSL編輯調試工具 OpenGL Shader Builder (Mac OS X) 在蘋果的開發者中心的下載Graphics Tools.dmp