Creating the Camera Class


Before you finish this chapter, you implement the camera class. During the Blockers game, you handled all the camera movements (mainly the view transform) on your own. Although it is a completely viable option, it can be a little annoying. Having an abstracted camera class is more natural. Create a new code file (call it camera.cs) in your project, and use the code from Listing 13.11 for the initial implementation.

Listing 13.11. Initial Camera Class
 using System; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace Tankers {     public class Camera     {         // Attributes for view matrix         private Vector3 eyeVector;         private Vector3 lookAtVector;         private Vector3 upVector;         // Matrix for the view transform         private Matrix  viewMatrixTransform;         // Attributes for projection matrix         private float fieldView;         private float aspectRatio;         private float nearPlane;         private float farPlane;         // Matrix for the projection transform         private Matrix  projectionMatrixTransform;     } } 

You probably recognize many of these variables from Blockers when you were setting up the camera for that game. These values map directly to the associated items in the projection and view matrices that you can create. You provide read-only properties for these as well, but there's no need for that information to appear in this book because you can see the code on the included CD for the implementation. Plus, defining read-only properties has been done numerous times, even in this chapter. You only have the properties as read-only so you cannot set them, which makes it pretty difficult to have the camera update any of these variables. Instead, you add two methods (Listing 13.12) to the class to set each of the required variables at the same time.

Listing 13.12. Setting Camera Properties
 public void SetViewParameters( Vector3 vEyePt, Vector3 vLookatPt,                               Vector3 vUpVec ) {     // Set attributes for the view matrix     eyeVector    = vEyePt;     lookAtVector = vLookatPt;     upVector    = vUpVec;     viewMatrixTransform = Matrix.LookAtLH( eyeVector, lookAtVector, upVector );     UpdateViewFrustum(); } public void SetProjParameters( float fFOV, float fAspect, float fNearPlane,                               float fFarPlane ) {     // Set attributes for the projection matrix     fieldView        = fFOV;     aspectRatio     = fAspect;     nearPlane  = fNearPlane;     farPlane   = fFarPlane;     projectionMatrixTransform = Matrix.PerspectiveFovLH( fFOV, fAspect,                                                        fNearPlane, fFarPlane ); } 

For the most part, these methods don't do much more than store the variables passed in and then update the associated matrix, but in reality, they don't need to do anything more. When the view matrix is updated, a method you haven't defined yet is called to update the view frustum.

I discussed the view frustum a few chapters ago, and if you remember, it's essentially the trapezoid area where the camera can see. The idea here is that you don't want to waste time by drawing things the camera obviously cannot see. You create an internal view frustum that in reality is a series of planes that define the boundaries of the frustum, and then you check whether an object is inside that frustum before rendering it. This practice is a quick and efficient way of rendering only objects the camera can see. The implementation of the method appears in Listing 13.13.

Listing 13.13. Creating the Frustum Planes
 public void UpdateViewFrustum() {     // First get the inverse viewproj matrix     Matrix mat = viewMatrixTransform * projectionMatrixTransform;     mat.Invert();     // Get the 8 corners of the view frustum     frustumPoints[0] = new Vector3(-1.0f, -1.0f,  0.0f); // xyz     frustumPoints[1] = new Vector3( 1.0f, -1.0f,  0.0f); // Xyz     frustumPoints[2] = new Vector3(-1.0f,  1.0f,  0.0f); // xYz     frustumPoints[3] = new Vector3( 1.0f,  1.0f,  0.0f); // XYz     frustumPoints[4] = new Vector3(-1.0f, -1.0f,  1.0f); // xyZ     frustumPoints[5] = new Vector3( 1.0f, -1.0f,  1.0f); // XyZ     frustumPoints[6] = new Vector3(-1.0f,  1.0f,  1.0f); // xYZ     frustumPoints[7] = new Vector3( 1.0f,  1.0f,  1.0f); // XYZ     for( int i = 0; i < frustumPoints.Length; i++ )         frustumPoints[i] = Vector3.TransformCoordinate(frustumPoints[i], mat);     // Now calculate the planes     frustumPlanes[0] = Plane.FromPoints(frustumPoints[0], frustumPoints[1],                        frustumPoints[2] ); // Near     frustumPlanes[1] = Plane.FromPoints(frustumPoints[6], frustumPoints[7],                        frustumPoints[5] ); // Far     frustumPlanes[2] = Plane.FromPoints(frustumPoints[2], frustumPoints[6],                        frustumPoints[4] ); // Left     frustumPlanes[3] = Plane.FromPoints(frustumPoints[7], frustumPoints[3],                        frustumPoints[5]); // Right     frustumPlanes[4] = Plane.FromPoints(frustumPoints[2], frustumPoints[3],                        frustumPoints[6] ); // Top     frustumPlanes[5] = Plane.FromPoints(frustumPoints[1], frustumPoints[0],                        frustumPoints[4]); // Bottom } 

To calculate the trapezoid where the frustum will reside, you first get the view and projection matrices and invert them. You then manually set the frustum points as if they were a cube with a length of 1 on each side. You do this because right after, you transform each of the coordinates by the inverted view and projection matrix, which "transforms" them into the trapezoid shape that is the view frustum. You then create the six planes that make up each side of the frustum. You've probably noticed that you never defined the points' and planes' variables being used here, so you want to do that as well:

 // View frustum data private Vector3[] frustumPoints = new Vector3[8]; private Plane[] frustumPlanes = new Plane[6]; 

With your set of planes defined now, how do you actually know whether an object lies within the frustum and should be rendered? There's a simple mathematical formula you can use to see whether a point is outside of a plane. (See Listing 13.14.)

Listing 13.14. Checking Whether an Object Is in Frustum
 public bool ObjectInFrustum(IMoveableObject obj) {     // Check to see if this point is in the plane     foreach(Plane p in frustumPlanes)     {         if (p.A * obj.Position.X + p.B * obj.Position.Y + p.C *             obj.Position.Z + p.D <= (-obj.Radius))         {             // The object is not in the view frustum, do not draw it             return false;         }     }     // By default, the object is in the frustum     return true; } 

Here you see that by default, the object is assumed to be within the frustum (and thus drawn); however, if it can be guaranteed that it is not, it is skipped. Did you notice the type of object passed into this method? This interface isn't defined anywhere but will be used for objects you want to render, particularly those that can be culled. You'll find the definition of this interface in Listing 13.15, and starting next chapter, you'll be using it. The code on the included CD has this interface defined in the game engine source file, but you may put it wherever you find it convenient.

Construction Cue

Culling is the act of not drawing an object that is in the scene because it would not have been seen anyway.


Listing 13.15. The IMoveableObject
 public interface IMoveableObject {     float Radius { get; } // The radius of the moveable object     Vector3 Position { get; } // The current position of the moveable object     Vector3 Direction { get; } // The direction the moveable object                                // is facing or moving     void Update(float elapsedTime, Level currentLevel);     // Update the moveable object     void Draw(GameEngine engine, Camera c); // Render the moveable object } 

Unfortunately, you can't compile this code because you haven't defined the level class yet. That's coming up right about now.



Beginning 3D Game Programming
Beginning 3D Game Programming
ISBN: 0672326612
EAN: 2147483647
Year: 2003
Pages: 191
Authors: Tom Miller

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