iPhone Cheetah 3D OpenGL ES顶点缓冲区对象(VBO)示例



我想在iPhone的Open GL ES 1.1游戏中使用顶点缓冲对象(VBO)来改进我对一些复杂模型的渲染。在阅读了关于SO和this的几篇帖子之后(http://playcontrol.net/ewing/jibberjabber/opengl_vertex_buffer_object.html)在教程中,我仍然很难理解VBO以及如何在给定Cheetah 3D导出模型格式的情况下实现它们。有人能给我一个实现VBO的例子,并用它来绘制具有给定数据结构的顶点,并解释语法吗?我非常感谢任何帮助!

#define body_vertexcount    434
#define body_polygoncount   780
// The vertex data is saved in the following format:
// u0,v0,normalx0,normaly0,normalz0,x0,y0,z0
float body_vertex[body_vertexcount][8]={
{0.03333, 0.00000, -0.68652, -0.51763, 0.51063, 0.40972, -0.25028, -1.31418},
{...},
{...}
}
GLushort body_index[body_polygoncount][3]={
{0, 1, 2},
{2, 3, 0}
}

我在ProOpenGL ES(Appress)第9章的帮助下编写了以下代码。我正在使用DrawElements命令获取EXC_BAD_ACCESS,我不知道为什么。有人能照一下吗?谢谢-

// First thing we do is create / setup the index buffer
glGenBuffers(1, &bodyIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bodyIBO);
// For constrast, instead of glBufferSubData and glMapBuffer, 
// we can directly supply the data in one-shot
glBufferData(GL_ELEMENT_ARRAY_BUFFER, body_polygoncount*sizeof(GLubyte), body_index, GL_STATIC_DRAW);
// Define our data structure
int numXYZElements = 3;
int numNormalElements = 3;
int numTextureCoordElements = 2;
long totalXYZBytes;
long totalNormalBytes;
long totalTexCoordinateBytes;
int numBytesPerVertex;
// Allocate a new buffer
glGenBuffers(1, &bodyVBO);
// Bind the buffer object to use
glBindBuffer(GL_ARRAY_BUFFER, bodyVBO);
// Tally up the size of the data components
numBytesPerVertex = numXYZElements;
numBytesPerVertex += numNormalElements;
numBytesPerVertex += numTextureCoordElements;
numBytesPerVertex *= sizeof(GLfloat);
// Actually allocate memory on the GPU ( Data is static here )
glBufferData(GL_ARRAY_BUFFER, numBytesPerVertex * body_vertexcount, 0, GL_STATIC_DRAW);
// Upload data to the cache ( memory mapping )
GLubyte *vboBuffer = (GLubyte *)glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
// Caclulate the total number of bytes for each data type
totalXYZBytes = numXYZElements * body_vertexcount * sizeof(GLfloat);
totalNormalBytes = numNormalElements * body_vertexcount * sizeof(GLfloat);
totalTexCoordinateBytes = numTextureCoordElements * body_vertexcount * sizeof(GLfloat);
// Set the total bytes property for the body
self.bodyTotalBytes = totalXYZBytes + totalNormalBytes + totalTexCoordinateBytes;
// Setup the copy of the buffer(s) using memcpy()
memcpy(vboBuffer, body_vertex, self.bodyTotalBytes);
// Perform the actual copy
glUnmapBufferOES(GL_ARRAY_BUFFER);

以下是我得到异常的绘图命令:

    // Activate the VBOs to draw
    glBindBuffer(GL_ARRAY_BUFFER, bodyVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bodyIBO);
    // Setup drawing
    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_TEXTURE_2D);
    glClientActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,lightGreyInt);
    // Setup pointers
    glVertexPointer(3, GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 0 );
    glTexCoordPointer(2, GL_FLOAT, sizeof(vertexStruct),  (char *)NULL + 12 );
    glNormalPointer(GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 24 );
    // Now draw the body
    glDrawElements(GL_TRIANGLES, body_polygoncount,GL_UNSIGNED_SHORT, (GLvoid*)((char*)NULL));
    //glDrawElements(GL_TRIANGLES, body_polygoncount, GL_UNSIGNED_SHORT, nil);
    //glDrawElements(GL_TRIANGLES,body_polygoncount*3,GL_UNSIGNED_SHORT,body_index);

首先,索引缓冲区太小,不仅有body_polygoncount索引,还有body_polygoncount * 3索引。你还搞砸了类型,因为它们是短裤,你需要GLushort而不是GLubyte,所以应该是

glBufferData(GL_ELEMENT_ARRAY_BUFFER, body_polygoncount*3*sizeof(GLushort),
             body_index, GL_STATIC_DRAW);

然后,你把属性的偏移搞砸了,因为你的数据首先包含纹理坐标,然后是法线,然后是每个顶点的位置,它应该是

glVertexPointer(3, GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 20 );   //3rd, after 5*4 byte
glTexCoordPointer(2, GL_FLOAT, sizeof(vertexStruct),  (char *)NULL + 0 ); //1st
glNormalPointer(GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 8 );       //2nd, after 2*4 bytes

最后,在glDrawElements调用中,你没有给出三角形的数量,而是给出元素(索引)的数量,所以它应该是

glDrawElements(GL_TRIANGLES, body_polygoncount*3,
               GL_UNSIGNED_SHORT, (GLvoid*)((char*)NULL));

否则,你的代码看起来是合理的(当然,映射是毫无意义的,你本可以再次使用glBufferData,但我想你这样做是为了学习),如果你理解它所做的一切,就没有什么了。

但我想知道,如果你只是使用没有VBO的客户端顶点阵列,并且我认为OpenGL ES 1.1没有即时模式glBegin/glEnd,那么所有这些错误也会发生。所以我想知道,如果你没有意识到这些错误,为什么你的游戏以前没有VBO。

最新更新