Jump to content
  • Advertisement
Sign in to follow this  
Morchaiel

DirectX / C++ First person camera - Wrong axis!

This topic is 3163 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone, I've been trying to get a simple first-person camera going in a DirectX program. I'm using C++ and the feb. DirectX SDK, working on a DirectX 10 platform. However, this camera's been giving me some trouble. I've tried on my own, I've tried searching for help, I've checked out the tutorials and documentation, but no matter what I do, I seem to be overlooking something. I want the camera to have the full range of motion, so pitch, yaw and roll. However, movement over one of the axis always goes by the world's axis, rather than the camera's own axis. The way I have it set up now ( see code ) allows me to yaw and roll around the camera's own axis, but it pitches on the world axis. So when I'm rolled 90 degrees, and move my mouse sideways, the camera moves up and down rather than left to right. Here's my camera's code, view matrix update code.I hope someone can help:
        //Three floats are used for the rotation, named yaw, pitch and roll.
        //A getter in the render function gets the updated view matrix.
        D3DXMATRIX rotationMatrix, yawMatrix, pitchMatrix, rollMatrix;

	D3DXMatrixRotationAxis( &yawMatrix, &defaultUp, yaw );

	D3DXMatrixRotationAxis( &pitchMatrix, &defaultRight, pitch );
	
	D3DXMatrixRotationAxis( &rollMatrix, &defaultView, roll );

	D3DXMatrixMultiply( &rotationMatrix, &rollMatrix, &yawMatrix );
	D3DXMatrixMultiply( &rotationMatrix, &pitchMatrix, &rotationMatrix );


	D3DXVec3TransformCoord( &view, &defaultView, &rotationMatrix );
	D3DXVec3TransformCoord( &up, &defaultUp, &rotationMatrix );

	D3DXVec3Normalize( &forward, &view );

	D3DXVec3Cross( &right, &up, &view );

	D3DXVec3Normalize( &up, &up );

	D3DXVec3Normalize( &right, &right );

	view += eye;

	D3DXMatrixLookAtLH( &viewMatrix, &eye, &view, &up );
I use three floats called yaw, pitch and roll in my camera class. These are updated based on mouse and keyboard input. The completed view matrix is retrieved by a getter in my render function.

Share this post


Link to post
Share on other sites
Advertisement
I'm not sure what defaultRight/Up/View are, but it sounds to me like you're trying to implement 6DOF motion using 'from scratch' Euler angles, which won't work.

If you want true 6DOF motion (that is, yaw, pitch, and roll always occur about the respective local axis, regardless of how the object is oriented), you'll need to store the object's orientation (e.g. using a quaternion or matrix) and update it incrementally using local rotations. (Don't forget to orthogonalize/normalize after updating to correct for accumulated numerical error.)

Share this post


Link to post
Share on other sites
Thanks for your reply, you're absolutely right. I shouldn't be applying the rotation to default axis.

I've tried globally declaring the rotation matrix, and storing the rotation data in there. At the start of the function, I grab the data from this matrix, and apply the roll, pitch and yaw to these axis. However, now I only get minute movements when I move my camera, after which it instantly snaps back to its original orientation. Here's my new code:

void Camera::Update()
{

prevRight.x = rotationMatrix._11;
prevRight.y = rotationMatrix._21;
prevRight.z = rotationMatrix._31;

prevUp.x = rotationMatrix._12;
prevUp.y = rotationMatrix._22;
prevUp.z = rotationMatrix._32;

prevView.x = rotationMatrix._13;
prevView.y = rotationMatrix._23;
prevView.z = rotationMatrix._33;

D3DXMATRIX pitchMatrix, yawMatrix, rollMatrix;

D3DXMatrixRotationAxis( &yawMatrix, &prevUp, yaw );

D3DXMatrixRotationAxis( &pitchMatrix, &prevRight, pitch );

D3DXMatrixRotationAxis( &rollMatrix, &prevView, roll );

D3DXMatrixMultiply( &rotationMatrix, &rollMatrix, &yawMatrix );
D3DXMatrixMultiply( &rotationMatrix, &pitchMatrix, &rotationMatrix );

D3DXVec3TransformCoord( &view, &prevView, &rotationMatrix );
D3DXVec3TransformCoord( &up, &prevUp, &rotationMatrix );
D3DXVec3TransformCoord( &right, &prevRight, &rotationMatrix );
D3DXVec3Cross( &right, &up, &view );

D3DXVec3Normalize( &forward, &view );

D3DXVec3Normalize( &up, &up );

D3DXVec3Normalize( &right, &right );

view += eye;

D3DXMatrixLookAtLH( &viewMatrix, &eye, &view, &up );
}

prevView, prevUp 
and
prevRight
are just 3 vectors that start off with the initial axis orientation. I'm probably missing something really simple here..

Share this post


Link to post
Share on other sites
Where are you initializing the world matrix? Assuming it is outside the main game loop, i'd look long and hard at these lines:

D3DXMatrixMultiply( &rotationMatrix, &rollMatrix, &yawMatrix );
D3DXMatrixMultiply( &rotationMatrix, &pitchMatrix, &rotationMatrix );

what is happening to rotationMatrix during the first multiplication...?

Share this post


Link to post
Share on other sites
The world matrix is initialized in the rendering function, which then calls the UpdateCamera function to get the view matrix. I see what you're saying, thanks for the pointer. The rotationMatrix gets overwritten by the multiplication. I'm not sure how to handle that, I've tried first combining the three rotations into one matrix and multiplying that by the global rotationMatrix, but that didn't seem to change a lot..

*edit*

I got it working.. I wasn't properly updating the rotation matrix. In my current update method, I update the rotation matrix's relevant values individually, and use a separate, locally initialized matrix to apply the new rotations to the camera's axis.

The camera has full 6DOF motion now, so jyk and Burnt_Fyr, thanks a lot, you've been a great help! Just for the reference, here's my new code:

void Camera::Update()
{
D3DXVECTOR3 currentUp, currentView, currentRight;
//Retrieve camera axis rotation since last update:
currentRight.x = rotationMatrix._11;
currentRight.y = rotationMatrix._21;
currentRight.z = rotationMatrix._31;

currentUp.x = rotationMatrix._12;
currentUp.y = rotationMatrix._22;
currentUp.z = rotationMatrix._32;

currentView.x = rotationMatrix._13;
currentView.y = rotationMatrix._23;
currentView.z = rotationMatrix._33;

D3DXMATRIX pitchMatrix, yawMatrix, rollMatrix;

//Apply yaw, pitch and roll over the camera's current axis.
D3DXMatrixRotationAxis( &yawMatrix, ¤tUp, yaw );

D3DXMatrixRotationAxis( &pitchMatrix, ¤tRight, pitch );

D3DXMatrixRotationAxis( &rollMatrix, ¤tView, roll );

D3DXMATRIX newRotationMatrix;
//Multiply the new rotation matrices.
D3DXMatrixMultiply( &newRotationMatrix, &rollMatrix, & yawMatrix );
D3DXMatrixMultiply( &newRotationMatrix, &pitchMatrix, & newRotationMatrix );
//Apply rotation to current view and up axis, storing the new axis orientation
//in view and up.
D3DXVec3TransformCoord( &view, ¤tView, &newRotationMatrix );
D3DXVec3TransformCoord( &up, ¤tUp, &newRotationMatrix );

//Cross our new up and view vectors to create the right vector.
D3DXVec3Cross( &right, &up, &view );

//Normalize the forward, up and right vectors.
D3DXVec3Normalize( &forward, &view );

D3DXVec3Normalize( &up, &up );

D3DXVec3Normalize( &right, &right );

//Set the view to match the camera's location.
view += eye;

//Create the view matrix from the new rotation vectors.
D3DXMatrixLookAtLH( &viewMatrix, &eye, &view, &up );

//Update the rotation matrix to match the camera's new axis alignment.
rotationMatrix._11 = right.x; rotationMatrix._12 = up.x; rotationMatrix._13 = forward.x;
rotationMatrix._21 = right.y; rotationMatrix._22 = up.y; rotationMatrix._23 = forward.y;
rotationMatrix._31 = right.z; rotationMatrix._32 = up.z; rotationMatrix._33 = forward.z;

//Reset yaw, pitch and roll;
yaw = 0.0f; pitch = 0.0f; roll = 0.0f;
}


[Edited by - Morchaiel on April 18, 2010 8:02:55 AM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!