Quaternion Camera Orbiting around a Sphere

Posted by jessejuicer on Game Development See other posts from Game Development or by jessejuicer
Published on 2012-06-05T20:21:49Z Indexed on 2012/06/05 22:48 UTC
Read the original article Hit count: 328

Filed under:
|
|

Background: I'm trying to create a game where the camera is always rotating around a single sphere. I'm using the DirectX D3DX math functions in C++ on Windows.

The Problem: I cannot get both the camera position and orientation both working properly at the same time. Either one works but not both together.

Here's the code for my quaternion camera that revolves around a sphere, always looking at the centerpoint of the sphere, ... as far as I understand it (but which isn't working properly):

(I'm only going to present rotation around the X axis here, to simplify this post)

Whenever the UP key is pressed or held down, the camera should rotate around the X axis, while looking at the centerpoint of the sphere (which is at 0,0,0 in the world). So, I build a quaternion that represents a small angle of rotation around the x axis like this (where 'deltaAngle' is a small enough number for a slow rotation):

D3DXVECTOR3 rotAxis;
D3DXQUATERNION tempQuat;

tempQuat.x = 0.0f;
tempQuat.y = 0.0f;
tempQuat.z = 0.0f;
tempQuat.w = 1.0f;

rotAxis.x = 1.0f;
rotAxis.y = 0.0f;
rotAxis.z = 0.0f;

D3DXQuaternionRotationAxis(&tempQuat, &rotAxis, deltaAngle);

...and I accumulate the result into the camera's current orientation quat, like this:

D3DXQuaternionMultiply(&cameraOrientationQuat, &cameraOrientationQuat, &tempQuat);

...which all works fine.

Now I need to build a view matrix to pass to DirectX SetTransform function. So I build a rotation matrix from the camera orientation quat as follows:

D3DXMATRIXA16 rotationMatrix;

D3DXMatrixIdentity(&rotationMatrix);

D3DXMatrixRotationQuaternion(&rotationMatrix, &cameraOrientationQuat);

...Now (as seen below) if I just transpose that rotationMatrix and plug it into the 3x3 section of the view matrix, then negate the camera's position and plug it into the translation section of the view matrix, the rotation magically works. Perfectly. (even when I add in rotations for all three axes). There's no gimbal lock, just a smooth rotation all around in any direction.

BUT- this works even though I never change the camera's position. At all. Which sorta blows my mind. I even display the camera position and can watch it stay constant at it's starting point (0.0, 0.0, -4000.0). It never moves, but the rotation around the sphere is perfect. I don't understand that. For proper view rotation, the camera position should be revolving around the sphere.

Here's the rest of building the view matrix (I'll talk about the commented code below). Note that the camera starts out at (0.0, 0.0, -4000.0) and m_camDistToTarget is 4000.0:

/*
D3DXVECTOR3 vec1;
D3DXVECTOR4 vec2;

vec1.x = 0.0f;
vec1.y = 0.0f;
vec1.z = -1.0f;

D3DXVec3Transform(&vec2, &vec1, &rotationMatrix);

g_cameraActor->pos.x = vec2.x * g_cameraActor->m_camDistToTarget;
g_cameraActor->pos.y = vec2.y * g_cameraActor->m_camDistToTarget;
g_cameraActor->pos.z = vec2.z * g_cameraActor->m_camDistToTarget;
*/

D3DXMatrixTranspose(&g_viewMatrix, &rotationMatrix);

g_viewMatrix._41 = -g_cameraActor->pos.x;
g_viewMatrix._42 = -g_cameraActor->pos.y;
g_viewMatrix._43 = -g_cameraActor->pos.z;
g_viewMatrix._44 = 1.0f;

g_direct3DDevice9->SetTransform( D3DTS_VIEW, &g_viewMatrix );

...(The world matrix is always an identity, and the perspective projection works fine).

...So, without the commented code being compiled, the rotation works fine. But to be proper, for obvious reasons, the camera position should be rotating around the sphere, which it currently is not. That's what the commented code is supposed to do. And when I add in that chunk of code to do that, and look at all the data as I hold the keys down (using UP, DOWN, LEFT, RIGHT to rotate different directions) all the values look correct! The camera position is rotating around the sphere just fine, and I can watch that happen visually too. The problem is that the camera orientation does not lookat the center of the sphere. It always looks straight forward down the z axis (toward positive z) as it revolves around the sphere. Yet the values of both the rotation matrix and the view matrix seem to be behaving correctly. (The view matrix orientation is the same as the rotation matrix, just transposed).

For instance if I just hold down the key to spin around the x axis, I can watch the values of the three axes represented in the view matrix (x, y, and z axes)... view x-axis stays at (1.0, 0.0, 0.0), and view y-axis and z-axis both spin around the x axis just fine. All the numbers are changing as they should be... well, almost.

As far as I can tell, the position of the view matrix is spinning around the sphere one direction (like clockwise), and the orientation (the axes in the view matrix) are spinning the opposite direction (like counter-clockwise). Which I guess explains why the orientation appears to stay straight ahead.

I know the position is correct. It revolves properly. It's the orientation that's wrong.

Can anyone see what am I doing wrong? Am I using these functions incorrectly? Or is my algorithm flawed? As usual I've been combing my code for simple mistakes for many hours. I'm willing to post the actual code, and a video of the behavior, but that will take much more effort. Thought I'd ask this way first.

© Game Development or respective owner

Related posts about c++

Related posts about directx