正确更新顶点缓冲区对象

时间:2014-10-29 16:09:21

标签: c++ opengl 3d vbo vertex-buffer-objects

我有一个用winapi编写的培训应用程序 所以,我已经在那里初始化了GL,并且我已经有了基于节点的系统,可以通过几个类来描述

class mesh
{
GLuint vbo_index; //this is for having unique vbo
float *vertex_array;
float *normal_array;
unsigned int vertex_count;

etc.. //all those mesh things.
....
}

class node
{
bool is_mesh; //the node may or may not represent a mesh
mesh * mesh_ptr; //if it does then this pointer is a valid address
}

我还有2个全局变量来保存可渲染网格的记录..

mesh **mesh_table;
unsigned int mesh_count;

现在我正在试验2个物体。所以我创建了两个类型为mesh :: cube的节点,其中包含可自定义数量的x y和z段。我的应用程序的预期行为是让用户在两个节点CUBE0,CUBE1之间单击并显示其可自定义的属性 - 段x,段y,段z。用户调整了两个目标'参数和它们在线框模式下呈现在彼此之上,因此我们可以实时看到它们的拓扑中的变化。

当第一次创建节点时,如果节点类型是网格,则生成网格对象并将其mesh_ptr写入 mesh_table < / strong>和 mesh_count 递增。之后,我的opengl窗口类为新网格创建一个唯一的顶点缓冲区对象,并将其存储在 mesh_ptr.vbo_index 中。

void window_glview::add_mesh_to_GPU(mesh* mesh_data)
{
    glGenBuffers(1,&mesh_data->vbo_index);
    glBindBuffer(GL_ARRAY_BUFFER ,mesh_data->vbo_index);
    glBufferData(GL_ARRAY_BUFFER ,mesh_data->vertex_count*3*4,mesh_data->vertex_array,GL_DYNAMIC_DRAW);
    glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL);//set vertex attrib (0)
    glEnableVertexAttribArray(5);
}

之后,用户可以调整参数,每次参数值改变时,对象的网格信息将根据新的参数值重新评估,同时仍然是相同的网格实例,之后

正在更新VBO数据
void window_glview::update_vbo(mesh *_mesh)
{
    glBindBuffer(GL_ARRAY_BUFFER,_mesh->vbo_vertex);
    glBufferData(GL_ARRAY_BUFFER,_mesh->vertex_count*12,_mesh->vertex_array,GL_DYNAMIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER,0);
}

并重新绘制整个场景

for (unsigned short i=0;i<mesh_count;i++)
    draw_mesh(mesh_table[i],GL_QUADS,false);
SwapBuffers(hDC);

单个网格的功能是

bool window_glview::draw_mesh(mesh* mesh_data,unsigned int GL_DRAW_METHOD,bool indices)
{
    glUseProgram(id_program);
    glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_index);
    GLuint id_matrix_loc = glGetUniformLocation(id_program, "in_Matrix");
    glUniformMatrix4fv(id_matrix_loc,1,GL_TRUE,cam.matrixResult.get());
    GLuint id_color_loc=glGetUniformLocation(id_program,"uColor");

    glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    glUniform3f(id_color_loc,mesh_color[0],mesh_color[1],mesh_color[2]);
    glDrawArrays(GL_DRAW_METHOD,0,mesh_data->vertex_count);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glUseProgram(0);
    return true;
}

问题是只有堆栈中的最后一个对象以这种方式绘制,而其他对象的点都是0 0 0,因此在视口中它使用适当的参数渲染一个多维数据集和一个立方体就像一个DOT enter image description here enter image description here

问题:我哪里出错?

2 个答案:

答案 0 :(得分:1)

您对glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_vertex);所做的事情存在根本性的误解。

设置绑定数组缓冲区,实际上只有少数几个命令使用(大多数是glVertexAttrib{I|L}Pointer (...)),绑定缓冲区本身不会做任何有用的事情。

你需要做的是:

bool window_glview::draw_mesh(mesh* mesh_data,unsigned int GL_DRAW_METHOD,bool indices)
{
    glUseProgram(id_program);

    //
    // Setup Vertex Pointers in addition to binding a VBO
    //
    glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_vertex);
    glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL);//set vertex attrib (0)
    glEnableVertexAttribArray(5);

    GLuint id_matrix_loc = glGetUniformLocation(id_program, "in_Matrix");
    glUniformMatrix4fv(id_matrix_loc,1,GL_TRUE,cam.matrixResult.get());
    GLuint id_color_loc=glGetUniformLocation(id_program,"uColor");

    glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    glUniform3f(id_color_loc,mesh_color[0],mesh_color[1],mesh_color[2]);
    glDrawArrays(GL_DRAW_METHOD,0,mesh_data->vertex_count);
    glBindBuffer(GL_ARRAY_BUFFER,0);
    glUseProgram(0);
    return true;
}

现在,如果你真的想让这个变得简单并且能够通过改变单个对象绑定来做到这一点,我建议你研究一下Vertex Array Objects。它们将持久存储顶点指针状态。

答案 1 :(得分:1)

你的平局中的

glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_index);实际上并没有做任何事情;有关顶点属性的信息根本没有绑定到缓冲区。它是在glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL);调用中设置的,每次上传新网格时都会被覆盖。

创建并使用VAO或将该来电从add_mesh_to_GPU移至draw_mesh

你要做的VAO:

void window_glview::add_mesh_to_GPU(mesh* mesh_data)
{
    glGenVertexArrays(1, &mesh_data->vao_index);//new GLInt field
    glBindVertexArray(mesh_data->vao_index);
    glGenBuffers(1,&mesh_data->vbo_index);
    glBindBuffer(GL_ARRAY_BUFFER ,mesh_data->vbo_index);
    glBufferData(GL_ARRAY_BUFFER ,mesh_data->vertex_count*3*4,mesh_data->vertex_array,GL_DYNAMIC_DRAW);
    glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL);//set vertex attrib (0)
    glEnableVertexAttribArray(5);
    glBindVertexArray(0);
}

bool window_glview::draw_mesh(mesh* mesh_data,unsigned int GL_DRAW_METHOD,bool indices)
{
    glBindVertexArray(mesh_data->vao_index);
    glUseProgram(id_program);
    GLuint id_matrix_loc = glGetUniformLocation(id_program, "in_Matrix");
    glUniformMatrix4fv(id_matrix_loc,1,GL_TRUE,cam.matrixResult.get());
    GLuint id_color_loc=glGetUniformLocation(id_program,"uColor");

    glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
    glUniform3f(id_color_loc,mesh_color[0],mesh_color[1],mesh_color[2]);
    glDrawArrays(GL_DRAW_METHOD,0,mesh_data->vertex_count);
    glUseProgram(0);
    glBindVertexArray(0);
    return true;
}