为了进行仿真,我们创建了一个OpenGL1.1视图,其中包含32 x 48矩形的网格。
每次CADisplayLink调用绘制函数时,我们都会绘制此网格,并且顶点位置永远不会改变。帧与帧之间唯一发生变化的是顶点的颜色。
这是我们的简化示例:
- (void)drawFrame {
// draw grid
for (int i = 0; i < numRectangles; i++) {
// ... calculate CGPoint values for vertices ...
GLshort vertices[ ] = {
bottomLeft.x, bottomLeft.y,
bottomRight.x, bottomRight.y,
topLeft.x, topLeft.y,
topRight.x, topRight.y
};
glVertexPointer(2, GL_SHORT, 0, vertices);
glColor4f(r, g, b, 1);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
}
OpenGL仪器建议使用顶点缓冲对象(VBO)以获得更好的性能。
有没有一个示例,该示例说明了如何在顶点不随帧变化的情况下建立非常基本,简单的顶点缓冲对象用法?
Apple提供了一个示例over here, under the section Use Vertex Buffer Objects to Manage Copying Vertex Data,但是它不完整。
GLuint vertexBuffer;
GLuint indexBuffer;
void CreateVertexBuffers()
{
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
}
它没有显示如何真正创建数据。前面的清单(应该是一个“不好的例子”)包含这两行:
const vertexStruct vertices[] = {...};
const GLubyte indices[] = {...};
因此,这两个数组或结构必须传递给:
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
和
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
?
根据Apple在Use Interleaved Vertex Data部分下的说法,这是iOS首选的“交错(结构数组)”格式吗?
最佳答案
您不应使用glDrawArrays绘制单个图元,而应使用大批量绘制。到目前为止,您仅使用常规的顶点数组,而不使用顶点缓冲区对象。
这个想法是,将所有矩形上的几何图形放到一个单独的VBO中(VBO本质上是存储在OpenGL中的顶点数组,而不是您的过程)。通过使用glBufferSubData可以更改单个顶点。
可以将顶点颜色放入顶点数组,因此也可以放入VBO。
更新资料
假设您有一些六角形:
GLfloat vertices[2][] = {
{0, 0}, // 0
{1, 0}, // 1
{0.5, 0.866}, // 2
{-0.5, 0.866}, // 3
{-1, 0}, // 4
{0.5, -0.866}, // 5
{-0.5, -0.866}, // 6
};
而您只想绘制三角形的一部分,例如由顶点[0,1,2],[0,3,4]和[0,5,6]组成的三角形,则需要创建以下索引数组
GLushort indices[] = {
0, 1, 2,
0, 3, 4,
0, 5, 6
};
并将其用作glDrawElements的索引。
更新2
许多计算机图形学和OpenGL新手犯错的一件事是,顶点不仅是位置,而且是顶点属性的组合。哪些属性构成顶点是程序员做出的设计选择。但是常用的顶点属性是
位置
正常
纹理坐标
顶点颜色
在OpenGL-3核心之前,position属性是必需的。由于OpenGL-3内核使着色器成为必需,因此顶点属性只是着色器中的任意输入数据,并且只要顶点着色器设法传递* gl_Position *输出,OpenGL就很高兴。
重要的是,如果所有属性都相同,则只有两个顶点相同。如果它们的一个属性不同,则它们不是相同的顶点。现在,让我们以前面的六边形为例。我们现在将三角形制作为红色,绿色和蓝色,并要添加两个三角形,以将红色和绿色的三角形扩展为某种菱形:
// x, y, red, green, blue
GLfloat vertices[5][] = {
// red
{0, 0, 1, 0, 0}, // 0
{1, 0, 1, 0, 0}, // 1
{0.5, 0.866, 1, 0, 0}, // 2
{1, 1, 1, 0, 0}, // 3
// green
{0, 0, 0, 1, 0}, // 4
{-0.5, 0.866, 0, 1, 0}, // 5
{-1, 0, 0, 1, 0}, // 6
{-1, 1, 0, 1, 0}, // 7
// blue
{0, 0, 0, 0, 1}, // 8
{0.5, -0.866, 0, 0, 1}, // 9
{-0.5, -0.866, 0, 0, 1}, // 10
};
我们现在要绘制的三角形是
GLushort indices[] = {
// the two red triangles
0, 1, 2,
3, 2, 1,
// the two green triangles
4, 5, 6,
5, 7, 6,
// the blue triangle
8, 9, 10
};
现在我们需要告诉OpenGL我们顶点数组的结构。这是gl…Pointer函数的stride参数输入图片的地方。如果非零,则跨步告诉OpenGL数组中每个顶点的起点之间的距离(以字节为单位)。通过使用正确的偏移量传递数据指针,这使得OpenGL访问正确的东西。在我们的情况下,顶点由
GLfloat的2个位置元素,偏移量为0
GLfloat的3个颜色元素,偏移量为2 * sizeof(GLfloat)
每个顶点相隔
sizeof(GLfloat)*5
个字节。我们将让C编译器通过简单地取消引用正确的数组元素并获取其地址来为我们执行偏移量计算:
glVertexPointer(2, GL_FLOAT, sizeof(GLfloat)*5, &vertices[0][0]);
glColorPointer(3, GL_FLOAT, sizeof(GLfloat)*5, &vertices[0][2]);
其余的只是
glDrawElements(GL_TRIANGLES, 5, GL_UNSIGNED_SHORT, indices)
。请注意,目前我们不使用VBO,而仅使用客户端顶点数组。 VBO建立在顶点阵列上。因此,我强烈建议您在处理VBO之前首先掌握顶点阵列。它们实际上很容易使用,但是存在一些概念上的陷阱,例如欺骗编译器为指针参数传递数字。
关于iphone - 如何在iOS的OpenGL ES 1.0中使用顶点缓冲对象(VBO)而不是数千次调用glDrawArrays?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/8329546/