Shooter Jaymin Kessler Q-Games Technology Team jaymin+gdc@q-games.com Shooter overview ! Game designed around mixing of various solids, liquids, and gasses ! Magma meets water, cools, and forms rock ! Ice meets magma and melts ! Magnetic liquid meets water to form a toxic gas, just like in real life ! Lasers melt ice and rock into water and magma ! Other cool effects like explosion chain reactions, and water turbulence Video ( for those who havent played it yet ) Video ( for those who havent played it yet ) Overview SPU based fluid simulation Parallel particle sim algorithms Game design built around mixing of different fluids Universal collision detection mechanism Particle flow rendering Collision detection by distance field Real-time SPU and GPU algorithms Level editing via stage editor Topographical design via templates Particle placement Existing fluid simulation algorithms Smoothed particle hydrodynamics Divide the fluid into particles, where each has a smoothing length Particle properties are smoothed over smoothing length by a kernel function Particles affected by other particles close by SPH formulation derived by spatially discretizing Navier-Stokes equations Used in astrophysics! What we actually used Goal: practical application in-game Ease of implementation Rapid control response Physical accuracy Cater to the strengths of the SPUs No SIGGRAPH framerates Fluid system developed for Shooter 2D particle collision simulation 32,768 particles running @ 60fps on 5 SPUs (could have done way more if needed ;) ) Verlet integration The good 4th order accurate ( Euler is 1st ) Greater stability than Euler Time-reversibility The bad Bad handling of varying time steps Needs 2 steps to start, start conditions are crucial Time-corrected verlet helps The version we used Applied to elemental particle sim location p(t) as a function of time t against velocity v(t) and ext force F(t) For mass m and sim interval !t p(t+!t) = p(t) + v(t)!t + F(t)!t 2 / 2m v(t) = ( p(t) p(t!t) ) / !t 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 5 Elemental Particle Simulation
A simple Verlet integration is applied to produce an
elemental particle physics simulation Particle location !(") is expressed as a Iunction oI time " , against velocity #(") and external Iorce $(") Particle mass % Simulation interval !" !("!") !(") #(")!" $(")!" 2 / 2% #(") ( !(") !("!") ) / !" !("!") !(") !("!") $(") #(") #("!") Incompressibility of liquid ! Liquids dont compress or expand to fill volumes, but... ! In our model, mass and gravity can compress lower particles ! Dont worry! We have a fix compression !! Maintaining the incompressibility of liquid ! Must maintain constant distance between particles ! Particles have an adjustable radius bias ! Each frame: ! Calculate the desired radius bias ! Based on max ingression of surrounding particles ! Lerp from current bias to desired bias ! Two different rates for expanding and contracting ! Contraction ~4x faster than expansion Maintaining the incompressibility of liquid Taken Irom an actual simulation !"#$% #$'( )*+",-(- #$'( Keeping particles apart Add repulsive force in the space between colliding particles Force of repulsion proportional to the number of colliding particles Increasing number of particles creates fluid-like behavior Keeping particles apart Simple-ish computation model All particles perfectly spherical, but with varying radius size Helped with ease of implementation Force oI repulsion Not all particles created equal ! Different particle combinations have different force of repulsion values ! Different chemical reactions simulated when fluids mix ! Different mass ! Some have rigid bodies, others dont ! Particle types propagate heat differently ! i.e. magma cools to form a rock-like solid Heat propagation ! Each particle carried thermal data ! When particles collide, heat is propagated ! Warmer particle to cooler one ! Same algorithm we use for force of repulsion ! Particle types have different thermal transfer values 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 22 Thermal propagation system for fluids Each particle carries its own thermal data Fluid flow changes with temperature and this is applied in-game When particles collide, heat is propagated Heat is transferred from the warmer particle to the cooler particle Heat transfer is calculated using the same algorithm used for the force of repulsion calculations Set values for thermal transfer for each particle type 20! 80! 40! 60! Thermal propagation 50! 50! Thermal propagation Equilibrium One other (mis)use of the particle system ! In-game collision detection ! Characters, missiles, etc. are surrounded by special dummy particles (interactors) 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 23 A particle flow system based on a simple collision detection device PixelJunk Shooter uses the particle flow system for most of the in-game collision detection Characters, missiles, etc. are surrounded by special dummy particles (interactors) for the purpose of collision detection When a collision is detected with an interactor by the SPU, the PPU is also notified
Merits of this approach
No need to implement a detection process to track each collision Depending on the location of the interactor particle, pretty much any collision can be simply detected and tracked ! Some benefits include ! No need to write lots of different collision detection systems ! Depending on the location of the interactor particle, pretty much any collision can be simply detected and tracked SPURS jobchain (in words) ! Yes, we really used SPURS ! SPU jobchain: 1)Collision detection and repulsive force calc 2)Force unification ( for multi-cell particles ) 3)Particle update ( verlet ) 4)Particle deletion, only 1 SPU used 5)Grid calc for the next frame ! PPU processing: ! Particle generation ! Jobchain building SPURS jobchain (in words) ! Yes, we really used SPURS ! SPU jobchain: 1)Collision detection and repulsive force calc 2)Force unification ( for multi-cell particles ) 3)Particle update ( verlet ) 4)Particle deletion, only 1 SPU used 5)Grid calc for the next frame ! PPU processing: ! Particle generation ! Jobchain building Collision job ! Collision detection between every particle in a cell ! Several cells pooled together to make one job ! Jobs are divided to help with load balancing ! Output ! Particle number ! Force of repulsion Force unification job ! If a particle is processed in more than one cell, we have to unify the results ! Output: Unified force of repulsion, acceleration, and other info by particle number 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 14 !Force of repulsion applied to each particle n the event that one particle straddles more than one cell: There is a need to unify the forces of repulsion in each cell The results for the previous job are unified for each particle number After unification, for acceleration/alignment to be stored in the LS the job has to be defined by the restrictions on LS capacity combined with the scope of particle numbers.
Output: Unified force of repulsion for each particle
Output Ior job11 thru job14 (particle no.; power oI repulsion)} Particle numbers can be duplicated job21 job22 job23 #20000)#29999 #10000)#19999 #0)#9999 *+,-./0123 Update job ! This is the BIG one ( in terms of code size ) ! Particle physics calculations, including verlet integration ! PPU notification of interesting events ! Like abrupt changes in fluid direction, triggering effects ! Output ! Updated particle data ! Particle deletion info ! Various other flags Particle delete job ! Only run on one SPU ! Very few particles deleted, around 10 per frame ! Take valid particles off the end, and overwrite deleted particles as we find them Particle grid division ! Used to parallelize workload ! O((n/k) 2 ) for k!1232 cells, or a 44x28 grid ( better than O(n 2 ) ) ! Multiple cells per job ! But what if a particle is on the border between two cells? Particle grid division ! Particles are processed ( hit test ) with every cell they touch ! In the next phase, we unify all forces acting on a particle ! After merge, the particle belongs to the upper left most cell it touches 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 10 Collision detection algorithms based on grid-splitting
Particles located on the borders of a cell
Particles are processed as part of both cells Particles are recorded as having occupied each cell To prevent two particles being registered to a multiple number of cells, the top left cell will always take precedence . . 0 1 2 0 1 2 (0,0) (1,0) (0,1) (1,1) )* 3 moved to (0,0) SPURS jobchain (in pictures) wait for SPU grid calculations add particles kick jobchain idle time ( fixed in Shooter 2 ) collision detection unify forces verlet update particle deletion grid calculations wait for SPU do other stuff! add particles kick jobchain collision detection idle time ( fixed in Shooter 2 ) PPU SPU SPURS jobchain (in-profiler) ~9000 particles Painfully obvious optimizations ! Heavy use of SoA ! big win even when converting to and from in the same job ! Avoid scalars ( especially multiple writes ) like the plague ! Or dont read/write the same buffer in the same loop ! As branch-free as possible ! Software pipelining and unrolling ! But less LS left for particles ! Favor intrinsics over asm :( ! Dylans inline asm site ! Possible through compiler communication Christers algorithm Is game too slow? move on move something to SPUS yes no Fluid rendering ! Render particles in a vertex array ! Three basic particle types: solid, liquid, and gas ! Each is rendered to a different offscreen buffer ! A vertex array is required for each particle type ! Upper particle limit is approx 30,000 ! three different vertex arrays for three particle types with 30,000 particles each is a waste ! One vertex array can be used for all three types Fluid rendering ! Vertex array built on the SPUs ! 1~5 SPUs used depending on the num particles ! Lists built in LS and DMAd to main memory ! The vertex array is 64 sectors ! Each sector contains one particle type ! Max 512 particles per sector ! Atomic DMA to coordinate shared list updates Fluid rendering ! Grouped particles rendered as a smooth flowing fluid ! Existing example: marching square/cube ! Related particles depicted as a polygon mesh ! The grid has to be fine, or liquid movement isnt smooth ! Currently patented ! Not by us 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 26 Fluid Rendering Grouped particles rendered as a smooth-flowing fluid An existing example: the marching square/cube Once the particle rubicon has been detected as passing into a grid, the related particles are depicted as a polygon mesh fluid The grid has to be very fine, or the liquid movement depicted is not smooth. This has been patented (expired?) Fluid rendering ! Render particles to a low-res offscreen buffer with a luminance texture ! Blur the offscreen buffer ! Scale up with bi-linear filter ! Use the resulting brightness to color the liquid 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 27 mage processing-based rendering Rendering procedures The low-resolution off-screen buffer renders particle images with the center textures lit bright Blur is added at the off-screen buffer Screen resolution is increased with the use of a bi-linear filter Only particles with a brightness value are colored as liquid Low-res oII screen AIter blur added Bi-linear Iilter and step 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 27 mage processing-based rendering Rendering procedures The low-resolution off-screen buffer renders particle images with the center textures lit bright Blur is added at the off-screen buffer Screen resolution is increased with the use of a bi-linear filter Only particles with a brightness value are colored as liquid Low-res oII screen AIter blur added Bi-linear Iilter and step Cohesiveness ! Free falling liquid causes particle distances to increase ! Liquid mass loses cohesiveness ! Opposite problem as compression ! Solution: dont fully clear the buffer ! Image lag effect maintains cohesiveness, even in motion 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 28 Fluid image lag effects When the liquid falls freely The distance between the particles increases and the liquid mass loses cohesiveness
When the liquid is rendered, the off-screen buffer is not
completely cleared, instead it reduces gradually The image lag effect means that even in movement cohesiveness is retained Water surface AA ! When rendering liquid to offscreen buffer, use a smooth step function ! Two thresholds used for water surface and for tinting 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 29 Brushing-up the FIuid Rendering
Detect the water surface, anti-aliasing
When the liquid is rendered on the off-screen buffer, a
smooth step function is used - anti-aliasing
Two different thresholds are used to detect the water
surface and for tinting
Detecting dramatic movement
Detect any sudden changes
in the liquid speed and direction (SPU update job)
Notify the PPU of this event
Triggers foam effects, etc.
SPU update job detects sudden changes in liquid speed and direction, and notifies the PPU to add foam effects Depicting movement ! Create a flow pattern to show movement ! Each particle gets a fixed random UV value [0..1] ! UV value converts to RG value ! Use a different color where RG is 0.5f, 0.5f 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 30 Expressing 'Flow': Visualization of Fluid Motion Flow of regular liquid f nothing flows along with the liquid, then how do we depict movement? Create a flow pattern to show movement Assign each particle with a fixed random UV value This UV value converts to a RG value off screen For the areas where RG=(0.5, 0.5), a different color is used 0.0 to 1.0 in actual 2D values Refraction ! From water and from magma heat ! Ping-pong between offscreen buffers ( tex feedback processing ) ! Degree and direction depends on particles fixed UV Distance field ! How does it work? ! Binary input image ! Walls are white ! Space is black ! Output image ! Wall core is bright ! Wall boundary is 0.5f ! Gets darker as you move away from wall ! 2 distance transforms: static and dynamic ! Sample uses ! Wall collision detection ! Making enlarged fonts look better Distance transform 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 32 Distance field What's a distance field? nput mage (binary image) Walls: white Space: black Output mage (distance field) Wall core: bright Wall boundary: Half-value (0.5) Distant from wall: dark Examples of the distance field in use mproving the appearance of fonts when enlarged Collision detection processing for topography, etc. Using distance transform for wall collision ! Look up characters pos in the distance field ! > 0.5f collision ! "0.5f no collision ! Moving away from a collision ! Get 4 distance field values near collision ! Look at gradient to move away from the wall Using distance transform for wall collision 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 33 Distance field and topographical collision detection Topographical (walls, obstacles) collision detection Obtain the distance field image value ! with respect to the character's position ! ~ 0.5 Wall collision ! 0.5 ! No collision Normal line calculation for the collision location Obtain distance field values from 4 locations near the collision Direction to increase the pixel value (gradient) = approaching the wall hit 0.3 0.6 Normal line Using distance transform for wall collision 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 43 Topographical collision processing and the particle flow system
Collision detection using the distance field
Distance field measures 256256 covering 65,536px
1px = 1 byte value of 64KB which can be stored in the SPU
When detecting a collision with the ground
The force of repulsion is applied in line with the collision
surface, proportional to the collision force
BTW...
Distance field calculations in PixelJunk Eden were only run
offline ! When detecting collision with the ground ! The force of repulsion is applied in line with the collision surface ! Proportional to the collision force Distance transform in-game Distance transform algorithms ! O(n 2 ) Chamfer distance ! Used with Manhattan distance ! 1ms for 256x256 on one SPU ! Also had a 512x512 version ! Dead reckoning ! A little more accurate ! Jump flooding ! Implementable on GPU ! 6ms *GASP* ! Parallel versions exist, but... Chamfer distance algorithm ! Two passes ( forward and back ) ! Propagate distance to closest wall ! Forward pass looks at upper and left neighbors ! Backwards pass looks at lower and right neighbors ! The larger the window, the more accurate ! We went with a 3x3 window Chamfer distance algorithm ( unsigned ) 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 35 Outline of the Chamfer Distance Algorithm (CDA)
Algorithm flow
nitial distance values for all pixels =
nputting 2 value images at the edges sets distance value to 0 (seed)
Distance propagation
Value is the reverse of the outer surface of an object (input black
region)
Signed distance field . distance value code can assist internal/external
nputting 2 value images at the edges sets distance value to 0 (seed)
Distance propagation
Value is the reverse of the outer surface of an object (input black
region)
Signed distance field . distance value code can assist internal/external
detection
0 0 0 2 1 0 1 2 2 1 0 1 2 3 2 1 0 1 0 1 2 0 1 2 0 1 2 1 1 1 )* 2+,- 2 2 3 ./0123 (seed) 4567 Signed distance Iield 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 38 Dead reckoning algorithm CDA: Just distance is propagated Errors accumulate for each propagation step Propagation position zero where distance = 0 is recorded for each cell Propagation window uses 3x3 Euclidean distance When distance is updated, distance is re-calculated from propagation position zero 0 0 1 ! 1 1 ! ! 5 Distance re-calculated 4\2 1 2 3 2 1 1 \2 \2 4\2 )*+,-./0123 Initial state Desired result Jump flooding ! Unlike DRA and CDA*, parallel processing is possible ! Works on GPU ! Log 2 (n) passes ! O(n 2 log 2 (n)) calculation ! Rough idea ! Compute an approximation to the Voronoi diagram of a given set of seeds in a 2D grid Jump flooding in action In every pass, the distance is cut in half. These images show all 8 passes on the GPU Platform comparison ! PS3 ! CDA: 1ms for 256x256 on one SPU ! PC ! Jump flooding: 8 passes required ! 5~6ms was too much time, so we split it up and did 4 passes per frame ! SPU vs GPU ! SPU: more complex processing possible ! GPU: awkward to program, and is already so busy with rendering Editor overview ! Functions ! Wall editing ! Based on templates ! Had procedural generation, but didnt use it ! Placing items, characters, etc ! Turning things on and off ! Wall, rock, fluid, enemies, gimmicks, items, survivors, verlet update, particles ! Fluid editor ! Flow simulation ! Execution/cancellation ! Various debugging visualizations Editor overview 2009/09/02 PixelJunk Shooter!"#$%PLAYSTATION3&'( 44 The Stage Editor
Functions
Regular functions such as topographical editing, location
Topographical design ! Different patterns for different things ! Different sized rocks, walls, ice, snow ! Each stage had unified design concepts ! Designers still have to hand-draw their levels ! One of the reasons it would be hard to release a level editor on PS3 Pattern templates ! Designers create patterns for wall decorations ! The level creator uses the templates to design the walls ! Templates broken into several parts ! Using randomized loops and reverses, joints are automatically made seamless ! Vector format for nice scaling Conclusion ! Fluid simulation system ! 32,768+ fluid particles @ 5SPU, 60FPS ! Heat transmission, constant distance maintenance, etc ! Universal collision detection system ! Real-time distance field ! CDA, 256!256, Manhattan@1SPU, 1ms ! Used for collision detection ! Also abused for ??? in Shooter 2 ! Note to self: if time left over, have that only on PS3 discussion I promised everyone on Twitter