I agree with the advice that you should group the triangles by "material" or texture and render them in buckets. When it comes to VBOs, you can consider the VBO to be rendering a single bucket. There is a possible optimization you could do with VBOs.
Instead of having the vertices, textures, normals and indices in VBOs for each bucket, you can have 1 set of VBOs store all of the vertex attributes for the model (vertices, normals, etc) and then have 1 element array VBO per bucket that has indices for just a single group.
That way you can bind the vertex attributes, and then iterate through a number of glDrawElement calls and bind each index VBO as needed. A further improvement would be to have a single index VBO, but sorted by texture, and then use the byte offset parameter to set the offset into the index VBO when rendering. Then you would still only do one VBO bind for indices, too.
Pseudo code might look like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| FloatBuffer vertices = readVertices(...); FloatBuffer normals = readNormals(...); FloatBuffer texCoods = readTextureCoords(...);
List<Triangle> tris = readTriangles(...); sortByMaterial(tris); IntBuffer indices = convertToIndices(tris); List<OffsetAndLength> groups = findGroups(tris);
glBindBuffer(GL_ARRAY_BUFFER, vertexVBOId); glEnableClientState(GL_VERTEX_POINTER); glVertexPointer(...); glBindBuffer(GL_ARRAY_BUFFER, normalVBOId); glEnableClientState(GL_NORMAL_POINTER); glNormalPointer(...); glBindBuffer(GL_ARRAY_BUFFER, textureVBOId); glEnableClientState(GL_TEXTURE_COORD_POINTER); glTexCoordPointer(...);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indicesVBOId); for (OffsetAndLength g: groups) { glDrawElement(GL_TRIANGLES, 0, g.length, GL_UNSIGNED_INT, g.offset * 4); }
|