
Designing a Physics Engine - todsacerdoti
https://blog.winter.dev/2020/designing-a-physics-engine/
======
physicles
If you restrict yourself to certain types of objects and environments, you can
use totally different techniques.

For a game dev class in uni, I wrote air hockey. This is straightforward
because you only have circles and lines, and there's no gravity so objects
can't rest on each other. I wrote an event-based physics engine, which
exploits the fact that the equations to find the time t of a future collision
are closed-form and you can just solve for t. If t is greater than the time to
the next frame, just step everything forward; if it's less, step to that
collision, then find the next one. Collision response is easy too: just choose
a reference frame where one of the pucks is stationary, then solve
conservation of momentum and energy.

This excludes some kinds of friction models, but if you choose one where
deceleration due to friction is independent of speed (perfectly valid for
lowish speeds), you're fine.

Another cool thing about an event-based system is that it makes it trivial to
write an AI: just have the system try N moves toward the nearest puck, and run
the simulation forward a few collisions to see if any of those moves results
in a puck going in the opponent's goal.

------
OneGuy123
It's one thing to create a physics engine which deals with a few balls.

But it's black magic to bring if from there to a proper game-ready physics
engine which can handle 30 stacked boxes and complex penetration problems.

There is a reason that there are very few physics engines compared to game
engines.

~~~
Animats
His engine is doing a pretty good job. I looked at the code and can't figure
out how he gets stable multipoint contact for the pile of balls out of that.
There's no linear complementary problem solver. There's no elaborate
integrator. Yet it's resolving problems where balls are in contact with many
other balls, and where many balls are constrained in multiple directions.
Naive approaches to that usually go "sprong" and send something flying.

Maybe it's just using a really tiny physics time step. That allows forces to
propagate through the whole pile over many time steps.

~~~
johndough
The trick is to only apply positive impulses and discard negative ones:
[https://github.com/IainWinter/IwEngine/blob/6f94a946a90db989...](https://github.com/IainWinter/IwEngine/blob/6f94a946a90db989412ff29320a0baeca7a5f8cb/IwEngine/src/physics/Dynamics/ImpulseSolver.cpp#L26)
Things will sort themselves out over several frames.

Objects might sink into each other a bit, but that is generally not very
noticeable unless you make huge piles of spheres. However, it might quickly
become a problem in 2D, since you only need a quadratic number of objects to
get a "critical" pile, compared to a cubic number of spheres in 3D.

~~~
IainWinter
That makes it so nothing explodes, and then there is a second solver that does
a small raw position correction after. So it's not lifelike realism, but it
works to stop objects sinking into each other too much. There is still a small
error though, I'd have to look into more iterations and all that.

------
inDigiNeous
I was writing my own 3D engine for some time also. I decided at some point I
would not venture into physics, that is where I would draw the line.

Then I understood that even doing proper collision detection would mean having
to implement some kind of physics in order to do proper frame independent
linear interpolation of objects moving in 3D space, in order for the objects
not to go through each other if the movement step is too big and also to do
proper moving of objects anyway in 3D space, as you can't just expect to
linearly transform an object from one place to another, as framerates might
wildly differ and the object might go through another if the frametime would
be too big for this particular frame we are rendering.

That is where I just stopped, and decided that it was too much work to do
anything proper by myself, and gave up on writing my own 3D engine.

I see many people are going through this process, writing their own engines
and libraries. Somebody told me when I started I should use an existing
engine, but I didn't listen. And that is a good thing, and at the same time,
wasting time to do something that could be done using existing libraries or
engines.

This is what I feel anytime I see somebody write about them re-inventing the
wheels, but I guess it's a process that many choose to go through for learning
and fun purposes.

~~~
TeMPOraL
> _proper frame independent linear interpolation of objects moving in 3D
> space_

Reminds me of another thing - back when I was trying to write my own 3D
engine, I've never heard of the concept that you _interpolate physics state
between rendering frames_. Something that's considered table stakes today.

When and how did that arise?

~~~
andrewflnr
I've never heard of that either. I thought you were just supposed to fix your
physics timestep and sort the graphics out later.

~~~
TeMPOraL
From what I vaguely understand, the goal here is to reduce jerkiness if you
render faster than you tick your physics. But then I always thought that
beyond stability, the other main reason to make your physics time step
independent from rendering is so that you can tick physics _more often_ than
you draw.

(Thinking about it now, I suppose this trick lets you update physics less
frequently than drawing while faking fluid movement, and free up CPU time for
other tasks.)

------
rikroots
I have huge admiration for anyone who manages to implement a physics engine.
I've tried to do this twice now (to integrate with my 2D canvas library) and
both times I've not been able to solve the collision response part of the
system.

Given that I failed my 'A' level maths in spectacular fashion (I honestly
don't get integration - it just doesn't compute for me) I'm obviously
attempting the impossible here. But I live in hope that one day I will somehow
stumble on a solution that looks like its working on screen ... which will be
enough for me.

I've tried combining my library with third party physics engines - but that,
too, is hard work. The best I've ever managed is with the Matter.js[1] engine
but the amount, and complexity, of code needed to create a scene is too much
for my tastes[2].

Maybe I'll go back for a third attempt if/when the second Covid wave hits.

[1] Matter.js home page - [https://brm.io/matter-js/](https://brm.io/matter-
js/)

[2] Codepen demo -
[https://codepen.io/kaliedarik/pen/zYvbwBy](https://codepen.io/kaliedarik/pen/zYvbwBy)

~~~
sillysaurusx
The solution is to borrow ideas from those who have done it before.

One idea comes from quake: for collision response, call a function recursively
until there's no more collision.

Basically, it pushes you away from a given plane. So the function looks like
pushAway(plane, you). If that pushes you into something else, you get pushed
away again, recursively.

If you imagine a V shape, the result is that you end up "standing" on the V,
because you're getting pushed away from both sides of the V equally.

I'm not sure my explanation is very good, so to simplify: just add recursion,
lol. (You'll need to limit the max recursion depth, or else you'll get a
frozen game.)

I used to try to solve things from first principles – and it's more fun to do
that – but there's no shame in copying the answer. Carmack's solutions tended
to be copied from the medical rendering field anyway. :)

~~~
rikroots
> The solution is to borrow ideas from those who have done it before.

I've tried that. Open various libraries, go through the code, work out
how/where they perform the collision response calculations, trace back the
vars passed into those calculations to see where their values get calculated,
etc, etc ... and clearly I keep missing some key step or other along the way.
I'm either misunderstanding the collision normal, or misinterpreting the
collision depth, or my understanding of torque is deeply flawed (very
possible, that one) ... frustration builds. Then I blame the engine coders for
being too clever with their code and try a different library.

I'll get there one day. Failure is not a disaster!

~~~
pasabagi
As somebody who also struggles with math, I feel that the problem is it's
extremely unforgiving. For instance, when I was trying to write some simple 3d
rotation matrices in lua, I kept on getting crazy results just because I'd
invariably mix up one cosine with a sine, or a plus with a minus. I don't
really have any thoughts about how to get around this though.

------
PudgePacket
> Note the use of pointers, this forces other systems to take care of the
> actual storing of objects, leaving the physics engine to worry about
> physics, not memory allocation.

Based on the access patterns in the code (iterating through every physics
object every step), keeping the physics objects behind a pointer is actively
cache hostile! If at all possible try to have these objects in contiguous
memory.

~~~
IainWinter
Yeah it's up to the person using it to store them sensibly. I use an ECS so
they are mostly all contiguous. I think that the pointer hurts the cache for
the fist iterations, but once the whole array is cached I think the pointer
becomes ok.

There is still that indirection though :(

------
virtue3
Fun book if anyone is ever interested: Physics for Game Developers Paperback –
November 15, 2001 by David M Bourg

------
petters
I don`t know much about physics engines, but I do know that there are much
more sophisticated integrators than x = x + v*dt. For example schemes for
gravity that keeps energy invariant.

Are any used in physics engines? I assume yes.

~~~
rhaps0dy
The naive integrator you're describing, just taking the differential equations
and substituting dt by a small, non-zero time step, is known as the Euler
integrator [1]. As you say, this scheme does not keep energy invariant. In
fact, energy may grow unbounded if you use it.

The simplest integrator that "preserves" energy is the Symplectic Euler [2]
integrator, which reads:

v <\- v + F/m * dt

x <\- x + v * dt

The key is that you use the _updated_ velocity to update the position in the
same time step. In this scheme, energy isn't exactly preserved, it varies a
little bit from one time step to the next. However, you can guarantee that the
energy fluctuations will remain bounded, if your time step is below a (fairly
large) critical value.

Reading the code of this blog post, the first version of the Step (at the
beginning of the blogpost) uses the Symplectic Euler scheme, and the second
version (towards the end) uses the naive Euler scheme. Bullet, a popular
physics engine, uses the Symplectic Euler method [3].

A popular, more sophisticated, scheme is the Runge-Kutta integrator, which
comes with variants that preserve the energy and ones that don't. The MuJoCo
simulator, used in robotics research, uses the Runge-Kutta method [4]

[1]
[https://en.wikipedia.org/wiki/Euler_method](https://en.wikipedia.org/wiki/Euler_method)

[2] [https://en.wikipedia.org/wiki/Semi-
implicit_Euler_method](https://en.wikipedia.org/wiki/Semi-
implicit_Euler_method)

[3]
[https://github.com/bulletphysics/bullet3/issues/2513](https://github.com/bulletphysics/bullet3/issues/2513)

[4]
[http://www.mujoco.org/book/computation.html](http://www.mujoco.org/book/computation.html)

~~~
IainWinter
Oh you're correct, I was trying to make the code more readable for the blog
post and didn't even think of that! Thanks for the heads up I would of never
caught that, and good info about different integrators, not going to pretend
that I knew all of it. It makes sense though because the velocity used for the
position would be a frame behind.

I was looking into the Runge-Kutta method, but it looked too complex for what
I was doing.

~~~
sgillen
Fixed step Rk4 is really not very complex once you understand numerical
integration. Not that you need it, plus it will be about 4x slower.

------
BenFrantzDale
Small suggestion: this should be an `Object` method:

``` obj->Force += obj->Mass * m_gravity; // apply a force

obj->Velocity += obj->Force / obj->Mass * dt; obj->Position += obj->Velocity *
dt;

obj->Force = vector3(0, 0, 0); // reset net force at the end ```

As in

``` void Object::Step(double dt_s, const vector3& g_mps2) { Force += Mass *
g_mps2; // apply a force

    
    
        Velocity += Force / Mass * dt_s;
        Position += Velocity * dt_s;
     
        Force = vector3(0, 0, 0); // reset net force at the end

} ```

~~~
rurban
So that it cannot be inlined and be 20x slower? Not so a good idea for a
physics loop.

------
adamnemecek
I feel like in this day and age, GPGPUs are underused for this purpose. I've
been working on a somewhat simpler problem recently, and eventually realized
that you can use GPGPUs for this purpose.

~~~
maccard
For games, gpus are often busy rendering. Parts of a physics engine
(integrators mainly) parallelize well, but in my experience, all the rest of
the code is very branchy, which doesn't work as well.

~~~
adamnemecek
You are right they are rendering, however say collision detection is
comparably less compute heavy than rendering.

I think with ECS, you can avoid a lot of this branching.

~~~
maccard
The basic implementation of GJK is inherently branchy - see [0] as an example.
Extracting the contact points is similarly branchy, I'm not sure offhand how
that would translate into gpgpu friendly code.

I'm also not sure it's worth it. If you have a small number of bodies, it
doesn't make sense to attempt the collision detection on the GPU, the benefit
of the GPU is really that it scales. If you _do_ have a large number of
bodies, youre likely going to be using lots of your GPU for rendering
anyway....

There's also the gameplay side of it - moving the bulk of the physics engine
to the GPU will make things like contact filtering, scene querying difficult
to do. Gameplay code is usually very straightforward, and adding in complex or
async callbacks likely would be met with resistance..

[0] [http://vec3.ca/gjk/implementation/](http://vec3.ca/gjk/implementation/)

------
appleflaxen
This is a really well-done video.

But why don't we want plane v. plane? Can't a flat surface hit another flat
surface?

~~~
ratww
In geometry a plane extends infinitely far, so unless two planes are perfectly
in parallel they will collide. Not too useful for collision detection (but
useful for other things).

------
layoutIfNeeded
That’s a very simplistic “physics engine”, that doesn’t handle rotational
motion at all...

~~~
IainWinter
Yeah that's why I used spheres :)

I plan to make a part 2 that covers more complex constraint based methods.
I'll put rotation in with that.

