The RenderQueue and the rendering process

The rendering queue

When I started the FlExtEngine, it was clear that I didn't want to bring the patched RenderGraph from OctoPort into it. Redesigning the RenderGraph, I thought about moving to a simple RenderQueue, storing all visible Renderables in a list. It had some advantages since I was considering having culling threads running in parallel, but it also lacked the auto-sorted aspect of the RenderGraph.

The FlExtEngine's RenderQueue is somewhat similar to the RenderGraph of OctoPort. Like it, it has a list a Steps, which themselves have children. The difference lie in the fact that children of the Steps are couples of Effect and Renderable, instead of Effects which had Renderable children. Keeping the Steps guarantee ordered rendering, such as filling shadow maps before using them, or updating some procedural textures.

Since a Renderable can be linked with more than a single Effect, it is preferable to store the Effect which will be applied on the Renderable in the Step, rather than look it up later, hence storing a pairing of Effect and Renderable, instead of a lonely Renderable. The issue with OctoPort's RenderGraph about the depth first pass, is easily solved by separating the data structure from the algorithm, allowing the engine to perform different operations on the same RenderingStep. Since it's what the Visitor Pattern is meant for, it is used here.

The RenderingPass (Visitor) does visit the RenderingStep it wants to process. The RenderingSteps used in OctoPort, and which will likely also end up in the FlExtEngine are : pre-processing, reflection and refraction, opaque, transparency, post-processing, and final. The planned RenderingPasses in FlExtEngine are: pre-process, reflection and refraction, depth first, opaque, transparent, post-process and final.

Since the RenderingQueue has a local store, it can be turned into a thread, and more than one of them may run in parallel. Being work in progress, I've not yet defined how and when those culling could be run in parallel, but with some Effects requesting rendering (such as an Effect rendering to a reflection cubemap, or a shadow map), an option would be to have a special function in the Effect interface asking for culling.

The rendering process

The RenderingProcess is the entry point of the rendering system. Its implementation is simple enough to allow for modifications, such as making it a deferred renderer. When a rendering request is received, the culling method of the SpatialGraph is called, with the provided Culler, which fills the RenderQueue with the visible Renderables.

Upon adding a Renderable to the RenderingQueue, all the Effects of the Renderable's Meta-Effect are looped over and registered to the appropriate RenderingStep. At the end of the culling process, the RenderingQueue contains only visible Renderables in its list of RenderingSteps.

After culling, the RenderingProcess will tell the RenderingPasses to visit the RenderingQueue. The opaque RenderingPass, for example, does sort the Renderables of the opaque RenderingStep by Effect. The transparent RenderingPass does sort the Renderables by depth (distance from the camera), from furthest away to closest (back to front depth sorting), and the depth-first RenderingPass does visit the opaque RenderingStep, and render the Renderables from the closest to the furthest away from the camera.