PS2 Linux Programming
Sprite Movement Using Matrices
Introduction
In the previous tutorial “Sprite Movement with Angles” the movement and rotation of a sprite generated using a textured triangle strip was introduced. In this tutorial the position and orientation of the sprite will be manipulated with matrix transformations. Using such transformations, full control of the sprite in three dimensions can be obtained using an orthogonal projection system. The material presented in this tutorial serves as a good introduction to the principles used in 3D graphics and games programming.
The structure used to hold the sprite information is shown below and is similar to the one used in the previous tutorial
typedef struct
{
Vector4 Pos; // position on screen (center)
Vector4 TR, BR, TL, BL; // untransformed coordinates
Matrix4x4 World; // world positional matrix
int w, h; // width and height
int u, v; // offset from texture top left
unsigned char r, g, b, a; // colour and alpha
int FCountMax; // Count to this value for frame change
int FCount; // Frame Counter
int NFrames; // number of animation frames
float Rot; // Rotation angle in radians
} PS2Sprite_t;
The main changes are as follows. The position of the sprite is now held in floating point using a vector class (Vector4). The untransformed coordinates of the sprite, top left (TL), bottom left (BL), top right (TR) and bottom right (BR) are also defined as Vector4, (these can now be stored in three dimensions). This allows for full manipulation of these coordinates in all three dimensions. The sprite now has a world transformation matrix associated with it, defined using the class Matrix4x4.
The rotation equation described in the previous tutorial is the perfect candidate for being turned into a matrix as illustrated below. (x,y,z,1) are the original coordinates which are transformed into (x’,y’,z’,w’).
The main reason why a 4x4 matrix is used is that translation in 3 dimensions cannot be accomplished with a 3x3 matrix so a homogeneous 4x4 matrix must be used instead. The translation matrix is:
(x,y,z,1) are the original coordinates and (x’,y’,z’,w’).are the translated coordinates.
One advantage of using matrices is that they can be multiplied together (concatenated) to form one final matrix that can be used to perform compound transformations. For example, to translate, rotate, then translate again two homogeneous translation matrices can be made as above, and a homogeneous rotation matrix and the three matrices concatenated to form a final transformation matrix.
Much of the initialisation that is performed in main.cpp has been described in previous tutorials and will not be repeated here. Before the render loop is entered, the sprite structure is initialised with appropriate information. Within the render loop, the sprite can be rotated with the left and right buttons and the circle and cross buttons are used to move the sprite backwards and forwards. Notice that the movement and rotation buttons are all pressure sensitive, so the harder the buttons are pressed the greater the associated action.
The GS packets are constructed using the BuildSprite2D() function which takes a pointer to the structure describing the sprite as a parameter. The world transformation matrix is built firstly by producing a rotation matrix from the angle of rotation of the sprite then by filling in the translational components. This matrix is then applied to the untransformed coordinated of the sprite to obtain their world or screen positions. As before, the XYZ data for the registers are constructed from the transformed coordinates of the quad.
On running the program the sprite is drawn on screen as an animated character which walks around the screen under control of the user. Full information on controlling the character is contained within the accompanying readme file.
This tutorial has introduced the concepts associated with movement and rotation under control of user input using transformation matrices. This tutorial provided some prerequisite information fundamental to understanding 3 dimensional graphics and games programming.
Postscript.
In the BuildSprite2D() function try using RotationX() and RotationY() instead of RotationZ() and observe the effect.
Dr Henry S Fortuna
University of Abertay Dundee