PS2 Linux Programming

 

 

Rendering Many Textured, Lit, Clipped Cubes

 

 

Introduction

 

This tutorial demonstrates the rendering of many similar models with the same vertex data. Different textures are used for some of the objects and the tutorial demonstrates uploading and selecting the correct texture. Two texture buffers are used in VRAM to hold the texture data.

 

 

Example Code

 

 

At the start of the program some initialisation of the boxes to be rendered is undertaken. Firstly, three differently coloured textures are loaded into static memory and the variable which tracks the current texture buffer is set to zero. The position vector for 15 boxes are then selected at random, so that the boxes are positioned randomly in front of the camera over a small spread of distance.

 

 

// Load three different textures.

CTexture Tex1, Tex2, Tex3;

Tex1.LoadBitmap("test.bmp");

Tex2.LoadBitmap("test2.bmp");

Tex3.LoadBitmap("test3.bmp");

 

// Two texture buffers, texbuf 0 = 480, texbuf 1 = 496

int iCurrentTexBuf = 0;

 

// Render the box 15 times

int iNumBoxes = 15;

 

// An array of positions of where to draw the box

Vector4 boxPositions[iNumBoxes];

 

//seed the random number generator

srand(time(NULL));

 

// Generate the random positions for all of the boxes.

for(int i = 0; i < iNumBoxes; i++)

{

     boxPositions[i] = Vector4(  8 - (rand() % 16),

                                 8 - (rand() % 16),

                                 8 - (rand() % 16) -12 , 1);

}

 

 

The main render loop is repeated below to illustrate the drawing process.

 

 

 

while(g_bLoop)

{

     // Fire off the previous frame's buffer (or init data if it's the first time)

     VIFDynamicDMA.Fire();

 

     pad_update(PAD_0);

 

     // Set up a world matrix that rotates the cube about it's own axis.

     static float sfRot = 0.0f;

     sfRot += 0.03f;

 

     // Clear the screen

     SPS2Manager.BeginScene();

 

     Matrix4x4 matWorld, matTrans, matRotY, matWVP;

     matRotY.RotationY(sfRot);

 

     // Upload the current texture to the free texture buffer

     Tex1.Upload((iCurrentTexBuf == 0) ? 480 :  496);

     iCurrentTexBuf ^= 1;

     Tex1.Select();

 

     for(int i = 0; i < iNumBoxes; i++)

     {   

          // Change to the second texture

          if(i == 5)

          {

              Tex2.Upload((iCurrentTexBuf == 0) ? 480 :  496);

              iCurrentTexBuf ^= 1;

              Tex2.Select();

          }

          // Then the third

          else if(i == 10)

          {

              Tex3.Upload((iCurrentTexBuf == 0) ? 480 :  496);

              iCurrentTexBuf ^= 1;

              Tex3.Select();

          }

 

          matTrans.Translation(boxPositions[i].x,

                               boxPositions[i].y,

                               boxPositions[i].z);

 

          matWorld = matRotY * matTrans;

          matWVP = matWorld * matViewProj;

 

          // Flush so that we wait for the previous cube to finish rendering

          // before we upload new data into that area of memory.

          VIFDynamicDMA.Add32(FLUSH);

 

          VIFDynamicDMA.AddUnpack(V4_32, 0, 8);

          VIFDynamicDMA.AddMatrix(matWVP);

          VIFDynamicDMA.AddMatrix(matWorld);

          VIFDynamicDMA.DMACall(iCubeAddr);

     }

 

     SPS2Manager.EndScene();

    

     // Check for exit condition

     if((pad[0].buttons & PAD_START)&&(pad[0].buttons & PAD_SELECT)) g_bLoop = false;

}

 

 

After some initialisation the first texture to be used is uploaded into VRAM, then a loop is entered which is repeated for each of the boxes to be drawn. Notice that after drawing 5 boxes the texture is changes and changed again after drawing 10 boxes. The texture is uploaded into alternate texture buffers in this example, although this is not necessary since the uploading and drawing is being done serially. Within the render loop the world transformation matrix for the box is calculated as is the concatenated vertex transformation matrix. Finally, the packet data is added to the dynamic memory. Firstly a “FLUSH” VIF code is added so that the upload process waits until the previous cube has been rendered. This is necessary since the same area of VU memory is being used to upload the data, transform the data and then kick it off to the GIF. Double buffering of VU memory could be used to prevent waiting at this point but this is the subject of a future tutorial. Following the “FLUSH” VIF Code an “”UNPACK” VIF code is added to unpack the vertex transformation matrix and world transformation matrix into VU memory. After adding these two matrices to dynamic memory, the vertex data for the cube to be rendered is called with the appropriate DMA call tag.

 

Notice that the “MSCALL” VIF code to start the VU program running is embedded within the static data packet so that the VU program is executed for each cube being uploaded. A “FLUSH” VIF code is inserted before the “MSCALL” again to ensure the VU is idle before commencing the rendering process.

 

 

Conclusions

 

This tutorial has demonstrated the rendering of several 3D models using vector unit one. The VU program is executed once for each model that is uploaded.

 

 

Dr Henry S Fortuna

University of Abertay Dundee

h.s.fortuna@abertay.ac.uk