Правильно обновлять объекты буфера вершин

У меня есть учебное приложение, написанное на 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 объектах. Поэтому я создаю 2 узла типа mesh::cube с настраиваемым количеством сегментов x y и z. Ожидаемое поведение моего приложения позволяет пользователю щелкнуть между двумя узлами CUBE0, CUBE1 и показать их настраиваемые атрибуты - сегменты x, сегменты y, сегменты z. Пользователь настраивает параметры обоих объектов, и они отображаются поверх друг друга в режиме каркаса, поэтому мы можем видеть изменение их топологии в режиме реального времени.

Когда узел создается в первый раз, если тип узла - меш, тогда объект ячейки генерируется, и его mesh_ptr записывается в приращения mesh_table и 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

ВОПРОС: Где я ошибся?

2 ответа

В вашей ничьей glBindBuffer(GL_ARRAY_BUFFER,mesh_data->vbo_index); на самом деле ничего не делает; информация об атрибуте вершины вообще не связана с буфером. это установлено в glVertexAttribPointer(5,3,GL_FLOAT,GL_FALSE,0,NULL); вызов, который перезаписывается каждый раз при загрузке новой сетки.

либо создать и использовать VAO или переместить этот вызов из add_mesh_to_GPU в draw_mesh:

для ВАО вы бы сделали:

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;
}

У вас есть фундаментальное недопонимание того, что 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. Они будут постоянно хранить состояние указателя вершины.

Другие вопросы по тегам