370 likes | 471 Vues
Christian Schüler. Building a Dynamic Lighting Engine for Velvet Assassin. Velvet Assassin. 3rd person stealth game Formerly known as “ Sabotage 1943” First concepts: late 2000 Release: April 2009 Platforms PC, X360 My role: tech. dir. plus lead engine programmer. Engine Goals.
E N D
Christian Schüler Building a Dynamic Lighting Engine for Velvet Assassin
Velvet Assassin • 3rd person stealth game • Formerly known as “Sabotage 1943” • First concepts: late 2000 • Release: April 2009 • Platforms PC, X360 My role: tech. dir. plus lead engine programmer
Engine Goals • Must look great! • (of course) • Everything is dynamically lit • 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?
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
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 (HL2 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. secondarypoints primary spot
Hybrid Lighting contd. primary directional secondarypoints
Bounce Light Gives appearance of first bounce indirect light from a surface. Must not illuminate the surface it is placed on. Has a half-sphere influence radius determined by axis. N L axis (N•L) ·f(axis•L)
Bounce Light contd. primary spot secondarybounce
Bounce Light contd. 2 secondaryambients primaryspot
Bounce Light contd. ... and even back in 2003 (it‘s not rocket science)
So, for each frame … • Get all primary lights in view • Distribute shadow map pool • Render shadow maps, for each: • Render all objects contained in light frustum • Get all objects in view • Render base pass • 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 = C0 ∙ T + S C0 original color T fog transmittance S fog in-scatter = (1−T) ∙ CFog traditionally
Fog Zones contd. C = ( C0 ∙ TB + SB ) ∙ TA + SA A B portal C = C0 ∙ ( TB ∙ TA)+ ( SB ∙ TA + SA)
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. 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?