Hello, I’m Glenn Fiedler and welcome to ** Virtual Go**, my project to simulate a Go board and stones.

In the previous article we detected collision between the go stone and the go board.

We’re working up to calculating collision response so the stone bounces and wobbles before coming to rest on the board, but in order to reach this goal we first need to lay some groundwork.

It turns out that irregular objects, like go stones, are easier to rotate about certain axes than others.

This tendency is a property of the distribution of mass in a go stone. In other words, the shape of the go stone contributes to how it moves, and how it reacts to collisions. If we neglect this effect we’ll never reproduce that unique ‘wobble’ go stones have when placed on the board.

It makes sense that we’re going to need to understand this before we apply collision response.

*Lets get started.*

## Rotation in 3D

Physics in 3D is considerably more difficult, for me at least, than physics in 2D.

Most of this this has to do with the complexity of rotation in three dimensions.

Consider the following case in two dimensions:

It’s easy because there is only one possible axis for rotation. Clockwise or counter-clockwise, no other rotation is possible, assuming we are rotating about the center of mass.

It follows that as long as we are only rotating about the center of mass, we can represent the orientation of an object in 2D with a single theta value, angular velocity with a scalar radians per-second, and a scalar ‘moment of inertia’ that works just like an angular equivalent of mass, eg: how hard it is to rotate that object.

When we move to three dimensions suddenly rotation can occur about any axis. Orientation becomes a quaternion, angular velocity a vector, and now for irregular shaped objects like go stones, we need some way to indicate that certain axes of rotation are easier to rotate about than others.

How can we represent an angular mass that depends on the shape of the object __and__ the axis of rotation?

## Inertia Tensor

The solution is to use an inertia tensor.

An inertia tensor is a 3×3 matrix with different rules to a normal matrix. It rotates and translates differently, but otherwise, it behaves like a 3×3 matrix and you use it to transform vectors.

Specifically, you use the inertia tensor to transform angular velocity to angular momentum, and the inverse of the inertia tensor to transform angular momentum to angular velocity.

Now this becomes quite interesting because Newton’s laws guarantee that in a perfectly elastic collision angular momentum is conserved but angular velocity is not necessarily.

Why is this? It’s because angular velocity depends on the axis of rotation, so even if the angular momentum has exactly the same magnitude post-collision the angular velocity can be different if the axis of rotation changes (it usually does).

Because of this we’ll switch to angular momentum as the primary quantity and we’ll derive angular velocity from it. For consistency we’ll also switch from linear velocity to linear momentum:

const float gravity = 9.8f * 10; const float fps = 60.0f; const float dt = 1 / fps; while ( !quit ) { stone.rigidBody.linearMomentum += vec3f(0,-gravity,0) * stone.rigidBody.mass * dt; stone.rigidBody.linearVelocity = stone.rigidBody.linearMomentum * stone.rigidBody.inverseMass; stone.rigidBody.angularVelocity = transformVector( inverseInertiaTensor, angularMomentum ); stone.rigidBody.position += stone.rigidBody.velocity * dt; quat4f spin = AngularVelocityToSpin( stone.rigidBody.orientation, stone.rigidBody.angularVelocity ); stone.rigidBody.orientation += spin * dt; stone.rigidBody.orientation = normalize( stone.rigidBody.orientation ); RenderStone( stone ); UpdateDisplay(); }

## Calculating The Inertia Tensor

Now we need a way to calculate the inertia tensor.

The general case is quite complicated because inertia tensors are capable of representing shapes that are non-symmetrical about the axis of rotation.

For example, think of an oddly shaped object attached to a drill bit off-center and wobbling about crazily as the drill spins.

The good news is that due to the symmetry of the go stone and because we’re always rotating about the center of mass, our inertia tensor is much simpler:

All we need to do in our case is to determine the I_{x}, I_{y} and I_{z} values.

These values represent how difficult it is to rotate the go stone about the x,y and z axes.

Interestingly, due to symmetry of the go stone, all axes on the xz plane are identical.

So really, we only need to calculate I_{x} and I_{y} because I_{z} = I_{x}.

## Numerical Integration

First lets calculate the inertia tensor via numerical integration.

To do this we just need to know is how difficult it is rotate a point about an axis.

Once we know this we can approximate the moment of inertia of a go stone by breaking it up into a discrete number of points and summing up the moments of inertia of all these points.

It turns out that the difficulty of rotating a point mass about an axis is proportional to the __square__ of the distance of that point from the axis and the mass of the point.

This is quite interesting because it indicates that the distribution of mass has a significant effect on how difficult it is to rotate an object about an axis.

One consequence of this is that a hollow pipe is actually more difficult to rotate than a solid pipe of the same mass. Of course, this is not something we deal with in real life often, because a solid pipe of the same material would be much heavier, and therefore harder to rotate due to increased mass, but if you could find a second material of lower density such that the solid pipe was exactly the same mass as the hollow pipe, you would be able to observe this effect.

In our case we know the go stone is solid not hollow, and we can go one step further and assume that the go stone has completely uniform density throughout. This means if we know the mass of the go stone we can divide it by the volume of the go stone to find its density. Then we can divide space around the go stone into a grid, and using this density we can assign a mass to each point in the grid proportional to the density of the go stone.

Now integration is just a triple for loop summing up the moments of inertia for points that are inside the go stone. This gives us an approximation of the inertia tensor for the go stone that becomes more accurate the more points we use.

## Interpreting The Inertia Tensor

A size 33 japanese go stone has width 22mm and height 9.2mm:

Using our point-based approximation to calculate its inertia tensor gives the following result:

As expected, I_{x} = I_{z} due to the symmetry of the go stone.

The inertia tensor indicates that its much harder to rotate the go stone about the y axis than axes on the xz plane.

Why is this?

You can see looking top-down at the go stone when rotating about the y axis a ring of mass around the edge of the stone is multiplied by a large r^{2} and is therefore difficult to rotate.

Contrast this with the rotation about the x axis, which has a much smaller portion of mass far away from the axis:

As you can see the distribution of mass around the axis tends to dominate the inertia tensor due to the r^{2} term. The same mass, twice the distance from the axis, is four times more difficult to rotate!

## Closed Form Solution

Exact equations are known for the moments of inertia of many common objects.

With a bit of math we can calculate closed form solutions for the moments of inertia of a go stone.

To calculate the exact equation for I_{y} we start with the moment of inertia for a solid disc:

Then we can integrate again, effectively summing up the moments of inertia of an infinite number of thin discs making up the top half of the go stone.

This leads to the following integral:

With a little help from Wolfram Alpha we get the following result:

float CalculateIy( const Biconvex & biconvex ) { const float h = height; const float r = biconvex.GetSphereRadius(); const float h2 = h * h; const float h3 = h2 * h; const float h4 = h3 * h; const float h5 = h4 * h; const float r2 = r * r; const float r3 = r2 * r; const float r4 = r3 * r; return pi * p * ( 1/480.0f * h3 * ( 3*h2 - 30*h*r + 80*r2 ) ); }

Plugging in the values for a size 33 stone, we get 0.303588 which is close to the approximate solution 0.304776.

Verifying exact solutions against numeric ones is a fantastic way to check your calculations.

Can __you__ derive the equation for I_{x}?

**Next:**

Collision Response And Coulomb Friction

**Next:**

Collision Response And Coulomb Friction

If you enjoyed this article please donate.

__Donations offset hosting costs and encourage me to write more articles!__

Hi Glenn,

This article is awesome!

This had been what I wanted to do for long time… you just realized my dream

Keep up the good work.

Hiroki Mori

The author of “The Interactive Way to Go”

I learned to play with “The Interactive Way To Go”.

Thank you very much!

Subscribed. I’m a non-programmer (well, sysadmin, and I think as a real programmer you know what that means for my programming “skill”) looking into doing computer vision to record real-life games . . . I think your job looks a lot harder. I’ve also been learning calculus on my own and it’s fantastic to see these real-simulated-life examples!

Awesome. Glad you like it!