Difference between revisions of "Draw Refactoring Notes"

From PioneerWiki
Jump to: navigation, search
m
 
(4 intermediate revisions by the same user not shown)
Line 12: Line 12:
 
Theory:
 
Theory:
  
# Do a collection pass and collect all objects to "bins" or "buckets"
+
# Do a collection pass, frustum cull and collect all objects to "bins" or "buckets"
 
# Depth write on, depth testing on. Sort and draw opaque objects, preferably front to back
 
# Depth write on, depth testing on. Sort and draw opaque objects, preferably front to back
 
# Depth write off, depth testing on. Sort and draw transparent objects, back to front
 
# 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 (question: why not turn off depth write instead?). If this is still necessary to do, object drawing needs to be separated into two phases (after Background is drawn):
+
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):
  
 
# Draw far objects: planets and their rings, stars. Depth will be cleared during this.
 
# Draw far objects: planets and their rings, stars. Depth will be cleared during this.
Line 24: Line 24:
  
 
  void Body::Render(Camera* camera, ...) {
 
  void Body::Render(Camera* camera, ...) {
    //calculate transformations etc.
 
 
     //instead of immediate drawing, add Graphic objects to be drawn later
 
     //instead of immediate drawing, add Graphic objects to be drawn later
 +
    //calculate transformations here
 
     camera->opaqueBucket.Add(Graphic(...))
 
     camera->opaqueBucket.Add(Graphic(...))
 
     camera->transBucket.Add(Graphic(...))
 
     camera->transBucket.Add(Graphic(...))
Line 47: Line 47:
 
=== Batching ===
 
=== Batching ===
  
To reduce the number of glDraw* calls, simple objects (thrusters, effect quads) can be batched into a temporary vertex buffer (check identical materials again), and then drawn at once. Note thrusters, lasers are additively blended and do not have to be individually sorted.
+
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).

Latest revision as of 22:50, 13 April 2013

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).