首页 > 编程语言 >OpenGL ES 2.0编程指导阅读笔记(六)顶点属性、顶点数组和缓冲对象

OpenGL ES 2.0编程指导阅读笔记(六)顶点属性、顶点数组和缓冲对象

时间:2023-02-02 18:13:24浏览次数:52  
标签:2.0 OpenGL buffer void object 顶点 GL 属性

顶点数据,又称顶点属性,给定了每个顶点的数据。
这类每个顶点的数据可以每个顶点分别给定,也可以给定一个所有顶点共用的常量。
在OpenGL ES 1.1中,顶点属性名称是预定义的,如position、normal、color、texture coordinates。这是因为OpenGL ES 1.1的固定功能流水线仅需要这些预定义的顶点属性。
在OpenGL ES 2.0中,顶点属性都是通用顶点属性。

给定顶点属性数据

可以使用GL_MAX_VERTEX_ATTRIBS来查询最多支持的顶点属性个数。

常数顶点属性

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

顶点数组

顶点数组指定了每个顶点的数据,它是保存在应用地址空间(即OpenGL ES所谓的客户端空间)中的缓冲。
顶点数组用以下函数指定:

void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *ptr);

type可以是GL_BYTE、GL_UNSIGNED_BYTE、GL_SHORT、GL_UNSIGNED_SHORT、GL_FLOAT、GL_FIXED、GL_HALF_FLOAT_OES。GL_HALF_FLOAT_OES不一定支持。
顶点数组缓冲的保存有两种方式:

  • 结构体数组:将一个顶点的所有属性保存为一个结构体,并将所有顶点的属性保存为一个数组
  • 数组的结构体:将所有顶点的每个属性保存为一个数组,然后将每个属性数组组成一个结构体

性能提示

如何保存顶点的不同属性

在OpenGL ES 2.0硬件实现中,结构体数组的保存方式具有更好的性能。因为一个顶点的所有属性保存在一起,在使用时更加连续。但是,结构体数组的保存方式会使得对顶点某个属性更新时,出现不连续的访存,而当顶点缓冲是一个缓冲对象时,整个顶点属性缓冲都需要更新。为了避免这种情况,可以将动态的顶点属性保存到独立的缓冲中。

顶点属性使用何种数据类型

应使用合适的、最小体积的数据类型,如颜色使用GL_UNSIGNED_BYTE,其他使用GL_HALF_FLOAT_OES。

normalized是怎样工作的

如果顶点属性不是单精度浮点类型,在被vertex shader用于计算之前,它会被转换成单精度浮点类型。
normalized控制这类型转换的方式,当其为0时,数据被直接转换成单精度浮点类型,当其为1时,会将原类型的整体表示范围映射到
归一化的范围内,具体如下:

顶点数据格式 转换到浮点操作
GL_BYTE \(\frac{2c+1}{2^8-1}\)
GL_UNSIGNED_BYTE \(\frac{c}{2^8-1}\)
GL_SHORT \(\frac{2c+1}{2^{16}-1}\)
GL_UNSIGNED_SHORT \(\frac{c}{2^{16}-1}\)
GL_FIXED \(\frac{c}{2^{16}}\)
GL_FLOAT \(c\)
GL_HALF_FLOAT_OES \(c\)

选择常量顶点属性或顶点数组

void glEnableVertexAttribArray(GLuint index);
void glDisableVertexAttribArray(GLuint index);

当顶点数组矩阵被禁用时,将会使用常量顶点属性数据。

在Vertex Shader中声明属性

在vertex shader中,可以对变量使用attribute修饰符。attribute修饰符不能用于数组和结构体,不能用于fragment shader。
可以使用GL_MAX_VERTEX_ATTRIBS查询OpenGL ES 2.0实现支持的vec4顶点属性数量。
float、vec2、vec3类型的属性会被计作一个vec4属性。
不像uniform和varying,属性不会被编译器自动打包。
被定义为attribute的变量是只读的。
如果attribute变量仅被声明而没有使用,该变量将不被认为是激活的。
可以使用GL_ACTIVE_ATTRIBUTES查询激活的属性数量:

void GLGetProgramiv(prgoram, GL_ACTIVE_ATTRIBTES, &numActivateAttribs);

可以用以下函数查询激活的顶点属性列表及其数据类型:

void GLGetActiveAttrib(GLuint program, GLint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name);

绑定顶点属性和vertex shader中的属性变量

OpenGL ES 2.0提供了两种方法将通用顶点属性索引映射到vertex shader中的属性变量名:

  • OpenGL ES 2.0绑定通用顶点属性索引到属性名称
  • 应用绑定顶点属性索引到变量名称
    glBindAttribLocation命令被用于绑定通用顶点属性索引到vertex shader中的一个属性变量。该绑定在程序下次link时生效,它不会修改当前已经完成link的程序的绑定关系。
void glBindAttribLocation(GLuint program, GLuint index, const GLchar *name);

在link阶段,OpenGL ES 2.0实现首先检查每个属性变量是否被使用glBindAttribLocation绑定,如果有,则使用指定的绑定,否则,就给它分配一个通用顶点属性索引。
因此,对于OpenGL ES 2.0自动分配的索引,需要先获取其分配结果,然后再指定数据。
使用以下函数获取属性变量的位置:

GLint glGetAttribLocation(GLuint program, const GLchar *name);

顶点缓冲对象

使用顶点数组给定的顶点数据保存在客户端内存中,每次调用glDrawArrays或glDrawElements(统称为draw call)时都需要复制到图形存储中。而缓冲对象允许OpenGL ES 2.0应用分配高性能图形存储并缓存顶点数据,直接从中进行渲染,而不必每次绘制时复制数据。
OpenGL ES支持两种缓冲对象:数组缓冲对象(array buffer objects)和元数组缓冲对象(element array buffer object)。数组缓冲对象用来保存顶点数据,以GL_ARRAY_BUFFER创建。元数组缓冲对象用来保存图元的索引,以GL_ELEMENT_ARRAY_BUFFER创建。
创建buffer object,分配buffer object name,注意buffer object name的命名空间为正整数:

void glGenBuffers(GLsizei n, GLuint *buffers);

绑定buffer object,当buffer object第一次进行绑定时,会为buffer object分配默认状态,绑定后分配的buffer object会成为渲染上下文中当前使用的array buffer object或element array buffer object:

void glBindBuffer(GLenum target, GLuint buffer);

与buffer object相关的状态有:

  • GL_BUFFER_SIZE:buffer object中数据的大小,默认为0
  • GL_BUFFER_USAGE:应用将如何使用buffer object中存储的数据的提示,具体如下表所示。
buffer usage索引 描述
GL_STATIC_DRAW 缓冲对象的数据将给定一次,然后被多次使用
GL_DYNAMIC_DRAW 缓冲对象的数据将给定多次,并多次使用
GL_STREAM_DRAW 缓冲对象的数据给定一次,然后使用少量几次

注意,GL_BUFFER_USAGE仅仅是一个提示而非保证,可能与实际使用情况不同。

buffer object数据建立和初始化:

void glBufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage);

其中,target可以为GL_ARRAY_BUFFER或GL_ELEMENT_ARRAY_BUFFER。

glBufferData保留了size大小的空间,如果data是合法指针,数据将被复制到分配的数据存储空间,如果data是NULL,分配的存储空间将是未初始化的。
buffer object的数据存储空间可以使用以下命令来部分初始化:

void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);

删除buffer object:

void glDeleteBuffers(GLsizei n, GLuint *buffers);

映射缓冲对象

OES_map_buffer扩展允许应用映射buffer object到应用的地址空间和解除映射,映射后,可以对buffer object的内容进行更新。
OpenGL ES 2.0仅允许对映射空间的写操作。

void *glMapBufferOES(GLenum target, GLenum access);
GLboolean glUnmapBufferOES(GLenum target);

其中,access只能是GL_WRITE_ONLY_OES,命令返回一个指向映射后地址空间的指针。

性能提示

glMapBufferOES应该只用于更新全部的buffer,使用该命令更新部分区域是不建议的,glMapBufferOES中也没有机制指定一个子区域。
如果需要更新的buffer正在被使用,GPU应该等待之前的正在使用该buffer的渲染命令完成后再返回指针。
合理的使用方法是,先使用glBufferData分配一个未初始化的buffer,紧接着使用glMapBufferOES更新全部区域,这种情况下,OpenGL ES实现可以对其正确地进行优化。

概念辨析

generic vertex attribute,通用顶点属性,vertex attribute,顶点属性,是同一概念,是从OpenGL ES 2.0的视角对顶点属性的描述。
attribute,属性,attribute variable,属性变量,是同一概念,是指vertex shader中声明的变量,是从shader的视角对顶点属性的描述。
属性变量的index,和其location是不同的概念。前者是查询属性变量列表时属性变量在列表中的排序,后者是属性变量与通用顶点属性绑定之后,属性变量对应的通用顶点属性的index。

标签:2.0,OpenGL,buffer,void,object,顶点,GL,属性
From: https://www.cnblogs.com/belatedluck/p/17073118.html

相关文章