After posting my previous question on tile maps, i've been tinkering with an implementation i'm rather pleased with so far but would like to gather some more information about submitting geometry to be rendered by OpenGL.

A little background information:

I've set up a tile map which renders "volumes" in a layered manner very much like Minecraft's implementation using voxels (note; i'm not creating another bloody minecraft clone!) but with a twist in that any "volume" can be extruded along the Y-axis to create variably sized tiles. This all works fine and for the purposes of my tile map, is exactly what I set out to achieve.

My question:

My current confusion lies within the realms of how the vertex data is submitted to be rendered. I'm conscious that when two volumes are rendered in a single tile (think of them as layers; rock on the bottom, mud or water on top), the bottom volume is not actually visible unless there are no neighbouring tiles. To this end, is there any point in submitting the vertices for an object that may not be visible?

Consider two cuboids side by side. From any angle, you can only ever see 5 faces of each cuboid as the other faces are adjacent. Does OpenGL recognise this and discard them (if glCullFace or another appropriate method is used/enabled?) or do I need to actually determine what is visible and remove redundant vertices myself? Is there any harm in not removing them?

For the purposes of my tile map, I don't imagine that my "world" will ever be large enough to cause issues with rendering speed but I'd would like to optimise this so non-visible volumes are simply not rendered. I've been toying with a few ideas for determining which volumes are visible before adding them to the VBO but was wondering how much leg work OpenGL would do for me. There's no point me trying to solve a problem that doesn't exist and also, would OpenGL be able to calculate this much quicker that my own implementation?

I'd like the tile map to be deformable whereby the top-most volumes can be removed or resized to reveal the volumes below (also, some tiles may be transparent, such as water) so rendering the whole tile map (or at least what is visible on screen) would seem necessary.

I have the implementation down and working so far and it's running at a reasonable speed without any issues. I'm just not sure how much work OpenGL does in the background with regards to rendering and culling vertex data that isn't actually visible due to it being obscured by other objects. Can anyone provide insight into this, or at least point me in the direction of where I can read up on such matters?

1 Answer
1

Vertices: Every triangle you submit to OpenGL must be checked against the view frustum. If you send geometry which is out of view, it still must be transformed (by your vertex shader) to find out that it is out of view. The more vertices in your scene, the more useful it is to cull vertices in your code before sending them to the GPU.

If this is a bottleneck for you, then (since you are using a tiled scene) you should break up your scene into chunks of several tiles, each of which is a separate VBO, and skip glDraw...ing them if they are outside the view frustum.

You asked: “is there any point in submitting the vertices for an object that may not be visible?” You should only do so if you find it is more expensive to do a test for whether they are visible than it is for the GPU to do so, or if they are (usefully) bundled together in a VBO that it would be inefficient to be adjusting all the time for new visibility.

Faces: You should remove the redundant faces that face toward each other; OpenGL doesn't know you're not going to be doing transparency in your shader, for example, and will fully process all of them. Keeping these redundant faces will waste both vertex and fragment processing capacity.

glCullFace is only relevant to removing the back-sides of triangles; it does nothing for obscured front sides and still requires the vertices to be checked, but it does allow skipping the fragment stage for that face.

Fragments: After the GPU has decided a triangle needs to be drawn, every pixel (fragment) in it needs to be processed individually (for texturing and other effects). At this point, the best you can do is order your data so that nearer-to-the-camera geometry is rendered first (e.g. render the mud before the rock), allowing the depth buffer test to skip full fragment processing.

It is worth noting that one of the easiest ways to bog down a GPU (due to insufficient fill rate) is to have many large triangles covering large areas of the screen; this could happen, for example, if the player zooms in on a complex multi-layered tile and you're either doing transparency or unnecessarily rendering obscured layers.