Let's take a closer look at what is happening when we move the shape that we are drawing.
Within XNA, the position at which we will draw graphics is tracked using the worldmatrix.A
matrix is a set of values, arranged in rows and columns, which can be
applied to the coordinates of our vertices in order to move them around
on the screen.
By combining multiple matrices, movement operations
can be grouped together. For example, we might want to move an object 1
unit to the right and then rotate it by 45 degrees. To do this, we
start with an empty matrix, apply the movement matrix, and then the
rotation matrix. The resulting matrix can be used to transform any
vertex coordinate so that it moves 1 unit to the right and rotates by
45 degrees. There is no need to separately apply the movement and
rotation to each vertex because the transformation matrix will perform
both steps in one calculation.
This allows for transformations to be built up into
greater and greater levels of complexity, but doesn't make calculating
the point onscreen at which each vertex will be drawn any more
difficult or processor-intensive.
1. Setting the Identity Matrix
We have already discussed the fact that XNA
maintains state for lots of properties that affect how it will render
to the screen, and that one of these is the world matrix. Each time we
begin drawing, a world matrix of some description will already be set,
usually from a previous call to Draw, and we won't
necessarily have any idea what it contains. We should therefore always
ensure that the world matrix is set prior to performing any drawing.
In order to reset this matrix to its initial state, we set the matrix to a preset set of values called the identity matrix.
This ensures that any rendering that takes place will initially be
centered at the origin—at coordinate (0, 0, 0)—and will not be rotated
or scaled at all.
We can obtain an identity matrix at any time from the static Matrix.Identity
property. To render objects without any transformation, set it as the
effect's world matrix prior to applying the effect passes.
A square with a width and height of one unit can be seen in Figure 1 after the identity matrix has been applied. It is directly centered on the origin of the coordinate system.
2. Applying Translation Transformations
In the terminology of matrix transformations, moving an object along one or more of the axes is called a translation.
The shape, size, and angle of the object are entirely unchanged; the
object is just moved left or right, up or down, and in or out of the
world to a new position.
Figure 2 shows the effect of a translation matrix. The image on the left shows
the unit square in position after the identity matrix has been loaded;
the image on the right shows the same square after it has been
translated 3 units in the x axis and −2 units in the y axis. (For
simplicity, we will ignore the z axis for the moment, but
transformation along the z axis is achieved in exactly the same way as
for the x and y axes.)
To obtain a translation matrix, call the static Matrix.CreateTranslation
function. This function has a couple of overloads: the first requires
three parameters (the translation distance for the x, y, and z axes,
respectively); the second accepts a single Vector3 parameter.
Both of them have their uses depending on the way you want to specify your movement. The Vector3 approach is very handy because it allows a movement path to be stored and easily transformed into a translation matrix.
NOTE
The Matrix.CreateTranslation function
has two different calling styles: one that returns its generated matrix
as a return value from the function, and another that returns the
matrix in an output parameter. All the other matrix generation
functions share these two approaches.
3. Applying Rotation Transformations
We can also rotate the objects that we draw. Objects can be rotated around any of the three axes, as shown in Figure 3.
Rotation around the x axisis around a horizontal
line drawn across the screen. If you held a sheet of paper in front of
you so that you were looking directly at the flat face of the paper,
rotation on the x axis would rotate the paper so that the bottom edge
was brought toward you and the top edge away, resulting in you looking
at the paper's front edge.
Rotation on the y axis is exactly the same, but rotating around a vertical line.
Z axis rotation is around a line that traces a path
into and out of the screen. This is the axis of rotation that we have
used in the ColoredSquare and NestedSquares example projects.
To obtain a matrix to rotate around one of these axes, call one of the following static functions:
Matrix.CreateRotationX to rotate around the x axis
Matrix.CreateRotationY to rotate around the y axis
Matrix.CreateRotationZ to rotate around the z axis
All three functions require the rotation angle to be passed as a parameter (in radians).
NOTE
Rotating around the z axis will result in counterclockwise rotation. To rotate clockwise, simply negate the rotation angle.
Rotation around other axes can also be achieved by using the Matrix.CreateFromAxisAngle function. It requires two parameters: an axis vector defining the line around which the rotation is to take place and the rotation angle.
To calculate the axis vector, imagine the rotation
axis as a line that passes through the origin point at (0, 0, 0). Then
determine a point that is on that line and provide its coordinate as
the values for the vector.
For example, if we want to rotate around a line that
slopes upward at a 45-degree angle, we can visualize it passing through
the origin point, as shown in Figure 4.
The figure shows a point that has been selected on the line at
coordinate (2, 2, 0), though any point on the line would be fine. This
coordinate forms the values for the axis vector.
One important detail must be taken into account for
the axis vector, however: it must be normalized. If it is not, the
objects will warp and distort as they rotate around it. Listing 1 provides an example of using the CreateFromAxisAngle function to rotate around the line from Figure 4.
Example 1. Rotating around an arbitrary axis
Vector3 axisVector = new Vector3(2, 2, 0);
axisVector.Normalize();
_effect.World = Matrix.CreateFromAxisAngle(axisVector, _angle);