PS2 Linux Programming
Putting The 3D Components Together
Introduction
This tutorial will combine
and consolidate many of the methods and techniques that have been introduced
over the previous few tutorials. A view into a 3D world which contains a controllable
textured quad will be configured. This tutorial will illustrate the following
new features and techniques:
·
The operation of the
z-buffer to properly depth sort 3d objects.
·
Clipping of 3d
objects to the view frustum.
·
The effect of
perspective when viewing 3d objects.
·
Perspective texture
distortion when using UV texture coordinates.
·
The use of the SPS2
wrapper class.
At this point in the
tutorial series some changes have been made to the structure and organisation
of the texture and font loading classes (ctexture.cpp/h and font.cpp/h) to
accommodate the use of the SPS2 wrapper class – older versions of these classes
will not work with the example code provided with this tutorial.
Again, it is emphasised
that some of the coding methods implemented here are by no means optimal and/or
efficient. However, as with the previous tutorials, the code is written in a
manner that should allow the reader to understand the methods and techniques
that are being used. It is then up to the reader to develop their own code in a
more efficient and structured manner once the techniques have been understood.
Nothing particularly new
in the way of coding is being introduced in this tutorial but rather it is an
accumulation of the techniques that have been introduced in the three tutorials
“SPS2 Wrapper Class”, “Introducing The Third Dimension” and “Viewing In Three
Dimensions”. These three tutorials should be investigated prior to this one.
In the tutorial code, the
4 vertices of a textured quad will be sent through a 3d graphics pipeline that
is configured with some sensible parameters. A local to world matrix is
configured to position the object in the world, a world to screen (or camera)
matrix is configured to obtain a view into the world, and a perspective
transformation matrix is configured to generate a canonical clipping volume.
Following clipping, a view port transformation matrix is configured to
transform and scale the 3d image onto a 2d screen.
In main.cpp two sprite
structures are declared and suitable values are assigned. The default (x, y,
z,) world position of Sprite[0] is (0, 0, -400) and of Sprite[1] is (0, 0,
-500). Both quads stand up parallel with the (x, y) plane. The camera has a
position of (0, 0, 10) and looks directly at the origin down the -z world axis.
The view to screen matrix
is configured such that the near plane is situated –5 units from the camera,
and the far plane at –1000. The aspect ration of the view is the traditional
4:3 and the field of view is set to 60 degrees.
The view port
transformation matrix is configured with a screen width and height in pixels
that is extracted from the SPS2 manager class. The x and y offset values are
set to 2048. Note that the value of 2048 is chosen to correlate with the frame
buffer arrangement used in the PS2, where the origin of the frame buffers is
situated at the point (2048, 2048) within GSmem. The z buffer resolution is set
to 24 bits which is (1<<24).
Notice also that a signal
handler is being used to capture all signal from the operating system that will
terminate the program. Capturing these signals allows the program to exit
gracefully, release all of the allocated resources and properly shutting down
the controller pad library.
The graphics pipeline
calculations for the textured quads are carried out in the function
BuildSprite2D() contained in the file packet.cpp. Firstly, the local to world
transformation matrix is built from the current position and rotation
parameters for the sprite and this matrix is applied to the untransformed
vertex coordinates to produce the world positions of the vertices. Next the
camera matrix is applied to the vertices to produce their positions in camera
space. The third step is to apply the view to screen transformation matrix which
performs the perspective transformation. Next, the resulting vertices are
divided by their homogeneous W coordinate which maps them and the view frustum
into a cube which extends between –1 and + 1 in all of the three axes. At this
point in the graphics pipeline the vertices can be easily be checked against
the view frustum for clipping purposes. The ClipCheck() function checks to see
if a vertex is within the view frustum: if it is outside of the frustum a
message is printed to the console to indicate that clipping has taken place and
a flag is set in the sprite structure to indicate that this vertex should be
clipped. This clipping flag is subsequently used to set the ADC bit of the XYZ2
vertex data within the graphics primitive data. If the ADC bit is set to 1, the
vertex will not perform a vertex or drawing kick within the graphics processor
and will be clipped out of the scene.
Following clipping, the
view port transformation matrix is applied to the vertex data to yield their
final 2d on screen positions. The textured sprites are then created using this
transformed and clipped vertex data.
On executing the example
code the familiar walking man textured quad will appear in the centre of the
view window with a blue textured tile behind. As stated above, the camera is
situated at (0, 0, 10) and looks directly down the –z axis. The man is
positioned at (0, 0, -400) and the blue square at (0, 0, -500). The movement of
the man is controlled by the control pad connected to port 1 in a similar
manner to in previous tutorials. The left side of the pad controls the three
axes of rotation and the right side of the pad controls the movement of the man
in the direction of each of the local axis. Note that the man movement is in
local axes directions and not in world axis directions – this can get a little
confusing once some rotation has been applied to the man. If for any reason the
man get “lost” on/off screen, pressing down on either of the left or right
analogue sticks will return the man to the default starting position.
Now try and observe the
following features.
·
Move the man to the
edges of the screen/frustum and observe that clipping will occur – polygons
will be clipped and a clipping message will appear on the console.
·
Move the man deeper
into the scene. When the depth of the man exceeds the depth of the blue tile
the man will appear to go behind the tile thus illustrating the effect of the z
buffer.
·
Moving the man closer
and further away from the camera will produce enlargement and reduction of the
image size respectively as expected with the perspective transformation.
·
Bring the man quite
close to the camera then hold down one of the rotation keys. It will be seen
that the texture distorts as it rotates. This is called perspective texture
distortion and is due to the fact that simple UV texture coordinates are being
used. This will be investigated and rectified in the next tutorial.
A simple 3D graphics
pipeline has been configured. Two textured quads have been transformed by the
graphics pipeline and drawn on screen. Several features including z-buffer,
perspective sizing, clipping, perspective texture distortion and movement in
three dimensions have been demonstrated.
Dr Henry S Fortuna
University of Abertay Dundee