You are on page 1of 60

Go With The Flow: Fluid and

Particle Physics in PixelJunk


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


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&'( 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


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


of characters, items, etc.

Fluid flow editing, flow simulation execution/cancellation

Topographical design functions based on templates


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

You might also like