Shader and Program編程基本概念 - 轉

原地址: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)操作

     支持的操作有:*,/,+,-,++,--,=,+=, -=, *=, /=,==, !=, <, >, <=, >=,&&,^^,||

[cpp] view plaincopy
 
  1. float myFloat;  
  2. vec4 myVec4;  
  3. mat4 myMat4;  
  4. myVec4 = myVec4 * myFloat; // Multiplies each component of myVec4  
  5.                            // by a scalar myFloat  
  6. myVec4 = myVec4 * myVec4;  // Multiplies each component of myVec4  
  7.                            // together (e.g., myVec4 ^ 2 )  
  8. myVec4 = myMat4 * myVec4;  // Does a matrix * vector multiply of  
  9.                            // myMat4 * myVec4  
  10. myMat4 = myMat4 * myMat4;  // Does a matrix * matrix multiply of  
  11.                            // myMat4 * myMat4  
  12. myMat4 = myMat4 * myFloat; // Multiplies each matrix component by  
  13.                            // the scalar myFloat  

     前面矩陣的行數就是結果矩陣的行數,後面矩陣的列數就是結果矩陣的列數。

8)自定義函數:

[cpp] view plaincopy
 
  1. vec4 myFunc(inout float myFloat,  // inout parameter  
  2.             out vec4 myVec4,      // out parameter  
  3.             mat4 myMat4);         // in parameter (default)  

     函數不能遞歸調用,因爲GPU不一定有Stack和流控。

9)Shading Language內嵌函數

     主要有以下幾類函數:

     (1)角度和三角函數

     (2)指數函數

     (3)通用函數(絕對值、取整、取餘、取小數部分等)

     (4)幾何函數

     (5)矩陣函數

     (6)向量比較函數

     (7)紋理查找函數

     (8)Derivative函數

10)控制流

  

[cpp] view plaincopy
 
  1. if(color.a < 0.25)  
  2. {  
  3.    color *= color.a;  
  4. }  
  5. else  
  6. {  
  7.    color = vec4(0.0);  
  8. }  
  9.   
  10. //For循環。只支持常數循環次數。  
  11.  //無論下標,還是循環變量,都只能使用編譯時可確定的常數。  
  12.  for(int i = 0; i < 3; i++)  
  13. {  
  14.    sum += i;  
  15. }  

   以下不允許(因爲下標爲變量或loop次數爲變量):

[cpp] view plaincopy
 
  1. float myArr[4];  
  2. for(int i = 0; i < 3; i++)  
  3. {  
  4.     sum += myArr[i]; // NOT ALLOWED IN OPENGL ES, CANNOT DO  
  5.                      // INDEXING WITH NONCONSTANT EXPRESSION  
  6. }  
  7. ...  
  8. uniform int loopIter;  
  9. // NOT ALLOWED IN OPENGL ES, loopIter ITERATION COUNT IS NONCONSTANT  
  10. for(int i = 0; i < loopIter; i++)  
  11. {  
  12.     sum += i;  
  13. }  


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)預處理 

    

[cpp] view plaincopy
 
  1. #define  
  2. #undef  
  3. #if  
  4. #ifdef  
  5. #ifndef  
  6. #else  
  7. #elif  
  8. #endif  
  9. __LINE__ // Replaced with the current line number in a shader  
  10. __FILE__ // Always 0 in OpenGL ES 2.0  
  11. __VERSION__ // The OpenGL ES shading language version (e.g., 100)  
  12. 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)指定變量精度(放在數據類型之前):
 

[cpp] view plaincopy
 
  1. highp vec4 position;  
  2. varying lowp vec4 color;  
  3. mediump float specularExp;  

               (2)指定默認精度(放在Vertex和Fragment shader源碼的開始處):

[cpp] view plaincopy
 
  1. precision highp float;  
  2. precision mediump int;  

          在Vertex Shader中,如果沒有默認的精度,則float和int精度都爲highp;在Fragment Shader中,float沒有默認的精度,所以必須在Fragment Shader中爲float指定一個默認精度或爲每個float變量指定精度。

17)結果一致性

  invariant可被應用於任何Vertex Shader Varying輸出變量,其目前是保證相同的操作和相同的輸入,其結果一樣。因爲由於Shader精度不一樣,其結果有可能不一樣。

[cpp] view plaincopy
 
  1. uniform mat4 u_viewProjMatrix;  
  2. attribute vec4 a_vertex;  
  3. invariant gl_Position;  
  4. void main  
  5. {  
  6.     // …  
  7.     gl_Position = u_viewProjMatrix * a_vertex; // Will be the same  
  8.                                               // value in all  
  9.                                               // shaders with the  
  10.                                               // same viewProjMatrix  
  11.                                               // and vertex  
  12. }  

也可指定所有的輸出變量都爲:invariant

[cpp] view plaincopy
 
  1. #pragma STDGL invariant(all)  

 

四、獲取和設置Uniforms

     通過GLint   glGetUniformLocation(GLuint program,const char* name).根據一個Uniform的名稱獲取其location.

     通過 glUniform***系列函數可以給一個location 設置一個Uniform的值。

[cpp] view plaincopy
 
  1. void glUniform1f(GLint location, GLfloat x)  
  2. void glUniform1fv(GLint location, GLsizei count,const GLfloat* v)  
  3.   
  4. void glUniform1i(GLint location, GLint x)  
  5. void glUniform1iv(GLint location, GLsizei count,const GLint* v)  
  6.   
  7. void glUniform2f(GLint location, GLfloat x, GLfloat y)  
  8. void glUniform2fv(GLint location, GLsizei count,const GLfloat* v)  
  9.   
  10. void glUniform2i(GLint location, GLint x, GLint y)  
  11. void glUniform2iv(GLint location, GLsizei count,const GLint* v)  
  12.   
  13. void glUniform3f(GLint location, GLfloat x, GLfloat y,GLfloat z)  
  14. void glUniform3fv(GLint location, GLsizei count,const GLfloat* v)  
  15.   
  16. void glUniform3i(GLint location, GLint x, GLint y,GLint z)  
  17. void glUniform3iv(GLint location, GLsizei count,const GLint* v)  
  18.   
  19. void glUniform4f(GLint location, GLfloat x, GLfloat y,GLfloat z, GLfloat w);  
  20. void glUniform4fv(GLint location, GLsizei count,const GLfloat* v)  
  21.   
  22. void glUniform4i(GLint location, GLint x, GLint y,GLint z, GLint w)  
  23. void glUniform4iv(GLint location, GLsizei count,const GLint* v)  
  24.   
  25. void glUniformMatrix2fv(GLint location, GLsizei count,  
  26.                         GLboolean transpose,const GLfloat* value)  
  27. void glUniformMatrix3fv(GLint location, GLsizei count,  
  28.                         GLboolean transpose,const GLfloat* value)  
  29. void glUniformMatrix4fv(GLint location, GLsizei count,  
  30.                        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)

     常量頂點屬性對所有頂點都是一樣的。因此只需要指定一個值就可以應用於所有頂點。一般很少使用。其設置函數有:

  

[cpp] view plaincopy
 
  1. void glVertexAttrib1f(GLuint index, GLfloat x);  
  2. void glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y);  
  3. void glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z);  
  4. void glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z,GLfloat w);  
  5. void glVertexAttrib1fv(GLuint index, const GLfloat *values);  
  6. void glVertexAttrib2fv(GLuint index, const GLfloat *values);  
  7. void glVertexAttrib3fv(GLuint index, const GLfloat *values);  
  8. 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)  //頂點數組指針

       舉例如下:

 

[cpp] view plaincopy
 
  1. GLfloat vVertices[] = {  0.0f,  0.5f, 0.0f,   
  2.                         -0.5f, -0.5f, 0.0f,  
  3.                          0.5f, -0.5f, 0.0f };  
  4.      
  5. // Set the viewport  
  6. glViewport ( 0, 0, esContext->width, esContext->height );  
  7.   
  8. // Clear the color buffer  
  9. glClear ( GL_COLOR_BUFFER_BIT );  
  10.   
  11. // Use the program object  
  12. glUseProgram (programObject );  
  13.   
  14. // Load the vertex data  
  15. 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)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章