XNA--Camera

          Depending on the genre of game that you’re creating, you might want to use a different type of camera, such asa fixed-position camera, a first-person camera, a third-person camera, a realtime strategy (RTS) camera, and so on. With so many different types of cameras, it is helpful to create a basic camera that can be extended to create more specific types of cameras.

          The camera’s frustum is defined by the camera’s view and projection matrices,

Camera Perspective Projection

           The camera frustum is specified by the viewing angle of the camera and the near and far clipping planes. You’ll create the projection matrix in theSetPerspectiveFovmethod (given this name because the camera’s field of view partly defines the viewing volume). You’ll also define the Projection property, which allows your program to get the projection matrix.

          Finally, inside the UpdateProjection method, you generate the new perspective projection matrix using theCreatePerspectiveFieldOfView method of XNA’s Matrix class.

// Perspective projection parameters
float fovy;
float aspectRatio;
float nearPlane;
float farPlane;
// Matrices and flags
protected bool needUpdateProjection;
protected bool needUpdateFrustum;
protected Matrix projectionMatrix;
// Get the camera projection matrix
public Matrix Projection
{
    get
    {
         if (needUpdateProjection) UpdateProjection();
          return projectionMatrix;
     }
}
// Set the camera perspective projection
public void SetPerspectiveFov(float fovy, float aspectRatio, float nearPlane,
float farPlane)
{
   this.fovy = fovy;
   this.aspectRatio = aspectRatio;
   this.nearPlane = nearPlane; 
   this.farPlane = farPlane;
   needUpdateProjection = true;
}
// Update the camera perspective projection matrix
protected virtual void UpdateProjection()
{
    // Create a perspective field of view matrix
    projectionMatrix = Matrix.CreatePerspectiveFieldOfView(
    MathHelper.ToRadians(fovy), aspectRatio, nearPlane, farPlane);
    needUpdateProjection = false;
    needUpdateFrustum = true;
}

Camera View (Position and Orientation)

       A camera is not defined solely by its frustum. You also need to specify where to position your camerain your 3D world, as well ashow to orient it. The camera’s position and orientation in the world are defined by the view matrix created in this section. You’ll create theSetLookAtmethod to set the camera view matrix, and the View property to retrieve it.By allowing your game to retrieve both the view and projection matrix, you make it possible for XNA to transform all 3D objects to your 2D screen.

        In order to create a view matrix using the Matrix.CreateLookAt method, you need to know three camera vectors (or directions):the heading (forward) vector, the strafe (right) vector, and the up vector. These vectors uniquely define the orientation of any object in 3D space. The SetLookAt method calculates these three vectors, starting from the camera’s position, its target, and its up vector.

// Position and target
Vector3 position;
Vector3 target;
// Orientation vectors
Vector3 headingVec;
Vector3 strafeVec;
Vector3 upVec;
// Matrices and flags
protected bool needUpdateView;
protected bool needUpdateFrustum;
protected Matrix viewMatrix;
// Get the camera view matrix
public Matrix View
{
    get
    {
        if (needUpdateView) UpdateView();
        return viewMatrix;
     }
}
// Set the camera view
public void SetLookAt(Vector3 cameraPos, Vector3 cameraTarget, Vector3 cameraUp)
{
    this.position = cameraPos;
    this.target = cameraTarget;
    this.upVec = cameraUp;
    // Calculate the camera axes (heading, upVector, and strafeVector)
    headingVec = cameraTarget - cameraPos;
    headingVec.Normalize();
    upVec = cameraUp;
    strafeVec = Vector3.Cross(headingVec, upVec);
    needUpdateView = true;
}
// Update the camera view
protected virtual void UpdateView()
{
    viewMatrix = Matrix.CreateLookAt(position, target, upVec);
    needUpdateView = false;
    needUpdateFrustum = true;
}
Camera Coordinate System
       Every time you change the camera’s configuration through the SetLookAt method, you need to calculate the three camera coordinate system vectors: its heading (z axis), strafe (x axis), and up (y axis).

You can calculate the camera vectors as follows:
         Heading: The heading vector is the direction from the camera’s position to its target position. It describes the direction the camera is facing. You can calculate this direction by subtracting the camera’s position from its target position.
        Up: The up vector defines the camera’s up direction and is used to orient the camera. For example, you can use the vector(0, 1, 0) to orient the camera up vector as the world y axis.

       Strafe: The strafe vector is the vector that isperpendicular to the heading and up vectors. This can be found by using the vector cross-product operation, which calculates a vector that is perpendicular to two other vectors at the same time. The Cross method of XNA’s Vector3 class performs a cross-production operation. Note that the vectors used in the cross-product operation must be unitary vectors (or you must normalize the resulting vector after the operation), and the order in which they are passed to the Cross method changes the direction of the resulting vector.

Camera Frustum

     Using the XNA BoundingFrustum class, you already have methods to check whether objects are inside the frustum, which will tell you whether they are inside or outside the sight of the camera.

public BoundingFrustum Frustum
{
get
{
     if (needUpdateProjection) 
         UpdateProjection();
      if (needUpdateView)
           UpdateView();
      if (needUpdateFrustum) 
           UpdateFrustum();
      return frustum;
}
}
protected virtual void UpdateFrustum()
{
     frustum = new BoundingFrustum(viewMatrix * projectionMatrix);
     needUpdateFrustum = false;
}

A Third-Person Camera

           In this section, you’ll extend the BaseCamera class from the previous section to create a more specific type of camera: a third-person camera. For this type of camera, you’ll create a class named ThirdPersonCamera, which inherits from the BaseCamera class. The third-person camera’s  goal is to follow an object while it moves, and the distance at which the camera follows an object must be variable. Otherwise, it would appear that the object is bound to the camera, resulting in jerky camera movement.

         To make the camera follow an object—for example, the player-controlled character—you need to define some parameters, such as the following:
            • The chase position, which is the position of the target object the camera must follow
         • The chase direction, which is the direction the camera should move to in order to reach the target object

         • The chase speed
         • The chase distance, which is the distance between the camera and the chase position

// Chase parameters
        float desiredChaseDistance;
        float minChaseDistance;
        float maxChaseDistance;
        float chaseSpeed;
        private Vector3 chasePosition;
        public Vector3 ChasePosition
        {
            get { return chasePosition; }
            set { chasePosition = value; }
        }
        private Vector3 chaseDirection;
        public Vector3 ChaseDirection
        {
            get { return chaseDirection; }
            set { chaseDirection = value; }
        }
        public void SetChaseParameters(float chaseSpeed,float desiredChaseDistance, float minChaseDistance, float maxChaseDistance)
        {
            this.chaseSpeed = chaseSpeed;
            this.desiredChaseDistance = desiredChaseDistance;
            this.minChaseDistance = minChaseDistance;
            this.maxChaseDistance = maxChaseDistance;
        }
            Every time the camera is updated, its position needs to be recalculated. The ideal, new camera position is equal to the camera’s chase position, minus the chase direction, multiplied by the chase distance, as shown in Figure 10-2. The desired new camera position would be the camera’s final position if it were placed at a fixed distance from the chase position. However, to allow the camera to move smoothly, the distance between the camera and the chase position may vary between a minimum and maximum range (defined in the attributes minChaseDistance and maxChaseDistance).
           Vector3 targetPosition = chasePosition;
        Vector3 desiredCameraPosition = chasePosition –chaseDirection * desiredChaseDistance;
        float interpolatedSpeed = MathHelper.Clamp(chaseSpeed * elapsedTimeSeconds, 0.0f, 1.0f);
        desiredCameraPosition = Vector3.Lerp(position, desiredCameraPosition,interpolatedSpeed);

private void UpdateFollowPosition(float elapsedTimeSeconds,bool interpolate)
        {
            Vector3 targetPosition = chasePosition;
            Vector3 desiredCameraPosition = chasePosition- chaseDirection *
            desiredChaseDistance;
            if (interpolate)
            {
                float interpolatedSpeed = MathHelper.Clamp(
                chaseSpeed * elapsedTimeSeconds, 0.0f, 1.0f);
                desiredCameraPosition = Vector3.Lerp(position,
                desiredCameraPosition, interpolatedSpeed);
                // Clamp the min and max follow distances
                Vector3 targetVector = desiredCameraPosition - targetPosition;
                float targetLength = targetVector.Length();
                targetVector /= targetLength;
                if (targetLength < minChaseDistance)
                {
                    desiredCameraPosition = targetPosition +
                    targetVector * minChaseDistance;
                }
                else if (targetLength > maxChaseDistance)
                {
                    desiredCameraPosition = targetPosition +
                    targetVector * maxChaseDistance;
                }
            }
            // Needed to recalculate heading, strafe, and up vectors
            SetLookAt(desiredCameraPosition, targetPosition, upVec);
        }
           Another feature you’ll add to the camera is the ability to rotate around its target. For that feature, you’ll want a way to define the maximum rotation speed of the camera and the current rotation of the camera. Also, because you want your camera’s rotation to start and stop smoothly, you’ll need to keep track of the current rotational speed.

        // Maximum allowed rotation
        public static float MAX_ROTATE = 30.0f;
       // Current rotation angles over the camera axes (heading, up, and strafe)
        Vector3 eyeRotate;
        // Rotation velocity over the camera axes
        Vector3 eyeRotateVelocity;
public Vector3 EyeRotateVelocity
        {
            get { return eyeRotateVelocity; }
            set { eyeRotateVelocity = value; }
        }
         The eyeRotate vector will store the current camera rotation, where the X, Y, and Z components of this vector represent the angle of the rotation around the camera’s strafe, up, and heading axes. Finally, the eyeRotateVelocity vector will store the velocity at which the camera rotation angle is updated.

protected override void UpdateView()
        {
            Vector3 newPosition = position - target;
            // Calculate the new camera position, rotating it around its axes
            newPosition = Vector3.Transform(newPosition,
                                            Matrix.CreateFromAxisAngle(upVec, MathHelper.ToRadians(eyeRotate.Y)) *
                                            Matrix.CreateFromAxisAngle(strafeVec, MathHelper.ToRadians(eyeRotate.X)) *
                                            Matrix.CreateFromAxisAngle(headingVec, MathHelper.ToRadians(eyeRotate.Z)));
            viewMatrix = Matrix.CreateLookAt(newPosition + target,target, upVec);
            needUpdateView = false;
            needUpdateFrustum = true;
        }
Updating the Camera
       You must implement a final method in the ThirdPersonCamera class: the Update method, as it was defined as an abstract method in the BaseCamera class earlier in this chapter. This Update method is called every time the camera needs to be updated. Inside the Update method, you need to update the camera’s attributes, as well as call the methods used to update the camera. The UpdateView and UpdateProjection methods use the camera’s attributes to update the camera’s view and projection matrix. These methods are called only when the view and projection matrices are retrieved through properties and need to be updated.
bool isFirstTimeChase = true;
public override void Update(GameTime time)
        {
            float elapsedTimeSeconds =
            (float)time.ElapsedGameTime.TotalSeconds;
            // Update the follow position
            UpdateFollowPosition(elapsedTimeSeconds, !isFirstTimeChase);
            if (isFirstTimeChase)
            {
                eyeRotate = Vector3.Zero;
                isFirstTimeChase = false;
            }
            // Calculate the new rotation based on the rotation speed
            if (eyeRotateVelocity != Vector3.Zero)
            {
                eyeRotate += eyeRotateVelocity * elapsedTimeSeconds;
                eyeRotate.X = MathHelper.Clamp(eyeRotate.X,
                -MAX_ROTATE, MAX_ROTATE);
                eyeRotate.Y = MathHelper.Clamp(eyeRotate.Y,
                -MAX_ROTATE, MAX_ROTATE);
                eyeRotate.Z = MathHelper.Clamp(eyeRotate.Z,
                -MAX_ROTATE, MAX_ROTATE);
                needUpdateView = true;
            }
        }






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值