Matt Kae's Programming Blog

Introduction: Rigid Body Physics

You're most likely here because you have some interest in the world of rigid body physics. Maybe you have some knowledge of rendering via OpenGL or Vulkan, and you want to begin watching your up-until-now static scene come to life. Well, you're in the right place! In the course of this tutorial series I will walk you through the entirety of a 2D rigid body physics system entirely in the web. All of this information will be extendable to other languages, but we will use JavaScript and WebGL in these blog posts. Additionally, much of the information presented here can be extended to 3 dimensions, but 3D carries some complications with it, that we will discuss in future blog posts.

In implementing a rigidy body physics system, we're primarily interested in two sub-fields of physics, namely dynamics and kinematics. Although I'm far as can be from being an expert in either of these fields, I will explain - from a programmer's persepctive - what they mean to me:

Finally, I must provide a disclaimer that all of rigid body systems are very math-y. You will need to know a decent amount of vector calculus and linear algebra to really understand what's going on here. I am going to assume that you have this knowledge. If you don't already have this knowledge, I will try and provide some resources on the Books n' References page of the website.


Part 1: Linear Forces

The first - and perhaps easiest - part of implementing any rigid body physics system is getting the entities in your scene to move in response to linear forces. With this implementation alone, you can achieve an interesting level of realism in your 2D (and even 3D) scene.

Let's begin by recalling the relationships between acceleration, velocity, and position.

Knowing all this, you should be able to understand the following source code fairly easily;

                        
function update(dtSeconds) {
    // Add up the forces acting on the circle
    const GRAVITY = 9.8;
    const lGravityForce = vec2(0, -1.0 * (lCircle.mass * GRAVITY));
    lCircle.force = addVec2(lCircle.force, lGravityForce);

    // Figure out acceleration (a = F / m)
    const lCurrentAcceleration = scaleVec2(lCircle.force, 1.0 / lCircle.mass);

    // Calculate the new velocity: v = v0 + a * t
    lCircle.velocity = addVec2(lCircle.velocity, scaleVec2(lCurrentAcceleration, dtSeconds));

    // Update the position based on velocity: x = x0 + v * t
    lCircle.position = addVec2(lCircle.position, scaleVec2(lCircle.velocity, dtSeconds));

    // Update the model matrix accordingly
    lCircle.model = translateMatrix(mat4(), lCircle.position.x, lCircle.position.y, 0);

    // Reset the force vector for the next update
    lCircle.force = vec2()
}
                        
                    

  • Force:N/A
  • Acceleration:N/A
  • Velocity:N/A
  • Position:N/A

Part 2: Rotational Forces

  • Force:N/A
  • Acceleration:N/A
  • Velocity:N/A
  • Position:N/A