2
\$\begingroup\$

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.

\$\endgroup\$
1
  • \$\begingroup\$ you can just use the spherical coordinate system with inclination azimuth and radius describing your camera movement, then you translate that to cartesian, you then take the camera position, that's the z axis vector for camera space, then you need to add the camera position to the target position, you specify the up vector, plug that into the direct x function for calculating the camera matrix or you use the cross product and make your own matrix and you're done, just a suggestion, quaternions work just aswell and they're probably easier to interpolate \$\endgroup\$
    – dreta
    Jun 6, 2012 at 20:01

1 Answer 1

4
\$\begingroup\$

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

That sounds suspicious to me. It sounds like your rotation matrix is the desired camera-to-world rotation, and you're trying to invert it to get the world-to-camera matrix, but what you described above is not the right way to invert an affine transform. Specifically, transposing the 3x3 part of the matrix is fine (since it's a rotation matrix and thus orthonormal), but you can't just negate the translation part; you have to negate it and then multiply it by the transposed 3x3 part.

(Proof: let M be the rotation matrix and V be the translation vector, and x be the point you're trying to transform; then, if x' = M * x + V, you can derive x = M^T * (x' - V) = M^T * x' - M^T * V.)

Since you're leaving out that multiply, you're effectively doing the translation and rotation in the wrong order. That explains why the camera's position rotates even though you're not moving it; the translation is acting in camera space instead of world space.

\$\endgroup\$
1
  • \$\begingroup\$ ahhh. that was it. thank you! 15 hours of debugging and searching finally over! \$\endgroup\$ Jun 5, 2012 at 21:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .