OpenGL — конвертировать из DisplayList для использования VBO

У меня есть следующие глобальные переменные:

vector<vector<unsigned int> > faces;
vector<float> vertexCoords;
unsigned int modelList;

В моей инициализации есть этот код:

glEnableClientState(GL_VERTEX_ARRAY);   // vertex array
glVertexPointer(3, GL_FLOAT, 0, &vertexCoords[0]);

modelList = glGenLists(1);  // generate display list
glNewList(modelList, GL_COMPILE);
for (unsigned int i = 0; i < faces.size(); i++) {
glBegin(GL_TRIANGLE_STRIP);
for (vector<unsigned int>::iterator it = faces[i].begin();
it != faces[i].end(); it++)
glArrayElement(*it - 1);
glEnd();
}
glEndList(); // End display list.

который в моем glutDisplayFunc я называю:

glCallList(modelList); // Execute display list.

Вместо DisplayList я бы хотел использовать VBO. Как я могу конвертировать этот код? Заранее спасибо.

0

Решение

Тебе повезло. В структуре вашей программы уже есть все. Мы можем даже обойти это раздражающее индексирование на основе 1.

Сначала создайте VBO:

GLuint vbo_id;
GLuint eabo_id; /* EIB = Element Array Buffer */
size_t eabo_n_elements;

void make_vbo()
{
GLuint genbuf_ids;
glGenBuffers(2, genbuf_ids);

vbo_id  = genbuf_ids[0];
eabo_id = genbuf_ids[1];

glBindBuffer(GL_ARRAY_BUFFER, vbo_id);

Выделите место для данных, любой скопируйте данные вершины в буфер. Поскольку ваш индексный массив элементов вершины смещен на единицу, мы выделяем еще одну вершину и копируем в нее данные со смещением (мы могли бы также использовать GL_ARB_draw_elements_base_vertex расширения, но я бы хотел показать это так:

    glBufferData(
GL_ARRAY_BUFFER,
(vertexCoords.size() + 3)*sizeof(vertexCoords[0]),
NULL,
GL_STATIC_DRAW );

glBufferSubData(
GL_ARRAY_BUFFER,
sizeof(vertexCoords[0])*3, /* offset by 1 vertex */
(vertexCoords.size())*sizeof(vertexCoords[0],
&vertexCoords[0]);

glBindBuffer(GL_ARRAY_BUFFER, 0);

То же самое для буфера массива элементов; Вы «сложили» два вектора друг в друга… что, кстати, не очень эффективно. Давайте развернем это. Сначала снова выделите память для буфера, но не копируйте в нее данные. Поскольку каждый подвектор может иметь различную длину (хотя, если он используется для конкретного режима примитивного рисования, они должны быть одинакового размера), сначала определите общее количество элементов (используя функцию C ++ 11). auto чтобы сохранить некоторую типизацию и чтобы мы могли использовать итераторы); также позже нам нужно знать это число, чтобы нарисовать их:

    eabo_n_elements = 0;
for(auto i = faces.begin(); i != faces.end(); i++) {
eabo_n_elements += i.size();
}

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eabo_id);
glBufferData(
GL_ELEMENT_ARRAY_BUFFER,
sizeof(faces[0][0]) * eabo_n_elements,
NULL,
GL_STATIC_DRAW );

Разверните и скопируйте данные лица в EAB

    size_t offset = 0;
for(auto i = faces.begin(); i != faces.end(); i++) {
size_t const len = i.size() * sizeof(i[0]);
glBufferSubData(
GL_ELEMENT_ARRAY_BUFFER,
offset,
len,
&i[0] );
offset += len;
}

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

Теперь мы можем нарисовать это. Технически мы могли бы использовать VAO (а с OpenGL-4 у нас должен быть один), но давайте сохраним это. Рисование VBO очень похоже на рисование из клиентских вершинных массивов. Теперь вы использовали glVertexPointer что указывает на то, что вы используете конвейер с фиксированной функцией. Мы можем использовать это. Но затем VBO стали функциональностью ядра OpenGL только с OpenGL-3 (до этого он долгое время был доступен в качестве расширения). Так что это glVertexAttribPointer плюс соответствующий шейдер вместо. Чтобы сделать переход как можно меньше, давайте переработаем ваше использование glVertexPointer, Основное отличие состоит в том, что мы связываем VBO перед тем, как glVertexPointer позвони и передай целочисленное приведение к указателю (которое на самом деле может вызывать UB для чего угодно, кроме 0) смещение в параметре данных:

void draw_vbo()
{
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
glVertexPointer(3, GL_FLOAT, 0, (void*)0);

Как только VBO будет «связано» с доступом к массиву вершин, мы можем его отменить. Данные по-прежнему будут получены из VBO.

    glBindBuffer(GL_ARRAY_BUFFER, 0);

И, наконец, сделать колл. Помните, что мы применили смещение из 1 элемента при копировании данных вершины в VBO. Поэтому мы просто проходим через индексы элемента вершины лица. Тот же шаблон, что и для VBO: Bind, приведение целочисленного смещения к указателю и передача его в glDrawElements

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eabo_id);
glDrawElements(GL_TRIANGLE_STRIP, eabo_n_elements, GL_UNSIGNED_INT, (void*)0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
1

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


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector