Building the Skybox


Building the Skybox

Now that we have a class that defines and handles a given face of the skybox, we are ready to construct the box itself. Listing 4 “6 shows the definition of the SkyBox class. The box is composed of the six faces of the cube, and there is also an enumeration to describe each of the six faces. The enumeration value is passed into the constructor of each face so that it knows its position within the cube. This defines the correct vertices for that face.

Listing 4.6: SkyBox Class Definition
start example
 public class SkyBox : Object3D, IDisposable  {  #region Attributes      private SkyFace[] m_faces = new SkyFace[6];      public enum Face { Top, Bottom, Front, Right, Back, Left }  #endregion 
end example
 

The constructor for the SkyBox accepts six arguments. Each argument is a string containing the complete path to a texture file that will be used for one of the box faces. These strings are used along with values from the face enumeration to construct each of the Sky Face members . Listing 4 “7 shows the constructor and Figure 4 “1 shows the six image files that will be used for the six textures.

click to expand
Figure 4 “1: Skybox faces
Listing 4.7: SkyBox Constructor
start example
 public SkyBox(string sFront, string sRight, string sBack, string sLeft,    string sTop, string sBottom) : base("SkyBox")  {      // Create the faces for the box.      m_faces[0] = new SkyFace(sFront, Face.Front);      m_faces[1] = new SkyFace(sLeft, Face.Right);      m_faces[2] = new SkyFace(sBack, Face.Back);      m_faces[3] = new SkyFace(sRight, Face.Left);      m_faces[4] = new SkyFace(sTop, Face.Top);      m_faces[5] = new SkyFace(sBottom, Face.Bottom);  } 
end example
 

The Dispose method for the class (shown in Listing 4 “8) calls the Dispose method for each of the faces. This ensures that the faces have the chance to free the textures and buffers as described earlier.

Listing 4.8: SkyBox Dispose Method
start example
 public override void Dispose()  {      for (int i = 0; i < 6; i++)      {          m_faces[i].Dispose();      } } 
end example
 

The heart of the class is its Render method shown, in Listing 4 “9. The SkyBox object has several unique features that will not be found in any other object that will be rendered. The viewpoint must always be in the center of the box; therefore the box must move as the camera moves. Even though the box is built with a finite size , it must appear to be a very long distance away. To give the illusion that the box is very far away, we will turn off writing to the Z-buffer. By doing this, everything else that is rendered will be drawn on top of the box and appear to be closer.

Listing 4.9: SkyBox Render Method
start example
 public void Render(Camera cam)  {     try       {       // Set the matrix for normal viewing.       Matrix matWorld = new Matrix();       matWorld = Matrix.Identity;       // Center view matrix for skybox.       Matrix matView;       matView = cam.View;       matView.M41 = 0.0f;       matView.M42 =   0.3f;       matView.M43 = 0.0f;       CGameEngine.Device3D.Transform.View = matView;       CGameEngine.Device3D.Transform.World = matWorld;       CGameEngine.Device3D.RenderState.ZbufferWriteEnable = false;       CGameEngine.Device3D.RenderState.CullMode =           Microsoft.DirectX.Direct3D.Cull.None;        // Pick faces based on camera attitude.        if (cam.Pitch > 0.0f)        {           m_faces[4].Render();        }        else if (cam.Pitch < 0.0f)        {           m_faces[5].Render();        if (cam.Heading > 0.0f &&cam.Heading < 180.0) m_faces[1].Render();        if (cam.Heading > 270.0f   cam.Heading < 90.0) m_faces[0].Render();        if (cam.Heading > 180.0f && cam.Heading < 360.0) m_faces[3].Render();        if (cam.Heading > 90.0f && cam.Heading < 270.0) m_faces [2], Render ();       // Restore the render states.       CGameEngine.Device3D.Transform.View = cam.View;       CGameEngine.Device3D.RenderState.ZbufferWriteEnable = true;  }  catch (DirectXException d3de)  {      Console.AddLine("Unable to render skybox ");     Console.AddLine(d3de.ErrorString);  }  catch (Exception e)  {     Console.AddLine("Unable to render skybox "); 
end example
 

The method begins by creating a world matrix for itself that is set to the identity matrix. This ensures that the box (whose vertices are all offset around a zero position) is not translated from that position. Copying the camera s matrix and adjusting the position down slightly creates a view matrix. Experience has shown me that by adjusting the position down, we get a better-looking horizon than if we were dead center in the box. These matrices are passed to the device, and the Z-buffer write enable flag is cleared in the render state so that the buffer will not be altered as we render the box. The culling in the render state is turned off by setting the state to None . Since we are only drawing the few faces that are in view, there is no sense having the device check for face culling. The pitch and heading of the camera are checked, and only the faces of the box that might be visible are rendered. Once the faces have been rendered, the view matrix and Z-buffer render states are restored to their normal conditions.

This completes the SkyBox class. If we run the game now, we see something like Figure 4 “2. We can move the camera using our mouse, and can look in all directions. Because we are near the center of the box, it appears that we are floating above the ground. As we turn full circle, it appears that we can see to the horizon in all directions. Mission accomplished.

click to expand
Figure 4 “2: Skybox only



Introduction to 3D Game Engine Design Using DirectX 9 and C#
Introduction to 3D Game Engine Design Using DirectX 9 and C#
ISBN: 1590590813
EAN: 2147483647
Year: 2005
Pages: 98

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net