你的位置:首页 > 操作系统

[操作系统]OpenGL ES 3.0之VertexAttributes,Vertex Arrays,and Buffer Objects(九)


  顶点数据,也称为顶点属性,指每一个顶点数据。指能被用来描述每个顶点的数据,或能被所有顶点使用的常量值。例如你想绘制一个具有颜色的立方体三角形。你指定一个恒定的值用于三角形的所有三个顶点颜色。但三角形的三个顶点位置是不同的,你需要指定一个顶点矩阵存储三个位置值。

指定顶点属性数据

  顶点属性数据可以使用顶点数组或常量值指定每个顶点数据,OpenGL ES 3.0 必须至少支持16 个顶点属性。应用应该能够查询编译器支持的确切属性数。下面的程序指出如何查询。

GLint maxVertexAttribs; // n will be >= 8glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);

  

  常量顶点属性
  常量顶点属性是指基元的所有顶点属性是相同的,因此仅仅对基元的所有顶点仅仅需要指定一个值。顶点属性常量使用下面的函数指定:

void glVertexAttriblf(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 glVertexAttriblfv(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);

 

  glVertexAttrib*通过索引来装在一般顶点属性,glVertexAttriblf和glVertexAttriblfv加载(x, 0.0, 0.0, 1.0)到顶点属性,glVertexAttrib2f and glVertexAttrib2fv 装载(x, y, 0.0, 1.0),glVertexAttrib3f 和glVertexAttrib3fv 装载(x, y, z, 1.0),glVertexAttrib4f and
glVertexAttrib4fv 装载(x, y, z, w)

 

  顶点数组

  顶点数组指定每个顶点的属性数据即存储在应用程序地址空间(OpenGL ES 叫clientspace)缓冲区的数据。它们提供有效的和灵活的方法指定顶点属性数据。顶点数组使用glVertexAttribPointer 或glVertexAttribIPointer函数指定:

 存储所有的顶点属性在一个缓冲区中,这种存储顶点属性的方法叫结构数组,这种方法描述每个顶点的所有属性。存储每个顶点属性到分开的缓冲区,这种存储顶点属性的方法叫数组结构每个顶点有四个属性—位置、法线、两个贴图坐标,这些属性被存储在一个缓冲区中,被所有顶点分享。顶点位置属性是三个浮点数(x, y, z)的矢量。法线也是三个浮点数的矢量,每个贴图坐标是两个浮点数的矢量。

 

结构数组代码示例

#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_TEXCOORDl_SIZE 2 // s and t#define VERTEX_POS_INDX 0#define VERTEX_NORMAL_INDX 1#define VERTEX_TEXCOORD0_INDX 2#define VERTEX_TEXCOORDl_INDX 3// the following 4 defines are used to determine the locations// of various attributes if vertex data are stored as an array// of structures#define VERTEX_POS_OFFSET 0#define VERTEX_NORMAL_OFFSET 3#define VERTEX_TEXCOORD0_OFFSET 6#define VERTEX_TEXC00RD1_0FFSET 8#define VERTEX_ATTRIB_SIZE (VERTEX_POS_SIZE + \                 VERTEX_NORMAL_SIZE + \                 VERTEX_TEXCOORD0_SIZE + \                 VERTEX_TEXC00RD1_SIZE)
float *p = (float*) malloc(numVertices * VERTEX_ATTRIB_SIZE* sizeof(float));// position is vertex attribute 0glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,              GL_FLOAT, GL_FALSE,              VERTEX_ATTRIB_SIZE * sizeof(float),              p);// normal is vertex attribute 1glVertexAttribPointer(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 2glVertexAttribPointer(VERTEX_TEXCOORDO_INDX,              VERTEX_TEXCOORD0_SIZE,              GL_FLOAT, GL_FALSE,              VERTEX_ATTRIB_SIZE * sizeof(float),              (p + VERTEX_TEXCOORD0_OFFSET));// texture coordinate 1 is vertex attribute 3glVertexAttribPointer(VERTEX_TEXCOORDl_INDX,              VERTEX_TEXC00RD1_SIZE,              GL_FLOAT, GL_FALSE,              VERTEX_ATTRIB_SIZE * sizeof(float),              (p + VERTEX_TEXC00RD1_0FFSET));

数组结构示例代码

float *position = (float*) malloc(numVertices *VERTEX_POS_SIZE * sizeof(float));float *normal = (float*) malloc(numVertices *VERTEX_NORMAL_SIZE * sizeof(float));float *texcoordO = (float*) malloc(numVertices *VERTEX_TEXCOORD0_SIZE * sizeof(float));float *texcoordl = (float*) malloc(numVertices *VERTEX_TEXC00RD1_SIZE * sizeof(float));// position is vertex attribute 0glVertexAttribPointer(VERTEX_POS_INDX, VERTEX_POS_SIZE,              GL_FLOAT, GL_FALSE,              VERTEX_POS_SIZE * sizeof(float),              position);// normal is vertex attribute 1glVertexAttribPointer(VERTEX_NORMAL_INDX, VERTEX_NORMAL_SIZE,              GL_FLOAT, GL_FALSE,              VERTEX_NORMAL_SIZE * sizeof(float),              normal);// texture coordinate 0 is vertex attribute 2glVertexAttribPointer(VERTEX_TEXCOORDO_INDX,              VERTEX_TEXCOORD0_SIZE,              GL_FLOAT, GL_FALSE,              VERTEX_TEXCOORD0_SIZE *sizeof(float), texcoordO);// texture coordinate 1 is vertex attribute 3glVertexAttribPointer(VERTEX_TEXCOORDl_INDX,              VERTEX_TEXC00RD1_SIZE,              GL_FLOAT, GL_FALSE,              VERTEX_TEXC00RD1_SIZE * sizeof(float),              texcoordl);

 

性能提示

1.如何存储不同的顶点属性。

  使用结构数组要比使用数组结构性能更有优,原因是每个顶点的属性数据能够被连续的读出,这种内存结构更有效。但使用array of structures 不好的是当我们想去修改指定的属性时。如果一个顶点属性需要被修改(像贴图坐标),这将必须更新顶点缓冲区。当顶点缓冲区作为缓冲区对象时,整个

顶点属性缓冲区将需要更新加载,

2.顶点属性使用哪种数据格式

  顶点属性数据格式 通过调用glVertexAttribPointer 函数的参数type指定,这样做不但影响顶点属性的绘图数据的存储要求,也影响全部的执行工作,它是渲染帧时的内存带宽的要求。数据量越小,对带宽要求越低。OpenGL ES 3支持16位浮点顶点格式命名gl_half_float,建议尽量使用gl_half_float,Texture coordinates, normals, binormals, tangent vectors都适合使用gl_half_float来存储,颜色使用四个GL_UNSIGNED_BYTE来存储每个顶点颜色,顶点位置应该存储为GL_FLOAT。

3.如何标准化glVertexAttribPointer 工作

  顶点属性在被顶点着色器使用前,作为单一精度的浮点值被存储在内存中。如果顶点属性的数据类型不是浮点数,那么它们的值将在着色器使用前转变为浮点值。normalized标志指示非浮点顶点属性数据转化为单一精度的浮点值。如果normalized符为false,顶点数值被直接转化为浮点值,转化非浮点变量为浮点类型是相似的

GLfloat f;GLbyte b;f = (GLfloat)b; // f represents values in the range [-128.0,// 127.0]

如果normalized为true,顶点数据类型如果是GL_BYTE, GL_SHORT 或 GL_FIXED 被匹配到[-1.0,1.0],数据类型如果是GL_UNSIGNED_BYTE or GL_UNSIGNED_SHORT 被匹配到[0.0,1.0]。下面描述非浮点值数据类型normalized转换过程

 也有可能访问整数顶点属性数据为整数的顶点着色器,而不将它们转换为浮点数。在这种情况下,glvertexattribipointer功能应使用顶点属性应该被声明为一个整数类型的顶点着色。

4.在常量顶点属性和顶点数组之间选择

int Init ( ESContext *esContext ){  UserData *userData = (UserData*) esContext->userData;  const char vShaderStr[] =                 "#version 300 es \n"                 "layout(location = 0) in vec4 a_color; \n"                 "layout(location = 1) in vec4 a_position; \n"                  "out vec4 v_color; \n"                  "void main() \n"                    "{ \n"                    " v_color = a_color; \n"                    " gl_Position = a_position; \n"                    "}";  const char fShaderStr[] =              "#version 300 es \n"              "precision mediump float; \n"              "in vec4 v_color; \n"              "out vec4 o_fragColor; \n"              "void main() \n"              "{ \n"              " o_fragColor = v_color; \n"              "}" ;  GLuint programObject;// Create the program object  programObject = esLoadProgram ( vShaderStr, fShaderStr );  if ( programObject == 0 )    return GL_FALSE;// Store the program object  userData->programObject = programObject;  glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );  return GL_TRUE;}
void Draw ( ESContext *esContext ){  UserData *userData = (UserData*) esContext->userData;  GLfloat color[4] = { 1.0f, 0.0f, 0.0f, 1.0f };  // 3 vertices, with (x, y, z) per-vertex  GLfloat vertexPos[3 * 3] =  {    0.0f, 0.5f, 0.0f, // v0    -0.5f, -0.5f, 0.0f, // v1    0.5f, -0.5f, 0.0f // v2  };  glViewport ( 0, 0, esContext->width, esContext->height );  glClear ( GL_COLOR_BUFFER_BIT );  glUseProgram ( userData->programObject );  glVertexAttrib4fv ( 0, color );  glVertexAttribPointer ( 1, 3, GL_FLOAT, GL_FALSE, 0,                vertexPos );  glEnableVertexAttribArray ( 1 );  glDrawArrays ( GL_TRIANGLES, 0, 3 );  glDisableVertexAttribArray ( 1 );}