game
physics
2012
dbalster@gmail.com
B E E R E N G I N E
agenda
required mathematics
vectors and scalars
projection of vector u on line v
v
u
projv(u)
vector projection
projv(u) = (u dot v / v dot v) * v
reflection of vector u on v
u
u'
v
n
vector reflection
n = constructed from v
reflect(u,n) = u – 2 ∗ n dot u ∗ n
vector identities
for vectors u, v and w
+ = add, ∙ = scalar mul, ⊙ = dot, ⊗ = cross
can be used to speed up operations
matrices
euler angles and rotations
quaternions
quaterion operations
mathematical stuff needed
let's start with physics
we have to remember/learn some important laws of physics
some units first
newton's laws of motion
movement
p1
p2
velocity
p1
p2
acceleration
mass
(linear) momentum
German!
force
still simple
let's handle time
simulation
simulating time
double dt = 1.0 / 60.0;
while (true)
{
simulate( dt );
render();
}
double t = 0.0;
void simulate( double dt )
{
t += dt; // accumulate time
if ( t >= 1.0 ) // each second
{
t = 0.0;
}
// full rotation in one second
rotation = sin( t * 2PI );
}
double t = 0.0;
void simulate( double dt )
{
t += dt; // accumulate time
if ( t >= 1.0 ) // each second
{
t -= 1.0; // !!
}
// full rotation in one second
rotation = sin( t * 2PI );
}
double dt = 1.0 / 60.0;
while (true)
{
simulate( dt ); (1)
render(); (2)
}
double last = now();
while (true)
{
double time = now();
double dt = time - last;
simulate( dt );
render();
last = time;
}
double last = now();
while (true)
{
double time = now();
double dt = time - last;
dt = clamp(dt, 0, 1/60);
simulate( dt );
render();
last = time;
}
simulation
double t = 0.0;
double rate = 1.0 / 10.0; // items per second;
void simulate( double dt )
{
t += dt; // accumulate time
while ( t >= 0 )
{
t -= rate;
spawn_item(...);
}
...
}
fixed / dynamic time steps
let's simulate physics!
// F=ma , dv/dt = a = F/m , dx/dt = v
t = 0
dt = 1 / 60
velocity = 0
position = 0
force = 10 // exact values doesn't really matter here
mass = 1
while ( t <= 10 ) // simulate for 10 seconds
{
position += velocity * dt
velocity += (force/mass) * dt
t += dt
}
print( simulated position after 10 seconds )
what did we just do?
Problems:
some numerical integrators
We need a method that
ordinary differential equations
= F(t,X), t is time X(0) = X0 is state at time 0
"dt" on both sides
=> dX = F( t,X(t) )
rewrite dX as difference quotient
=> ( X(t+h) - X(t) ) / h = F( t,X(t) )
move stuff to right
=> X(t+h) = X(t) + h F( t,X(t) )
this is how we're going to solve it numerically
dX
dt
Runge-Kutta 4th order method
t0, X0 is initial time and state(-vector)
h is our step size
a = h F(t0,X0)
b = h F(t0+½h,X0+½a)
c = h F(t0+½h,X0+½b)
d = h F(t0+h, X0+c)
X1 = X0 + 1/6(a+2(b+c)+d) , t1 = t0 + h
Runge-Kutta 4th order method
xn+1 = xn + h/6 (a+2b+2c+d)
a = f( tn , xn )
b = f( tn + h/2 , xn + h/2 * a )
c = f( tn + h/2 , xn + h/2 * b )
d = f( tn + h , xn + h * c )
...and this is easy to implement for your f(t,X)
Verlet integration method
xi+1 = 2xi - xi-1 + a * dt2
xi is your position, a is acceleration, dt is timestep
solve this problem
A car stands still and starts to accelerate with a m/s2 for n seconds. Where is the car after this time?
euler method
// euler integration
float euler( float dt, float acceleration, float seconds )
{
float velocity = 0.0f; // m/s
float x = 0.0f; // m
for (float t=0; t<seconds; t+=dt)
{
x += velocity * dt;
velocity += acceleration * dt;
}
return x;
}
printf( "%f\n", euler( 0.1, 10.0, 10.0 ) );
verlet method
// verlet integration
void verlet( float dt, float acceleration, float seconds )
{
float x = 0.0f; // m
float previous = x;
for (float t=0; t<seconds; t+=dt)
{
float saved = x;
x = 2*x - previous + acceleration * dt*dt;
previous = saved;
}
return x;
}
printf( "%f\n", verlet( 0.1, 10.0, 10.0 ) );
runge kutta method (1)
void rungekutta(float dt, float acceleration, float seconds)
{
Vector X; // abusing Vector as state vector
X.x = 0.0f; // position in m
X.y = 0.0f; // velocity in m/s
Function f(acceleration); // later explained
for (float t=0; t<seconds; t+=dt)
{
X = rungekutta4(t, X, dt, f);
}
printf("p=%f, v=%f\n",X.x,X.y);
}
runge kutta method (2)
// looks like math in C++
// "Vector" has all required properties
Vector rungekutta4(float t, Vector X, float h, Function& f)
{
Vector a,b,c,d;
float h2 = h/2.0f;
a = f( t ,X );
b = f( t+h2 ,X + a*h2 );
c = f( t+h2 ,X + b*h2 );
d = f( t+h ,X + c*h );
return X + (a+(b+c)*2+d)*(h/6.0f);
}
runge kutta method (3)
// C++ supports "function objects"
struct Function
{
float acceleration;
Function(float _acceleration) : acceleration(_acceleration)
{
}
Vector operator()( float dt, const Vector& X )
{
return Vector(
X.y, // derivation of position is velocity
acceleration // derivation of velocity is acceleration
);
}
};
using numerical solvers
for (int i=0; i<numsteps; ++i)
{
apply forces, impulses, ...
check constraints/collisions and take action
integrate / solve ODE
}
Constraints
Constraint: hinge
hooke's law ("springs")
F = -kx
x displacement of spring in equilibrium (m)
k spring rate constant (N/m)
spring constraint
simple collision handling
Recall
what are we doing
current list of tools
Let's do it!
~ live demo ~
sphere collision: reflection
contact
contact surface
opposing contact surface normals
sphere collision: handling velocities with vector projection
original velocities
projected velocities
sphere collision: handling velocities with vector projection
original velocities
projected velocities
new velocities
summary of live demo
advanced collision detection
sphere, aabb, obb, capsule, ...
collision detection workflow
collision detection problems
continuous collision detection
large time step / high velocity
static
static
no collision during steps
collision during steps
bounding volumes
bounding sphere
calculate bounding sphere
sphere: trivial operations
sphere vs ray
hit on |VC| < radius !
center
origin
V
R1
R2
VR
VC
contact point between two spheres
n = c1-c2
p = (c1 + r1n + c2-r2n) * 0.5
c1
c2
axis-aligned bounding boxes AABB
point in AABB
given point P (x,y,z) and AABB A(min,max)
P inside A if
P>A.min and P<A.max
construct AABB
vector min = (flt_max,...)
vector max = (flt_min,...)
for each p in object :
if p.x < min.x : min.x = p.x
if p.y < min.y ...
...
if p.x > max.x : max.x = p.x
...
construct AABB (2)
so AABB reconstruction can be avoided during scenegraph transform
merging two AABBs
vector min = min( a.min, b.min )
vector max = max( a.max, b.max )
vector center = min+(max-min)/2
intersection of two AABB
min1
min1
min2
min2
max2
max1
max2
max1
intersection of two AABB (2)
bool aabb3_intersects( ABB3 a, AABB3 b )
{
var r[3];
r[0] = a.r[0] + b.r[0];
r[1] = a.r[1] + b.r[1];
r[2] = a.r[2] + b.r[2];
return
((a.c[0]-b.c[0] + r[0]) < 2*r[0]) &&
((a.c[1]-b.c[1] + r[1]) < 2*r[1]) &&
((a.c[2]-b.c[2] + r[2]) < 2*r[2]);
}
oriented bounding boxes
OBB
intersection of two OBB
a on p
b on p
c on p
c
a
a
plane p
project box onto a plane and make 1D check
capsules
r
calculate capsules
capsule-capsule collision
r1
r2
déjà-vu
time step problem
r1
r2
collision detection
bounding volume hierarchies (BVH)
collision detection process
compound bounding volumes
rigid bodies
adding mass and rotation
rigid body dynamics
difference particle and rigid body
mass, density, volume
F = ma <=> m = F/a
1kg = 1 N/m/s2
weight ≠ mass !
density = mass per volume
density: δ = dm/dv <=>
dm = δ dv => mass = ∫dm = ∫δ dv
numerical method for finding mass
m1
m3
m2
m4
F1
F3
F2
F4
(length of force vectors is acceleration)
system of masses
m = Σi=1..∞ mi = m1+m2+m3...
Newton's 2nd law: F=ma <=> m=F/a
Σi=1..∞ mi = Σi=1..∞Fi/ai
velocity and acceleration
velocity (v) is
1st derivative of position over time in m/s
acceleration (a) is
1st derivative of velocity over time
2nd derivative of position over time over time in m/s2�
center of mass / barycenter
finding center of mass
applying force to a rigid body
if you apply a force to a point of the body, which is incident to the center of mass:
=> so far we dealt only with linear motion
linear and angular motion
angular velocity
w(t) is called angular velocity
w
P
Origin
w x r
r
angular acceleration
a(t) = dw(t) / dt
situation so far
center of mass
angular velocity
linear velocity
rigid body simulation skeleton
integration
integrate angular position (1)
"angular position += angular velocity * dt"
derivative of dq(t)/dt (quaternions)
dq(t)/dt = 0.5 w(t) q(t) where
w(t) is angular velocity as quaternion (over time
q(t) is our current (t) rotation as quaternion
we could call this "spin"
integrate angular position (2)
q' = 0.5 w * q * dt
We skipped a lot (!) of math, proofs and background, but the result is obviously easy to implement!
(Note: w should be normalized after this)
integrate angular velocity (1)
"angular velocity += angular acceleration * dt"
angular acceleration a:
a = dw(t)/dt (first derivative of ang. velocity)
= d2q(t)/dt2 (second derivative or rotation)
...but following this path will get more and more complex (no explanation here).
angular acceleration (2) in R3
Newton's second law (the one about inertia)
F = ma (for linear motion), where
F=force, m=mass, a=lin. acceleration
L = I w (for angular motion), where
L = angular moment, I = inertia, w=ang. velocity. Another equation says
torque = I α, where α is ang. acceleration.
mass properties of a rigid body
moment of inertia tensor
calculating moment of inertia
| Ixx | Ixy | Ixz |
I = | Ixy | Iyy | Iyz |
| Ixz | Iyz | Izz |
Ixx = Σk=1..N mk(yk2 + zk2) | Ixy = -Σk=1..N mkxkyk |
Iyy = Σk=1..N mk(xk2 + zk2) | Ixz = -Σk=1..N mkxkzk |
Izz = Σk=1..N mk(xk2 + yk2) | Iyz = -Σk=1..N mkykzk |
changing rotation
Rotation won't change unless changed.
(Newton's 1st law, the one about inertia)
It only changes, if we apply an impulse to it (through collision response)!
Applying an impulse to the system
center of mass r
linear velocity v
ang. velocity w
Impulse J
contact c
body has mass m and moment of inertia I
impulse: position
So, we have a mass m and a force J
=> velocity += J / m (F=ma !)
impulse: rotation
(this is 2D, correct axis is screen z)
r
J
J ⊗ r
impulse: rotation (2)
w = angular velocity
new w = old w + (r ⊗ J) * I-1
summary
what have we learned
what's still missing
and much much more... have fun learning!
I hope you enjoyed it.