D3DXQUATERNION-Based Camera for Flight Simulations

Tuesday Oct 12th 2004 by Ejaz Anwer
Share:

Learn about a DirectX Quaternion-based camera class to implement the camera modal in 3D flight simulations.

Introduction

CCamera is a DirectX Quaternion-based camera class for flight simulations. If you don't know what Quaternion is and why to use it, then I would recommed to go through http://www.cprogramming.com/tutorial/3d/quaternions.html so that you can have a good idea what a Quaternion really is.

After going through the above link, you might think that: Do I have to write my own Quaternion class to implement Quaternion in my application/game/game engine?

Details

Well, if you are using DirectX 9.0, don't worry; Microsoft has already taken care of all the Quaternion stuff for you and has provided you with D3DXQUATERNION structure along with a certain set of APIs that you can use to manipulate the Quaternion the way you want.

Based on D3DXQUATERNION, CCamera is a Camera class that can be used for flight simulations. Before we proceed, let me explain some terms that will be used later on; this a good time to discuss them.

• Roll: Roation around Z-Axis i.e. Rotation around the front-to-back axis
• Pitch: Rotation around X-Axis i.e. Rotation around the side-to-side axis
• Yaw: Rotation around Y-Axis, i.e. Rotation around the vertical axis

To have a good understanding of them, I found a very good example (I don't know where, but it really helped). Look at the front wall where you are sitting and consider that three vectors are coming out of your head. One is going from your right ear onwards, one from your head upward, and one from your nose away.

Now, if you rotate the vector that is coming out of your right ear (X-Axis), your focus will shift from the wall's current location amd will shift to the new location. This is Pitch. Similarly, if you you rotate the vector that is coming from your nose, it is roll; if you rotate the vector coming out of your head, it's Yaw. By varying these three vectors, you can change the orientation of your camera.

• Move: Translate Forward-Backward
• Strafe: Translate Left-Right
• Up: Tanslate Up-Down
• Slerp: Spherical Linear Interpolation. Interpolating between two orientations uses quaternions in a smooth way, depending upon the angle to interpolate.

Okay, now let's move on to CCamera. CCamera aggregates D3DXQUATERNION for the rotiaon purposes, D3DXVECTOR3 to the position management, in 3D space. To implement CCamera, create an object of it, like in the sample

`wiCam::CCamera TheCamera;`

and before rendering your scene, manipulate the camera orientation. You can see that in Display(), in which the scene is being rendered. The effect of your implementation will be calculated in the aggregated quaternion/vector and when you extract the view matrix to render, the overall effect will be applied to the view matrix and will be returned to you, like so:

```   // Update the view matrix representing the cameras
// new position/orientation.

D3DXMATRIX V = *TheCamera.GetViewMatrix();
Device->SetTransform(D3DTS_VIEW, &V);
```

and GetViewMatrix is implemented as

```const D3DXMATRIX * CCamera::GetViewMatrix()
{
if (m_bNeedUpdated)
{
Update();
}

return &m_matView;
}

void CCamera::Update()
{
// 1) Build a new view matrix

// 1.1) First calcuate Translation
D3DXMATRIX matTranslation;

D3DXMatrixTranslation(  &matTranslation ,
-m_vectPosition.x ,
-m_vectPosition.y ,
-m_vectPosition.z );

// 1.2) Now calculate rotation, by taking the conjucate of the
// quaternion
D3DXMATRIX matRotation;
D3DXMatrixRotationQuaternion( &matRotation,
&D3DXQUATERNION( -m_quatOrientation.x ,
-m_quatOrientation.y ,
-m_quatOrientation.z ,
m_quatOrientation.w ));

// 2) Apply rotation & translation matrix at view matrix
D3DXMatrixMultiply(&m_matView , &matTranslation , &matRotation );

// 3) Set flag to false, to save CPU
m_bNeedUpdated = false;
}
```

To change the camera orientation, you can use the public interface methods, as shown here:

```if( KEY_DOWN('W') ) TheCamera.Move( 1.0f * timeDelta);   // Forward
if( KEY_DOWN('S') ) TheCamera.Move( -1.0f * timeDelta);  // Backward
if( KEY_DOWN('A') ) TheCamera.Strafe(-1.0f * timeDelta); // Left Side
if( KEY_DOWN('D') ) TheCamera.Strafe(1.0f * timeDelta);  // Right Side
if( KEY_DOWN('R') ) TheCamera.Up(1.0f * timeDelta);      // Upward
if( KEY_DOWN('F') ) TheCamera.Up(-1.0f * timeDelta);     // Downward
if( KEY_DOWN('B') ) TheCamera.SetSpeed(++fSpeed);        // Increase
// Translation
// Speed
if( KEY_DOWN('V') ) TheCamera.SetSpeed(--fSpeed);        // Decrease
// Translation
// Speed
if( KEY_DOWN('J') ) TheCamera.SetRPM(++fRPM);            // Increase
// Rotation
// Per Minute
if( KEY_DOWN('K') ) TheCamera.SetRPM(--fRPM);            // Decrease
// Rotation
// Per Minute
if( KEY_DOWN('N') ) TheCamera.Roll(0.02f);               // Roll left
// side
if( KEY_DOWN('M') ) TheCamera.Roll(-0.02f);              // Roll right
// side
if( KEY_DOWN(VK_UP)) TheCamera.Pitch(0.02f);             // Pitch
// upward
if( KEY_DOWN(VK_DOWN)) TheCamera.Pitch(-0.02f);          // Pitch
// downward
if( KEY_DOWN(VK_LEFT)) TheCamera.Yaw(-0.02f);            // Yaw Sideways
if( KEY_DOWN(VK_RIGHT)) TheCamera.Yaw(0.02f);
```

If you run the sample, press the space bar and keep holding the key; you'll find that the camera rotates at your back. Well, this is Slerp. You can adjust its speed as well. For the sake of this article, I've hardcoded a target quaternion, and calculated the slerp so that you can see its implementation and execution, In real flight simulation, you'll have to get the target quaternion from your target and then you'll be able to implement Slerp between your current orientation and the target orientation.

Other then that, the rest of the code implements the DirectX and some utility functions, which has nothing much to do with the camera. The code is copy right un-protected and you can use it freely. If you use it, do let me know about that. Have fun.