As I mentioned the other day, I'm doing a little tinkering with C# and XNA for game development. Well, I say game development, so far it's just bashing my head against the issues of working in 3D...

When I can be bothered I like to stick in links to Wikipedia or elsewhere in case people want to follow up terms. Most of the terms I'm using today are embedded deep in two main pages: Rotation Representation and Transformation Matrix. Italic blocks in the text will summarise these things as best I can.

There's a marvellous tutorial for building a game engine at Innovative Games; I've been using pieces of that, although I think I may have to write my own rotation tracking because I can't get the Innovation one to work.

To an extent, I understand transformation matrices. Because 3D graphics are all about manipulating points in three-dimensional space (and eventually mapping the whole lot down onto a plane to fit it onto a monitor) they use transformation matrices a lot; you could probably learn all you really needed to know in a couple of days, but as always I would rather understand than learn by rote in case I need that little extra problem-solving.

The result of multiplying a vector (such as a point in 3D space) by an appropriate matrix is another vector: a different point in space. Matrices exist for all kind of transformations (moving, rotating, reflecting) and multiplying matrices together composes them into the one you'd need to do multiple transformations in a row.

For the current project I'm using models in a 'flatland' scenario: all my 'actors' are confined to two dimensions (at z=0) and only capable of looking around in that plane. With one degree of freedom on rotation I'd like to track it with a scalar (obviously), but since the engine talks in Euler vectors I'd need to convert my fixed-axis rotation into one of those.

A rotation always leaves one line (the axis) in the space intact. This can be represented by a 3-vector, but any length of vector in the right direction will work, so there's only really two degrees of freedom in it. A Euler rotation vector is the unit vector (i.e. length = 1) in the right direction, expanded in length by the desired angle of rotation.

If you didn't follow that, try it again. An Euler vector is the unit vector in the direction of the axis of rotation, multiplied by the angle of rotation. I'm only rotating about the z-axis, with unit vector z = (0,0,1), so my Euler vector should be (0,0,a) for an angle a (I can't be bothered to look for a theta...).

If they work as described, the functions Matrix.CreateFromYawPitchRoll(0,0,a) and Matrix.CreateRotationZ(a) should return the same matrix. To be honest, I haven't checked if they do, but I have established one thing: by the time the engine converts my facing to an Euler vector and then to a matrix, the rotation has changed. It's definitely a rotation about z, but not of angle a.

I'm beginning to wonder whether the matrix from an Euler vector E might be equal to the composition of axis-rotation matrices of the respective components. After all, you rotate about one axis (moving the other two), then the next (which finalises the third) and the final one. I can't prove it, but it feels about right.

In the end I fixed it by overriding the base Draw() (from the engine's Actor class) to create the rotation matrix directly from my facing scalar. As written Actor deals with rotations in a slightly inconsistent way: it converts between matrices and Euler vectors a lot and I seem to have proven that the conversions are capable of breaking rotations (which if true would be a fairly chunky bug in the library, but I'd have to do some more testing before I made that claim).

Along the way I wrote my own CreateRotationZ(a) as a reference and found that it behaves the same as the framework one (which is a vote of confidence for both, although I must admit I had to look up how to build such a matrix). I refreshed my memory on some stuff I should probably still remember and gained more insight into the evil that is computer graphics. I think I'll go and modify Engine.Actor so that it doesn't use Euler vectors...