Hello World!
This is my first developer blog entry for the Excalibur game and NanoFX-Evolved engine and it revolves around controlling a ship in a Newtonian environment (pardon the pun!).
As many of you know, I am the lead programmer of Excalibur and have designed/developed the architecture that supports the quality and flexibility you see now and will soon be exploring through the NanoFX-Evolved engine!
As a developer, having such awesome people making up the programming and art teams really makes all the difference, not just in terms of the final product, but also the journey we are taking to reach it! It would not be possible without you all - so congratulations and award each other cookies!

Now onto the meaty stuff! Essentially I've been looking for a way to control ships using forces and torques in a true Newtonian system. This has involved me learning physics, which has in turn thrown up some rather interesting abstractions which people really don't talk about. For example:
Angular momentum does not exist! It is a lie physics teachers tell you because they don't understand the true reasons things turn. Luckily however, angular momentum is a pretty neat model so it comes in pretty handy.
Firstly I am going to distinguish between a
particle and a
body.
- Particle - Something to which physics can be applied but has no size. A point in 3D space with a given mass. It is impossible to turn a particle.
- Body - A set of particles that have been stuck together and bound with various atomic forces. These thus have a "size" and can be visible turned by applying forces at different points on the shape.
It starts to make sense where the term "rigid body mechanics" comes from now.

One of the requirements of the game engine is that it should allow bodies to have different moments of inertia [1]. A moment of inertia is essentially a way of describing how the layout of the particles in a body change the way it rotates. (For example, a hollow wheel requires less force to rotate at the same speed as a solid wheel. There is a great article on wikipedia which describes several of these formulae [2]).
To support the requirement of variable moments of inertia and a consistent acceleration value in the hard points (assuming equal moment distributions about the centre of mass in each axis), we require 6 "thrusters" to be placed at the edge of the body in each axis. To ensure a true rotation (and no movement as a result) it is important that each thruster has an equal and opposite force pushing at the other side of the body. Newtons laws tell us that the body will remain in the same place in space, but the forces will make the body rotate.
The following equation can be used to apply a force at a point.
## Compute the force for a thruster that rolls the ship.
vForceA = vDirection * fMagnitude
vForceB = -vDirection * fMagnitude
## Compute the torque for this thruster. X = Cross Product.
vTorqueA = vPointA X vForceA
vTorqueB = vPointB X vForceB
## Resolve the forces from this thruster.
vThrusterForce = vForceA + vForceB
vThrusterTorque = vTorqueA + vTorqueB
Ok.. cool! Do you notice anything we can do here to make things easier? vForceA and vForceB are equal and opposite and so resolve to the value of 0 (the body does not move, but can rotate!).
Now we want to make the body rotate at a given rate of acceleration. This is fairly easy because we can use the good old
Force = Mass * Acceleration.
We get the following code:
## Compute the "strength" of the force required to provide a desired acceleration.
## Note here that our acceleration is simply describing our direction and speed in each axis.
vForce = vAcceleration * fMass
## Compute the torque for this thruster. X = Cross Product.
vTorqueA = vPointA X vForce
vTorqueB = vPointB X -vForce
## Resolve the forces from this thruster.
vThrusterForce = 0
vThrusterTorque = vTorqueA + vTorqueB
Right! So that's all good. Works a treat.

Here is a screenshot!

The first problem that we run into is that the code is extremely messy, slow and could be a damn site better for each thruster. Luckily we can
simplify the above calculations by doing them in local space (i.e. relative to the model rather than the world).
Lets take a look at a simplified version of the actual code:
// Compute the force to be added by this thruster using F = ma.
// We need not apply it to the body because the forces cancel.
Vector3 vForce = Vector3.Multiply(vAngularAccel, fMass);
// Compute the torque to be applied as a result of applying this force at a point.
Vector3 vTorque = new Vector3(0f, 0f, 0f);
// Roll.
vTorque.Add(Vector3.Cross(new Vector3(vPoint.X, 0f, 0f), new Vector3(0f, vForce.X, 0f)));
vTorque.Add(Vector3.Cross(new Vector3(-vPoint.X, 0f, 0f), new Vector3(0f, -vForce.X, 0f)));
// Pitch.
vTorque.Add(Vector3.Cross(new Vector3(0f, vPoint.Y, 0f), new Vector3(0f, 0f, vForce.Y)));
vTorque.Add(Vector3.Cross(new Vector3(0f, -vPoint.Y, 0f), new Vector3(0f, 0f, -vForce.Y)));
// Yaw.
vTorque.Add(Vector3.Cross(new Vector3(0f, 0f, vPoint.Z), new Vector3( vForce.Z, 0f, 0f)));
vTorque.Add(Vector3.Cross(new Vector3(0f, 0f, -vPoint.Z), new Vector3(-vForce.Z, 0f, 0f)));
Ok... now we can see that there are 15 memory allocations, 39 multiplications and I didn't even bother counting the additions, subtractions and variable assignments. This will not do!
Luckily we can decompose our cross product call into the following maths:
x = Ay * Bz - Az * By;
y = Az * Bx - Ax * Bz;
z = Ax * By - Ay * Bx;
Since we are doing our calculations in local space (i.e. the thruster directions and positions will never impact on the axes other than the ones they deal with), we can basically find the axes for each operation where the value is 0 and remove them from the calculation.
This means the above section of code to compute the torque translates into the following call:
// Compute the force to be added by this thruster using F = ma.
// We need not apply it to the body because the forces cancel.
Vector3 vForce = Vector3.Multiply(vAngularAccel, fMass);
// Compute the torque to be applied as a result of applying this force at a point.
Vector3 vTorque = new Vector3(vPoint.Y * vForce.Z * 2, vPoint.Z * vForce.X * 2, vPoint.X * vForce.Y * 2);
Notice that the
*2 is there because the force we apply is as a result of
both engines (and we know that a minus times a minus is a plus - so it works out as *2). 2 Memory allocations and 9 multiplications, no additions and considerably less memory copies.

Tips and tricks:(1) Local space calculations are awesome for optimising things!
(2) Don't just "use the toolkits". Understand what your code is doing under the hood and decompose your cross products!
(3) Fitting it into an architecture can be tricky and I'm going to cover that in the next blog post thing.
References[1]
http://en.wikipedia.org/wiki/Moment_of_inertia[2]
http://en.wikipedia.org/wiki/List_of_moment_of_inertia_tensorsNext...In my next post I will describe how I used these mechanisms to provide a nicer interface for the AI and player to control the ships.

John
Disclaimer: I am not a physics person, actually quite the opposite. You know, the kind of geek who can "get" a physics joke without actually understanding what is funny! This series of blog entries is based on my own research and tests and should not be used in any sort of safety critical or production environment. It should be taken as a rough guide, nothing more. 