Need help with my BSP rendering function

Started by
2 comments, last by moNoKnoT 12 years, 8 months ago
Hi. I am switching from intermediate rendering to vertex arrays. Here is my rendering function:



// Render the mesh
void WLD::render(GLuint* textures, long curRegion, CFrustum cfrustum)
{

int lastTexIndex = 0;
int num = 0;

// Set up rendering states
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

// Set up my indices
GLuint indices[3];

// Cycle through the PVS
while(num < regions[curRegion].visibility.size())
{
int i = regions[curRegion].visibility[num];

// Make sure the region is not "dead"
if(!regions.dead && regions.meshptr != NULL)
{
// Check to see if the mesh is in the frustum
if(cfrustum.BoxInFrustum(regions.meshptr->min[0], regions.meshptr->min[2], regions.meshptr->min[1], regions.meshptr->max[0], regions.meshptr->max[2], regions.meshptr->max[1]))
{
// Cycle through every polygon in the mesh and render it
for(int j = 0; j < regions.meshptr->polygonCount; j++)
{
// Assign the index for the polygon to the index in the huge vertex array
// This I think, is redundant
indices[0] = regions.meshptr->poly[j].vertIndex[0];
indices[1] = regions.meshptr->poly[j].vertIndex[1];
indices[2] = regions.meshptr->poly[j].vertIndex[2];

// Enable texturing and bind the appropriate texture
if(regions.meshptr->poly[j].tex != lastTexIndex)
{
glBindTexture(GL_TEXTURE_2D, textures[regions.meshptr->poly[j].tex]);
lastTexIndex = regions.meshptr->poly[j].tex;
}

glVertexPointer(3, GL_FLOAT, sizeof(Vertex), &vertices[0].x);

glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vertices[0].u);

// Draw
glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, indices);

}
}
}
num++;
}

// End of rendering - disable states
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}



I know it doesn't make sense to render each triangle one by one. It defeats the purpose. But I am having trouble getting this all to work together.

Each zone file is broken into regions which are linked to meshes. Those meshes have polygons, not share with other meshes. Those polygons have a texture integer which is reference to the loaded textures and then 3 indices which are the index into the vertex array. The vertex array contains all the vertices in the zone.

Here is a basic diagram region->mesh->poly array->3 pointers to the index in the vertex array.

So I am trying to figure out a better way to do this. Would it make sense to use the[font="arial, helvetica, sans-serif"][size=2] glDrawRangeElements. The only hang up is that I am not sure what my indices should be. I could use the first polygons index in the vertex array as the start and then the last index from the last polygon as the end. Not sure what I use for the indices though. Also, how do I manage multiple textures. I can't use a texture map, and if I can continue to just bind the texture, that would be best.[/font]
[font="arial, helvetica, sans-serif"]
[/font]
[font="arial, helvetica, sans-serif"]Here is the vertex struct by the way:[/font]
[font=arial, helvetica, sans-serif][size=2][/font][font="arial, helvetica, sans-serif"]
struct Vertex
{
float x, y, z; // The x, y and z floating point values
float u, v; // The u - v texture coordinates
float padding[3]; // needs to be multiple of 32
};

[/font]
[font="arial, helvetica, sans-serif"]
[/font]
[font="arial, helvetica, sans-serif"]Please let me know if I need to be more clear and I am sorry if I have done something wrong. I have no formal training in this.[/font]
Advertisement
You should sort the triangles of each mesh by the material ID when building the BSP-tree, so that you can loop over all "materials"/textures in a mesh, bind the texture, and render all triangles which use that texture in one batch. The vertex array should only be bound once for each region.
If you are using 32-bit indices it might be beneficial to merge all the vertex data of all regions together into one vertex array or, yet even better, one big VBO. If that is impossible try to go with 16-bit indices.

That should reduce the number of OpenGL (draw) calls. However, I believe the number of draw calls necessary to render a BSP map is one of the reasons why BSP trees have fallen out of favor lately. The leafs are just way too small.

You should sort the triangles of each mesh by the material ID when building the BSP-tree, so that you can loop over all "materials"/textures in a mesh, bind the texture, and render all triangles which use that texture in one batch. The vertex array should only be bound once for each region.
If you are using 32-bit indices it might be beneficial to merge all the vertex data of all regions together into one vertex array or, yet even better, one big VBO. If that is impossible try to go with 16-bit indices.

That should reduce the number of OpenGL (draw) calls. However, I believe the number of draw calls necessary to render a BSP map is one of the reasons why BSP trees have fallen out of favor lately. The leafs are just way too small.


Thank you for the reply. When we are talking about indices, are we talking about the polygon references to the vertices. For example, polygon 1 of mesh 1 references vertices 0, 3 and 9. Are those the indices?

Also, which drawing call should I use? Drawing range or draw elements or something else I haven't listed?

Thank you for the reply. When we are talking about indices, are we talking about the polygon references to the vertices. For example, polygon 1 of mesh 1 references vertices 0, 3 and 9. Are those the indices?

Also, which drawing call should I use? Drawing range or draw elements or something else I haven't listed?


You can actually load the vertex lump straight in, bind it and render everything with very little effort. I think you may have overcomplecated the issue in the way you've organised your vertex data.

Load in the vertex lump and dump it to a vbo (process endian's etc once you have it all working), after this you start rendering with this...


glBindBuffer(GL_ARRAY_BUFFER_ARB, uVBO);
glVertexPointer(3, GL_FLOAT, sizeof(BSP46_VERTEX), BUFFER_OFFSET(0));


Then loop through visble surfaces list and render each surface in turn like this...


switch (pSurface->uType)
{
case BSP46_SURF_TYPE_TRIANGLE_INDEX:
glDrawElements(GL_TRIANGLES, pSurface->uIndices, GL_UNSIGNED_INT, &pBsp46->pIndicies[pSurface->uFirstIndex]);
break;
case BSP46_SURF_TYPE_PATCH:
glDrawArrays(GL_TRIANGLES, pSurface->uFirstVertex, pSurface->uVertices);
break;
case BSP46_SURF_TYPE_FLARE:
break;
default:
glDrawArrays(GL_TRIANGLE_FAN, pSurface->uFirstVertex, pSurface->uVertices);
break;
}


I change the values in the indicies array to be able to render them like this, I also store pre-processed beizer patch vertex data in same vbo but you should get an idea from the above...

- Kevin.
http://www.kevin-fell.co.uk

This topic is closed to new replies.

Advertisement