PS2 Linux Programming
Perspective Correct Texture Mapping (STQ)
Introduction
In this tutorial STQ texture coordinates are used in order to provide perspective correct texture mapping of a quad. Processing of the texture coordinated is undertaken by the Vector Unit.
Perspective texture distortion is illustrated in figure 1 below.
Figure 1
The basic problem is that uniform steps in screen space do not equate to uniform steps in world coordinates. Since texturing is performed in screen space, after the geometry has been transformed, the texture (which should be correct in world space) becomes distorted.
The GS has the ability to correct texture perspective distortion. This is done by giving the GS texture coordinates (S, T, Q) for each vertex. S, T and Q are defined below:
S = s/W
T = t/W
Q = 1/W
The s and t values are the texture coordinates in texture space measured from the top left hand corner of the texture (similar to the use of u and v texture coordinates) where both s and t are floating point numbers which range from 0.0f to 1.0f. (0.0f, 0.0f) is the top left hand corner of the texture and (1.0f, 1.0f) is the bottom right hand corner of the texture. W is the homogeneous vertex coordinate resulting from the application of the perspective transformation matrix to a vertex.
The untransformed vertex data is stored in the static packet area as before. Each vertex now has STQ texture coordinates, colour and position associated with it. The structure of the vertex data is given below:
// Add the quad
VIFStaticDMA.AddVector(Vector4(0, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-3.0f, 3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(3.0f, 3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-3.0f,-3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(0, 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(-3.0f,-3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1, 0, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(3.0f, 3.0f, 0.0f, 1.0f)); // Vert (xyzw)
VIFStaticDMA.AddVector(Vector4(1 , 1, 1, 0)); // TexCoord (STQ)
VIFStaticDMA.AddVector(Vector4(0x80, 0x80, 0x80, 0x80)); // Colour (RGBA)
VIFStaticDMA.AddVector(Vector4(3.0f, -3.0f, 0.0f, 1.0f)); // Vert (xyzw)
The STQ vertex data is specified in floating point format as a four element vector. Only the first three parameters are of interest, the first being s, the second being t and the third being q. Notice that q=1 for all of the vertices. The true value of q will be calculated during the transformation process by VU1. Also notice that the fourth parameter of the STQ vector (the w component) is not being used. This can be useful for transferring additional configurational information to the VU.
A new section of code has been added to the VCL to process the texture coordinates. These are the last three lines of the code repeated below.
MatrixMultiplyVertex Vert, fTransform, Vert
Div q, vf00[w], Vert[w] ; Work out 1.0f / w
mul.xyz Vert, Vert, q ; Project the vertex by dividing by W
lq STQ, StartSTQ(iVertPtr) ; Load the texture coordinates
mul STQ, STQ, q ; Divide by W
sq STQ, StartSTQ(iVertPtr) ; Store the texture coordinates back
Firstly the vertex is transformed by the transformation matrix as before. Then q, which equals 1/w is computed and stored in the special q register within the VU. The q value is then used to process the texture coordinate. Each of the supplied stq texture coordinates are divided by w (or multiplied by q) to generate the correct texture coordinate data for the GS. The data is then written back to VU memory.
When building the GIFTag, the texture coordinate setting being used is now STQ (PRIM_FST_STQ). When the STQ data is sent to the GIF, the Q value is stored in an internal GIF register and is not sent to the GS. When the colour data is sent to the GIF, the currently stored Q value within the GIF is sent to the GS as well as the RGBA values.
The functional operation of the tutorial code is identical to that of the previous tutorial. However, when observing the texture on the quad as it rotates it can be seen that the texture displays no distortion.
This tutorial has demonstrated the use of perspective correct texture mapping using VU1 to process the texture coordinates.
Dr Henry S Fortuna
University of Abertay Dundee