• 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)

  • 相关阅读:
    2016奇虎360研发工程师内推笔试编程题:找镇长
    2016奇虎360研发工程师内推笔试编程题:找到字符串第一个只出现一次的字符
    lintcode: 最长无重复字符的子串
    lintcode :同构字符串
    lintcode : 跳跃游戏
    lintcode :单词搜索
    Project Euler 110:Diophantine reciprocals II 丢番图倒数II
    Project Euler 109 :Darts 飞镖
    Project Euler 108:Diophantine reciprocals I 丢番图倒数I
    Project Euler 107:Minimal network 最小网络
  • 原文地址:https://www.cnblogs.com/sanjin/p/3580331.html
Copyright © 2020-2023  润新知