The absolute fastest way to do this is to create render lists and render ALL objects in one function.
However this is not the easiest. But, at least, in Direct3D programming using this method you are guaranteed to only make Device state changes only when absolutely necessary and only when applicable to objects that need the device states changed. Altering device states for every single object is a major hack and a tremendous slow down.
For instance if you have several alpha blended objects and you use the method of a virtual draw....is every alpha blended object going to turn alpha blending on and then off again? If you have even 50 of these objects on screen then that is 100 device state changes for 1 render. Way too many.
Turn alpha blending on, render all alpha blended objects, Turn alpha blending off.
In other words, state changes should NOT be made by the object itself, but by the render function that draws all the objects.
This is not the easiest thing to code, but it is very fast when you get it working right.
You should also only make texture changes when necessary in Direct3D. Set texture, render ALL polies that use that texture, set texture to another texture, render ALL polies that use that texture, etc, etc.
OpenGL is a bit different but using display lists and render lists are not foreign to OpenGL either.
- Decide what objects are in the frustrum and which ones are not - ala quadtree, binary space partition tree, etc.
- Don't worry about those that are partially in and partially out of the frustrum - it takes more time to subdivide these objects or clip them against the frustrum than it does for the video hardware to simply auto-clip them with onboard routines.
- Place all of these objects in a render list, sorted by Z order
- Render all objects in the list.
- Wash, rinse, repeat.