D3DXQUATERNION-Based Camera for Flight Simulations

WEBINAR: On-demand webcast

How to Boost Database Development Productivity on Linux, Docker, and Kubernetes with Microsoft SQL Server 2017 REGISTER >

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.

References

www.google.com
www.gamedev.net
Introduction to 3D Game Programming with DirectX 9.0



Downloads

Comments

  • Thank you! Very nice work...

    Posted by Calvin on 01/25/2017 09:11pm

    Thanks

    Reply
  • Slerp

    Posted by brekehan on 07/30/2007 11:29pm

    I don't quite understand the slerp function. It is not discussed in the article. Can someone give me a little insight as to what it does? I googled slerp and all I can get is complicated math explanations. I am trying to understand its purpose. I see it being called when the space bar is hit in the main code, but don't see any comments on the space bar.

    • RE:

      Posted by Ejaz on 07/31/2007 07:48am

      The basic idea of SLERP (Spherical Linear Interpolation) is, generatation of a series of quaternions between two quaternion orientations (which you specify). The series of quaternions will result in smooth motion between the first and end quaternion (something which both the Euler and Axis Angle representation cannot achieve consistently).

      Reply
    • RE: Slerp

      Posted by brekehan on 07/31/2007 07:42am

      That was the mathematical Explanation I was speaking of. It is too hard to understand and I am a Math Minor! I assume it is a calculation between two rotations, but I don't see its use. Why can't I just assign my rotation that I want to achieve in my game? What is the advantage of Slerp? What situations would you need to calculate between two rotations?

      Reply
    • Re: Slerp

      Posted by Ejaz on 07/31/2007 12:41am

      Please take a look at http://en.wikipedia.org/wiki/Slerp

      Reply
    Reply
  • problem with camera circular movement

    Posted by sepul on 03/28/2006 05:13pm

    when I rotate camera circular style (left-top-right-down-...) on each move, the camera gets rotated around z-axis I have the same exact problem with my own class too, do you how can this problem be solved ? thanks

    Reply
  • Excellent example

    Posted by luisleal on 12/09/2004 05:05pm

    This example was clear, woked well and I was able to create a C# version. Thanks

    Reply
  • Test message - Please ignore

    Posted by Brad Jones on 11/19/2004 09:28am

    This is a test message that will be removed.

    Reply
  • A very good tutorial

    Posted by hese on 11/15/2004 07:54am

    This tutorial is very helpful and the sample works fine except when I'm trying to rotate x-axis and y-axis simultaneously. Then the z-axis rotates too. I know it happens because the yaw and the pitch operations are done separately but I don't know how to correct it. I'm also trying to modify the camera class so that I could use it for an object other than the actual camera. My goal is to get the object to rotate and to move towards the camera by using the Slerp function. I modified the SetTransform function's parameters as below. D3DXMATRIX V = *TheObjectCamera.GetViewMatrix(); g_pDevice->SetTransform(D3DTS_WORLD, &V); How should I modify the Camera class or is there an easier way to do this? P.S. I'm programming a space simulation game just for fun.

    • hese

      Posted by hese on 11/22/2004 09:13am

      Yes I would be happy to send my implementation. Where do I send it?

      Reply
    • From Ejaz Anwer (posted by the Webmaster)

      Posted by Brad Jones on 11/19/2004 09:29am

      Well, I think you should compute a cross product of the two 
      vectors to get the 3d vector (which will be mutually orthogonal) for 
      the y-axis according to the other two new vectors. D3DXVec3Cross will 
      serve the purpose for you.
      
      For the second part, in case of matrix computation, order is very 
      critical. Is it possible that you send a copy of your implementation, so 
      that I can see exactely how it is implemented and what is the 
      problem?

      Reply
    • Re: Re: A very good tutorial

      Posted by hese on 11/18/2004 09:26am

      Thank you very much for answering. I understand you point about the spinning but I'm trying to rotate x- and y-axis by a mouse just like in any ordinary fps game. I still want the camera to move in the direction of the orientation so I can't use a constant y-axis. And for the second part, I made a copy of the camera class and tried to modify that so it could give me the orientation of the particle (the orientation and movement of the particle isn't in any way depending of the position or orientation of the camera). For instance I modified the Update function by changing the order in which the translation and rotation matrices are multiplied so the particle rotates around itself. I've succeeded in getting the slerp function to work correctly for the particle in XZ-plane (in other words the particle rotates around a constant y-axis, up vector(0,1,0), and moves towards the camera's position) but when I'm trying to add y-axis it starts acting strangely. And thank you for the link to the MeshViewer example. It will probably solve my problem if I'm able to modify it so that the particle moves to the direction of the orientation. P.S. Is there any way I can add empty lines to my text so it would be easier to read?

      Reply
    • Re: A very good tutorial

      Posted by Ejaz on 11/16/2004 12:27pm

      Dear hese, I'm not sure that I preceive what exactly you want to do and how you are doing. In case of Roll/Pitch/Yaw, when you press up/down key, the pitch is changed, so if you hold any of the key and press left/right, Yaw start along with it. Values are calculated, orientation is updated, and in the end, the renderer renders the new scene, which gives the fell of spining (this gives the view of the pilot). For the second part, I guess the rotation of a particular object should be associated with the object itself, coz you may have other objects in the scene (sooner or later) and each object rotation behaviour shouldn't be the part of the camera. What you can do is, place the camera (at some particular point), render the object, upon rotaion of the object, update its (object) orientation and when the main renderer will start its work, it will go through each object in the scene and render the update oriented object. I don't know that exactly this will help, but have a look at http://www.codeguru.com/Cpp/G-M/directx/directx8/article.php/c6701/ for managing multiple objects in a scene and changing there orientation. Regards, Ejaz.

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date