How to get rid of camera z-axis rotation

Started by
39 comments, last by BlackJoker 9 years, 6 months ago

Hello.

I have an issue with my quternion based camera: when I move it only on X and Y axis fast it is also begin rotate around Z axis, but it shouldn`t.

I use sharpDX lib and my code is following:


public void RotateX(float _degree_angle)
        {
            if (cameraType == CamType.ThirdPerson)
            {
                _degree_angle = -_degree_angle;
            }

            qRotation = Quaternion.Multiply(Quaternion.RotationAxis(Vector3.UnitX, MathUtil.DegreesToRadians(_degree_angle)), qRotation);
            
            UpdateViewMatrix();
        }

        public void RotateY(float _degree_angle)
        {
            if (cameraType == CamType.ThirdPerson)
            {
                _degree_angle = -_degree_angle;
            }

            qRotation = Quaternion.Multiply(Quaternion.RotationAxis(Vector3.UnitY, MathUtil.DegreesToRadians(_degree_angle)), qRotation);
            
            UpdateViewMatrix();
        }


private void UpdateViewMatrix()
        {
            qRotation = Quaternion.Normalize(qRotation);

            if (CameraType == CamType.ThirdPerson)
            {
                ViewMatrix = Matrix.Translation(Vector3.Negate(position)) * Matrix.RotationQuaternion(qRotation);

                position -= new Vector3(ViewMatrix.M13, ViewMatrix.M23, ViewMatrix.M33) * radius;

                ViewMatrix = Matrix.LookAtLH(position, lookAt, new Vector3(ViewMatrix.M12, ViewMatrix.M22, ViewMatrix.M32));
            }
            else
            {
                ViewMatrix = Matrix.Translation(Vector3.Negate(position)) * Matrix.RotationQuaternion(qRotation);
            }
        }

I tried to change order of multiplying for x and y quaternion rotations like this:


qRotation = Quaternion.Multiply(Quaternion.RotationAxis(Vector3.UnitY, MathUtil.DegreesToRadians(_degree_angle)), qRotation);

qRotation = Quaternion.Multiply(qRotation, Quaternion.RotationAxis(Vector3.UnitX, MathUtil.DegreesToRadians(_degree_angle2))); 

This helps - after that camera no longer rotate on Z-axis during fast moving on x-y axis, but if I move it on diagonal, if begins to rotate around all 3 axis, describing virtual 8 digit.

Could someone please point me the right way working with quaternions to stop camera rotation around Z-axis when I don`t need this?

This issue is driving me crazy.

Advertisement

I use front, side and up vector for my camera. after each update, I will set the y component of the side vector zero, so that no rotation around z axis is possible. After that, I will normalize the vector and recompute the front and up vector.

Could you please give the code responcible for recomputing the front and up vectors?

Or (better) the whole view matrix update.

D3DXVECTOR3 eye; //camera position

D3DXVECTOR3 at; //where you look at

D3DXVECTOR3 up(0,1,0); //assume the up vector is always pointing up, could have problem when you look straight up

D3DXVECTOR3 front = Normalize(at - eye);

D3DXVECTOR3 side = cross(front,up); //if you look through front vector, side vector will be on your right

use D3DXMatrixLookAtLH(....) or XMMatrixLookAtLH(...) to update the view matrix

Thanks, but side and front is not using in XMMatrixLookAtLH(...) or D3DXMatrixLookAtLH(...). Where and when I need to apply them?

D3DXVECTOR3 eye; //camera position

D3DXVECTOR3 at; //where you look at

D3DXVECTOR3 up(0,1,0); //assume the up vector is always pointing up, could have problem when you look straight up

D3DXVECTOR3 front = Normalize(at - eye);

D3DXVECTOR3 side = cross(front,up); //if you look through front vector, side vector will be on your right

use D3DXMatrixLookAtLH(....) or XMMatrixLookAtLH(...) to update the view matrix

Doesn't D3DXMatrixLookAtLH(....) or XMMatrixLookAtLH(...) take as income parameters the mentioned 'eye', 'at' and 'up' and construct 'front' and 'side' automatically?

If you rotate around the X axis, then rotate around the Y axis, then undo the rotation around the X axis, and finally undo the rotation around the Y axis, the resulting transformation is a rotation around the Z axis. This is a feature of rotations in 3D space, and you will observe it regardless of whether you use quaternions or anything else to represent them.

Perhaps instead of rotating around the X and Y axes, you meant to control pitch and yaw. If that's the case, use those angles to build the rotation from scratch every time.

D3DXVECTOR3 eye; //camera position

D3DXVECTOR3 at; //where you look at

D3DXVECTOR3 up(0,1,0); //assume the up vector is always pointing up, could have problem when you look straight up

D3DXVECTOR3 front = Normalize(at - eye);

D3DXVECTOR3 side = cross(front,up); //if you look through front vector, side vector will be on your right

use D3DXMatrixLookAtLH(....) or XMMatrixLookAtLH(...) to update the view matrix

Doesn't D3DXMatrixLookAtLH(....) or XMMatrixLookAtLH(...) take as income parameters the mentioned 'eye', 'at' and 'up' and construct 'front' and 'side' automatically?

After 'side = cross(front,up)', set 'side.y = 1', then normalize it, then recompute the up vector.

At this time, 'eye' and 'at' haven't changed, but 'up' has changed.

If you have rotation angle, álvaro's method would be simpler.

If you rotate around the X axis, then rotate around the Y axis, then undo the rotation around the X axis, and finally undo the rotation around the Y axis, the resulting transformation is a rotation around the Z axis. This is a feature of rotations in 3D space, and you will observe it regardless of whether you use quaternions or anything else to represent them.

Perhaps instead of rotating around the X and Y axes, you meant to control pitch and yaw. If that's the case, use those angles to build the rotation from scratch every time.

Could you please write working example for your suggestion?

We already tried to accum degrees, but as a result, camera moving not on orbit, but on trajectory 8 (rotating in all 3 axis at the same time).

If you're trying to do a 3rd person camera, I'll echo Álvaro and suggest you just keep track of camera yaw and position then construct the transform each frame.

Pseudo code:


class Camera
{
 float m_yaw; // Should be a value between 0 and 2 PI
 float m_pitch; // Value between -PI/2 and PI/2
 Vector3 m_position;
 Matrix  m_cameraMatrix;
 
 void Update()
 {
 	Vector2 deltaMousePos; // Assume this is a 2D vector that has the delta X/Y of our mouse cursor since the last frame.
 	
 	m_yaw += deltaMousePos.x;
 	m_pitch += deltaMousePos.y;
 	
 	// Construct our rotation based on our current yaw/pitch
 	Quaternion yRotation(Vector3::UnitY, m_yaw);
 	Quaternion xRotation(Vector3::UnitX, m_pitch);
 	
 	m_cameraMatrix = Matrix::Identity;
 	m_cameraMatrix *= (xRotation * yRotation);
 	m_cameraMatrix.translation = m_position; // Restore our position.
 }
 
}

This topic is closed to new replies.

Advertisement