Индексный буфер OpenGL не работает при загрузке объектов один за другим

Я изучаю OpenGL и столкнулся с «препятствием».
Я нарисовал несколько домов (блоков и пирамид), используя индексный буфер.
Это прекрасно работает при загрузке всех вершин (из всех домов) в вершинный буфер и использовании 1 большого индексного буфера. Теперь я хочу анимировать объекты и загружать их в вершинный буфер один за другим, чтобы я мог выполнять преобразование объектов один за другим. Код не сильно отличается от одного большого буфера, но когда я делаю это, я просто вижу, как на экране появляются случайные фигуры. Мой код выглядит следующим образом:

У меня есть мировой класс, который содержит список трехмерных объектов, имеет один большой список всех вершин (для ознакомительных целей), один большой список индексов (также пробный) и метод для добавления объекта Object3D в мир.

class World
{
public:
World();
~World();

vector<Object3D> objects;
vector<glm::vec3> Vertices;
vector<GLushort> Indices;

void AddObject(Object3D &object);

};

Класс Object3D:

class Object3D
{
public:
Object3D();
~Object3D();

glm::vec3 Position;
vector<glm::vec3> Vertices;
vector<unsigned int> Indices;
};

Метод World AddObject просто добавляет объект в список «объекты» и добавляет вершины и индексы в списки «Вершины» и «Индексы», чтобы создать один большой буфер:

void World::AddObject(Object3D &object) {

int oldVerticesSize = Vertices.size();
objects.push_back(object);
Vertices.insert(Vertices.end(), object.Vertices.begin(), object.Vertices.end());

for each (GLushort index in object.Indices)
{
Indices.push_back(index + oldVerticesSize);
}
}

Когда я рендерил большой буфер со всеми вершинами и индексами (как показано ниже), он работает нормально.

void WorldRenderer::Render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glBindVertexArray(Vao); //use vao
glDrawElements(GL_TRIANGLES, World.Indices.size(), GL_UNSIGNED_SHORT, 0);
//glDrawArrays(GL_TRIANGLES, 0, World.Vertices.size());
glBindVertexArray(0); //release vao

//Model = glm::rotate(Model, 0.01f, glm::vec3(0.0f, 1.0f, 0.0f));
Mvp = Projection * View * Model;

glUniformMatrix4fv(UniformMvp, 1, GL_FALSE, glm::value_ptr(Mvp));
glutSwapBuffers();

//glutPostRedisplay();

}

Когда я зацикливаюсь на объектах и ​​загружаю вершины объектов в буфер по одному объекту за раз (как показано ниже), он показывает некоторые случайные «формы», которые продолжают «стрелять вокруг» или быстро изменяться. Что я здесь не так делаю?
Спасибо заранее за любые советы.

void WorldRenderer::Render()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

int index = 0;
for each (Object3D mesh in World.objects)
{
Mvp = Projection * View * Model;

UpdateBuffer(mesh.Vertices, mesh.Indices);

glBindVertexArray(Vao); //use vao
glDrawElements(GL_TRIANGLES, mesh.Indices.size() , GL_UNSIGNED_SHORT, 0);
glBindVertexArray(0); //release vao
glUniformMatrix4fv(UniformMvp, 1, GL_FALSE, glm::value_ptr(Mvp));
index++;
}

glutSwapBuffers();
}

Метод UpdateBuffers:

void WorldRenderer::UpdateBuffer(vector<glm::vec3> vertices, vector<unsigned int> indices) {

//fill Vbo
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBufferData(GL_ARRAY_BUFFER, vertices.size(), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

//fill ibo
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(unsigned int), indices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

glBindVertexArray(Vao);
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
}

Для первого метода Render (без цикла) буферы создаются один раз в методе init, который выглядит следующим образом:

void WorldRenderer::Init(int argc, char ** argv) {
InitGlutGlew(argc, argv);
InitMatrices();

glDisable(GL_CULL_FACE);
//-------------- init buffers --------------
// vbo vertices
glGenBuffers(1, &Vbo);
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
glBufferData(GL_ARRAY_BUFFER, World.Vertices.size() * sizeof(glm::vec3),
&World.Vertices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
//ibo
glGenBuffers(1, &Ibo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, World.Indices.size() * sizeof(unsigned int),
&World.Indices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

// VAO setup
glGenVertexArrays(1, &Vao);
glBindVertexArray(Vao);
// Bind vertices to vao
glBindBuffer(GL_ARRAY_BUFFER, Vbo);
//Bind elements
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Ibo);

//------ init shaders -----------
InitShader();
}

1

Решение

Как только я увижу твой UpdateBuffer функция, я чувствую, что glBufferData за vbo не загружен должным образом.

Второй параметр vertices.size() возвращает только количество элементов в векторе, но не фактический размер объекта.

Таким образом, второй параметр должен быть vertices.size() * sizeof(glm::vec3)

И третий параметр в порядке, так как он возвращает указатель на базовый массив. Если не работает …. прямо передайте адрес первого элемента, как показано ниже.

В целом это должно быть примерно так, как показано ниже.

glBufferData(
GL_ARRAY_BUFFER,
vertices.size() * sizeof(glm::vec3),
&vertices[0],
GL_STATIC_DRAW
);

Проверьте, работает ли это.

Почему вы видите различия?

Первый рендер:

Ваш буфер содержит все мировые данные для вершин непрерывно, когда glDrawElements называется.
Так вот последняя вершина mesh1 продолжается с первой вершины mesh 2…. Итак, вы видите своего рода замкнутую форму.

Второй рендер:

ваш буфер содержит только одну сетку данных за раз, когда glDrawElements называется.

так что ваша форма заканчивается для каждой сетки после вызова glDrawElements,

Чтобы получить тот же результат, что и при первом рендеринге, вы должны сначала обновить буфер одной вершины для всех сеток (используйте glBufferSubData).

Тогда позвони glDrawElements один раз. Тогда вы увидите тот же результат.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]