Rotating an object around its local origin

I’m trying to write a 3D rotation function to rotate an object the way you would in 3ds Max or Maya (i.e. you rotate the object around its local axes). I know that’s not really how it works in OpenGL, so I tried translating the object to the origin, applying the rotation, then putting it back, but it still seems to be rotating around the axes of the world coordinate system. Am I going about this the wrong way, or is it my code?

Here is my display() function

public void display(GLAutoDrawable drawable) 
    {
        GL gl = drawable.getGL();

        // Clear the drawing area
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        // Reset the current matrix to the "identity"
        gl.glLoadIdentity();
        
        cube.finalizeRotation(gl);

        // Move the "drawing cursor" around
        //gl.glTranslatef(0.0f, 0.0f, -10.0f);
        cube.finalizeTranslate(gl);
        cube.finalizeScaling(gl);
        
        //Here's where we start drawing. ORDER MATTERS.
        //In case you want to do textures or something, you need to draw
        //everything in counter-clockwise order.
        // Draw A Quad
        gl.glBegin(GL.GL_QUADS);
        
            gl.glColor4f(0.5f, 0.5f, 1.0f, 0.2f);    // Set the current drawing color to light blue            
            cube.stackMaker(gl);
            
        // Done Drawing The Quad
        gl.glEnd();

        // Flush all drawing operations to the graphics card
        gl.glFlush();
    }

Here is my rotation method

public void finalizeRotation(GL gl)
    {
        gl.glTranslatef(0.0f, 0.0f, 0.0f);
        gl.glRotatef(degreesX, 1.0f, 0.0f, 0.0f);
        gl.glRotatef(degreesY, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(degreesZ, 0.0f, 0.0f, 1.0f);
    }

[quote] I know that’s not really how it works in OpenGL, so I tried translating the object to the origin, applying the rotation
[/quote]
this is the right method when you want to rotate an object around a given point p translate(-p),rotatexyz,translate§, but in case you want to rotate around local axis of an object you dont need to translate to world origin, you need to rotate object in object space before setting its position in the word, hum… like your code.

so,
rotate object around its axis XYZ or XZY or …
translate object to its pos
display object

is that help ?

also a common error can be that your local axis is not really close to your object geometry, wich cause rotation to appear wrong. you can try that under max move the pivot very far than rotate the object, this will give the impression that the object is not rotating around its axis.

gl.glTranslatef(0.0f, 0.0f, 0.0f); does not translate to the origin, it translates by the values [0; 0; 0] so it does nothing here and can be removed.

Like DzzD said, rotating around the objects origin is achieved by rotating the object before translating it, so your problem might be the corner points of your cube not being symetric to the origin…

Ok, let me clarify a little. When my program starts and I rotate my object it works fine. The issue is when I try to rotate my object after translating it somewhere else. I took out the translate to (0,0,0) since, you’re right, it doesn’t do anything. What do I need to do in order to be able to rotate an object as if it is at its origin after moving it in world space?

I edited my code thusly and it acts a little better, but not much:

public void finalizeRotation(GL gl)
    {
        gl.glTranslatef(distanceXinit, distanceYinit, distanceZinit);
        gl.glRotatef(degreesX, 1.0f, 0.0f, 0.0f);
        gl.glRotatef(degreesY, 0.0f, 1.0f, 0.0f);
        gl.glRotatef(degreesZ, 0.0f, 0.0f, 1.0f);
    }

Also, how would I be able to move the pivot point (local origin) around like in 3ds Max? Right now the pivot seems to be at one end of my object and I’d like it to be in the middle.

Just rotate before translate, that’s it. Since your display() code starts with gl.glLoadIdentity(), it should work. You simply can’t rotate around the origin after you translated the object using the glTranslate and glRotate functions. In more complex applications like a modeller you usually have a scenegraph that associates an own matrix with an object. So modifications to that matrix result in object local transformations and in the final rendering the matrices are multiplicated down the scenegraph hierarchy to get the world location and orientation of the object.

You should take a look at matrix and vector math and how matrix multiplication can be used to concatenate transformation steps.

For concatenating transformations, the most important thing to realize is that with opengl, the last applied transform is applied to vertices first.
For example, when you finalizeRotate() then finalizeTranslate() then finalizeScale(), you really scale, translate, the rotate the vertices.
I’ve found that it works better to scale, rotate, then translate, which means you would call finalizeTranslate() then finalizeRotate() then finalizeScale(). You should also remove the glTranslate() call from finalizeRotate() since it’s not needed at all.

Ooops, you are right. I never really noticed that, since I early moved on to a matrices for concatenating transformations. This would probably explain the OPs unexpected rotation behaviour, once the animation accumulated the translations.

So should I go straight to a scenegraph or is there a way to do it without one? Changing the order of the transforms didn’t help much and I started looking at using quaternions (like in the ArcBall tutorial on NeHe), but I’m not sure which one would be easier to implement and maintain in the long run, since this is going into software that is actually going to be used be somebody (i.e. I’m not just doing this for the lulz). Also, if a scenegraph would be better, is there one that works nicely with jogl that wouldn’t undo all of my work? I looked at Zith3D and that looks pretty good, but I don’t know much about one scenegraph API from another. Would it be worth it to write my own little scenegraph? All I need is transformation nodes.

The moment you decide to make a simple scenegraph with just transformation nodes, you’ve signed your soul to the devil. The temptation to add more and more functionality will bloat the code until you decide to rewrite it, in which case it gets better but you have to spend so much more time on it. I speak from experience, so I would recommend that you use an existing scenegraph (although they will probably have some learning curves). Other scenegraphs include: java3D, jME, xith3D, aviatrix (don’t know how good that is). jME is built on top of LWJGL, which is reasonably similar to JOGL, and java3D has an option to use JOGL as its internal renderer.

But keep in mind that you normally won’t be able to use GL commands with a scenegraph, since one of the goals of a scenegraph is to abstract away the rendering layer.

Well, I know this is a game development board, but I’m not actually doing game development with this app (gasp). It’s sort of a 3D graph with selectable cubes. All the functionality I need is basically in transformations and selections, colour and transparency manipulation, a basic camera, and maybe a light. I may end up using Xith3D, although it looks like a real pain to get working with NetBeans. I’d have to rewrite everything if I go with an existing scenegraph, so I want to know if it is a better idea to use the existing scenegraph or write my own with functionality for only the features I need.

sort to jump into the middle of the conversation but I’m having some trouble with this exact topic. I have a Earth based system with vehicles orbiting the earth and I’m trying to implement a goto method to take me to the vehicle and rotate about its local center and I have that working but I noticed that the further the vehicle is away from the center of the earth then the rotations get very very jittery for my vehicle. I mean, that as I rotate my view around the vehicle, the vehicle looks like it is jumping in place and when I draw shapes around the vehicle change position relative to the vehicle even though I’m not updating their positions at all. If I move the vehicle and shapes inside the earth (near the 0,0,0 center) then the rotations are smooth and I don’t get any jitter. I realize it has to do with some math errors dealing with multiple glRotate calls and glTranslate calls and the combination of the near/far clipping plane, the scale of the vehicle, the kitchen sink, and a first born child, but I have no idea how to being to fix it.

So, I sort of have 2 questions…has anyone experienced a similar issue and if so what did you do to fix it (if you did succeed)?
Or, second, does someone have a good framework for these types of rotations and recentering or possibly a good camera code that they would be willing to share? I’m at my wits end…if I can make a animated gif I’ll post it.

[quote=“Z-Knight,post:12,topic:32004”]
It’s all in the order of rotations.

how so? can you elaborate?

Why would the order of rotations make any difference? I mean, if I move the objects to 0,0,0 and perform the rotations then there is no jitter…as I move them out farther and farther from center do the rotations cause jitter.

What I do is basically the following:
I chose the body to focus on and translate that body to the origin
I then apply these rotations based on mouse inputs:
gl.glRotated(rotX, 1.0, 0.0, 0.0);
gl.glRotated(rotZ, 0.0, 0.0, 1.0);
Then I translate the body back to its position

I did notice one thing…when I only rotate about one axis and keep the other axis at 0 degrees then I don’t see jitter…but as soon as the other rotation is non-zero (ie rotZ is 1.0 degree for example) and I move my mouse to rotate rotX then I see jitter…and again, only if the object is not at the center. SO, it makes me think that there is more than just order of rotations that could be at fault, it seems like the distance of the object and the need to perform multiple translates is causing issues too.

Also, I do have a very near clipping plane because the object I have is a vehicle who I want to be able to zoom close too and yet I want to see the Earth background below it and so the far clipping plane is far as well and I wonder if the combination of these two and the other factors are combining for the jitter. Just as a test I reduced the far clipping plane significantly to see if maybe the ratio of the distances of far clipping plane to close clipping plane is a factor and it is not…the jitter still exists even though I have a low ratio.

Rotations are not a commutative operation like translations are, therefore order matters.

I would venture to guess that your initial translation to the origin is not zeroing out because of floating point error. You might want to try something more along the lines of:
Push a matrix on the stack (glPushMatrix())
Load an identity matrix (glLoadIdentity())
Translate to your position
Apply your rotations
Draw all of your vertices relative to this position
Pop the matrix off of the stack (glPopMatrix())

If it looks backwards, it’s because matrices are applied in reverse order. lhkbob suggested the same order earlier.

I’m still having a problem and so i decided to simplify my test case to the simplest form that I could think of and I’ve made a quick and dirty example.

I also posted this question on the OPENGL forums since JavaGaming was down…here is what I posted:
http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=240770&fpart=2

I’ve created a quick demo of my problem and you can run it from here:

  [url=http://www.zaczek.com/jogl/TestRotations.jnlp]TestRotations.jnlp[/url]  

I implemented some rudimentary keyboard and mouse rotations but nothing real so don’t be surprised if the rotations are not acting as you expect - just quick and dirty:

Mouse Inputs - use left mouse button to rotate around

Keyboard Inputs:
1 - Focus on “Earth” (Earth Size: 6000 unit radius)
2 - Focus on Teapot located at 0, 0, 0
3 - Focus on Teapot located at 1000, 1000, 1000
4 - Focus on Teapot located at 10000, 10000, 10000
5 - Focus on Teapot located at 30000, 30000, 30000
6 - Focus on Teapot located at 60000, 60000, 60000
7 - Focus on Teapot located at 100000, 100000, 100000

Q - Far Clipping Plane: 100
W - Far Clipping Plane: 1000
E - Far Clipping Plane: 10000
R - Far Clipping Plane: 100000
T - Far Clipping Plane: 1000000
Y - Far Clipping Plane: 10000000
U - Far Clipping Plane: 100000000

A - Near Clipping Plane: 5.0
S - Near Clipping Plane: 0.5
D - Near Clipping Plane: 0.05
F - Near Clipping Plane: 0.005
G - Near Clipping Plane: 0.0005
H - Near Clipping Plane: 0.00005
J - Near Clipping Plane: 0.000005

Note that when viewing at 10,000 away from the earth (key 4) changing the clipping plane distance has no effect on the jitter…I can have a small far to near clipping ratio and still have horrible jitter.

Here is my display() method…note, this code is in JOGL but it would be almost exactly the same in OPENGL:


public void display(GLAutoDrawable drawable) {
    GL gl = drawable.getGL();

    if (reset) {
      int width = getWidth();
      int height = getHeight();
      gl.glViewport(0, 0, width, height);
      gl.glMatrixMode(GL.GL_PROJECTION);
      gl.glLoadIdentity();
      // Set the Field-of-View, Aspect Ratio, Near & Far clipping planes
      glu.gluPerspective(65.0, (double) width / (double) height, nearPlane, farPlane);
      gl.glMatrixMode(GL.GL_MODELVIEW);
      reset = false;
    }

    // Clear Screen And Depth Buffer
    gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
    
    // Reset/Clear matrix
    gl.glLoadIdentity();

    // Update light position
    // 0 in the last component causes jagged terminator on planets, 1 results
    // in a smooth terminator but the location of the sunlight is no longer
    // correct...not sure why.  Old code used a 0 (zero) very successfully,
    // what changed?!
    gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition, 0);

    gl.glPushMatrix();         
      double posX = Math.cos(rotY * Math.PI / 180.0) * radiusOffset;
      double posY = Math.sin(rotY * Math.PI / 180.0) * radiusOffset;

      double zX = Math.cos(rotX * Math.PI / 180.0) * radiusOffset;
      double zY = Math.sin(rotX * Math.PI / 180.0) * radiusOffset;

      
      double eyeX = systemX + posX;
      double eyeY = systemY + posY;
      double eyeZ = systemZ + zY;
      
      glu.gluLookAt(eyeX,    eyeY,    eyeZ,
                    systemX, systemY, systemZ,
                    0,       1,       0);
      
      System.out.println("Eye:  " + eyeX + ", " + eyeY + ", " + eyeZ);
      System.out.println("View: " + systemX + ", " + systemY + ", " + systemZ);
      
      // Draw stars
      displayStars(gl);
      
      // Draw Teapot
      gl.glPushMatrix();
        gl.glEnable(GL.GL_LIGHTING);
        gl.glEnable(GL.GL_COLOR_MATERIAL);
        gl.glDisable(GL.GL_CULL_FACE);
        gl.glTranslated(teapotX, teapotY, teapotZ);
        GLUT glut = new GLUT();
        gl.glColor3f(1f, 1f, 0f);
        glut.glutSolidTeapot(0.01);
        gl.glDisable(GL.GL_LIGHTING);
        gl.glColor3f(1f, 1f, 1f);
        glut.glutWireTeapot(0.0101);
        
        gl.glScaled(0.02, 0.02, 0.02);
        displayAxes(gl);        
      gl.glPopMatrix();

      // Draw Earth
      displayEarth(gl);      
      
    gl.glPopMatrix();

    // Flush The GL Rendering Pipeline
    gl.glFlush();
  }

Here are the links to the source codes:
KeyHandler.java
MouseHandler.java
Renderer.java
ResourceRetriever.java
TestRotations.java
TextureReader.java
BitmapLoader.java
stars.jpg
earth.jpg

BTW, Icetigris, I hope I didn’t hijack your thread here and if so please let me know and I’ll move my crap out of here into a separate thread…I just realized that your question may not be answered yet, sorry.

@Z_Knight,
I took a look at your demo, and when I was looking at the far away teapots (the ones not near the origin), I always saw the jittering, even when I only rotated about one axis. Changing the near/far ratios didn’t change anything and I’m not surprised. This seems like a floating point error problem since floats only have 5-7 digits of precision (can’t remember this late at night ;D). Changing to double precision probably won’t help you since many opengl implementations just convert doubles to floats to use them internally.

I can only suggest looking into the solutions described by continuous worlds. I’ve never implemented a technique like that, but it sounds like what you’re interested in. Otherwise maybe you could rig something up similarly to how java3d uses Locales.

I just did a small float/double test like the one a poster did at the OpenGL site and I’m kind of disappointed by the results…assuming I did this simple thing correctly:


    float  tmpf = 10000.029588568046f;
    double tmpd = 10000.029588568046;
            
    System.out.println(" float: " + tmpf + "\n"
                     + "(cast): " + (double)tmpf + "\n"
                     + "double: " + tmpd);

Resulted in:


 float: 10000.029
(cast): 10000.029296875
double: 10000.029588568046

Sigh…so does this mean that internally doubles are being converted to floats and if so is there something I could do to overcome this? Is there a flag to force using doubles or is there some manipulation that could be done to handle doubles better?

I updated my code and the demo and I think I figured out something…

here is the demo link: TestRotations.jnlp

This time it defaults to the “non jitter” code…press ‘L’ to toggle between jitter and non-jitter code.

In the jitter code (original code) I created an Earth and a teapot and I set the gluLookAt() to move the view to the teapot location and to rotate around the teapot…because of the precision of floats I believe this caused the jitter as you moved the teapot farther from 0,0,0. To fix this I tried to apply a global glTranslated() and translate the entire system by the distance of the teapot…ie move everything back by this distance so that the teapot was at 0,0,0 and my view would be looking at 0,0,0 and I figured in this case the precision would not be a problem because I was using gluLookAt() around the 0,0,0 point instead of some far distance such as 10000, 10000, 10000. Well…this still caused jitter because (I believe) the glTranslated() would apply the 10000 distance translation which effectively is a matrix multiplication which still cause the precision problem.

SO…I did the following to change the display method to make the system not-jitter. I still translate the objects by the distance to the teapot…so the earth gets moved down and the teapot is moved to 0,0,0, etc…but the difference is that instead of a global glTranlated() I apply the differencing in position directly on each object and so now the jitter is not present.

Note, that updated the demo and the codes that are linked above…I also added a couple of things. I draw a white line from the Earth to the teapot (just because) and I have a wireframe blue/cyan sphere that is a fixed size and I use it see that when I press the various scale keys I could see things scale relative to something…you can turn of the wireframe sphere using the ‘P’ key.

To scale the system (earth, teapot scale) press the Z, X, C, V, B, N keys to scale from 1, 10, 100, 1000, 10000, 100000, respectively.

I updated the demo: TestRotations.jnlp

Now, pressing ‘L’ toggles through the 3 modes and the corresponding gluLookAt() values are displayed at bottom left.
0) No jitter - each object translated explicitly so that the focused objects are moved to 0,0,0

  1. Jitter - global glTranslate() call which translates everything via a single call
  2. Jitter - No translations, gluLookAt() points at object at the specified location

so this shows that I need to move the objects in the scene by the negative distance of the object that is the focus object and have gluLookAt point at 0,0,0 to avoid the jitter…using a global translation or not translating the object at all but using gluLookAt to look at the object at its offset point causes jitter.