Shader and Program编程基本概念

    1. 一、本文关注的问题:
      • 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) 结构体 : 用基本类型和复合类型构建结构体。
      1. 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) 自定义函数:
      1. 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 Atrributes

      一、Vertex Attributes简介
         Vertex属性即顶点数据,它指定了每个顶点的各种属性数据。在OpenGL ES1.1中,顶点属性有四个预定义的名字:position(位置), normal(法线), color(颜色), 和 texture coordinates(纹理坐标)。在OpenGL ES2.0中,用户 必须定义“顶点属性的名字”
      二、常量顶点属性(Constant Vertex Attribute)
      常量顶点属性对所有顶点都是一样的。因此只需要指定一个值就可以应用于所有顶点。一般很少使用。其设置函数有
    1. 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);  

      三、 如何装载顶点数据?(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
                                                 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 );  

      四、顶点属性数据存储方式
      1.一个顶点的所有属性存储在一起(Array of Structures)
         如下图所示,顶点的位置(x,y,z)、法线(x,y,z)和两个纹理坐标(s,t)存储在一起,如下图所示:
      例子代码如下(当然,此代码在CPU上运动):
      #define VERTEX_POS_SIZE         3 // x, y and z  
      #define VERTEX_NORMAL_SIZE      3 // x, y and z  
      #define VERTEX_TEXCOORD0_SIZE   2 // s and t  
      #define VERTEX_TEXCOORD1_SIZE   2 // s and t  
       
      #define VERTEX_POS_INDX         0  
      #define VERTEX_NORMAL_INDX      1  
      #define VERTEX_TEXCOORD0_INDX   2  
      #define VERTEX_TEXCOORD1_INDX   3  
       
      // the following 4 defines are used to determine location of various  
      // attributes if vertex data is are stored as an array of structures  
      #define VERTEX_POS_OFFSET       0  
      #define VERTEX_NORMAL_OFFSET    3  
      #define VERTEX_TEXCOORD0_OFFSET 6  
      #define VERTEX_TEXCOORD1_OFFSET 8  
       
      #define VERTEX_ATTRIB_SIZE  VERTEX_POS_SIZE + \  
                                 VERTEX_NORMAL_SIZE + \  
                                 VERTEX_TEXCOORD0_SIZE + \  
                                 VERTEX_TEXCOORD1_SIZE  
                                   
      float *p = malloc(numVertices * VERTEX_ATTRIB_SIZE  
                       * sizeof(float));  
       
      // position is vertex attribute 0  
      glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,  
                           GL_FLOAT, GL_FALSE,  
                           VERTEX_ATTRIB_SIZE * sizeof(float),  
                           p+VERTEX_POS_OFFSET);  
       
      // normal is vertex attribute 1  
      glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE,  
                           GL_FLOAT, GL_FALSE,  
                           VERTEX_ATTRIB_SIZE * sizeof(float),  
                           (p + VERTEX_NORMAL_OFFSET));  
       
      // texture coordinate 0 is vertex attribute 2  
      glVertexAttribPointer(VERTEX_TEXCOORD0_INDX, VERTEX_TEXCOORD0_SIZE,  
                           GL_FLOAT, GL_FALSE,  
                           VERTEX_ATTRIB_SIZE * sizeof(float),  
                           (p + VERTEX_TEXCOORD0_OFFSET));  
       
      // texture coordinate 1 is vertex attribute 3  
      glVertexAttribPointer(VERTEX_TEXCOORD1_INDX, VERTEX_TEXCOORD1_SIZE,  
                           GL_FLOAT, GL_FALSE,  
                           VERTEX_ATTRIB_SIZE * sizeof(float),  
                           (p + VERTEX_TEXCOORD1_OFFSET));  
      2. 顶点的每个属性单独存储(Structure of Arrays)
      例子代码如下(当然,此代码在CPU上运动):
      #define VERTEX_POS_SIZE         3 // x, y and z  
      #define VERTEX_NORMAL_SIZE      3 // x, y and z  
      #define VERTEX_TEXCOORD0_SIZE   2 // s and t  
      #define VERTEX_TEXCOORD1_SIZE   2 // s and t  
       
      #define VERTEX_POS_INDX         0  
      #define VERTEX_NORMAL_INDX      1  
      #define VERTEX_TEXCOORD0_INDX   2  
      #define VERTEX_TEXCOORD1_INDX   3  
       
       
      #define VERTEX_ATTRIB_SIZE  VERTEX_POS_SIZE + \  
                                 VERTEX_NORMAL_SIZE + \  
                                 VERTEX_TEXCOORD0_SIZE + \  
                                 VERTEX_TEXCOORD1_SIZE  
                                   
      float *position  = malloc(numVertices * VERTEX_POS_SIZE *  
                               sizeof(float));  
      float *normal    = malloc(numVertices * VERTEX_NORMAL_SIZE *  
                               sizeof(float));  
      float *texcoord0 = malloc(numVertices * VERTEX_TEXCOORD0_SIZE *  
                               sizeof(float));  
      float *texcoord1 = malloc(numVertices * VERTEX_TEXCOORD1_SIZE *  
                               sizeof(float));  
       
      // position is vertex attribute 0  
      glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,  
                           GL_FLOAT, GL_FALSE,  
                           VERTEX_POS_SIZE * sizeof(float), position);  
       
      // normal is vertex attribute 1  
      glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE,  
                           GL_FLOAT, GL_FALSE,  
                           VERTEX_NORMAL_SIZE * sizeof(float), normal);  
       
      // texture coordinate 0 is vertex attribute 2  
      glVertexAttribPointer(VERTEX_TEXCOORD0_INDX, VERTEX_TEXCOORD0_SIZE,  
                           GL_FLOAT, GL_FALSE, VERTEX_TEXCOORD0_SIZE *  
                           sizeof(float), texcoord0);  
       
      // texture coordinate 1 is vertex attribute 3  
      glVertexAttribPointer(VERTEX_TEXCOORD1_INDX, VERTEX_TEXCOORD1_SIZE,  
                           GL_FLOAT, GL_FALSE,  
                           VERTEX_TEXCOORD1_SIZE * sizeof(float),  //也可为0,因为数据是紧接着存放的  
                           texcoord1);  
      

      3. 哪种顶点属性数据存储方式在GPU上性能更好?
         答案是: 把一个顶点的所有属性放在一起(array of structures)。其原因是每个顶点的属性数据以连续的方式读取,使内存访问效率更高。其缺点是,如果要修改其中部分属性数据,将导致整个属性buffer全部重新装载,解决此问题的方法是把这些需要动态修改的属性数据放在单独的buffer中。
      五、 顶点属性数据类型优化
         顶点属性数据类型不会影响在GPU上每个顶点占用的内存,但在Render a Frame时,它影响CPU与GPU之间的内存带宽。推荐尽量使用GL_HALF_FLOAT_OES。

      六、glVertexAttribPointer中的归一化参数
         如果normalized为GL_FALSE:则直接把数据转换为GLfloat,因为Vertex Shader内部把顶点属性当作GLfloat(32位)来进行存储。
         GL_BYTE, GL_SHORT or GL_FIXED被归一化为[-1,1];GL_UNSIGNED_BYTE or GL_UNSIGNED_SHORT被归一化为[0.0,1.0]。具体转换公式为:

      七、选择常量或顶点数组Vertex Attribute
      可通过以下函数来Enable或Disable顶点数组(Vertex Array)。
      void glEnableVertexAttribArray(GLuint index);
      void glDisableVertexAttribArray(GLuint index);
      其关系如下图所示:

      八、申明attribute变量(在Vertex Shader中)

           Attribute变量的数据类型只能为:float, vec2,vec3, vec4, mat2, mat3, and mat4;Attribute变量不能为数组或结构。如下面的申明是错误的:         
      attribute foo_t a_A; // foo_t is a structure  
      attribute vec4 a_B[10];  
      每个GPU支持GL_MAX_VERTEX_ATTRIBS vec4。float、vec2和vec3也被当作一个vec4来进行存储;mat2、mat3、mat4被分别当作2、3、和4个vec4来进行存储。

      九、把“顶点属性索引”绑定到“顶点属性名”

         把“顶点属性索引”绑定到“顶点属性名”有以下两个方法:
         1) OpenGL ES 2.0 把“顶点属性索引”绑定到“顶点属性名”,当link program时,OpengGL ES 2.0执行此绑定。然后应用程序通过glGetAttribLocation(失败时返回-1)获取“顶点属性索引”。
      GLint glGetAttribLocation(GLuint program, const GLchar *name)  
          2) 应用程序通过glBindAttribLocation 把“顶点属性索引”绑定到“顶点属性名”,glBindAttribLocation在program被link之前执行。
      void glBindAttribLocation(GLuint program, GLuint index,const GLchar *name)  
         在link program时,OpenGL ES 2.0对每个定点属性执行如下操作:
          (1)首先检查属性变量是否被通过glBindAttribLocation绑定了属性索引,如果是,则使用此绑定的属性索引;否则,为之分配一个属性索引

      十、顶点buffer对象(Vertex Buffer Objects)

         顶点数组(Vertex Array)被保存在客户端内存,当执行glDrawArrays 或 glDrawElements时,才把它们从客户端内存copy到图形内存。这样占用了大量的内存带宽,Vertex Buffer Objects允许OpengGL ES2.0应用在高性能的图形内存中分配并cache顶点数据,然后从此图形内存中执行render,这样避免了每次画一个原语都要重发送数据。
         Vertex Buffer Objects有以下两种类型:
         (1)array buffer objects:通过GL_ARRAY_BUFFER标记创建,并存储vertex data。
            (2)element array buffer objects:通过GL_ELEMENT_ARRAY_BUFFER标记创建,并存储indices of a primitive。
         创建和绑定Vertex Buffer Objects例子代码如下:
      void initVertexBufferObjects(vertex_t *vertexBuffer,  
                                  GLushort *indices,  
                                  GLuint numVertices, GLuint numIndices  
                                  GLuint *vboIds)  
      {  
        glGenBuffers(2, vboIds);  
        glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);  
        glBufferData(GL_ARRAY_BUFFER, numVertices * sizeof(vertex_t),  
                     vertexBuffer, GL_STATIC_DRAW); //save vertex attribute data  
        // bind buffer object for element indices  
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds[1]);  
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,  
                     numIndices * sizeof(GLushort),indices,  
                     GL_STATIC_DRAW); // save element indices that make up the primitive  
      }  
      有无Vertex Buffer Object画图例子:  
      #define VERTEX_POS_SIZE 3 // x, y and z  
      #define VERTEX_NORMAL_SIZE 3 // x, y and z  
      #define VERTEX_TEXCOORD0_SIZE 2 // s and t  
      #define VERTEX_POS_INDX 0  
      #define VERTEX_NORMAL_INDX 1  
      #define VERTEX_TEXCOORD0_INDX 2  
      //  
      // vertices – pointer to a buffer that contains vertex attribute  
      data  
      // vtxStride – stride of attribute data / vertex in bytes  
      // numIndices – number of indices that make up primitive  
      // drawn as triangles  
      // indices - pointer to element index buffer.  
      //  
      void drawPrimitiveWithoutVBOs(GLfloat *vertices, GLint vtxStride,  
                                   GLint numIndices, GLushort *indices)  
      {  
        GLfloat *vtxBuf = vertices;  
        glBindBuffer(GL_ARRAY_BUFFER, 0);  
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);  
        glEnableVertexAttribArray(VERTEX_POS_INDX);  
        glEnableVertexAttribArray(VERTEX_NORMAL_INDX);  
        glEnableVertexAttribArray{VERTEX_TEXCOORD0_INDX);  
        glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,  
                              GL_FLOAT, GL_FALSE, vtxStride, vtxBuf);  
        vtxBuf += VERTEX_POS_SIZE;  
        glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE,  
                              GL_FLOAT, GL_FALSE, vtxStride, vtxBuf);  
        vtxBuf += VERTEX_NORMAL_SIZE;  
        glVertexAttribPointer(VERTEX_TEXCOORD0_INDX,  
                              VERTEX_TEXCOORD0_SIZE, GL_FLOAT,  
                              GL_FALSE, vtxStride, vtxBuf);  
        glBindAttribLocation(program, VERTEX_POS_INDX, "v_position");  
        glBindAttribLocation(program, VERTEX_NORMAL_INDX, "v_normal");  
        glBindAttribLocation(program, VERTEX_TEXCOORD0_INDX,"v_texcoord");  
        glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT,indices);  
      }
      void drawPrimitiveWithVBOs(GLint numVertices, GLfloat *vtxBuf,  
                                GLint vtxStride, GLint numIndices,  
                                GLushort *indices)  
      {  
        GLuint offset = 0;  
        GLuint vboIds[2];  
        // vboIds[0] – used to store vertex attribute data  
        // vboIds[1] – used to store element indices  
        glGenBuffers(2, vboIds);  
        glBindBuffer(GL_ARRAY_BUFFER, vboIds[0]);  
        glBufferData(GL_ARRAY_BUFFER, vtxStride * numVertices,  
                     vtxBuf, GL_STATIC_DRAW);  
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboIds[1]);  
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,  
                     sizeof(GLushort) * numIndices,  
                     indices, GL_STATIC_DRAW);  
        glEnableVertexAttribArray(VERTEX_POS_INDX);  
        glEnableVertexAttribArray(VERTEX_NORMAL_INDX);  
        glEnableVertexAttribArray{VERTEX_TEXCOORD0_INDX);  
        glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,  
                              GL_FLOAT, GL_FALSE, vtxStride,  
                              (const void*)offset);  
        offset += VERTEX_POS_SIZE * sizeof(GLfloat);  
        glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE,  
                              GL_FLOAT, GL_FALSE, vtxStride,  
                              (const void*)offset);  
        offset += VERTEX_NORMAL_SIZE * sizeof(GLfloat);  
        glVertexAttribPointer(VERTEX_TEXCOORD0_INDX,  
                              VERTEX_TEXCOORD0_SIZE,  
                              GL_FLOAT, GL_FALSE, vtxStride,  
                              (const void*)offset);  
        glBindAttribLocation(program, VERTEX_POS_INDX, "v_position");  
        glBindAttribLocation(program, VERTEX_NORMAL_INDX, "v_normal");  
        glBindAttribLocation(program, VERTEX_TEXCOORD0_INDX,"v_texcoord");  
        glDrawElements(GL_TRIANGLES, numIndices, GL_UNSIGNED_SHORT, 0);  
        glDeleteBuffers(2, vboIds);  
      }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值