Thread: Model orientations in 3D

  1. #1
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607

    Model orientations in 3D

    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:

    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;
    }
    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.

    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.
    Last edited by VirtualAce; 10-31-2006 at 04:47 AM.

  2. #2
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Another problem.

    Every time I attempt to set the camera's orientation to the object it's viewing - such as an in-cockpit view mode, the camera experiences gimbal lock as well as the ship. However I'm using axis angle representations for both camera and ship. For some reason when I set the camera's vectors to the object's vectors, gimbal lock occurs.

    What a mess Euler angles are. I have no choice but to switch over to quaternions or otherwise I will have to do some complex math and gimbal equations all of which will suck precious CPU cycles.

    In order to correctly orient my models so they don't gimbal lock I'm setting local up,look, and right vectors to their origin's and then performing 3 axis angle rotations to create the matrices and then multiplying the matrices together to arrive at the final rotation matrix. This is then concatenated with the translation matrix to arrive at the final world matrix. What a disaster. I cannot just extract the vectors from the object's current orientation because the angles are all wrong. It works until you reach 180 to 360 degrees of yaw at which point the up is down, down is up, right is left and left is right. Crazy.


    I have no idea how these game companies did flight sims w/o using quaternions back in the early days. I've been trying to get around it by using axis angle rotations but I think I've come to my wit's end and all just to avoid stupid gimbal lock.

    Back to the drawing board.

    Here is a sample of my disastrous code:

    Code:
    void CShip::Render(float fTimeDelta)
    {
      
      m_pOrient->Reset();
      
      m_pOrient->Pitch();
      m_pOrient->Yaw();
      m_pOrient->Roll();
        
      if (m_spMyCamera->GetViewMode()==COCKPIT)
      {
        
        
        D3DXMATRIX matInvView;
        D3DXMATRIX matView;
        D3DXMATRIX matTrans;
        D3DXMATRIX matWorld;
        m_spDevice->GetTransform(D3DTS_VIEW,&matView);
        
        D3DXMatrixInverse(&matInvView,NULL,&matView);
        D3DXMatrixTranslation(&matTrans,0.0f,-2.0f,0.0f);
        
        matWorld=matTrans*matInvView;
            
        m_spDevice->SetTransform(D3DTS_WORLD,&matWorld);
        
      }
      else
      {
        
        D3DXMATRIX matWorld;
        D3DXMATRIX matRot;
        D3DXMATRIX matTilt;
      
        D3DXMatrixIdentity(&matRot);
        D3DXMatrixIdentity(&matTilt);
        
      
        D3DXMATRIX matTrans;
      
        D3DXVECTOR3 vecPos;
        m_pOrient->GetPosition(&vecPos);
        D3DXMatrixTranslation(&matTrans,vecPos.x,vecPos.y,vecPos.z);
      
        D3DXVECTOR3 vecUp=D3DXVECTOR3(0.0f,1.0f,0.0f);
        D3DXVECTOR3 vecRight=D3DXVECTOR3(1.0f,0.0f,0.0f);
        D3DXVECTOR3 vecLook=D3DXVECTOR3(0.0f,0.0f,1.0f);
      
        D3DXMATRIX matYaw;
        D3DXMATRIX matPitch;
        D3DXMATRIX matRoll;
      
        D3DXMatrixRotationAxis(&matYaw,&vecUp,m_pOrient->GetYaw());
        D3DXMatrixRotationAxis(&matPitch,&vecRight,m_pOrient->GetPitch());
        D3DXMatrixRotationAxis(&matRoll,&vecLook,m_pOrient->GetRoll());
            
           
        matRot=matYaw*matPitch*matRoll;          
        
        matWorld=matRot* matTrans;
      
        m_spDevice->SetTransform(D3DTS_WORLD,&matWorld);
      }
      
      
      m_spDevice->SetRenderState(D3DRS_CULLMODE,D3DCULL_CCW);
      
      
      m_pMesh->Render(fTimeDelta);
      
      if (m_spMyCamera->GetViewMode()==COCKPIT) m_pHUDSys->Update(fTimeDelta);
    }
    I've also tried some axis angle rotations on the X and Z plane for facing and the Y plane for tilt to cause the camera look, up, and right vectors to line up with the object's. It works but the gimbal lock problem still exists.
    Last edited by VirtualAce; 11-01-2006 at 05:05 AM.

  3. #3
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    why are you inverting your view matrix? Matrix inversions are expensive, best to avoid if possible.

  4. #4

    Join Date
    May 2005
    Posts
    1,042
    Yeah, I'm really not entirely sure what's going on with all of that. I normally lock my camera's angles so that I cannot look straight up or straight down, but I changed it so that I COULD and it still worked. The best I can do is post for you how I implemented my camera...I just collect the angles about each axis first of all (in my Camera:: GatherInputOverFrames() function), and then I tell OpenGL to build the proper view matrix. I also calculate my View Strafe/Right and Up vectors in my Camera::MatrixCheckMouse function.

    However, for aligning my models, I run the physics, which integrates a quaternion, and then converts it to a matrix. I'm guessing that posting my matrix3x3 to quaternion code would be useless seeing as how I'm in a different coordinate system.

    Code:
    void	FPSCam::MatrixCheckMouse()
    {
    	GatherInputOverframes();	
    	mView = Vector3(0, 0, -1);
    	mUp	  = Vector3(0, 1, 0);
    	
    	Matrix4x4 tempmatrix;
    	tempmatrix.InitFromAngles(RAD2DEG(xRadians), RAD2DEG(yRadians), 0);
    	tempmatrix.TransformDir(&mView);
    		
    	mStrafe = CrossProduct(mView, mYAxis);
    	mStrafe.Normalize();
    	
    	mUp = CrossProduct(mStrafe, mView);
    	mUp.Normalize();	
    	return;
    }
    ...
    void	FPSCam::GatherInputOverframes()
    {
    	POINT MousePos;
    	GetCursorPos(&MousePos);
    	
    	static	POINT	NewPos;
    
    	if(MousePos.x == Export.mVars.MiddleX && MousePos.y == Export.mVars.MiddleY)
    	{
    		Export.DisableState(MOUSEMOVED);
    		return; 
    	}
    	
    
    	SetCursorPos(Export.mVars.MiddleX, Export.mVars.MiddleY);
    	
    	Export.SetState(MOUSEMOVED);
    	
    	float YDeviation = (Export.mVars.MiddleY - MousePos.y);		
    	float XDeviation = (Export.mVars.MiddleX - MousePos.x);		
    
    	//FIXME: got rid of this when physics was removed
    //	float	framespeed = (Export.mVars.TWOPI* 8) * gpPhysics->mFrameTime; //8 full rotations per second
    	float	framespeed = (Export.mVars.TWOPI*8) * .01;
    
    	//fixme: i know this used to use screenheight, changed on purpose so it goes same speed along each axis
    	float XDegRad = (Export.mVars.PI * YDeviation) * (1/(Export.mVars.Width*.5)); //radians to rotate view vector about X axis
    	
    	if(XDegRad > 0 && XDegRad > framespeed)
    		XDegRad = framespeed;
    	else	if(XDegRad < 0 && XDegRad < -framespeed)
    		XDegRad = -framespeed;
    	
    	xRadians += XDegRad;
    	
    	/*
    	this is actually 89 degrees, gimbal lock is impossible in this scenario
    	however in order to have a valid move direction i sorta need to have X and Z components which is impossible
    	if you are looking straight upward
    	*/
    	
    /*
    	if(xRadians > 1.553343) 
    	{
    		xRadians = 1.553343;
    		XDegRad = 0;
    	}
    	
    	else	if(xRadians < -1.553343)
    	{
    		xRadians = -1.553343;
    		XDegRad = 0;
    	}
    */
    	float YDegRad = (Export.mVars.PI * XDeviation) * (1/(Export.mVars.Width*.5)); //radians to rotate view vector about Y axis	
    
    	if(YDegRad > 0 && YDegRad > framespeed)
    		YDegRad = framespeed;
    	else	if(YDegRad < 0 && YDegRad < -framespeed)
    		YDegRad = -framespeed;
    	
    	yRadians	+=	YDegRad;
    }
    
    ...
    
    	R_GenerateViewMatrix(RAD2DEG(Export.mpPlayer.mpCam->xRadians),RAD2DEG(Export.mpPlayer.mpCam->yRadians),0,Pos);	
    ...
    
    void	R_GenerateViewMatrix(float	pitch, float yaw, float roll, Vector3 & translation)
    {
    	if(pitch)
    	{
    		NT_GL(glRotatef(-pitch,1,0,0));
    	}
    	if(yaw)
    	{
    		NT_GL(glRotatef(-yaw,0,1,0));
    	}
    	if(roll)
    	{
    		NT_GL(glRotatef(-roll,0,0,1));
    	}
    		NT_GL(glTranslatef(-translation.x,-translation.y,-translation.z));
    }
    I'm not immature, I'm refined in the opposite direction.

  5. #5
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    why are you inverting your view matrix? Matrix inversions are expensive, best to avoid if possible.
    If you set the camera position to some arbitrary 3D point and take an object at 0,0,0 in model space and transform it with the inverse view matrix it will move the object to the camera.

    This is the only way I was able to get the ship to follow the camera and not experience all of the wild rotations.

    To explain what's happening may require me sending a demo or something.


    The object rotates correctly from an external viewpoint. The object camera also works correctly and pans around the object just fine. The fly-by camera will also work fine when it is imlpemented. What is not working is the in-cockpit camera.

    So my question is how do I stick the camera in the cockpit of the ship? I thought I could orient the camera the same as the ship, thus setting the camera's up, look, and right vectors to that of the ship....however it does not work and gimbal lock occurs.

    This problem will probably also affect chase view camera to an extent because that camera must to follow the ships' movements and always face down the positive Z axis of the ship or object look vector.

    I'm implementing four camera modes for ALL objects in the game.

    • Cockpit (not applicable to non-cockpit object such as planetary bodies, space stations, etc)
    • Chase mode - applicable to all objects, but fairly boring with planetary bodies
    • Object mode - applicable to all objects in the game (camera pans around object), will be used to render picture-in-picture images of targeted objects as well.
    • Fly-by mode - camera is translated along the positive look vector some distance ahead and then a matrix is calculated to point the camera toward a certain position in the object. After object moves a certain distance from the camera, camera mode is then set to object mode.


    The problem lies in the camera/object differences. My camera continually 'builds-up' it's vectors rather than begin with the original vectors each time and then rotating/translating to the correct point in space.

    Objects, on the other hand, always start with their orientations reset. This means that their up, right and look vectors are set to:

    1.0f,0.0f,0.0f
    0.0f,1.0f,0.0f
    0.0f,0.0f,1.0f

    Pitch, yaw and roll are 'built-up' by moving the mouse. Once it is time to render, the object is then rotated by the amounts on those 3 axes. Then the actual object vectors are actually rotated as well. I have not found a suitable way to use the vectors as the rotation values so I'm having to store pitch, yaw, and roll due to this problem.
    1 rotation rotates the 3D model, and 1 rotation rotates the vectors for the model.
    I thought I could take this matrix and use it as the rotation for both model and vectors, but it does not work for the model.

    Right.x,Right.y,Right.z,0.0f
    Up.x,Up.y,Up.z,0.0f
    Look.x,Look.y,Look.z,0.0f
    Pos.x,Pos.y,Pos.z,1.0f
    Last edited by VirtualAce; 11-02-2006 at 02:32 AM.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I think I found the problem. My ship is not rotating correctly and is still experiencing gimbal lock. So my new question is how do you rotate an object or a 3D model using axis angle orientations and yet not experiencing gimbal lock?

    Since my COrient3D class always maintains 3 vectors then it make sense that my up, right, and look vectors never become aligned and thus should never gimbal lock.

    I have looked at quaternions but it seems that they are a tool used to interpolate between orientations w/o having the problems of Euler angles. However in the end even quats must be stuck back into matrix form to be used by the hardware. As of right now the quaternions look great for my camera class and chase cameras, etc, but not for actual object orientations. Several websites have recommended AGAINST using quaternions for all object
    orientations.

    I've done some experimenting with rotating one vector onto another vector (or making one vector point the same direction as another) and it works but my results have been rather 'jerky' which is a known issue with my system.
    Quaternions will solve this but they won't solve my current problem.

    Sorry for asking this but all of you know if I'm asking this I'm also hard at work on finding a solution. Any help is and will be appreciated.

    Also, the internet seems to be really good at showing how to do a camera or some other isolated operation but most if not all the sites are absolutely terrible at explaining how to integrate these into an engine. Several camera tutorials out there but very few model orientation tutorials or explanations.
    Last edited by VirtualAce; 11-04-2006 at 11:06 PM.

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I've almost got it but I'm still not orienting the ship correctly. So far cockpit and chase mode both work but when you switch to object view the ship is not pointing in the direction of travel as evidenced by the stars flying by it.

    Also in flyby view mode, which currently just detaches the camera from the object, the object is NOT facing the direction of travel.

    I'm going to try to orient the vehicle to point towards it's look vector because any rotations I do just do not orient the model correctly. I'm not sure why this is. I have no idea what is going to happen when I get various ships in this system all flying around your ship. Right now most of it works for 1 ship but I may not be able to display other ships correctly.

    Some of this is starting to make sense but I'm still a bit puzzled by other portions.

    To do a chase camera I'm doing this:

    1. Get the current view matrix
    2. Get it's inverse
    3. Translating to a position relative to 0,0,0 since that is where the inverse puts the object relative to the camera - so a 0.0f,-2.0f,18.0f will put the camera 2 units above, and 18 units behind the actual object.
    4. World=Trans*InvView

    To do a cockpit camera:
    1. Get the current view matrix
    2. Get the inverse of it
    3. Translate to the cockpit location relative to 0,0,0 or the center of the model.
    4. Render the virtual cockpit around the player at this location. (TODO: Make the virtual cockpit model)
    5. World=Trans*InvView

    To do an object camera:
    1. Translate from the object a set distance.
    2. Render

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I fixed it.

    Here is a screenshot....not much diff....but it works.

    The fix is this:

    Camera matrix
    Right.x,Up.x,Look.x,0
    Right.y,Up.y,Look.y,0
    Right.z,Up.z,Look.z,0
    -dot(Right,cameraPos),-dot(Up,cameraPos),-dot(Look,cameraPos),0

    Object matrix
    Right.x,Right.y,Right.z,0
    Up.x,Up.y,Up.z,0
    Look.x,Look.y,Look.z,0
    Pos.x,Pos.y,Pos.z,1
    Last edited by VirtualAce; 03-12-2011 at 11:42 AM.

  9. #9
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    Nice, ship looks better too (I don't think I could make that out of paper). Are you using smooth shading? I can see the polys.

  10. #10
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    The gouraud shading is on, but not working for the ship. Not sure what's going on there but it doesn't matter b/c I'm about to scrap it and use my per-pixel shader anyways.

  11. #11
    Darkness Prevails Dark_Phoenix's Avatar
    Join Date
    Oct 2006
    Location
    Houston, Texas
    Posts
    174
    Looking good Bubba. Maybe sometime soon I'll understand enough DirectX so I can get my game idea started.

    Its not hard, I just don't have a lot of time to spend on it....
    Using Code::Blocks and Windows XP

    In every hero, there COULD be a villain!

  12. #12
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Note to all who use Blender

    If you perform a subsurf divide on your model and/or a smooth you MUST perform a remove doubles on the model or you will have more than one normal per vertex. This will cause Direct3D to mess up and will only perform flat-shading. This was the problem in the screenshots above. You can really tell if your model is correct or not by using the DX model viewer and setting it to render normals. If you have 2 or 3 normals per vertex, you have this problem and need to remove doubles. You should only have 1 normal per vertex in DX model viewer.

    Here is a corrected screenshot.
    Last edited by VirtualAce; 03-12-2011 at 11:41 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. 3d model with lighting effects
    By redacted user in forum Tech Board
    Replies: 2
    Last Post: 10-10-2008, 05:31 PM
  2. 3d Model file format
    By glo in forum Game Programming
    Replies: 4
    Last Post: 09-15-2008, 04:33 PM
  3. Help with file reading/dynamic memory allocation
    By Quasar in forum C++ Programming
    Replies: 4
    Last Post: 05-17-2004, 03:36 PM
  4. I'm completely stuck!
    By tek in forum C++ Programming
    Replies: 0
    Last Post: 08-23-2003, 06:43 PM
  5. 3D starfield
    By VirtualAce in forum Game Programming
    Replies: 6
    Last Post: 06-26-2003, 12:40 PM