我想知道在OpenGL中使用vbo的最简单的方法...我已经尝试运行一些有效的例子,但是所有其他信息都让我感到困惑,这让我很困惑......此刻这就是我的意思有
GLuint vboId = 0;
const int trisize = (m_tris.size()/2)*3;//m_tris is an index array for verts and normals
GLfloat* vertices = new GLfloat[trisize];
GLfloat* normals = new GLfloat[trisize];
int j=0;
for (int i=0; i<m_tris.size(); i+=2) {
normals[j] = m_normals[m_tris[i+1]*3];
vertices[j++] = m_vertices[m_tris[i]*3];
normals[j] = m_normals[m_tris[i+1]*3+1];
vertices[j++] = m_vertices[m_tris[i]*3+1];
normals[j] = m_normals[m_tris[i+1]*3+2];
vertices[j++] = m_vertices[m_tris[i]*3+2];
} //im pretty sure this loop is right as its what i used before to display mesh correctly without vbo's using glVertex3f
glGenBuffersARB(1, &vboId);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, vboId);
glBufferDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices)+sizeof(normals), 0, GL_STATIC_DRAW_ARB);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, 0, sizeof(vertices), vertices);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, sizeof(vertices), sizeof(normals), normals);
glVertexPointer(sizeof(vertices), GL_FLOAT, 3, 0);
glNormalPointer(GL_FLOAT, 3, (void*)sizeof(vertices));
在我有的渲染方法
glDrawArrays(GL_TRIANGLES, 0, this->getTriNum()); //0 is the vboId?
我也有一个运行一次的方法......
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
当我尝试运行我的代码时,我得到“EXC_BAD_ACCESS”
关于我做错什么的任何建议......或者非常简单的vbo实现都会非常有帮助
答案 0 :(得分:24)
你正在做的事情看起来是正确的,除了sizeof(vertices)给出了地址的大小,而不是数组的大小。因此,当你调用glBufferData时,你正在分配8个字节,当你调用glBufferSubData时,你用顶点数组的前四个字节填充那8个字节,然后填充法线数组的前四个字节。然后,当你去调用glDrawArrays时,第一个indice会导致数组索引超出范围异常(因此EXC_BAD_ACCESS)。
// Data
GLuint geometry_array = 0;
GLuint indice_array = 0;
GLfloat *geometry;
GLuint *indices;
您可以采用不同的方式进行初始化,但我将所有数据交错为每个顶点数组32个字节。只要正确使用glVertexPointer,glNormalPointer和glTexCoordPointer,您选择设置数组的任何方式都可以正常工作。
// Initialize
geometry = new GLfloat[8*num_geometry];
indices = new GLuint[num_indices];
/* Fill geometry: 0, 1, 2 = vertex_xyz
* 3, 4, 5 = normal_xyz
* 6, 7 = tex_coord_uv
*/
glGenBuffers(1, &geometry_array);
glBindBuffer(GL_ARRAY_BUFFER, geometry_array);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*8*num_geometry, NULL, GL_DYNAMIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(GLfloat)*8*num_geometry, geometry);
glGenBuffers(1, &indice_array);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indice_array);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*num_indices, NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(GLuint)*num_indices, indices);
渲染功能有五个步骤。首先,绑定缓冲区,以便OpenGL知道在哪里找到几何和indice数据。其次,为每种类型的数据启用各种客户端状态。如果你留下一个,那么这种类型的数据将不会被渲染,如果将它们全部删除,你的整个对象将不会被渲染。第三,你必须告诉OpenGL你的数组中包含每种类型的数据。在这种情况下,32字节几何数据以12字节的顶点数据开始,因此起始偏移应为零或NULL。由于每个vertex-normal-texcoord组合是32个字节,即步长。 “sizeof(GLfloat) 8”表示从偏移量为NULL的32个字节,将有另一个顶点xyz组。在法线的情况下,每个正常xyz组在顶点xyz组的偏移之后是12个字节,因此“(float )(sizeof(GLfloat)* 3)”作为起始偏移。同样,步长为32个字节。第四,你必须告诉它绘制与indice数组相关的所有三角形。最后,如果要使用其他渲染方法,则应禁用客户端状态。
//Render
// Step 1
glBindBuffer(GL_ARRAY_BUFFER, geometry_array);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indice_array);
// Step 2
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
// Step 3
glTexCoordPointer(3, GL_FLOAT, sizeof(GLfloat)*8, (float*)(sizeof(GLfloat)*5));
glNormalPointer(GL_FLOAT, sizeof(GLfloat)*8, (float*)(sizeof(GLfloat)*3));
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*8, NULL);
// Step 4
glDrawElements(GL_TRIANGLES, num_indices, GL_UNSIGNED_INT, NULL);
// Step 5
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
答案 1 :(得分:3)
This is a VBO tutorial with an working example。示例接缝很简单,因此您可以将其用作参考。
答案 2 :(得分:1)
OpenGL - VBO, Shader, VAO有一个简单的例子,它显示了基于VBO的渲染所需的API调用的基本顺序。该示例从传统立即模式转换为基于现代着色器的渲染。
示例代码可以在Github project OpenGl-Render上访问,并在Windows和Linux上运行。
答案 3 :(得分:0)
sizeof(vertices)
和sizeof(normals)
同时给你4个,因为vertices
和normals
是指针(不是数组)。您应该对所有glBuffer *命令使用trisize * sizeof(GLfloat)
。
另外,对于glDrawArrays,你应该指定顶点的数量(= triangles * 3)。
此外,最后2个命令应该如下所示:
glVertexPointer(3,GL_FLOAT,0,NULL)
glNormalPointer(GL_FLOAT,0,(void*)(trisize * sizeof(GLfloat)));
结论:你在一段相对简单的代码中犯了很多错误。您没有正确阅读基本文档。也许,这个问题应该被关闭。