资料来源:
OpenGL ES3.0编程指南
https://www.cnblogs.com/gaofengworking/p/4943204.html
https://blog.youkuaiyun.com/tianxiawuzhei/article/details/46639553
顶点数据也称作顶点属性,指定每个顶点的数据。这种逐顶点数据可以为每个顶点指定,也可以用于所有的顶点的常量。
想要绘制一个固定颜色的三角形,可以指定一个常量用于三角形的全部三个顶点
常量顶点属性
常量顶点属性对于一个图元的所有顶点都相同,所以对一个图元的所有顶点只需要采用一个值:
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);
上面这些命令用来给由index指定的顶点属性加载数据。其中glVertexAttrib1f和glVertexAttrib1fv会加载(x, 0.0, 0.0, 1.0),glVertexAttrib2f和glVertexAttrib2fv会加载(x, y, 0.0, 1.0),glVertexAttrib3f和glVertexAttrib3fv会加载(x, y, z, 1.0),glVertexAttrib4f和glVertexAttrib4fv会加载(x, y, z, w)。在实际中,常量顶点属性提供了和使用标量/向量统一变量等价的功能,两者都可以选用。
顶点数组
顶点数组指定每个顶点的属性,是保存在应用程序地址空间的缓冲区。顶点数组用glVertexAttribPointer()
或者glVertexAttribIPointer()
来指定:
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
vertexStride, vertexBuffer);
//参数一:通用属性的句柄,在上个demo中指的是mPositionHandle
//参数二,指的是一个顶点的属性包含的size的值,在demo中设置为3
//参数三:数据格式,与数组的type一致
//参数四:标识非浮点数据在转换成浮点时是否规范化
//参数五:每个顶点由size指定的定点属性分量的顺序存储,即告诉程序对应每个顶点的位置
//参数六:顶点数组
顶点缓冲区对象(VBOS)
当使用顶点数组的时候,顶点数据是保存在客户内存中(一般指cpu),在进行glDrawArray()
或者glDrawElements()
等绘图调用时候,这些数据会从客户内存复制到图形内存(指gpu)。**如果我们没有必要再绘图调用时都复制顶点数据,则可以在图形内存中缓存这些数据,这种方法可以改善渲染性能,也会降低内存和电力的消耗。**这就是顶缓冲区对象的意义。
顶点缓冲区对象让opengl es应用程序在图像内存中分配和缓存数据,并且在这个内存中渲染,避免每次绘制图元时候重新发送数据
3.0中支持两类缓冲区对象,用于指定顶点和图元数据:
- **数组缓冲区对象。**标识GL_ARRAY_BUFFER指定数组缓冲区对象用于创建保存顶点数据的缓冲区对象
- **元素数组缓冲区对象。**GL_ELEMENT_ARRAY_BUFFER标识指定的元素数组缓冲区对象用于创建保存图元索引的缓冲区对象。
数组缓冲区用于保存一个或者多个图元的顶点属性数据,而元素数组缓冲区对象保存了一个或者多个图元的索引,以数组缓冲区做例子:
private void createVertextBuffer(){
int[] value = new int[1];
GLES30.glGenBuffers(1, value,0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, value[0]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,vertexBuffer.position(),vertexBuffer,GLES30.GL_STATIC_DRAW);
}
glGenBuffers()
用来获取未使用的缓冲对象,其中参数一标识需要返回的缓冲对象数量,参数二标识返回分配的缓冲对象的位置句柄。
注意:glGenBuffers()返回的句柄是0以外的无符号整数,0值由opengl es保留
glBindBuffer()
用于指定当前缓冲区对象,参数一使用GL_ARRAY_BUFFER
或者GL_ELEMENT_ARRAY_BUFFER
来标识缓冲对象,参数二表示需要使用的缓冲区对象句柄。glBufferData()
用来绑定缓冲区数据,参数一与上相同,参数二标识缓冲区的数据存储大小(以字节数表示),,参数三为数据,参数四为使用缓冲区存储的数据对象的提示。如果参数三是一个有效数据,则内容会被复制且分配到缓冲区对象中。
在Android中的使用(居于https://my.oschina.net/u/3863980/blog/1829185 Demo改进):
private void createVertextBuffer(){
int[] value = new int[1];
GLES30.glGenBuffers(1, value,0);
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, value[0]);
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,vertexBuffer.capacity()*4,vertexBuffer,GLES30.GL_STATIC_DRAW);
}
public void onDraw(){
// Add program to OpenGL ES environment
GLES30.glUseProgram(mProgram);
// get handle to vertex shader's vPosition member
mPositionHandle = GLES30.glGetAttribLocation(mProgram, "vPosition");
createVertextBuffer();
// Enable a handle to the triangle vertices
GLES30.glEnableVertexAttribArray(mPositionHandle);
// Prepare the triangle coordinate data
GLES30.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES30.GL_FLOAT, false,
0, 0);//这里注意最后两个参数需要改成0,0标明不从cpu中拿数据了,从gpu拿数据,所以方法是不一样的
// get handle to fragment shader's vColor member
mColorHandle = GLES30.glGetAttribLocation(mProgram, "aColor");
// Set color for drawing the triangle
GLES30.glVertexAttrib4fv(mColorHandle, color, 0);
// Draw the triangle
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, vertexCount);
// Disable vertex array
GLES30.glDisableVertexAttribArray(mPositionHandle);
}
总而言之,使用顶点缓冲区对象能够减少cpu和gpu之间复制的数据量,从而获得更好的性能。
顶点数组对象(VAO)
这个特性是在opengl es3.0 中引入的,提供包含在顶点数组/顶点缓冲区对象配置之间切换所需要的所有状态的单一对象.只需要在设置缓冲区数据的时候glGenVertexArrays一个顶点数组对象ID,然后调用glBindVertexArray绑定已经生成数组对象的ID,在绘制图元的时候调用glBindVertexArray切换相应缓冲区内的数据并进行绘制.glDeleteVertexArray删除一个或者多个顶点数组对象.
映射缓冲区对象
应用程序设置缓冲区对象数据调用glBufferData的时候,可以将缓冲区对象数据存储映射到应用程序的内存地址空间,优点:减少应用程序的内存占用,只需要存储数据的一个副本.避免数据复制步骤通过映射出的GPU存储缓冲区对象的内存地址. 调用glMapBufferRange返回缓冲区存储数据范围的指针,出现错误则反悔NULL,glUnmapBuffer取消之前缓冲区映射。