Самый основной рабочий пример VBO - PullRequest
18 голосов
/ 23 февраля 2011

Я хочу знать самый простой способ использования vbo-ов в OpenGL ... Я попытался запустить несколько примеров, которые работают, но затуманены всей другой информацией, которая меня действительно смущает ... на данный момент это то, что яу меня есть

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 ]

24 голосов
/ 23 февраля 2011

То, что вы делаете, выглядит правильно, за исключением того, что sizeof (вершины) дает вам размер адреса, а не размер массива.Итак, когда вы вызываете glBufferData, вы выделяете 8 байтов, а когда вы вызываете glBufferSubData, вы заполняете эти 8 байтов первыми четырьмя байтами массива вершин, а затем первыми четырьмя байтами массива нормали.Затем, когда вы идете к вызову glDrawArrays, первый индекс вызывает исключение индекса массива за пределами границ (следовательно, 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 знал, где найти вашу геометрию и данные индексов.Во-вторых, включите различные состояния клиента для каждого типа данных.Если вы пропустите один из них, данные этого типа не будут отображаться, а если пропустить все из них, весь ваш объект не будет отображаться.В-третьих, вы должны указать OpenGL, где каждый тип данных содержится в вашем массиве.В этом случае 32-байтовые данные геометрии начинаются с 12 байтов данных вершины, поэтому начальное смещение должно быть нулевым или NULL.Поскольку каждая комбинация vertex-normal-texcoord составляет 32 байта, это размер шага.«sizeof (GLfloat) 8» говорит, что 32 байта от смещения NULL, будет другая группа вершин xyz.В случае нормалей каждая нормальная группа xyz составляет 12 байтов после смещения для группы вершин xyz, следовательно, "(float ) (sizeof (GLfloat) * 3)" в качестве начального смещения.Опять же, размер шага составляет 32 байта.В-четвертых, вы должны сказать ему, чтобы нарисовали все треугольники, связанные с массивом индексов.Наконец, вы должны отключить состояния клиента, если вы хотите использовать другой метод рендеринга.

//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);
3 голосов
/ 23 февраля 2011

Это учебник VBO с рабочим примером . Пример выглядит простым, поэтому вы можете использовать его в качестве справочного материала.

1 голос
/ 11 октября 2016

OpenGL - VBO, Shader, VAO имеет простой пример, который показывает базовую последовательность вызовов API, необходимых для рендеринга на основе VBO.Пример переходит из устаревшего непосредственного режима в современный рендеринг на основе шейдеров.

К коду примера можно получить доступ в Github-проекте OpenGl-Render и работает как в Windows, так и в Linux.

0 голосов
/ 23 февраля 2011

sizeof(vertices) и sizeof(normals) дают вам 4, потому что vertices и normals являются указателями (а не массивами). Вы должны использовать trisize * sizeof(GLfloat) для всех команд glBuffer *.

Кроме того, для glDrawArrays вы должны указать количество вершин (= треугольники * 3).

Кроме того, последние 2 команды должны выглядеть следующим образом:

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

Вывод: вы сделали много ошибок в относительно простом куске кода. Вы не прочитали основную документацию должным образом. Возможно, этот вопрос следует закрыть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...