Draw Refactoring Notes

From PioneerWiki
Jump to: navigation, search

The main goal is the correct drawing of transparent objects. This is also a nice chance to get rid of the fixed function matrix stack operations.

Transparent objects include:

  • ship thrusters
  • light billboards
  • lasers
  • shield effects
  • glass cockpits
  • planet rings
  • star halos

Theory:

  1. Do a collection pass, frustum cull and collect all objects to "bins" or "buckets"
  2. Depth write on, depth testing on. Sort and draw opaque objects, preferably front to back
  3. Depth write off, depth testing on. Sort and draw transparent objects, back to front

Step 2 will not work, since bodies are currently drawn back to front. After drawing distant planets, or when shaders are off, the depth buffer is cleared. If this is still necessary to do, object drawing needs to be separated into two phases (after Background is drawn):

  1. Draw far objects: planets and their rings, stars. Depth will be cleared during this.
  2. Draw closer objects: cities, ships, lasers

Pass camera to all renderable objects:

void Body::Render(Camera* camera, ...) {
   //instead of immediate drawing, add Graphic objects to be drawn later
   //calculate transformations here
   camera->opaqueBucket.Add(Graphic(...))
   camera->transBucket.Add(Graphic(...))
}

Notes for optimization

A smarter structure will also allow for some optimizations - someday.

State sorting

Objects can be sorted by material or material properties. When everything uses Materials the Renderer will avoid some state switches by comparing material pointers. Example: thrusters all use the same material.

Early Z

In theory, depth testing can be done as soon as a vertex shader finishes. This can avoid running costly fragment shaders for invisible fragments. However Pioneer cannot benefit from this since all fragment shaders calculate a custom depth - the shader needs to be fully run before the final depth is known. It's not too bad, since we don't have that much overdraw - mostly the player is seeing black space.

In any case, the problem can be worked around with a Z prepass - render all objects using a shader that only does the depth calculation, then turn depth write off and draw the objects again with the usual fragment shader (but without gl_FragDepth).

We might see the benefit in cities with many, complex buildings.

Batching

To reduce the number of glDraw* calls, simple objects (thrusters, effect quads) can be copied into temporary vertex buffers (check identical materials again), and then drawn at once. Note thrusters, lasers are additively blended and do not have to be individually sorted.

New notes (2013)

Planets mix opaque and transparent geometry. Since zbuffer is cleared after rendering a faraway planet, the planet's surface, rings and atmosphere need to be rendered in one go.

Models may mix opaque and transparent geometry. Such models need to be therefore drawn twice, with the appropriate node masks used during draw traversal. A special visitor should be used to update the nodemasks to prevent unnecessary traversal as high as possible (matrix transform with transparent children should be marked transparent).