iPhone Cheetah 3D OpenGL ES 顶点缓冲对象 (VBO) 示例
Posted
技术标签:
【中文标题】iPhone Cheetah 3D OpenGL ES 顶点缓冲对象 (VBO) 示例【英文标题】:iPhone Cheetah 3D OpenGL ES Vertex Buffer Object (VBO) Example 【发布时间】:2012-03-17 23:37:25 【问题描述】:我想在我的 iPhone 版 Open GL ES 1.1 游戏中使用顶点缓冲区对象 (VBO) 来改进我对一些复杂模型的渲染。在阅读了关于 SO 和这个(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
我在 Pro OpenGL 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);
【问题讨论】:
假设您已经知道顶点数组和 OpenGL 的其余部分是如何工作的(您提到 your OpenGL ES 1.1 游戏建议)。您可能还看here,但您问题中的链接教程看起来很合理(不过我只是看了一眼)。 您遇到了哪些问题?我们不只是为您编写代码。数据结构和语法你不明白怎么办?尽可能明确,以便我们制定合理的答案。 我已经粘贴了我的代码,我在使用 glDrawElements 调用渲染交错数据时特别遇到了麻烦。我正在获取 EXC_BAD_ACCESS,非常感谢您的帮助 - 【参考方案1】:首先,您的索引缓冲区太小,您不仅有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 也能运行。
【讨论】:
谢谢 - 我看到了我的错误.. 现在它是有道理的。我之前画的像:// 画枪 - gunX 的渲染和纹理程序 //glBindTexture(GL_TEXTURE_2D,lightGreyInt); glVertexPointer(3, GL_FLOAT, sizeof(vertexStruct), &interpolatedVerticesGun[0][5]); glTexCoordPointer(2, GL_FLOAT, sizeof(vertexStruct), &interpolatedVerticesGun[0][0]); glNormalPointer(GL_FLOAT, sizeof(vertexStruct), &interpolatedVerticesGun[0][2]); glDrawElements(GL_TRIANGLES,gun2_polygoncount*3,GL_UNSIGNED_SHORT,gun2_index);以上是关于iPhone Cheetah 3D OpenGL ES 顶点缓冲对象 (VBO) 示例的主要内容,如果未能解决你的问题,请参考以下文章
如何使用用于 iPhone 开发的 OpenGL ES 渲染 3D 对象(顶点和法线存储在头文件中)?
iPhone OpenGL:使用 gluUnProject(端口)并检测点击对象