Game Development Reference
InDepth Information
This algorithm can't cope when the
x
and
y
vectors are parallel. We can easily
modify the algorithm to do that, rather than returning when check for zero fails. We
could use a different
y
value (by inverting one or swapping two of its nonzero ele
ments, for example) and recalculate
z
. We will return to this issue later, after making
some improvements to the calculation code itself.
We can improve the efficiency of this longhand form by manually performing the
vector products (rather than calling the vector product operator in the
Vector3
class).
First notice that if the initial Y axis is pointing along the Y axis, then any value for
the resulting Z axis must be at right angles to the Y axis. This can only happen if the
resulting Z axis has a zero Y component.
Second, rather than normalizing the vectors at the end, we can ensure that they
are normalized as we go. We do this by making sure that the calculation of the Z axis
ends with a normalized vector. Because the vector product obeys the equation

=
×
=


y
z
x
z
x
sin
θ
and we know the X and Z axes are at right angles (sin
θ
=
1) and both are normalized

=
=
(
1) then the resulting Y axis must have a magnitude of 1: it is normalized.
The shorthand code looks like this:
z
x
// The output axes
Vector y, z;
// Scaling factor to ensure the results are normalized.
const real s = 1.0/real_sqrt(x.z*x.z + x.x*x.x);
// The new Z axis is at right angles to the world Y axis.
z.x = x.z*s;
z.y = 0;
z.z = x.x*s;
// The new Y axis is at right angles to the new X and Z axes.
y.x = x.y*z.x;
y.y = x.z*z.x  x.x*z.z;
y.z = x.y*z.x;
There is one further problem to address. If the contact normal passed in (as the X
axis) is already pointing in the direction of the worldspace Y axis, then we will end
up with zero for all three components of the Z axis. In this case, using the worldspace
Y axis is not a good guess; we need to use another. We can use either the worldspace
X axis or Z axis. The code I've implemented uses the worldspace X axis.
To make the algorithm as stable as possible we switch between using the world
space Y axis and the X axis as a best guess, depending on which the contact normal