iPhone Cheetah 3D OpenGL ES Пример вершинного буфера (VBO) - PullRequest
4 голосов
/ 18 марта 2012

Я хотел бы использовать Vertex Buffer Objects (VBOs), чтобы улучшить мой рендеринг довольно сложных моделей в моей игре Open GL ES 1.1 для iPhone. После прочтения нескольких постов по SO и этому (http://playcontrol.net/ewing/jibberjabber/opengl_vertex_buffer_object.html) учебнику) у меня все еще возникают проблемы с пониманием VBO и с тем, как их реализовать, учитывая мой формат экспортной модели Cheetah 3D. Может кто-нибудь дать мне пример реализации 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 Ответ

3 голосов
/ 19 марта 2012

Ну, во-первых, ваш буфер индексов слишком мал, у вас есть не просто 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, если вы не знаете об этих ошибках.

...