Подтвердить что ты не робот

Большинство основных рабочих примеров vbo

Я хочу узнать простейший метод использования 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 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 была бы очень полезной

4b9b3361

Ответ 1

То, что вы делаете, выглядит правильно, за исключением sizeof (vertices) дает размер адреса, а не размер массива. Таким образом, когда вы вызываете 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. Так как каждая вершина-нормальная-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

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

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

Ответ 4

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

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