Sie sind auf Seite 1von 74

KRAFT

The design of the KRAFT 3D rigid body physics engine

Who are we

BeRo

urs

What is KRAFT

A engine for real-time 3D physics simulation

Rigid body physics


3D collision detection
Constraints
Continuous collision detection and response
Multithreaded / Parallelized

Object Pascal library

Developed for games

Works on most operating systems and platforms, which is by FreePascal (and Delphi, of
course) supported

Inspired by the design and ideas of and from the open-source Box2D and the closed-source
Rubikon (from Valve) physics engines.
Many thanks to Erin Catto (Box2D) and Dirk Gregorius (Rubikon/Valve)

This talk is NOT about how a general


physics engine is structured and designed.
This talk is about how the KRAFT physics
engine is structured and designed in
contrast to other physics engines.

In other words:
This talk does not describe how a physics
engine works in general
This talk does describe how the KRAFT
physics engine is different.

General structure of KRAFT

Discrete broad phase

Discrete mid phase

Multi-threaded on per rigid-body-pair basis

Discrete narrow phase

Multi-threaded on per rigid-body-pair basis

Multi-threaded on per island basis

Discrete integration (Solver)

Collision response
Constraints

Gyroscope simulation
etc.

Continuous collision detection and response phase

including joints and so on

Single-threaded, because the current CCD time-step-subdividing implementation inside KRAFT must be processed in a serial way

KRAFT has no compound shapes

A rigid body in KRAFT can have multiple shapes without a need for compound shapes or similar constructs,
which would only increase the code complexity

Simpler and smaller code

Anatomy of a physics tick inside KRAFT


Discrete broad phase
When
no
mesh
shapes

Discrete mid phase


Discrete narrow phase
When
CCD is off

Discrete solver
When
CCD is on

Continuous collision detection and response

Anatomy of a physics tick inside KRAFT


Discrete broad phase
When
no
mesh
shapes

Discrete mid phase


Discrete narrow phase
When
CCD is off

Discrete solver
When
CCD is on

Continuous collision detection and response

Broad phase

Find shape pairs for comparison

Dynamic AABB BVH tree based

Make selections quickly


Avoid selecting shapes which cant collide to each other
Inspired by Box2D, but here extended for the usage in 3D
The dynamic AABB BVH tree will only updated when the shape AABB of a rigid body isnt no longer inside the
expanded AABB of a tree node

Node AABB is expanded by

Constant bounds

Current velocity of the owner rigid body of a shape (for dynamic and kinematic rigid bodies, but
not for static rigid bodies)
Performs better than Sweep-and-prune (SAP) based broad phases, Octree based broad phases and simple
grid-based spatial-hashing based broad phases in the most cases for the CPU-side application in 3D worlds

Generates contact pairs for the next mid phase and over-next narrow phase steps

Broad phase

Temporal caching (the best optimization is that you must to do nothing)


New possible contact pairs will be only generated when a contact pair did exist not yet

Contact pairs, these are no longer in contact (expanded-AABB-wise), will destroyed


Realized by a dynamic-sized dirty-queue-buffer (which can only grow on the memory
manager allocation-side, no (or very seldom) shrinks due to performance reasons)
All shapes, which have a new world position and/or world orientation or which are
fresh inserted into the simulated world, are inserted into this one dirty-queue-buffer
The broad phase processes then only these shapes from this one dirty-queuebuffer, and clears then this one dirty-queue-buffer (i.e. the count of contained
items will be reset to zero, but the already allocated memory will neither freed or
shrinked)

Anatomy of a physics tick inside KRAFT


Discrete broad phase
When
no
mesh
shapes

Discrete mid phase


Discrete narrow phase
When
CCD is off

Discrete solver
When
CCD is on

Continuous collision detection and response

Mid phase

Handles the possible contact detection between convex shapes and single
triangles of mesh shapes
Uses the same temporal caching concept as the broad phase

Realized with a secondary contact pair list, but here convex shapes versus triangle subshapes from mesh shapes

Generates contact pairs for the next narrow phase step

Mid phase

Temporal caching (the best optimization is that you must to do nothing)


Very similar temporal caching concept as at the broad phase, just on convex shapes versus
triangle sub-shapes from mesh shapes basis.

New possible contact pairs will be only generated when a contact pair did exist not yet
Contact pairs, these are no longer in contact (expanded-AABB-wise), will destroyed
Realized by a dynamic-sized dirty-queue-buffer (which can only grow on the memory manager
allocation-side, no (or very seldom) shrinks due to performance reasons)

All shapes, which have a new world position and/or world orientation or which are fresh
inserted into the simulated world, are inserted into this one dirty-queue-buffer

The mid phase processes then only these shapes from this one dirty-queue-buffer, and
clears then this one dirty-queue-buffer (i.e. the count of contained items will be reset to
zero, but the already allocated memory will neither freed or shrinked)

Anatomy of a physics tick inside KRAFT


Discrete broad phase
When
no
mesh
shapes

Discrete mid phase


Discrete narrow phase
When
CCD is off

Discrete solver
When
CCD is on

Continuous collision detection and response

Narrow phase

Compare individual contact pairs


Handles the actual collision detection between convex shapes
Accurate as possible but also efficient as possible comparisons
Every CPU worker thread have a own fixed pre-allocated triangle convex hull
shape, whichll refilled with new triangle vertices for each non-triangle shape vs
triangle sub-shape (of a parent mesh shape) collision detection, so that the CPU
worker threads are truly independent of each other, and so that it is only really
necessary to pre-allocate N(=count of CPU worker threads) reusable triangle
convex hull shape class instances on the physics engine initialization.

Terminology Convex versus concave


0

4
5

Convex

Concave

Terminology Convex Hull

Convex Set C

Convex HuIl CH(C)

Two shapes in touching contact

Two shapes in overlapping contact

Contact points
struct ContactPoint {
Vector3 position;
float penetrationDepth;
};

Penetration depth

Contact manifolds
struct ContactManifold {
int countContactPoints;
ContactPoint contactPoints[4];
Vector3 normal;
};

Normal

Solving contact
Normal
2

Penetration depth

Solving contact
Normal
2

rel

=(

=0

Solving contact

+P

-P

Normal

Solving contact
Normal

Penetration depth

= Delta time

rel

= (0.1 )

Incremental vs one-shot manifolds


Incremental manifold
Find closest points (for
example with GJK/EPA
or MPR) to incrementally
build a contact manifold
contact point by contact
point over multiple
several frames

One-shot manifold
Find closest features (for
examples with SAT) to
compute a contact
manifold in one single shot
using clipping techniques
and analytical geometry
techniques

KRAFT supports both approaches, where the one shot manifold approach is the
default

Building incremental manifolds

Margins

Normal

Building incremental manifolds


=0

=1

=2

A quick look how a incremental manifold is constructed over multiple several


frames. Hopefully you can see the issues with this approach already.

Building incremental manifolds


=0

=1

=2

Ooooh!
This is the worst case where objects might rotate out of the world

What is a stable contact manifold?

A contact manifold is stable when the center of mass projects inside manifold
Following from this we need at least up to four frames to construct a stable
contact manifold using the incremental manifold approach

1 point: We can rotate freely about the first contact point

2 points: We can still rotate about the axis through the two contact points across a diagonal
(for example like a hinge)
3 points: We can still rotate around the axis through the two contact points across a diagonal
4 points: Stable manifold after a minimum of four frames
1 point
2 points
3 points
4 points

Incremental manifold

Incremental manifolds are a great and simple solution


BUT it has its issues

Building one shot manifolds

Touching features

Building one shot manifolds


Normal
Clip polygon

Clip plane

Building one shots manifolds


=0

=1

=2

A quick look how a one shot manifold is constructed at multiple several frames.
Hopefully you can see the advantages with this approach.

Collision shapes
r

r
c

Sphere

Capsule

4
5

HuIl

Mesh

KRAFT supports only exactly these base collision shapes

Collision shapes

KRAFT has no special box or triangle shapes as those can be efficiently


handled as convex hull

Box
8 vertices, 6 faces
Triangle
3 vertices, 2 faces (one face in two orientations double-sided face)

KRAFT also has no cylinder or cone shapes

If needed, those could be describe as reasonably tessellated convex polyhedra

The collision table


Sphere
Sphere
Capsule
Hull
Mesh

YES

Capsule

Hull

Mesh

YES

YES

YES

YES

YES

YES

YES

YES
NO

Contact creation makes heavy use of three well-know algorithms:

GJK (GilbertJohnsonKeerthi) for non-penetrating cases (two closest points, distance)

MPR (Minkowski Portal Refinement) for penetrating cases (two penetration points, penetration depth, penetration normal)

cheaper than EPA (Expanding Polytope Algorithm) for the two-algorithm GJK/EPA combination solution

GJK for non-penetrating data (two closest points, distance)

EPA for penetrating data (minimum separation vector, penetration depth)

SAT (Separating Axis Test) for convex polyhedra (minimum separation vector, penetration depth, two closest points, distance)

GJK and MPR terminology - Support extreme point


Supporting extreme point P for direction d returned by support mapping function Support(d)

P=Support(d)

P=Support(d)

GJK and MPR terminology - Minkowski sum


A B = { PA + PB | PA A, PB B }

GJK and MPR terminology - Minkowski sum

If we reflect B about the origin, we get:


-B = { -PB | PB B }

GJK and MPR terminology - Configuration Space Object (CSO)

The Configuration Space Object (CSO) of A and B is the Minkowski Sum of A and -B, denoted A B.
Geometrically, the Configuration Space Object (CSO) of A and B is a shape, which is the collection of
points, where each point is the result of a point from A minus a point from B.
A B = { PA - PB | PA A, PB B }
The Configuration Space Object (CSO) has one important property, that when the Configuration Space
Object (CSO) of two shapes contains the origin, the two shapes are colliding.

GJK (GilbertJohnsonKeerthi)

GJK finds the closest points P1 and P2 and distance d between two
disjoint convex shapes

GJK (GilbertJohnsonKeerthi)

KRAFTs GJK implementation also features simplex caching as temporalbased performance optimization
GJK relies solely on a support mapping function to iteratively generate closer
simplices to the correct answer using the Minkowski sum (CSO) of two
convex shapes

GJK terminology - Simplex


Simplex

0 - simplex

1 - simplex

2 - simplex

3 - simplex

GJK - Base algorithm in detail


1.
2.
3.
4.
5.
6.
7.

Initialize simplex set Q with up to d+1 points from C (in d dimensions)


Compute point P of minimum norm in CH(Q)
If P is the origin, then exit and return 0.0
Reduce Q to the smallest subset Q of Q, such that P in CH(Q)
Let V = Support(-P)
If V no more extreme in direction -P than P itself, then exit and return length
(P)
Add V to Q. Go to step 2

GJK - Base algorithm in detail


INPUT: Convex polyhedron C given as the convex hull of a set of points

GJK - Base algorithm in detail


1.

Initialize simplex set Q with up to d+1 points from C (in d dimensions)

Q = { Q0 ,Q1 , Q2 }

Q1
C

Q2

Q0

GJK - Base algorithm in detail


2.

Compute point P of minimum norm in CH(Q)

Q = { Q0 ,Q1 , Q2 }

Q1
C

P
Q2

Q0

GJK - Base algorithm in detail


3. If P is the origin, then exit and return 0.0
4. Reduce Q to the smallest subset Q of Q, such that P in CH(Q)

Q = { Q1 , Q 2 }

Q1
C

P
Q2

Q0

GJK - Base algorithm in detail


5. Let V = SC(-P) be a supporting point in direction -P

Q = { Q2 , V }

Q1
C
V

Q0

Q2

V` = SC(-P) = Q2

GJK - Base algorithm in detail


6. If V no more extreme in direction -P than P itself, then exit and return length(P)

Q = { Q2 , V }

DONE!

Q1

C
V
P
Q2

Q0

GJK - Distance sub-algorithms

First approach: Solve algebraically

Used in original GJK paper


Johnsons distance sub-algorithm

Searches all simplex subsets

Solves system of linear equations for


each subset

Recursive formulation

It is from the era when math operations


were expensive

Robustness problems

Second approach: Solve geometrically

Mathematically equivalent

But more intuitive

Therefore easier to make robust


Use straightforward primitives:

Closest point on edge to point

Closest point on triangle to point

Closest point on tetrahedron to point

GJK (GilbertJohnsonKeerthi)
For more complete details see links in the last References slide

MPR (Minkowski Portal Refinement)

MPR finds the two contact points (or alternatively penetration depth
and (not-always-optimal-best) minimum separation normal vector)
between two penetrating convex shapes

MPR (Minkowski Portal Refinement)

The algorithm was created by Gary Snethen in 2006 and was first published in
Game Programming Gems 7 (XenoCollide)
The algorithm was used in Tomb Raider: Underworld and other games created by
Crystal Dynamics and its sister studios within Eidos Interactive
MPR, like GJK, relies on a support mapping function to iteratively find the correct
answer using the two penetrating contact points of two convex shapes
Unlike GJK, MPR does not provide the shortest distance between separated
shapes
MPR can easily be combined with one another using operations such as sweep,
shrink-wrap and affine transformation (example usage: simple continuous nonrotational collision detection)

MPR - Simplified description for the 2D case


Phase 1: Portal Discovery

Figure 1a. Here we see a convex shape, representing BA, and the origin. Our
objective is to determine if the origin lies within BA, given only the support
mapping of BA to represent the surface.

Figure 1b. We obtain a point that we know lies somewhere deep within BA. We
can obtain such a point by subtracting any point deep within A from any point deep
within B. The geometric centers of A and B are excellent choices.

Figure 1c. We construct a normal that originates at the interior point and points
towards the origin. We then find the support point in the direction of this ray.

Figure 1d. We construct a ray that is perpendicular to the line between the support
just discovered and the interior point. There are two choices for this ray, one for
each side of the line segment. We choose the ray that lies on the same side of the
segment as the origin. We use this ray to find a second support point on the
surface of BA.

Figure 1e. We now have three points, which form an angle. The origin lies
somewhere within this angle.

Figure 1f. We create a line segment between the two support points. This line
segment is called a portal, because the origin ray must pass through the line
segment on its way to the origin.

Source: http://xenocollide.snethen.com/mpr2d.html

MPR - Simplified description for the 2D case


Phase 2: Portal Refinement

Figure 1f: If the origin lies on the same side of the portal as the interior point, then it
lies within the dotted triangle, and must therefore lie within BA. When this is the
case, we terminate with a hit. In this example, the point lies on the outside of the
portal, so the algorithm continues.

Figure 1g: We construct a normal perpendicular to the portal, pointing away from
the interior. We use this normal to obtain a third support point on the surface of B
A. If the origin lies outside of the support line formed by the point and the normal,
we know that the origin lies outside of BA. In this case, the point lies on the inside
of the support line, so the algorithm continues.

Figure 1h: The three support points form a triangle. We know the origin ray passes
through the interior edge of this triangle, because it is a portal. It therefore must exit
through one of the outer edges. To determine which edge it passes through, we
construct a segment between the new support point and the interior point. If the
origin lies on one side of the segment, the origin ray must pass through the outer
edge that lies on the same side of the segment. If the origin lies on the other side,
the origin ray must pass through the other outer edge.

Figure 1i: The outer edge that passes the test becomes the new portal, and we
discard the unused support point. The algorithm continues from the beginning of
phase 2, using the new portal. In the second iteration of our example, the origin lies
on the inside of the new portal, so we will terminate with a hit.

Source: http://xenocollide.snethen.com/mpr2d.html

MPR (Minkowski Portal Refinement)


Higher Dimensions
As demonstrated above, the 2D version of MPR constructs a ray that passes from an
interior point through the origin. It then finds a portal that the ray passes through, and refines
the portal by moving it closer and closer to the surface of the shape until the origin either lies
inside the portal or outside a support line on the surface of the shape. The basic flow of
MPR is the same in every dimension. In 3D, the portal becomes a triangle rather than a line
segment. In 4D, the portal becomes a tetrahedron.

Source: http://xenocollide.snethen.com/mpr2d.html

SAT (Separating axis test)

The very first:

Separating axis test and NOT Separating axis theorem, it is NOT a theorem, it is a test
method.
KRAFT SATs implementation uses a gauss-map optimized and temporal optimized SAT variant
SAT can tell us things like:
Axis of minimum penetration
Minimum penetration distance
Touching features
Temporal coherence
Store the result from last frame
If a separating axis in the last frame was detected, then we could try this first in the current
frame. The chances are high, that it will still be a separating axis.
If a overlap in the last frame was detected, then we could try to rebuild the contact manifold
from the last features again. The chances are high, that they still realize the contact manifold,
so that we can skip the whole SAT.

SAT (Separating axis test)

Separating Axis versus Separating Line in 2D, including Projected Intervals

SAT overlap test - simple variant without Gauss Map


Axis[] axes = GetTheAxesToTest();
for (int i = 0; i < axes.length; i++) {
Axis axis = axes[i];
Projection p1 = shape1.project(axis);
Projection p2 = shape2.project(axis);
if (!p1.overlap(p2)) {
return false;
}
}
return true;

SAT (Separating axis test)

For details for a Gauss-Map-optimized SAT, which is much faster than the naive SAT, see
http://box2d.org/files/GDC2013/DGregorius_GDC2013.zip

Anatomy of a physics tick inside KRAFT


Discrete broad phase
When
no
mesh
shapes

Discrete mid phase


Discrete narrow phase
When
CCD is off

Discrete solver
When
CCD is on

Continuous collision detection and response

Solver

Solves contact constraints


Solves joint constraints
Position projection / post-stabilization

Inspired by Box2D
In turn inspired by position based dynamics
Can be called Nonlinear Gauss-Seidel
Uses a Baumgarte-like parameter for position correction of unilateral constraints to avoid
overshoot

It has freely configurable count of velocity iterations and position projection


iterations

Like Box2D

Anatomy of a physics tick inside KRAFT


Discrete broad phase
When
no
mesh
shapes

Discrete mid phase


Discrete narrow phase
When
CCD is off

Discrete solver
When
CCD is on

Continuous collision detection and response

A simple scenario

Source: http://box2d.org/files/GDC2013/ErinCatto_GDC2013.zip

Missed collision events lead to tunneling

Source: http://box2d.org/files/GDC2013/ErinCatto_GDC2013.zip

Simple solutions

Solution #1

Make floors and walls thicker


At higher speeds the collision can be missed again
It can work for some games, but it puts the burden on the level designer

Solution #2

Add speculative contact points

Look for potential contact points in the future and add additional constraints to the
contact solver.
Restitution needs special handling
Speculative constraints may be invalid and cause ghost collisions where an object may
appear to hit an invisible wall
More constraints to solve

Better solutions

Solution #3 and #4

Use the time of impact


Compute the time of impact between objects
Non-sub-stepping TOI solutions (#3) can lead to a visual hitch in the motion
Sub-stepping TOI solutions (#4) eliminate hitching
But it takes more CPU time

Simple time of impact solutions

Solution #1

Solution #2

Time of impact via ray cast

Used in Tomb Raider: Legend

Problematic for oblong shapes and rotating movements


Time of impact via linear cast

Problematic for rotating movements

Solution #3

Time of impact via brute force

Accurate

But it takes a lot of CPU time

Found by numerical root finding for each feature pair

O(N^2) cost in 2D
O(N^3) cost in 3D

Better time of impact solutions

Solution #4
Time of impact via Conservative Advancement
Works by considering the distance between two moving shapes
If the distance is non-zero then the shapes can move by some amount
without driving the distance to zero
The distance and closest points can be calculated using GJK
Iterative algorithm
Marches time forward until there is a hit or a miss
Each iteration requires a new GJK call, so that is the main cost of the
algorithm
Hundreds of calls to GJK would certainly lead to frame spikes

Time of impact via Conservative Advancement


float t = 0.0f;
float d = computeDistance(t);
while((abs(d) > tolerance) && (t < 1.0f)){
float delta = abs(d) / velocityBound;
t += delta;
d = computeDistance(t);
}
if(t < 1.0f){
timeOfImpact = t;
}else{
timeOfImpact = noTimeOfImpact;
}

Better time of impact solutions

Solution #5
Time of impact via Bilateral Advancement
Invented by Erin Catto
A enhancement to Conservative Advancement
Allows the use of standard root finding algorithms
Critical for producing reliable performance
Uses closest features
Not brute force, its an iterative algorithm
For more details see http://box2d.org/files/GDC2013/ErinCatto_GDC2013.zip

References
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.

http://www.cas.mcmaster.ca/~carette/SE3GB3/2006/notes/gjk1_pres.pdf
http://xenocollide.snethen.com/ (MPR)
http://box2d.org/files/GDC2015/DirkGregorius_Contacts.pdf
http://box2d.org/files/GDC2014/DirkGregorius_ImplementingQuickHull.pdf
http://box2d.org/files/GDC2013/DGregorius_GDC2013.zip
http://box2d.org/files/GDC2013/ErinCatto_GDC2013.zip
http://box2d.org/files/GDC2011/GDC2011_Catto_Erin_Soft_Constraints.pdf
http://box2d.org/files/GDC2010/GDC2010_Catto_Erin_GJK.pdf
http://www.bulletphysics.org/Bullet/phpBB3/viewforum.php?f=19
http://twvideo01.ubm-us.net/o1/vault/gdc2013/slides/822403Gregorius_Dirk_TheSeparatingAxisTest.pdf

Das könnte Ihnen auch gefallen