Thread: Rendering models in different orientations

  1. #1
    Registered User
    Join Date
    Nov 2008
    Posts
    41

    Rendering models in different orientations

    Hi everyone,
    I have run into a huge brick wall. I am writing a true-3d space flight simulator in OpenGL. Each object in the world will have an orientation defined by a direction vector and an up vector. Each object also has a position vector.

    Here is what I thought was the easiest way to render a model. gluLookat seemed extremely appropriate for what I wanted to do. (Does this make sense?)

    Code:
    void GraphicsEntity::render() const{
        glPushMatrix();
        
            glTranslatef(pos.getx(), pos.gety(), pos.getz());
            gluLookAt(0, 0, 0, dirVec.getx(), dirVec.gety(), dirVec.getz(), upVec.getx(), upVec.gety(), upVec.getz());
            
            glCallList(model->getDisplayList());
            
        glPopMatrix();
    }
    I have written methods for the Entity class which pitch the object up and down and yaw left and right, changing the direction and up vectors appropriately (I have checked and they are being changed correctly). The entity class also has a 'right vector'.

    The problem is that when I pitch a ship up or down in the game, it always only rotates around the ship around the world x axis and in the case of yawing left or right it always rotates around the world y axis, when it SHOULD rotate around the right vector and up vector of the object respectively. The idea being that no matter what rotations you have already done the yaw will still turn the ship left or right from the ship's perspective.

    Here are some screenshots of what I have so far:
    Before any rotations
    After pitching up
    Yawing after pitching

    Any help would be appreciated, and more clarification on any aspect can be given.

  2. #2
    Registered User
    Join Date
    Mar 2007
    Posts
    416
    I understand your problem, but I have no idea what your code looks like or how you are calculating the vector in which the ship should be heading. But what I would try is getting the ships pitch in relation to the axis (all of them perhaps), and adjust the vector according to how it is in relation to all the axises. Such as, if it is pitched up (as in your picture) then it rotates around the vector in which it is heading. Try it with your hand, when you have your hand pitched up, how do you yaw right? You most likely rotate it about the vector (could be thought of as an axis i guess) that your hand was at when you were only pitched up and not yawing. Hope that idea helps.

  3. #3
    Registered User
    Join Date
    Nov 2008
    Posts
    41
    Thank you scwizzo, but I believe that's what I'm doing already. Here's how I calculate the direction and up vectors:
    Code:
    // Pitchs (rotates) the direction and up vectors 'd' degrees around the right vector
    void Entity::pitch(float d){
        vecRotate(dirVec, d, rightVec);
        Vector3d::cross(rightVec, dirVec, upVec);
    }
    
    // Yaws (rotates) the right and direction vectors 'd' degrees around the up vector
    void Entity::yaw(float d){
        vecRotate(dirVec, d, upVec);
        Vector3d::cross(dirVec, upVec, rightVec);
    }
    So a pitch always rotates the direction vector around the right vector and then does a cross product to update the up vector.

    The vecRotate function is complicated and is based on the equations from here, and I am quite certain it is working correctly as I have check what vectors are getting outputted after each pitch/yaw. So the vectors being represented in the object are correct but the rendering process is somehow wrong. Here is my glut display function:
    Code:
    //GLUT displays the scene with this function
    void display(){
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        
        glPushMatrix();
        glEnable(GL_TEXTURE_2D);
        
        drawBackground();
        
        glTranslatef(a, b, x);
        
        ge.render();
    
        glDisable(GL_TEXTURE_2D);
    
        glPopMatrix();
        
        glutSwapBuffers();
    }
    Where 'ge' is a global Entity variable that I'm testing with.

    Perhaps I am misunderstanding what gluLookAt does?

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    You are running into gimbal lock where one rotation about an axis causes a rotation about another axis. Another way of saying it is that gimbal lock is when one axis of rotation is mapped either partially or fully onto another axis of rotation.

    Solutions to this are to use axis-angle orientations or quaternions.

    Rotations for airplanes and spacecraft
    Yaw is a rotation about the up vector.
    Pitch is a rotation about the right vector.
    Roll is a rotation about the look vector.

    For spacecraft and airplanes the up vector does not always line up with world up. So if you take an airplace and pitch 90 degrees up and yaw the craft should yaw back and forth as it normally does in any other orientation. If you are not using axis-angle or quaternion rotations the yaw will actually map onto the look vector and the aircraft will roll instead of yaw.

  5. #5
    Registered User
    Join Date
    Nov 2008
    Posts
    41
    Thanks Bubba, I didn't think think this was gimbal lock, but I will now look it up thoroughly. Unfortunately it looks like I will need to do quite a bit of re-writing.

    EDIT: I still don't understand why this would happen as I do re-adjust the two other vectors after a pitch or yaw, but I will take your word for it.

    EDIT2: I have been reading this site and it says that only Euler Angle Representation suffers from gimbal lock, which is not what I am doing as I have no angles at all.
    Last edited by Noise; 12-16-2008 at 10:33 PM.

  6. #6
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    If you are rotating about y, then x and then z and are not using axis-angle then you are going to gimbal lock.

    Code:
    // Pitchs (rotates) the direction and up vectors 'd' degrees around the right vector
    void Entity::pitch(float d){
        vecRotate(dirVec, d, rightVec);
        Vector3d::cross(rightVec, dirVec, upVec);
    }
    
    // Yaws (rotates) the right and direction vectors 'd' degrees around the up vector
    void Entity::yaw(float d){
        vecRotate(dirVec, d, upVec);
        Vector3d::cross(dirVec, upVec, rightVec);
    }
    It appears that vecRotate is incorrect. Why would yaw need the direction vector?

    Code:
    void X3DCamera::Yaw(float angle)
    {
        D3DXMATRIX T;
    
        if (CameraType == LANDOBJECT) 
        {
            D3DXMatrixRotationY(&T,angle);
        }
        
        if (CameraType == AIRCRAFT) 
        {
            D3DXMatrixRotationAxis(&T,&Up,angle);
        }
    
        D3DXVec3TransformCoord(&Right,&Right,&T);
        D3DXVec3TransformCoord(&Look,&Look,&T);
    }
    This is DirectX but it is doing the same thing you need to do. First I create an axis rotation matrix about the vector (axis) I need to rotate around. Then I transform my other two remaning vectors (axes) by the matrix computed in the previous step.

    Prior to spitting out a view matrix in the case of a camera and model matrix in the case of an object I make sure the 3 vectors are orthogonal to each other.

    TransformCoord is basically:

    result.x = vector.x * matrix(0,0) + vector.y * matrix(0,1) + vector.z * matrix(0,2);
    result.y = vector.x * matrix(1,0) + vector.y * matrix(1,1) + vector.z * matrix(1,2);
    result.z = vector.x * matrix(2,0) + vector.y * matrix(2,1) + vector.z * matrix(2,2);

    For OpenGL or RH systems use the transpose of matrix().

    Pseudocode for orthogonalizing object vectors and ensuring they are orthonormal.

    Normalize(Look)
    Up = Normalize(Cross(Right,Look))
    Right = Normalize(Cross(Up,Look))
    Last edited by VirtualAce; 12-17-2008 at 12:26 AM.

  7. #7
    Registered User
    Join Date
    Nov 2008
    Posts
    41
    Quote Originally Posted by Bubba View Post
    If you are rotating about y, then x and then z and are not using axis-angle then you are going to gimbal lock.
    In the case of a pitch I rotate around whatever the rightVec for the object is, and in the case of a yaw I rotate around the upVec.

    Quote Originally Posted by Bubba View Post
    It appears that vecRotate is incorrect. Why would yaw need the direction vector?
    Ok so, the dirVec is the direction the object is facing. So when you do a yaw you rotate the dirVec around the upVec. And then I use cross product to update the rightVec to the new orientation as well, since it is cheaper than vecRotate.

    vecRotates the first argument around the third argument a number of degrees given by the second argument.

    I have tested vecRotate quite a bit so I don't believe it is incorrect.

    Quote Originally Posted by Bubba View Post

    Code:
    void X3DCamera::Yaw(float angle)
    {
        D3DXMATRIX T;
    
        if (CameraType == LANDOBJECT) 
        {
            D3DXMatrixRotationY(&T,angle);
        }
        
        if (CameraType == AIRCRAFT) 
        {
            D3DXMatrixRotationAxis(&T,&Up,angle);
        }
    
        D3DXVec3TransformCoord(&Right,&Right,&T);
        D3DXVec3TransformCoord(&Look,&Look,&T);
    }
    This is DirectX but it is doing the same thing you need to do. First I create an axis rotation matrix about the vector (axis) I need to rotate around. Then I transform my other two remaning vectors (axes) by the matrix computed in the previous step.

    Prior to spitting out a view matrix in the case of a camera and model matrix in the case of an object I make sure the 3 vectors are orthogonal to each other.

    TransformCoord is basically:

    result.x = vector.x * matrix(0,0) + vector.y * matrix(0,1) + vector.z * matrix(0,2);
    result.y = vector.x * matrix(1,0) + vector.y * matrix(1,1) + vector.z * matrix(1,2);
    result.z = vector.x * matrix(2,0) + vector.y * matrix(2,1) + vector.z * matrix(2,2);

    For OpenGL or RH systems use the transpose of matrix().

    Pseudocode for orthogonalizing object vectors and ensuring they are orthonormal.

    Normalize(Look)
    Up = Normalize(Cross(Right,Look))
    Right = Normalize(Cross(Up,Look))
    This is theoretically what I do in my code, but for some reason it always rotates around the y and x axes instead of around the ship's up and right vectors. I really don't understand. Again I suspect I may be misunderstanding how gluLookAt works.
    Last edited by Noise; 12-17-2008 at 02:01 AM.

  8. #8
    Registered User
    Join Date
    Nov 2008
    Posts
    41
    PROBLEM SOLVED.

    Everything was working fine and my method of representing orientations with vectors was fine. The problem was, as I suspected, gluLookAt not doing what I thought it should do. Instead I looked up change of basis in my old maths textbooks and realized that changing basis from world co-ordinates to the ships co-ordinates can be done like this:

    Code:
    void GraphicsEntity::render() const{
        glPushMatrix();
        
            glTranslatef(pos.getx(), pos.gety(), pos.getz());
            
            GLfloat basisChange[16] = {rightVec.getx(), rightVec.gety(), rightVec.getz(), 0, 
                                       upVec.getx(), upVec.gety(), upVec.getz(), 0, 
                                       -dirVec.getx(), -dirVec.gety(), -dirVec.getz(), 
                                       0, 0, 0, 0, 1};
            glMultMatrixf(basisChange);
            
            glCallList(model->getDisplayList());
            
        glPopMatrix();
    }
    This is easy since the basis vectors for the ship are exactly the orientation vectors I had been using to represent orientation. I cannot explain why gluLookAt behaved the way it did, but this solution works, as a pitch or yaw will rotate the ship around the ships axes now.

    Ship before any rotations
    After pitching up
    And then yawing anti-clockwise works correctly

    In case anyone was interested.

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Why are you using a look at matrix to orient your objects?

  10. #10
    Registered User
    Join Date
    Nov 2008
    Posts
    41
    Not sure what you mean. If you're referring to gluLookAt, even though it was designed for setting up the camera, I thought it would still work for facing objects in the correct orientation.

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    It does provided they have a target to look at. But orienting objects is not always about what they are looking at. Most of the time you orient an object via it's up, look, and right vectors. The only time you would need look at functionality is if you want your object to face another .

  12. #12
    Registered User
    Join Date
    Nov 2008
    Posts
    41
    Fair enough.

    It is strange that no book or articles I have read mention a technique like mine (where you use three basis vectors for each object orientation), they only ever list Euler angles, axis angle, and quaternions. Is this because it is inefficient in some way?

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    It's probably because it's generally on the first or second page of the chapter -- it's true for any linear transformation, not just a rotation, that the columns of the transformation matrix are the change-of-basis vectors. (Granted, I don't have all that many game math books on my shelf, but they all get there pretty quick, and well before talking about rotations.)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. scene graph rendering techniques
    By ichijoji in forum Game Programming
    Replies: 7
    Last Post: 03-19-2006, 12:17 AM
  2. Need help with drawing Multiple models?
    By salman86 in forum Game Programming
    Replies: 9
    Last Post: 08-07-2005, 12:59 PM
  3. Manual rendering disappears
    By Magos in forum Windows Programming
    Replies: 7
    Last Post: 02-29-2004, 09:25 PM
  4. voxel based rendering
    By Silvercord in forum Game Programming
    Replies: 1
    Last Post: 03-20-2003, 05:14 PM