Realistic rotation of a 3D ball as it rolls on a surface [OpenGL]

Discussion in 'OT Technology' started by RockmCockmRobot, Aug 23, 2009.

  1. I am trying to teach myself some basic OpenGL and have been going through the NeHe tutorials and understand most of it, in fact I even added a bunch of code to one of them so that you can use the mouse to look around like you can in any first person game and the WASD keys to move the camera around.

    But now I have this little marble like ball on a flat surface and I am using the arrow keys to move it around, not "jerkily" like a simple implementation would be where you push left and it instantly starts moving left and then instantly stops when you release it but with acceleration while you hold the key, deceleration due to a friction coefficient on the surface, and all that good stuff.

    It looks great except I am having a problem getting the sphere to rotate correctly so that it is in "sync" with its movement (the ball is textured so you can tell it looks wrong). From the origin if I go straight forward or back, along the z-axis, it rotates about the x-axis and looks perfect. Also if I go straight left or right from the origin (along the x-axis) it looks perfect and rotates about the z-axis. The problem, however, occurs when I combine movement on both of these axes. Say for example I move it forward a quarter rotation, then attempt to move left... it ends up rotating about the y-axis in the world coordinate system (spinning on its south pole, as it moves left, if that helps you picture it).

    I know why this happens, it's because when I moved it forward a quarter rotation I also rotated the spheres z-axis up so that it lines up with the y-axis in world coordinates (from front-back to top-bottom). I just don't know how to compensate for that... I mean its easy if it were only half or quarter rotations that I had to worry about but it's not, which leads me to believe I will have to, for example, use its current rotation about the x-axis to determine the percentage split between rotation on the z-axis and rotation on the y-axis whenever I want to move left-right... Thinking along these lines it seems like I will have to take into account the current rotation on all 3 axes to determine the amount of rotation on all 3 axes every time it moves in any direction. That is unless of course there is a much easier way to do this :)x:), maybe by loading the identity matrix after each rotation to re-allign the axes of the sphere with the world coordinate system, or something.

    So I guess my question is has anyone done this before, is there complex as hell math involved or is there some easy method that OpenGL provides?
     
  2. deusexaethera

    deusexaethera OT Supporter

    Joined:
    Jan 27, 2005
    Messages:
    19,712
    Likes Received:
    0
    There is complex math involved, but I don't know if OpenGL provides an easy way to do it or not. My first question is: is the way you're rolling the ball around the way you're supposed to do it?
     
  3. That is a good question... and I will try to answer how I am doing it but keep in mind I am following a tutorial and am interpreting and trying to understand code that wasn't originally written by me.

    So the original code was working with a single polygon object, I took the code that made that object "work" and turned it into a C++ class so I can make any number of these objects and make them "work" the same way. Basically every object has an (x,y,z) coordinate, a (dx,dy,dz) velocity vector (dx as in "change in x"), an (xrot, yrot, zrot) rotation angle.

    When I press the up arrow key, for example, I simply add a constant value to the current objects dz value (forward/backward is on the z-axis, left-right on the x-axis, and up-down on the y-axis). Every iteration of the main loop I add the dx, dy, and dz values to the x, y, and z coordinates (respectively) for each object. I also (currently, which is the problem) add to the rotation angle in this manner: z-coordinate change = rotate about x-axis, x-coordinate change = rotate about z-axis (and I don't really worry about movement on the y-axis, yet).

    So, now I have all these values representing position and rotation but here is how they are applied to the object that is rendered. The first thing I do is load the identity matrix, I then apply rotation and translation for the camera position and vector, then loop through each object doing the following for each: push the current matrix to "save it", translate the matrix based on the current (x,y,z) coordinate of the object, rotate the matrix based on the current angle of rotation of the object, draw the object, then pop the matrix to restore the one that was saved (identity matrix plus camera translation and rotation).

    Here are some code snippets to help you follow
    Code:
    void DrawScene()
    {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    
        glLoadIdentity();
        
        //Rotate and Translate Camera
        glRotatef(lookz, 1.0, 0, 0);
        glRotatef((360 - lookxy), 0, 1.0 ,0);
        glTranslatef(0 - cameraPosition.x, 0 - cameraPosition.y, 0 - cameraPosition.z);            
        
        //Draw All Objects
        for(unsigned int i = 0; i < cubes.size(); i++)
        {
            cubes[i]->draw();
        }
    
        for(unsigned int i = 0; i < spheres.size(); i++)
        {
            spheres[i]->draw();
        }
    }
    
    
    void sphere::draw()
    {
        glPushMatrix();
        
        if(active)
        {
            move();
            rotate();
        }
    
        glTranslatef(xpos,ypos,zpos);
        glRotatef(xrot, 1, 0, 0);
        glRotatef(yrot, 0, 1, 0);
        glRotatef(zrot, 0, 0, 1);
    
        glBindTexture(GL_TEXTURE_2D, textureIndex);
    
        gluSphere(quadric, radius, 40, 40);
        
        glPopMatrix();
    }
    
    
     
  4. deusexaethera

    deusexaethera OT Supporter

    Joined:
    Jan 27, 2005
    Messages:
    19,712
    Likes Received:
    0
    This is probably so vague as to be useless, but as best I can remember you'll need to get the sines and cosines of the angle of each axis and use those values as multipliers to determine how much each axis gets moved the next time the object is rotated.

    It's too goddamned late for this kind of math; I'll try to figure it out in the morning.
     
  5. Actually that helps, I already do something similar to move the camera in the direction it is facing, maybe not the same thing but I use trig for it:

    Code:
    if(keys[VK_W])
     {
         cameraPosition.x -= (float)(sin(lookxy*piover180) * cos(lookz*piover180)) * MOVE_SPEED;            
         cameraPosition.z -= (float)(cos(lookxy*piover180) * cos(lookz*piover180)) * MOVE_SPEED;
         cameraPosition.y -= (float) sin(lookz*piover180) * MOVE_SPEED;
     }
    
    
     
  6. If anyone else was interested in this I found what I was looking for here:
    http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/

    Where the axis of rotation is parallel to the surface and perpendicular to the direction of movement.

    Now to translate that math to code...
     
  7. deusexaethera

    deusexaethera OT Supporter

    Joined:
    Jan 27, 2005
    Messages:
    19,712
    Likes Received:
    0
    Lemme know if it works.
     

Share This Page