I'm having a lot of problems getting my models to act correctly in 3D. Currently I'm using Euler angles via axis angle rotations.
The class for the camera works well and uses the standard up,right and look vector system.
To pitch I rotate about the right vector.
To yaw I rotate about the up vector.
To roll I rotate about the look vector.
This all works perfect for the camera and there is no gimbal lock or veering between angles (as angle axes begin to map onto one another). This tends to produce a bobbing sensation as the angles map onto one another and thus you lose a degree of freedom.
Now I took the camera class and used it for the COrient3D class. I figured hey it works for the camera why wouldn't it for the models? Boy was I way off.
Here are the problems:
- Models act fine until they reach negative pitch at which point the look vector and nose of the model do not line up.
- As you approach the +90 to -90 the effects of this can be seen quite clearly as your model begins to waiver about and no longer follow the look vector.
- If you yaw while in a positive or negative pitch it works fine until yaw reaches a certain point and then the vectors go haywire.
- The ship nose should point straight down the +z axis of the look vector, but the ship movement begins to be completely different from the direction it is pointing.
Now if I absolutely cannot do this type of game using euler angles then I will switch to quaternions, but I think something else is wrong.
Here is some of the code:
What I've done here is take the GetViewMatrix() function from CCamera and used it to create the final rotation matrix for the object. I cannot do a D3DXMatrixRotationYawPitchRoll() because that suffers from gimbal lock which would effectively 'undo' all my axis angle rotations.Code:COrient3D::COrient3D()
{
m_vecRight=D3DXVECTOR3(1.0f,0.0f,0.0f);
m_vecUp=D3DXVECTOR3(0.0f,1.0f,0.0f);
m_vecLook=D3DXVECTOR3(0.0f,0.0f,1.0f);
m_vecPos=D3DXVECTOR3(0.0f,0.0f,0.0f);
m_iObjType=OBJECT_AIR;
m_fYaw=0.0f;
m_fRoll=0.0f;
m_fPitch=0.0f;
}
void COrient3D::Walk(float fUnits)
{
if (m_iObjType==OBJECT_GND)
m_vecPos+=D3DXVECTOR3(m_vecLook.x,0.0f,m_vecLook.z)*fUnits;
if (m_iObjType==OBJECT_AIR)
m_vecPos+=m_vecLook*fUnits;
}
void COrient3D::Roll(float fAngle)
{
m_fRoll+=fAngle;
D3DXMATRIX T;
D3DXMatrixRotationAxis(&T,&m_vecLook,fAngle);
D3DXVec3TransformCoord(&m_vecRight,&m_vecRight,&T);
D3DXVec3TransformCoord(&m_vecUp,&m_vecUp,&T);
}
void COrient3D::Pitch(float fAngle)
{
m_fPitch+=fAngle;
D3DXMATRIX T;
D3DXMatrixRotationAxis(&T,&m_vecRight,fAngle);
D3DXVec3TransformCoord(&m_vecUp,&m_vecUp,&T);
D3DXVec3TransformCoord(&m_vecLook,&m_vecLook,&T);
}
void COrient3D::Yaw(float fAngle)
{
m_fYaw+=fAngle;
D3DXMATRIX T;
if (m_iObjType==OBJECT_GND) D3DXMatrixRotationY(&T,fAngle);
if (m_iObjType==OBJECT_AIR) D3DXMatrixRotationAxis(&T,&m_vecUp,fAngle);
D3DXVec3TransformCoord(&m_vecRight,&m_vecRight,&T);
D3DXVec3TransformCoord(&m_vecLook,&m_vecLook,&T);
}
void COrient3D::GetRotMatrix(D3DXMATRIX *outMatrix)
{
D3DXVec3Normalize(&m_vecLook,&m_vecLook);
D3DXVec3Cross(&m_vecUp,&m_vecLook,&m_vecRight);
D3DXVec3Normalize(&m_vecRight,&m_vecRight);
D3DXVec3Cross(&m_vecRight,&m_vecUp,&m_vecLook);
D3DXVec3Normalize(&m_vecLook,&m_vecLook);
D3DXVECTOR3 vecPos=m_vecPos;
float x=D3DXVec3Dot(&m_vecRight,&vecPos);
float y=D3DXVec3Dot(&m_vecUp,&vecPos);
float z=D3DXVec3Dot(&m_vecLook,&vecPos);
(*outMatrix)(0,0)=m_vecRight.x;
(*outMatrix)(0,1)=m_vecUp.x;
(*outMatrix)(0,2)=m_vecLook.x;
(*outMatrix)(0,3)=0.0f;
(*outMatrix)(1,0)=m_vecRight.y;
(*outMatrix)(1,1)=m_vecUp.y;
(*outMatrix)(1,2)=m_vecLook.y;
(*outMatrix)(1,3)=0.0f;
(*outMatrix)(2,0)=m_vecRight.z;
(*outMatrix)(2,1)=m_vecUp.z;
(*outMatrix)(2,2)=m_vecLook.z;
(*outMatrix)(2,3)=0.0f;
(*outMatrix)(3,0)=0.0f;
(*outMatrix)(3,1)=0.0f;
(*outMatrix)(3,2)=0.0f;
(*outMatrix)(3,3)=1.0f;
}
You may notice the translation has been taken out of this matrix. It is done at a later time just in case I may want to scale the object prior to translation and I didn't think COrient3D should care about scale.
This code works fine for the camera but is completely backwards for the object. After negating certain vectors you can get the object to fly correctly, but the issues I mentioned above pop up quickly.
I tried code to rotate the object to always face down the positive Z axis of the look vector, but it did not change the object orientation leading me to believe it is already in this orientation.
Please help me figure this out. These orientations are driving me nuts.