Building a Dynamic Lighting Engine for Velvet Assassin
Building a Dynamic Lighting Engine for Velvet Assassin Christian Schüler
Velvet Assassin 3 rd person stealth game > Formerly known as “Sabotage 1943” > First concepts: late 2000 > Release: April 2009 > Platforms PC, X 360 > My role: tech. dir. plus lead engine programmer
Engine Goals > Must look great! > > Everything is dynamically lit > > (of course) Cannot use Lightmaps Lighting is part of gameplay If it looks dark, the player should be hidden! > Light sources become game entites. >
Engine Goals? So, what about. . . > … scene visibility > … light influence > … indirect lighting (like radiosity) … if every object can possibly move, even light sources?
First Engine (2003)
Axioms (2003) World is a loose octree of objects > Objects are OBB trees of triangles > Multi-pass lighting with stencil shadows > Occlusion culling for visibility > Indirect illumination via bounce lights >
Shipping Engine (2009)
Axioms (2009) World is a loose octree of objects > Objects are OBB trees of triangles > Hybrid single/multi-pass lighting with shadow maps > Portals for visibility > Indirect illumination via bounce lights > + XBox 360 specific optimizations
Loose Octrees Thatcher Ulrich (2001): > Cells are overlapping (loose) > Insertion is efficient > No need to rebuild the whole octree if an element moves! Perfect as spatial index of a dynamic scene!
Loose Octrees contd. Extended volume Base cell
Loose Octrees contd. Object inserted if inside extended volume O(1) insertion
Loose Octrees contd. Used in finding out Objects in a view frustum > Objects influenced by a light > Lights influencing an object > Broad phase for ray tests > Gameplay objects in range > And everything can be dynamic!
OBB Trees Oriented Bounding Box Tree S. Gottschalk et al (1995) Used on the polygon level > Build as a pre-process over mesh data > Allows efficient ray-mesh and mesh-mesh interference tests >
OBB Trees contd. Axis aligned … … vs oriented!
OBB Trees contd. Construction: • Principal axes (gaussian point distribution)* • Minimize Box volume (possibly iterative) *eigenvectors of covariance matrix
Hybrid Lighting A hybrid between multi-pass and single-pass forward renderer: > One pass for each primary light > One pass for all secondary lights combined
Hybrid Lighting contd. Primary lights Classic multi-pass (Doom 3 style) > One pass per primary light > Can cast shadows > The light queries for surrounding geometry >
Hybrid Lighting contd. Secondary lights Classic single-pass (HL 2 style) > Lights collected into one pass > > (shader variation based on count) Can not cast shadows > The geometry queries for surrounding lights > > (up to a maximum amount)
Hybrid Lighting contd. secondary points primary spot
Hybrid Lighting contd. primary directional secondary points
Bounce Light Gives appearance of first bounce indirect light from a surface. N axis L (N • L) · f(axis • L) Must not illuminate the surface it is placed on. Has a half-sphere influence radius determined by axis.
Bounce Light contd. primary spot secondary bounce
Bounce Light contd. 2 secondary ambients primary spot
Bounce Light contd. . and even back in 2003 (it‘s not rocket science)
So, for each frame … 1. 2. 3. Get all primary lights in view Distribute shadow map pool Render shadow maps, for each: > > > Get all objects in view Render base pass > > Render all objects contained in light frustum For each object, collect nearest N secondary lights (sorted by importance) for the shader Render additive passes for each … > … primary light: for each object that is in the view and also in the light frustum. That is why you need an efficient spatial index data structure.
Fog Zones A. k. a. : There has to be at least one benefit for manual portalization! Here it is: Fog Zones!
Fog Zones contd. portal separates fog environments
Fog Zones contd. … from the other side
Fog Zones contd. Multiply-Add is your friend! (instead of lerping against a constant fog color) C = C 0 ∙ T + S C 0 T S original color fog transmittance fog in-scatter = (1−T) ∙ CFog traditionally
Fog Zones contd. C = ( C 0 ∙ TB + S B ) ∙ TA + S A A B portal C = C 0 ∙ ( TB ∙ TA ) + ( S B ∙ TA + S A )
Fog Zones contd. > Modify T and S of the new environment with T and S from the portal polygon > Calculate fog from the distance of the portal > Repeat recusively
Fill Optimization > Only done for XBox 360 > Selected particle effects rendered into off-screen render target at half resolution to save fill rate > > (against half resolution depth buffer) Composited over the final image
Fill Optimization contd.
Fill Optimization contd. Again, multiply-add solves the math (in the form of pre-multiplied alpha) Off-screen target: CTarget’ = (1−AParticle) · CTarget + CParticle ATarget’ = (1−AParticle) · ATarget + AParticle Compositing: CFrame’ = (1−ATarget) · CFrame + CTarget
Multi-threading XBox 360 needed it; a dual-core PC at least benefits > First thread performs all spatial queries and compiles a “drawlist” > Second thread sets shader registers, render states and submits batches > Most scenes from 300 to 1200 batches/frame >
The End Questions?
- Slides: 37