最基本的工作vbo示例

时间:2011-02-23 13:31:24

标签: c++ opengl

我想知道在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实现都会非常有帮助

4 个答案:

答案 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个,因为verticesnormals是指针(不是数组)。您应该对所有glBuffer *命令使用trisize * sizeof(GLfloat)

另外,对于glDrawArrays,你应该指定顶点的数量(= triangles * 3)。

此外,最后2个命令应该如下所示:

glVertexPointer(3,GL_FLOAT,0,NULL)
glNormalPointer(GL_FLOAT,0,(void*)(trisize * sizeof(GLfloat)));

结论:你在一段相对简单的代码中犯了很多错误。您没有正确阅读基本文档。也许,这个问题应该被关闭。