Milan Nankov – Blog

Unit Testing Games (Part 1) – Vectors and Transformations 2008/11/25

Test driven development and testing in general are mandatory techniques if you are serious about the code that you create. That is especially true in game development where almost every piece of code is very complex. In this first post about testing I will give you a little insight about testing vectors and transformations.

The code that I am going to provide is written for the XNA framework and the Visual Studio testing framework but the concepts that are described in this post can be applied to any game development and testing platforms.

In many cases ensuring that a vector is the one we expect is not as straight forward as writing:

To illustrate the problem imagine that we have a vector (0, 0, -200), we perform some operations that transform the vector by rotating it around the Y axis by 90 degrees, and we want to assert that the operation is done correctly. You might be baffled to find that after the transformation the vector does not equal exactly (-200, 0, 0), but rather something like (-200, 0, 0.000008742278). This “error” has to do with floating-point numbers and round-off errors. So in order to be able to test our code we have to allow for such imprecision.

The Visual Studio testing framework provides a method that we can use to compare floating-point numbers with a specified tolerance. We just have to build on top of that in order to create a method that we can use for vector comparison. Let’s call the method VectorsAreEqual and inplement it in a class called MathAssert.

The method is very simple and probably the only question remaining is what a good value for the delta is? The value should be as precise a possible, but at the same time not too precise so it can eliminate the floting-point errors. In my tests I am using a value of 0.00001 which in my opinion is good enough.

Now that we have created our method we can easily compare the vectors (-200, 0, 0.000008742278) and (-200, 0, 0) and assert that they are equal:

Transformations are another fundamental part of game programming and being able to test them is crucial. If you are building a scene graph, for example, you probably want to make sure the when a parent node rotates all of its child nodes rotate as well. So we need a way to verify that the resulting transformations are computed as expected. As you might know transformations are composed of linearly independent vectors called basis vectors. A 2D transformation matrix has 2 basis vectors, while a 3D matrix has 3.

2D Transformations

The illustrations above show 3 different two-dimensional transformations and their basis vectors. First (on figure 1) we have identity transformation which does not alter vectors in any way. On the second figure we have a transformation that performs 90 degree rotation of vectors. On figure 3 we have a transformation that performs scaling along the X axis.

As you might know every basis vector corresponds to a single axis of the coordinate space that its transformation describes. In figure 1, for example, the first basis vector corresponds to the X axis and the second vector corresponds to the Y axis. Similarly on figure 2 the first basis vector corresponds to the X axis but the difference there is that the X axis of this transformation points up.
In order to test a transformation for correctness we need to assert that the basis vectors are the ones that we expect.

XNA’s Matrix class can give us a lot of information and we can easily get the basis vectors. The three basis vectors are Matrix.Right, Matrix.Up, and Matrix.Forward. So if we expect to have a transformation that would rotate a vector around the Y axis by 90 degrees we would expect to have (-1, 0, 0) for Forward, (0, 0, -1) for Right, and (0, 0, 1) for Up.

So in order to test a transformation we have to test the 3 basis vectors. For convenience we create a a new method called BasisIsCorrect in our MathAssert class:

Now all we have to do to test a transformation is to use this method.

Happy testing.

  • Hristo Deshev

    Great tips!

    Just a small suggestion for your MathAssert.VectorsAreEqual() implementation — use the Assert.AreEqual overloads that take a message to be thrown when the assert fails. This way the client code will get a meaningful exception like “Z coordinates do not match: expected X, actual Y!” instead of the default “Expected X, actual Y.”