在上一篇博客 iOS — OpenGLES之简单的图形绘制 中,使用OpenGLES绘制了基本的三角形和矩形。在矩形绘制过程中,使用到了VBO,即Vertex Buffer Object,可视为GPU中的一块缓冲区buffer,用于存储顶点的所有信息。OpenGL在GPU中记录着这个VBO的id和对应的显存地址(或地址偏移)。
如果不使用VBO,就直接从CPU主存中传递顶点数据到GPU中进行运算和渲染。绘制图形的过程,实际上就是将内存中存储的vertices和indices等数据通过glDrawElements/glDrawArrays拷贝到GPU中。而频繁地在CPU/GPU之间传递数据的效率很低,因此可使用VBO缓存顶点数据,只在初始化缓冲区及在顶点数据有变化时才需要对该缓冲区进行操作,能大大减少CPU/GPU之间的数据拷贝开销。
绘制红色三角形
设置viewPort,顶点数组
glViewport(0, 0, self.view.frame.size.width, self.view.frame.size.height);
GLfloat vertices[] = {
0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f };
不使用VBO时
则不使用VBO时,绘制三角形如下:
// 给_positionSlot传递vertices数据
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(_positionSlot);
// Draw triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
[_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
其中,glVertexAttribPointer用于传递顶点着色器的位置信息。函数原型:
void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride,const GLvoid * pointer)
参数意义如下:
index:顶点数据在着色器程序中的属性,这里即_positionSlot。
size:每个顶点属性的组件数量,这里3表示每个顶点由三个元素组成,如0.0f, 0.5f, 0.0f。
type:每个顶点属性的组件类型,这里即GL_FLOAT。
normalized:指定当被访问时,固定点数据值是否应该被归一化或直接转换成固定点值,这里即GL_FALSE。
stride:指定相邻两个顶点数据之间的偏移量,即间隔大小。OpenGL根据该间隔从由多个顶点数据组成的数据块中跳跃地读取相应的顶点数据。这里vertices数组中仅存储顶点数据(x,y,z),因此相邻两个顶点数据之间的间隔本应为 sizeof(float) * 3 。但此处传递默认参数0的原因在于:0表示在顶点数组中每个顶点数据都是紧密排列的,OpenGL会自动计算各个顶点数据的大小得到对应的间隔。
注意:该函数的最后一个参数pointer的意义会因是否使用VBO而不同。
pointer:未使用VBO时,其指向CPU内存中的顶点数据数组,因此这里是vertices。
而使用VBO时,表示该顶点数据在顶点缓存对象VBO(GL_ARRAY_BUFFER)中的起始偏移量,具体使用示例请看使用VBO绘制三角形的代码。
那么,详细解释了该函数的所有参数,再回头看其未使用VBO时的调用方式:
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, vertices);
是不是都清楚了呢?
使用VBO时
使用VBO时,先创建、绑定VBO,传递顶点数组
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(_positionSlot);
// Draw triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
[_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
先看glVertexAttribPointer,之前说过了其各个参数的意义,这里调用如下:
glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, 0, 0);
最后一个参数pointer为0,即顶点数据在VBO(GL_ARRAY_BUFFER)中的起始