原地址:http://blog.csdn.net/myarrow/article/details/7737313
一、本文關注的問題:
• Shader and program 對象介紹
• 創建並編譯一個Shader對象
• 創建並鏈接一個Program對象
• 獲取並設置uniforms
• 獲取並設置attributes
在OpenGL ES中,每個program對象有且僅有一個Vertex Shader對象和一個Fragment Shader對象連接到它。
Shader:類似於C編譯器
Program:類似於C鏈接器
glLinkProgram操作產生最后的可執行程序,它包含最后可以在硬件上執行的硬件指令。
二、Shader和Program編程概述
1. 創建Shader
1)編寫Vertex Shader和Fragment Shader源碼。
2)創建兩個shader 實例:GLuint glCreateShader(GLenum type);
3)給Shader實例指定源碼。 glShaderSource
4)在線編譯shaer源碼 void glCompileShader(GLuint shader)
2. 創建Program
1)創建program GLuint glCreateProgram(void)
2)綁定shader到program 。 void glAttachShader(GLuint program, GLuint shader)。每個program必須綁定一個Vertex Shader 和一個Fragment Shader。
3)鏈接program 。 void glLinkProgram(GLuint program)
4)使用porgram 。 void glUseProgram(GLuint program)
對於使用獨立shader編譯器編譯的二進制shader代碼,可使用glShaderBinary來加載到一個shader實例中。
三、 Shading Language中的數據類型與變量
1. Uniforms and Attributes
Uniforms 是一個program 中統一分配的,vertext 和fragment中同名的Uniform必須同類型。對應於不經常變化的變量(用於存儲只讀常量值的變量)。
Attributes 變化率高的變量。主要用來定義輸入的每個點屬性。
Uniforms and Attributes 在shader中通過location 和 name 來對應的。
2. 數據類型
1)三類基本數據類型:float , int , boolean
2)復合類型:浮點、整型、布爾向量 vec2 , vec3,vec4。vector訪問方式有以下兩種:
(1).操作:數學{x, y, z, w}, 顏色{r, g, b, a}或 紋理坐標{s, t, r, q},但不能混用,舉例如下:
vec3 myVec3 = vec3(0.0, 1.0, 2.0); // myVec3 = {0.0, 1.0, 2.0}
vec3 temp;
temp = myVec3.xyz; // temp = {0.0, 1.0, 2.0}
temp = myVec3.xxx; // temp = {0.0, 0.0, 0.0}
temp = myVec3.zyx; // temp = {2.0, 1.0, 0.0}
(2)[ ]操作:[0]對應x,[1]對應y,[2]對應z,[3]對應w。[ ]中只能為常量或uniform變量,不能為整數量變量(如:i,j,k)。
3)矩陣:mat2, mat3,mat4 (按列順序存儲)
mat3 myMat3 = mat3(1.0, 0.0, 0.0, // 第一列
0.0, 1.0, 0.0, // 第二列
0.5, 1.0, 1.0); // 第三列
可用[ ]或.操作符來訪問:
mat4 myMat4 = mat4(1.0); // Initialize diagonal to 1.0 (identity)
vec4 col0 = myMat4[0]; // Get col0 vector out of the matrix
float m1_1 = myMat4[1][1]; // Get element at [1][1] in matrix
float m2_2 = myMat4[2].z; // Get element at [2][2] in matrix
4)常量
const float zero = 0.0;
const float pi = 3.14159;
const vec4 red = vec4(1.0, 0.0, 0.0, 1.0);
const mat4 identity = mat4(1.0);
5)結構體: 用基本類型和復合類型構建結構體。
struct fogStruct
{
vec4 color;
float start;
float end;
} fogVar;
fogVar = fogStruct(vec4(0.0, 1.0, 0.0, 0.0), // color
0.5, // start
2.0); // end
vec4 color = fogVar.color;
float start = fogVar.start;
float end = fogVar.end;
6)數組:類似於C語言,索引從0開始。在創建時不能被初始化,索引只能為常量或uniform變量。
float floatArray[4];
vec4 vecArray[2];
7)操作
支持的操作有:*,/,+,-,++,--,=,+=, -=, *=, /=,==, !=, <, >, <=, >=,&&,^^,||
- float myFloat;
- vec4 myVec4;
- mat4 myMat4;
- myVec4 = myVec4 * myFloat; // Multiplies each component of myVec4
- // by a scalar myFloat
- myVec4 = myVec4 * myVec4; // Multiplies each component of myVec4
- // together (e.g., myVec4 ^ 2 )
- myVec4 = myMat4 * myVec4; // Does a matrix * vector multiply of
- // myMat4 * myVec4
- myMat4 = myMat4 * myMat4; // Does a matrix * matrix multiply of
- // myMat4 * myMat4
- myMat4 = myMat4 * myFloat; // Multiplies each matrix component by
- // the scalar myFloat
前面矩陣的行數就是結果矩陣的行數,后面矩陣的列數就是結果矩陣的列數。
8)自定義函數:
- vec4 myFunc(inout float myFloat, // inout parameter
- out vec4 myVec4, // out parameter
- mat4 myMat4); // in parameter (default)
函數不能遞歸調用,因為GPU不一定有Stack和流控。
9)Shading Language內嵌函數
主要有以下幾類函數:
(1)角度和三角函數
(2)指數函數
(3)通用函數(絕對值、取整、取余、取小數部分等)
(4)幾何函數
(5)矩陣函數
(6)向量比較函數
(7)紋理查找函數
(8)Derivative函數
10)控制流
- if(color.a < 0.25)
- {
- color *= color.a;
- }
- else
- {
- color = vec4(0.0);
- }
- //For循環。只支持常數循環次數。
- //無論下標,還是循環變量,都只能使用編譯時可確定的常數。
- for(int i = 0; i < 3; i++)
- {
- sum += i;
- }
以下不允許(因為下標為變量或loop次數為變量):
- float myArr[4];
- for(int i = 0; i < 3; i++)
- {
- sum += myArr[i]; // NOT ALLOWED IN OPENGL ES, CANNOT DO
- // INDEXING WITH NONCONSTANT EXPRESSION
- }
- ...
- uniform int loopIter;
- // NOT ALLOWED IN OPENGL ES, loopIter ITERATION COUNT IS NONCONSTANT
- for(int i = 0; i < loopIter; i++)
- {
- sum += i;
- }
11)Uniforms(前輟修改)
Uniform前輟修飾的變量初始值由外部程序賦值。在program中具有統一訪問空間,存儲空間有限。在Shader中是只讀的,只能由外部主機程序傳入值。
它用於存儲shader需要的各種數據,如:變換矩陣、光照參數和顏色。基本上,對於Shader是一個常量,但在編譯時其值未知,則應當作為一個uniform變量。
Uniform變量在Vertex Shader和Fragment Shader之間共享。當使用glUniform***設置了一個uniform變量的值之后,Vertex Shader和Fragment Shader中具有相同的值。
Uniform變量被存儲在GPU中的“常量存儲區”,其空間大小是固定的,可通過API<glGetIntegerv>查詢(GL_MAX_VERTEX_UNIFORM_VECTORS 或 GL_MAX_FRAGMENT_UNIFORM_VECTORS )。
12)Attributes(前輟修改)
Attribute類型的變量只有Vertex Shader才有。Attribute前輟修飾的變量定義的是每個Vertex的屬性變量,包括位置,顏色,法線和紋理坐標
Attribute 類型的變量在Vertex Shader中是只讀的,只能由外部主機程序傳入值。
Attribute 類型的變量:是為每個被正在畫的頂點所指定的數據。在畫圖前,每個頂點的屬性由應用程序輸入。
與Uniform變量一樣,其存儲數量也是有限制的。可用glGetIntegerv(GL_MAX_VERTEX_ATTRIBS)進行查詢。GPU至少支持8個屬性,所以Vertex Shader源碼中不要超過8個attributes。
13)Varyings
Varying變量用於存儲Vertex Shader的輸出和Fragment Shader的輸入。在Vertex Shader和Fragment Shader中必須申明同一個Varying變量。
與Uniform和Attribute一樣,其存儲數量也是有限制的,可用glGetIntegerv(GL_MAX_VARYING_VECTORS)進行查詢。GPU至少支持8個Varying vector,所以Vertex Shader源碼中不要超過8個Varying vector。
GLint maxVertexAttribs; // n will be >= 8
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);
14)預處理
- #define
- #undef
- #if
- #ifdef
- #ifndef
- #else
- #elif
- #endif
- __LINE__ // Replaced with the current line number in a shader
- __FILE__ // Always 0 in OpenGL ES 2.0
- __VERSION__ // The OpenGL ES shading language version (e.g., 100)
- GL_ES // This will be defined for ES shaders to a value of 1
15) Uniform Attribute Varying存儲空間最小值
變量類型 |
GPU必須支持的最小個數 |
Vertex Uniform Vectors |
128 |
Fragment Uniform Vectors |
16 |
Vertex Attributes |
8 |
Varying Vectors |
8 |
16) 精度限定(Precision Qualifiers)
關鍵詞:lowp highp mediump
(1)指定變量精度(放在數據類型之前):
- highp vec4 position;
- varying lowp vec4 color;
- mediump float specularExp;
(2)指定默認精度(放在Vertex和Fragment shader源碼的開始處):
- precision highp float;
- precision mediump int;
在Vertex Shader中,如果沒有默認的精度,則float和int精度都為highp;在Fragment Shader中,float沒有默認的精度,所以必須在Fragment Shader中為float指定一個默認精度或為每個float變量指定精度。
17)結果一致性
invariant可被應用於任何Vertex Shader Varying輸出變量,其目前是保證相同的操作和相同的輸入,其結果一樣。因為由於Shader精度不一樣,其結果有可能不一樣。
- uniform mat4 u_viewProjMatrix;
- attribute vec4 a_vertex;
- invariant gl_Position;
- void main
- {
- // …
- gl_Position = u_viewProjMatrix * a_vertex; // Will be the same
- // value in all
- // shaders with the
- // same viewProjMatrix
- // and vertex
- }
也可指定所有的輸出變量都為:invariant
- #pragma STDGL invariant(all)
四、獲取和設置Uniforms
通過GLint glGetUniformLocation(GLuint program,const char* name).根據一個Uniform的名稱獲取其location.
通過 glUniform***系列函數可以給一個location 設置一個Uniform的值。
- void glUniform1f(GLint location, GLfloat x)
- void glUniform1fv(GLint location, GLsizei count,const GLfloat* v)
- void glUniform1i(GLint location, GLint x)
- void glUniform1iv(GLint location, GLsizei count,const GLint* v)
- void glUniform2f(GLint location, GLfloat x, GLfloat y)
- void glUniform2fv(GLint location, GLsizei count,const GLfloat* v)
- void glUniform2i(GLint location, GLint x, GLint y)
- void glUniform2iv(GLint location, GLsizei count,const GLint* v)
- void glUniform3f(GLint location, GLfloat x, GLfloat y,GLfloat z)
- void glUniform3fv(GLint location, GLsizei count,const GLfloat* v)
- void glUniform3i(GLint location, GLint x, GLint y,GLint z)
- void glUniform3iv(GLint location, GLsizei count,const GLint* v)
- void glUniform4f(GLint location, GLfloat x, GLfloat y,GLfloat z, GLfloat w);
- void glUniform4fv(GLint location, GLsizei count,const GLfloat* v)
- void glUniform4i(GLint location, GLint x, GLint y,GLint z, GLint w)
- void glUniform4iv(GLint location, GLsizei count,const GLint* v)
- void glUniformMatrix2fv(GLint location, GLsizei count,
- GLboolean transpose,const GLfloat* value)
- void glUniformMatrix3fv(GLint location, GLsizei count,
- GLboolean transpose,const GLfloat* value)
- void glUniformMatrix4fv(GLint location, GLsizei count,
- GLboolean transpose,const GLfloat* value)
為矩陣uniform變量設置值的函數中的transpose必須為GL_FALSE,它目的為兼容性,但在 OpenGL ES 2.0中並沒有工作。
一旦你設置了一個Program中unifrom變量的值之后,即使你激活了另外一個Program,此uniform的值不變。即uniform變量是Program的局部變量。
五、Vertex Attributes
Vertex屬性即頂點數據,它指定了每個頂點的數據。在OpenGL ES1.1中,頂點屬性有四個預定義的名字:position(位置), normal(法線), color(顏色), 和 texture coordinates(紋理坐標)。在OpenGL ES2.0中,用戶必須定義“頂點屬性的名字”。
1. 常量頂點屬性(Constant Vertex Attribute)
常量頂點屬性對所有頂點都是一樣的。因此只需要指定一個值就可以應用於所有頂點。一般很少使用。其設置函數有:
- void glVertexAttrib1f(GLuint index, GLfloat x);
- void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y);
- void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);
- void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z,GLfloat w);
- void glVertexAttrib1fv(GLuint index, const GLfloat *values);
- void glVertexAttrib2fv(GLuint index, const GLfloat *values);
- void glVertexAttrib3fv(GLuint index, const GLfloat *values);
- void glVertexAttrib4fv(GLuint index, const GLfloat *values);
2. 如何裝載頂點數據?(Vertex Arrays)
Vertex Array(頂點數組):是一個存儲在應用程序空間(Client)中的內存buffer,它存儲了每個頂點的屬性數據。
如何把頂點數據組的數據傳遞給GPU呢?
void glVertexAttribPointer(GLuint index,
GLint size, //每個屬性元素個數有效值1-4(x,y,z,w)
GLenum type, //數組中每個元素的數據類型
GLboolean normalized,
GLsizei stride, //如果數據連續存放,則為0或
//size*sizeof(type)
const void *ptr) //頂點數組指針
舉例如下:
- GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f,
- -0.5f, -0.5f, 0.0f,
- 0.5f, -0.5f, 0.0f };
- // Set the viewport
- glViewport ( 0, 0, esContext->width, esContext->height );
- // Clear the color buffer
- glClear ( GL_COLOR_BUFFER_BIT );
- // Use the program object
- glUseProgram (programObject );
- // Load the vertex data
- glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
2.1 一個頂點的所有屬性存儲在一起(Array of Structures)
如下圖所示,頂點的位置(x,y,z)、法線(x,y,z)和兩個紋理坐標(s,t)存儲在一起,如下圖所示:
2.2 頂點的每個屬性單獨存儲(Structure of Arrays)