iPhone Cheetah 3D OpenGL ES Vertex Buffer Object (VBO) пример
Я хотел бы использовать Vertex Buffer Objects (VBO) для улучшения визуализации несколько сложных моделей в моей игре Open GL ES 1.1 для iPhone. Прочитав несколько постов на так и это (http://playcontrol.net/ewing/jibberjabber/opengl_vertex_buffer_object.html) учебник, я все еще испытываю проблемы с пониманием VBO и как их реализовать, учитывая мой формат 3D-модели экспорта Cheetah. Не мог бы кто-нибудь привести мне пример реализации VBO и использования его для рисования моих вершин с заданным структура данных и объяснение синтаксиса? Я очень ценю любую помощь!
#define body_vertexcount 434
#define body_polygoncount 780
// The vertex data is saved in the following format:
// u0,v0,normalx0,normaly0,normalz0,x0,y0,z0
float body_vertex[body_vertexcount][8]={
{0.03333, 0.00000, -0.68652, -0.51763, 0.51063, 0.40972, -0.25028, -1.31418},
{...},
{...}
}
GLushort body_index[body_polygoncount][3]={
{0, 1, 2},
{2, 3, 0}
}
Я написал следующий код с помощью главы 9 из Pro OpenGL ES (Appress). Я получаю EXC_BAD_ACCESS с командой DrawElements, и я не уверен, почему. Не мог бы кто-нибудь пролить немного света? Спасибо -
// First thing we do is create / setup the index buffer
glGenBuffers(1, &bodyIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bodyIBO);
// For constrast, instead of glBufferSubData and glMapBuffer,
// we can directly supply the data in one-shot
glBufferData(GL_ELEMENT_ARRAY_BUFFER, body_polygoncount*sizeof(GLubyte), body_index, GL_STATIC_DRAW);
// Define our data structure
int numXYZElements = 3;
int numNormalElements = 3;
int numTextureCoordElements = 2;
long totalXYZBytes;
long totalNormalBytes;
long totalTexCoordinateBytes;
int numBytesPerVertex;
// Allocate a new buffer
glGenBuffers(1, &bodyVBO);
// Bind the buffer object to use
glBindBuffer(GL_ARRAY_BUFFER, bodyVBO);
// Tally up the size of the data components
numBytesPerVertex = numXYZElements;
numBytesPerVertex += numNormalElements;
numBytesPerVertex += numTextureCoordElements;
numBytesPerVertex *= sizeof(GLfloat);
// Actually allocate memory on the GPU ( Data is static here )
glBufferData(GL_ARRAY_BUFFER, numBytesPerVertex * body_vertexcount, 0, GL_STATIC_DRAW);
// Upload data to the cache ( memory mapping )
GLubyte *vboBuffer = (GLubyte *)glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);
// Caclulate the total number of bytes for each data type
totalXYZBytes = numXYZElements * body_vertexcount * sizeof(GLfloat);
totalNormalBytes = numNormalElements * body_vertexcount * sizeof(GLfloat);
totalTexCoordinateBytes = numTextureCoordElements * body_vertexcount * sizeof(GLfloat);
// Set the total bytes property for the body
self.bodyTotalBytes = totalXYZBytes + totalNormalBytes + totalTexCoordinateBytes;
// Setup the copy of the buffer(s) using memcpy()
memcpy(vboBuffer, body_vertex, self.bodyTotalBytes);
// Perform the actual copy
glUnmapBufferOES(GL_ARRAY_BUFFER);
Вот команды рисования, где я получаю исключение:
// Activate the VBOs to draw
glBindBuffer(GL_ARRAY_BUFFER, bodyVBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bodyIBO);
// Setup drawing
glMatrixMode(GL_MODELVIEW);
glEnable(GL_TEXTURE_2D);
glClientActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,lightGreyInt);
// Setup pointers
glVertexPointer(3, GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 0 );
glTexCoordPointer(2, GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 12 );
glNormalPointer(GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 24 );
// Now draw the body
glDrawElements(GL_TRIANGLES, body_polygoncount,GL_UNSIGNED_SHORT, (GLvoid*)((char*)NULL));
//glDrawElements(GL_TRIANGLES, body_polygoncount, GL_UNSIGNED_SHORT, nil);
//glDrawElements(GL_TRIANGLES,body_polygoncount*3,GL_UNSIGNED_SHORT,body_index);
1 ответ:
Ну, во-первых, ваш буфер индексов слишком мал, у вас есть не только индексы
body_polygoncount
, но иbody_polygoncount * 3
. Вы также испортили тип, так как они шорты, вам нужноGLushort
, а неGLubyte
, поэтому это должно бытьglBufferData(GL_ELEMENT_ARRAY_BUFFER, body_polygoncount*3*sizeof(GLushort), body_index, GL_STATIC_DRAW);
И затем, вы перепутали смещения ваших атрибутов, так как ваши данные содержат сначала координаты текстуры, затем Нормаль, а затем положение для каждой вершины, это должно быть
glVertexPointer(3, GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 20 ); //3rd, after 5*4 byte glTexCoordPointer(2, GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 0 ); //1st glNormalPointer(GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 8 ); //2nd, after 2*4 bytes
И, наконец, в вызове
glDrawElements
вы не даете число треугольников, но число элементов (индексов), поэтому оно должно бытьВ противном случае ваш код выглядит разумным (конечно, отображение было бессмысленным, и вы могли бы просто использоватьglDrawElements(GL_TRIANGLES, body_polygoncount*3, GL_UNSIGNED_SHORT, (GLvoid*)((char*)NULL));
glBufferData
снова, но я думаю, что вы сделали это для обучения), и если вы поняли все, что он делает, больше ничего нет.Но мне интересно, что все эти ошибки также произошли бы, если бы вы просто использовали клиентские массивы вершин без VBO, и я думал, что OpenGL ES 1.1 не имеет немедленного режима
glBegin/glEnd
. Поэтому мне интересно почему ваша игра раньше работала без VBO, если вы не знаете об этих ошибках.