3D rotation

Hi

I have the following method that draws a cylinder using gluCylinder().

The GL quadric is oriented so that its axis is along the z-axis (0,0,1). Since my Cylinder object can be arbitrarily oriented it is necessary to correctly rotate the cylinder. This is done using the method directionAngles(), which computes the direction angles between the rotated cylinder z-axis and the fixed global axes (1,0,0), (0,1,0) and (0,0,1).

For cylinder axes (1,0,0) and (0,1,0) the cylinder is correctly oriented. However, if I set the axis to lie along th z-axis (0,0,1) then it incorrectly points in the x-direction.

Can anyone see what I’m doing wrong?

Thanks

Graham

public void toOpenGL(final javax.media.opengl.GLAutoDrawable gLDrawable)
{
    javax.media.opengl.GL       gl  = gLDrawable.getGL();
    javax.media.opengl.glu.GLU  glu = new javax.media.opengl.glu.GLU();
    
    // cylinder base circle 1 centre and axis
    Point3D                 base1Centre  = getEndCircle1Centre();
    Vector3D                cylinderAxis = getAxisVector();
    double                  baseCircle1Radius = getEndCircle1Radius();
    double                  baseCircle2Radius = getEndCircle2Radius();
    double                  axisLength = axisLength();
    Double  alpha = new Double();
    Double  beta  = new Double();
    Double  gamma = new Double();
    cylinderAxis.directionAngles(alpha,beta,gamma,true);
    
gl.glTranslated(base1Centre.getX(),base1Centre.getY(),base1Centre.getZ());  // translate wrt base circle 1
gl.glRotated(alpha.getValue(),1.0,0.0,0.0);                                 // rotate the cylinder on the x axis
gl.glRotated(beta.getValue(),0.0,1.0,0.0);                                  // rotate the cylinder on the y axis
gl.glRotated(gamma.getValue(),0.0,0.0,1.0);                                 // rotate the cylinder on the z axis

    javax.media.opengl.glu.GLUquadric   quadric = glu.gluNewQuadric();          // create a pointer to the quadric object
    glu.gluQuadricNormals(quadric,javax.media.opengl.glu.GLU.GLU_SMOOTH);       // create smooth normals
    glu.gluQuadricTexture(quadric,true);                                        // Create Texture Coords
    glu.gluQuadricOrientation(quadric,javax.media.opengl.glu.GLU.GLU_OUTSIDE);  // normals acting outwards
    if (joglObject.getIsWireframe())
        glu.gluQuadricDrawStyle(quadric,javax.media.opengl.glu.GLU.GLU_LINE);
    else
        glu.gluQuadricDrawStyle(quadric,javax.media.opengl.glu.GLU.GLU_FILL);
    glu.gluCylinder(quadric,baseCircle1Radius,baseCircle2Radius,axisLength,25,15);    // quadric - base1 radius - base2 radius - axis length - circ div - axis div 

    glu.gluDeleteQuadric(quadric);                                              // free up quadric memory
}

public void directionAngles(Double alpha, Double beta, Double gamma, final boolean degrees)
{
double n = norm();
if (Functions.abs(n) > Tolerances.TOLERANCE)
{
if (!degrees)
{
alpha.setValue(Functions.acos(ma/n));
beta.setValue(Functions.acos(mb/n));
gamma.setValue(Functions.acos(mc/n));
}
else
{
alpha.setValue(Functions.radiansToDegrees(Functions.acos(ma/n)));
beta.setValue(Functions.radiansToDegrees(Functions.acos(mb/n)));
gamma.setValue(Functions.radiansToDegrees(Functions.acos(mc/n)));
}
}
}

Just off of the top of my head, I believe that this is referred to as gimbal lock (experienced when trying to represent every rotation as a sequence of x,y,z angle rotations). You may want to switch to arbitrary axis angles or using quaternions. openmali and javax have a vecmath package that provides good support for these math objects.

BTW I didn’t check your code, it’s just the problem you described seemed to fit gimbal lock very well.

Hi

Thanks for your reply.

An object such as a cylinder is stored as:

public class Cylinder3D
{

/** End cap 1. */
protected PlanarCircle3D mEndCircle1;
/** End cap 2. */
protected PlanarCircle3D mEndCircle2;
/** Cylinder axis. */
protected Curve3D mAxis;
/** Specifies whether or not the cylinder is open. */
protected boolean mIsOpen;

//…
}

It’s then the mapping of this object to the opengl representation that I’m not clear about.

It’s one thing using glRotate() to rotate an object about an arbitrary vector but it’s another thing to map an object from one orthogonal coordinate system to another.

Thanks for suggesting gimbal lock. I found a useful description at: http://en.wikipedia.org/wiki/Gimbal_lock

Graham

Quaternions are not enough to solve the problem of gimbal lock. You need to use non eulerian transforms to avoid gimbal lock and it is easier to use this kind of transform with quaternions. A lot of people use quaternions + eulerian transforms, that leads to gimbal lock, I proved it, I worked on gimbal lock during 6 months in 2006. I can show you the formula (given by Pascal Mignot, teacher and researcher at the University of Reims, France) if you want, I need to have a look at my report.

Hi gouessej

I’d be very interested in seeing the equations.

I’ve spent all day trying all sorts of coordinate transformations between local and global axes, using quaternions, euler angles, etc. and still can’t get it to work. Any rotation can be reducd to an angular rotation about an arbitrary axis but this is an unnatural way of thinking of mapping one orthogonal coordinate system to another. I also tried converting an orthogonal 3x3 rotation matrix to axis-angle form which I then fed into glRotate(angle,(axis)) but still can’t get it to work!!

My email address is gmseed@gmail.com.

Thanks for your assistance as this is driving me crazy!!

Graham

I’ve had good success using 3x3 rotation matrices, you just have to make sure that the angle you give opengl is in degrees. If I’m starting with the identity as my transform, or I’m pushing relative rotation transforms, it’s helpful to create the 3x3 matrix by envisioning the axis of the desired basis. Then the columns of the rotation are those axis, if you want to convert a local coordinate system into a world or parent system.

It reduces the risk of gimbal lock as it decreases the accumulation of errors (you start with the identity) but it doesn’t solve the problem completely. It is not so simple. I’m going to post the formula today, I’m at work, I need to find the report.

http://www.univie.ac.at/cga/faq/angles.html

The answer is here:

The current rotations must respect the previous rotations to avoid gimbal lock to prevent any alignment of rotation axis which causes this problem. This problem doesn’t depend on the mathematical way you choose to express rotations, it depends on the way to combine rotations. The problem comes from Euler’s classical transform: R=Rx.Ry.Rz

Implicitely or explicitly you use it with matrices, quaternions, Euler or Cardan angles, …

You should correct this transform and it works whatever you used to express your rotations:

R=R[R[R[Ox,a]Oy,b]R[Ox,a]Oz,c] . R[R[Ox,a]Oy,b] .R[Ox,a].

Contributed by Julien Gouesse

Interesting, but could you explain the notation when you wrote the equation:
Specifically, what math operations are you doing when you say R[Ox, a], or R[ R[Ox, a]Oy, b]

Thanks,

R[Ox,a] is a rotation around the X axis of an angle measuring a. Then you can apply such a tranform on another axis. I have a source code that uses this algorithm but it is very complicated and it is in C++ as I haven’t put this in TUER for the moment. If you’re interested, let me know.

The source code (under GPL licence) is here, in C++ unfortunately:

http://membres.lycos.fr/javalution/download/gimballock.zip

The link seemed broken, and would eventually redirect to lycos.fr’s homepage. I can’t say exactly what happened since I can’t speak French. Is there anyway you could e-mail me the zip?

Now the link should work. If not, I will transfer the zip onto another server because I want to allow everyone to download the source code.