【GLSL教程】(四)shder的簡單示例
GLSL的Hello World
這一節中包含一個最基本的shader,它提供如下功能:頂點變換然後使用單一的顏色渲染圖元。
頂點shader
前面已經說過,頂點shader負責完成頂點變換。這裡將按照固定功能的方程完成頂點變換。
固定功能流水線中一個頂點通過模型檢視矩陣以及投影矩陣進行變換,使用如下公式:
vTrans = projection * modelview *incomingVertex
首先GLSL需要訪問OpenGL狀態,獲得公式中的前兩個矩陣。前面講過,GLSL可以獲取某些OpenGL狀態資訊的,這兩個矩陣當然包括在內。可以通過預先定義的一致變數來獲取它們:
- uniform mat4 gl_ModelViewMatrix;
- uniform mat4 gl_ProjectionMatrix;
attribute vec4 gl_Vertex;
為了輸出變換後的頂點,shader必須寫入預先定義的vec4型變數gl_Position中,注意這個變數沒有修飾符。
現在我們可以寫一個僅僅進行頂點變換的頂點shader了。注意所有其他功能都將喪失,比如沒有光照計算。頂點shader必須有一個main函式,如下面的程式碼所示:
- void main()
- {
- gl_Position =gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
- }
GLSL提供一些派生的矩陣,也就是說gl_ModelViewProjectionMatrix是上面兩個矩陣的乘積,所以頂點shader也可以寫成下面這樣:
- void main()
- {
- gl_Position =gl_ModelViewProjectionMatrix * gl_Vertex;
- }
vec4 ftransform(void);
使用這個函式的另一個原因是float資料型別的精度限制。由於資料精度的限制,當使用不同的順序計算時,可能得到不同的結果,因此GLSL提供這個函式保證獲得最佳效能的同時,還能得到與固定功能流水線相同的結果。
這個函式按照與固定功能相同的步驟對輸入頂點進行變換,然後返回變換後的頂點。所以shader可以重新寫成如下形式:
- void main()
- {
- gl_Position =ftransform();
- }
片斷shader也有預先定義的變數gl_FragColor,可以向其中寫入片斷的顏色值。下面的程式碼就是一個片斷shader,將所有片斷繪製成淡藍色:
- void main()
- {
- gl_FragColor =vec4( 0.4, 0.4, 0.8, 1.0);
- }
http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/glutglsl5_2.0.zip
顏色shader
GLSL可以讀取一些OpenGL狀態,在本節我們將學習如何訪問在OpenGL中設定的glColor變數。
GLSL有一個屬性變數記錄當前顏色,也提供易變變數從頂點shader向片斷shader傳遞顏色值。
- attribute vec4 gl_Color;
- varying vec4 gl_FrontColor; // writable onthe vertex shader
- varying vec4 gl_BackColor; // writable onthe vertex shader
- varying vec4 gl_Color; // readable on thefragment shader
1、OpenGL程式通過glColor傳送顏色資訊。
2、頂點shader通過屬性gl_Color接收顏色值。
3、頂點shader計算正面和反面的顏色,然後分別儲存在gl_FrontColor和gl_BackColor中。
4、片斷shader接收易變變數gl_Color中儲存的插值產生的顏色,由當前圖元的方向決定顏色是gl_FrontColor還是gl_BackColor插值產生的。
5、片斷shader根據易變變數gl_Color設定gl_FragColor。
前 面說過頂點shader和片斷shader中傳遞的易變變數要有相同的名字,但這裡是個例外,頂點shader中的gl_FrontColor和 gl_BackColor會根據圖元的方向,自動轉變為片斷shader中的gl_Color。還要注意屬性變數gl_Color和易變變數 gl_Color沒有衝突,因為前者只存在於頂點shader,後者只存在於片斷shader。
下面是頂點shader的例子,只計算了正面顏色:
- void main()
- {
- gl_FrontColor =gl_Color;
- gl_Position =ftransform();
- }
片斷shader更加簡單:
- void main()
- {
- gl_FragColor = gl_Color;
- }
http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/colorglut_2.0.zip
扁平shader(Flatten Shader)
著色器程式設計讓我們可以探索一些新效果,本節的例子展示了用奇怪的方法操作頂點得到的效果。
首先我們要得到一個扁平的3D模型,只需要在應用模型檢視變換時將模型頂點的z座標設為0就行了。下面是頂點shader的程式碼:
- void main(void)
- {
- vec4 v = vec4(gl_Vertex);
- v.z = 0.0;
- gl_Position =gl_ModelViewProjectionMatrix * v;
- }
片斷shader與“GLSL中的Hello World”一節相同,就只用設定一種顏色。
一個扁平的茶壺效果如下:
更進一步,我們需要在z座標上使用一個正弦函式。將z座標作為x座標的函式,這樣茶杯將呈現波浪的效果:
- void main(void)
- {
- vec4 v =vec4(gl_Vertex);
- v.z = sin( 5.0*v.x)* 0.25;
- gl_Position =gl_ModelViewProjectionMatrix * v;
- }
頂點shader的程式碼如下:
- uniform float time;
- void main(void)
- {
- vec4 v =vec4(gl_Vertex);
- v.z = sin( 5.0*v.x +time* 0.01)* 0.25;
- gl_Position =gl_ModelViewProjectionMatrix * v;
- }
·setup: 獲取一致變數的儲存位置
·render: 更新一致變數
設定(setup)步驟只有一條語句:
loc =glGetUniformLocation(p,"time");
這裡p是程式的控制代碼,time與頂點shader中定義的一致變數名稱相同。變數loc是Glint型別的,必須定義在下面的渲染(render)函式也可以訪問到的地方。渲染函式如下所示:
- void renderScene(void)
- {
- glClear(GL_COLOR_BUFFER_BIT| GL_DEPTH_BUFFER_BIT);
- glLoadIdentity();
- gluLookAt( 0.0, 0.0, 5.0,
- 0.0, 0.0, 0.0,
- 0.0f, 1.0f, 0.0f);
- glUniform1f(loc, time);
- glutSolidTeapot( 1);
- time+= 0.01;
- glutSwapBuffers();
- }
本節的GLEW原始碼:
http://lighthouse3d.com/wptest/wp-content/uploads/2011/03/flatten_2.0.zip