Matrices And You Part 3 : Practical Uses

Pratical uses of rotation matrices

Err... Only rotation?

Yep. Right now it’s the most useful thing I’ve found about matrices, besides them being a fantastical mathematical object which you probably will have hours of fun multiplicating on paper.

But... I just have to give one more math concept : orthogonality.


Orthogonality is intuitively a graphical concept, but can be expressed theoretically as well. I prefer to start by the theoric approach.

In theory

If you take those two 2D vectors :

A = [ 1, 0 ]
B = [ 0, 1 ]

No matter how hard you try, it is impossible to express B as a linear combination of A. By that I mean, you can’t add up a series of A’s and get B in return :

B = x * A   <-- will never happen

Because of that, we can say that B and A are orthogonal. Geometrically, they’re also perpendicular.

But it goes worse. Take those three 3D vectors :

A = [ 5, 0, 0 ]
B = [ 0, 0, 2 ]
C = [ 0, 3, 0 ]

Here, it is impossible to express any vector in this set as a linear combination of the two others. In other words, you can’t add up a scaled version of A and a scaled version of B and get C in return, or any substitution :

A = x * B + y * C   <-- won't happen
B = x * A + y * C   <-- nope
C = x * A + y * B   <-- sorry

And because of that, we can say that A, B and C are mutually orthogonal. They’re also perpendicular to each other, but that’s a bit harder to visualize.

In practice, and in pictures

Now take this graphical representation, rendered in TV3D (what else?).

Flashy. What is it?

  • The red line is the X axis
  • The green line is the Y axis
  • The blue line is the Z axis
  • The magenta plane (red + blue) is the XZ plane
  • The yellow plane (red + green) is the XY plane
  • The cyan plane (green + blue) is the ZY plane

The axis actually are a visual representation of linear combinations.

  • The X axis is formed of any linear combination of the X unit vector (XAxis = a * [1, 0, 0])
  • The Y axis is formed of any linear combination of the Y unit vector (YAxis = a * [0, 1, 0])
  • The Z axis is formed of any linear combination of the Z unit vector (ZAxis = a * [0, 0, 1])

Same thing for the planes!

  • The XZ plane is formed of any combination of the X and Z unit vectors (XZPlane = a * [1, 0, 0) + b * [0, 0, 1])
  • The XY plane is formed of any combination of the X and Y unit vectors (XYPlane = a * [1, 0, 0) + b * [0, 1, 0])
  • The ZY plane is formed of any combination of the Z and Y unit vectors (ZYPlane = a * [0, 0, 1) + b * [0, 1, 0])

a and b in the formulas above are any scalar, so any single value at all.

Why do you torture me so?

Why did I do this? Take any plane. It is impossible to obtain a unit vector of the remaining axis within this plane. That is to say that the set formed of the three X, Y and Z unit vectors is mutually orthogonal.

Now take the three vectors that form the 3D rotation matrix, and its default untouched value :

{{ Right.x,   Right.y,   Right.z },        {{ 1, 0, 0 },
 { Up.x,      Up.y,      Up.z },        =   { 0, 1, 0 },
 { Forward.x, Forward.y, Forward.z }}       { 0, 0, 1 }}

That means that the set of unit vectors that is an untouched rotation matrix is mutually orthogonal!

  • Right = [ 1, 0, 0 ] is mutually orthogonal to Up and Forward
  • Up = [ 0, 1, 0 ] is mutually orthogonal to Right and Forward
  • Forward = [ 0, 0, 1 ] is mutually orthogonal to Up and Right

And even better, it stays true whatever the rotation matrix is. It’s logical after all... whereever you’re looking at, the orthogonality and perpendicularity stays between each other.

My head a splode.

Even if you didn’t understand the process, as long as you understand the conclusion : a rotation matrix is formed of three mutually orthogonal vectors. I know I went fast on this, yet said alot of stuff you don’t necessarily need to know.

But here’s why I told you about orthogonal sets in the first place : the cross product operation.

Cross product

The cross product (the symbol is simply X) is an operation whose definition you don’t really need to know. Too much information is like not enough.

Its effect is that if you feed it two vectors, it will return a vector that is orthogonal to those two vectors. And it is easy to guess the direct uses of this property.

How do I use it in TV3D? And what for exactly?

  • It’s available in TVMathLibrary, the operation in 6.5 is called TVVec3Cross. As for its uses... A section break please.

By example

Align mesh to landscape

Here’s something that is heard every once in a while in the forum : “How do I align a mesh to the landscape?”

There is a trigonometry approach. There always is a trig approach, with tangents and arc-tangents, sinus and cosinus, pythagoras here and there and so on. But there is also a simpler matrix-based approach!

What do we want to do?

  • We want to build a rotation matrix that rotates the mesh so that it’s aligned to the landscape.

What do we have in-hand?

  • We have the mesh, its position on the landscape and the landscape itself.

What tools do we have, and what do they do?

  • The cross product, and it provides the remaining vector of the rotation matrix if we have the other two.

How can we get those two vectors?

What are those again? The Up vector, the Right vector and the Forward vector.

  • The destination Up vector is the landscape normal where the mesh stands!
  • The destination Right and Forward vectors should be as close as possible to the current vectors, since we don’t want to rotate the mesh around the Y axis, or as little as possible.
What are the operands of the cross product then?

Like in many situations, we have one fixed vector, and two tentative vectors. We have two choices :

  • Work with Right and obtain Forward;
  • Work with Forward and obtain Right.

Since the current Forward and Right vectors (from the current rotation matrix) are orthogonal, taking one or the other will give the same result.

I chose to work with Forward since it’s more intuitive; we want to look into the same direction as before, as much as possible.

C# version :

// Get the landscape normal, store it in the top vector
TV_3DVECTOR TopVector = Landscape.NormalAt(Position.x, Position.z);
// Get the current rotation matrix's vector -- could also be done with GetBasisVectors
TV_3DMATRIX CurrentRotationMatrix = Mesh.RotationMatrix();
// Get the Forward vector out of the matrix, store it in the tentative Forward vector
TV_3DVECTOR TentativeForwardVector = new TV_3DVECTOR(CurrentRotationMatrix.m31, CurrentRotationMatrix.m32, CurrentRotationMatrix.m33);
TV_3DVECTOR RightVector = new TV_3DVECTOR(), ForwardVector = new TV_3DVECTOR();
// Use the cross product to get the actual Right vector
Maths.TVVec3Cross(ref RightVector, TopVector, TentativeForwardVector);
// Re-use the cross product to get the actual Forward vector; one that is really orthogonal to the two others
Maths.TVVec3Cross(ref ForwardVector, RightVector, TopVector);
// Normalize the two calculated vectors to avoid a scaling rotation matrix!
Maths.TVVec3Normalize(ref RightVector, RightVector);
Maths.TVVec3Normalize(ref ForwardVector, ForwardVector);
// Construct the rotation matrix from the vectors
CurrentMatrix.m11 = RightVector.x;
CurrentMatrix.m12 = RightVector.y;
CurrentMatrix.m13 = RightVector.z;
CurrentMatrix.m21 = TopVector.x;
CurrentMatrix.m22 = TopVector.y;
CurrentMatrix.m23 = TopVector.z;
CurrentMatrix.m31 = ForwardVector.x;
CurrentMatrix.m32 = ForwardVector.y;
CurrentMatrix.m33 = ForwardVector.z;
// And assign it
Mesh.RotationMatrix = CurrentMatrix;

VB.Net version (thanks to Hawthorne!) :

Function BindMatrixToLand(ByVal InMatrix As TV_3DMATRIX, ByVal Scale As TV_3DVECTOR, ByVal Position As TV_3DVECTOR) As TV_3DMATRIX
	With InMatrix
		Dim TopVector As TV_3DVECTOR = TVLandscapeObject.GetNormal(.m41, .m43)
		Dim TentativeForwardVector As New TV_3DVECTOR(.m31, .m32, .m33)
		Dim RightVector As New TV_3DVECTOR()
		Dim ForwardVector As New TV_3DVECTOR()
		MathLibrary.TVVec3Cross(RightVector, TopVector, TentativeForwardVector)
		MathLibrary.TVVec3Cross(ForwardVector, RightVector, TopVector)
		MathLibrary.TVVec3Normalize(RightVector, RightVector)
		MathLibrary.TVVec3Normalize(ForwardVector, ForwardVector)
		.m11 = RightVector.x * Scale.x
		.m12 = RightVector.y * Scale.y
		.m13 = RightVector.z * Scale.z
		.m21 = TopVector.x * Scale.x
		.m22 = TopVector.y * Scale.y
		.m23 = TopVector.z * Scale.z
		.m31 = ForwardVector.x * Scale.x
		.m32 = ForwardVector.y * Scale.y
		.m33 = ForwardVector.z * Scale.z		
		.m41 = Position.x
		.m42 = Position.y
		.m43 = Position.z
	End With
	Return InMatrix
End Function

Note : The VB.Net version takes scale and position components in parameters so that you can keep them after the matrix transformation, and use SetMatrix instead of SetRotationMatrix (which is unavailable with TVMiniMesh).

And there you have it; your mesh is aligned to your landscape. That is to say how magic matrices are.

A couple of oddities worth noting :

  • We need to re-cross the tentative vector to get its real value. Else you’ll end up with a non-orthogonal rotation matrix, and a skewed mesh.
  • The order of the arguments in the cross products defines the result’s sign. In other words :
Vector1 X Vector2 = -(Vector2 X Vector1)
  • So unless you want to end up with Left, Bottom or Backward vectors, here is the cross product order to follow :
Top X Forward = Right
Right X Top = Forward
Forward X Right = Top


tutorialsarticlesandexamples/matrices_and_you3.txt · Last modified: 2013/11/22 13:32