Reducing expressions (function/equations)
containing vector operations
using an orthogonal basis matrix

Author Jakob Gath (Hel)
Edited by Søren Dreijer (Halloko)

7/8-2005

This paper concerns itself with the making of an ortho-normal basis matrix when you only know one basis vector. This can be extremely useful when rewriting equations containing vector operations.

If you are a skilled mathematician you will know about the Gram Schmidt method which is used to make an orthogonal matrix (not necessarily normalized) from n linearly independent vectors (in n dimensions). Our approach is that we only know one vector so the Gram Schmidt method isn’t suitable.

What if you for some reason wanted to rotate all your vectors into a new space (v-space), where an important vector, say,



was represented as



This would be nice in a function of the type



where ni and nj are two arbitrary vectors, since we could represent this function in v-space as



Get the idea?
But how do we make a matrix that can rotate v, ni and nj into the v-space when only knowing one basis vector - the normalized v vector itself?

We will need two vectors which are perpendicular to the v vector (note that we work in 3 dimensions).

To do this, we will represent the direction of the v vector in polar coordinates. That is



because we are searching for an ortho-normal basis matrix, .

Now, the algorithm is easier to express in pseudo-c++ code:

	v0 = normalize(v);
	theta = acos(v0.x);
	if(theta == 0) // Watch out for precision errors 
	{
		// v0 must be the vector (0, 0, 1)
		v1 = (r, 0, 0);
	}
	else
	{
		/* NOTE
		Adding pi/2 to theta will rotate v1 90 degrees, which will 
		make v1 perpendicular to v0. Note that you can not add 
		pi/2 to phi and get the same result.
		*/
		theta1 = theta + pi/2;
		v1 = (	v0.x / sin(theta) * sin(theta1),
			v0.y / sin(theta) * sin(theta1),
			cos(theta1));
	}
We will only be needing one more basis vector, v2, which, in 3 dimensions, is very easy to calculate by using the cross product between v0 and v1:

v2 = cross(v0, v1)

This will generate the following right-handed () matrix,



If you want a left-handed () matrix simply invert the cross product:

v2 = -cross(v0, v1) = cross(v1, v0))

The matrix above will take any vector in v-space and rotate it into world space. This is the opposite of what we want, but the inverse matrix will do the right thing and is calculated because the matrix is happening to be an ortho-normal matrix, such as;



So, the matrix that rotates vectors in world space into v-space is:



q.e.d.

Note that if the vectors v0, v1 and v2 were not of unit length we would have to calculate the inverse matrix, but this would also have reduced the equation further because the v vector would be presented as in v-space, .

If you want to use this method the algorithm would look like this

	v0 = v;
	r=magnitude(v);
	// Divide by length
	theta = acos(v0.x / r);
	if(theta == 0) // Watch out for precision errors 
		v1 = (r, 0, 0);
	else
	{		
		theta1 = theta + pi/2;
		// Note that the z component is multiplied by r
		v1 = (	v0.x / sin(theta) * sin(theta1), 
			v0.y / sin(theta) * sin(theta1),
			r * cos(theta1));
	}
	v2 = cross(v0, v1);
	M(v0,v1,v2).inverse();
Jakob Gath
Blacksmith Studios

Return to articles overview

Copyright Blacksmith Studios 2005 ©