PDA

View Full Version : How to rotate about FIXED axes?



JiauFoo
04-06-2001, 01:58 AM
Hi all.

I'm having some trouble modeling the rotational human shoulder joint.

The shoulder (or rather, arm) can rotate in the x, y and z axes. However, after each rotation, the axes are rotated too. Meaning that it's very hard to tell which direction the next rotation is going to occur in.

How do I make the shoulder/arm rotate about a fixed x, y and z axis, regardless of it's current orientation?

Thanks for any help. Need it badly.

EricK
04-06-2001, 09:58 AM
You could call glLoadIdentity between your calls to glRotate

JiauFoo
04-06-2001, 05:44 PM
Sorry, already tried glLoadIdentity between rotates. Doesn't work.

You see, I need to glTranslate down the rotated x-axis to draw the arm (and other connected appendages). After glLoadIdentity, the whole arm disappears.

But thanks for your suggestion, anyway.

mango
04-07-2001, 05:53 PM
Use (or rather think in) local coordinates.

JiauFoo
04-07-2001, 07:12 PM
Sounds like it might work - except that I'm still a beginner at this, and don't really know the transformational matrices that would be required.

Any hints would be helpful ...

Deiussum
04-08-2001, 06:14 AM
If you haven't already, read the chapter on transformations in the Red Book. If you don't know what the Red Book is do a search on this forum for it and you'll find a link to a downloadable version of it. I don't have a link offhand because I actually bought the book. It's an invaluable resource.

JiauFoo
04-08-2001, 06:45 AM
I've read the Transformation chapter in the red book. But I still can't solve it.

A rotation, say about a fixed x-axis will rotate the local axes, right? So, how do you do ANOTHER rotation, on top of the first rotation, say, about the ORIGINAL x-axis?

It's a little beyond me, since, after multiple consecutive rotations, I have little idea where the local x, y and z axes are w.r.t. the original x, y, z axes.

I've found someone's web-page, where (s)he used something called Quarterions (???) to solve this problem. Since I have to submit my project REAL SOON (tm), I won't have the luxury of reading and understanding it. Too bad.

I just wanted to know if someone had some reasonably simple method of doing multiple consecutive rotations about invariant axes.

harsman
04-09-2001, 12:22 AM
How about transforming the "fixed" axes of the identity transform to your current local coordinate system and then rotating around them? That should be fairly easy to visualize.

Deiussum
04-09-2001, 08:51 AM
Some code might help to understand what you are doing exactly, but my first instinct is that you don't really need Quaternions to model a human arm.

Here's some quick pseudocode to demonstrate how I would probably do this.




// Might have to play with the right order of x/y/z rotations
DoShoulderRotations();
DrawUpperArm();

// This should just have to rotate on one axis depending on how you are envisioning
// the initial orientation of the arm.
DoElbowRotation();
// This should also only need to be around one axis
DoForeArmRotation();
DrawForeArm();

// This will maybe be two axis rotations depending on how realistic you want it
DoWristRotations();
DrawHand();

// If you really want to get fancy and do fingers then do this..

for each finger
{
glPushMatrix();
DoFirstJointRotations();
DrawFirstBone();
DoSecondJointRotations();
DrawSecondBone();
DoThirdJointRotations();
DrawThirdBone();
glPopMatrix();
}


I take back what I said above, quaternions might come in handy for things like the ball and socket joint of the shoulder. Most of the other joints have a limited rotation, however so breaking it into individual axis rotations would probably be easier.

Also... all of the above code assumes that the local origin of your objects is at the position of the joint. If it isn't, then you would have to throw in some translations as well so that the rotational point would be the joint.

[This message has been edited by Deiussum (edited 04-09-2001).]

mango
04-09-2001, 06:49 PM
I read in the advanced forum that you have got a new job Deiussom so congratulations!
I do not think that the pseudo code works without a translation to the next object after the parent object.

If the arm is along the x-axis is it not very difficult to draw it just draw one part and translate to the next and so on. If you do not reset the modelview matrix does it works if the distance is relative from the parent object to the child object. Adding rotations is not very difficult if also the angles are local parent-child object. The translations would be the same since the local coordinate system has also been rotated. Note that even if you just rotate around the shoulder is the whole arm moved.

Another observation is how similar this is traversing some more traditional datatypy recursive.

JiauFoo
04-09-2001, 08:06 PM
Hi Deiussum!

I had no problems modelling the arm, forearm, hand and (all five) fingers (with all three joint things).

It's just the darned ball-and-socket shoulder-to-arm joint that's got me confounded.

Anything simpler than quarternions?

JiauFoo
04-09-2001, 08:07 PM
Hi Harsman!

Erm ... I'm just a newbie to OpenGL. Could you run that by me in newbie terms?

harsman
04-10-2001, 01:53 AM
Now you're trying to rotate the arm around a world axis, but your problem is that you also have defined the position of the arm according to the shoulders coordinate system, and the shoulder's x-axis (or whatever) is not the same as the world x-axis. If you express the world x-axis in the shoulders local coordinate system you can then rotate around that without problems. This is jusrt a transform.

EricK
04-10-2001, 04:39 AM
Originally posted by JiauFoo:
Sorry, already tried glLoadIdentity between rotates. Doesn't work.

You see, I need to glTranslate down the rotated x-axis to draw the arm (and other connected appendages). After glLoadIdentity, the whole arm disappears.

But thanks for your suggestion, anyway.

I guess I don't really understand what the problem is but I can say that that I have experience doing exactly what you want to do. In robotics and mechanical engineering the arm is called a "kinematic chain". If you do a web search I bet you will find information that will help. In fact the first page I hit was this somewhat cute example: http://www.museoffire.com/Lyceum/Dojo/Tutorials/Anatomy/T0D3.htm
(check the home page for more useful info)
Anyhow, I believe there are two ways you can approach this problem. You could use glLoadIdentity but you need to keep track of the bodies in the so called "world coordinates". It is not too hard to create code that will give you the transformation from a body's local coordinates to the world coordinates. After all if you have the transformation matrix from world to body frame the inverse is just the transpose of that matrix. However, it sounds like you are currently using local coordinates to make it easy to place the next body in the chain. If that is the case then you should be able to use the matrix stack to temporarily store the current matrix then pop it off the stack when you are done. You probably need to multiply the two matrices (obviously the shoulder effects the location and orientation of the rest of the arm).

Finally, unless you post your code or pseudo code we are just guessing.

Deiussum
04-10-2001, 12:41 PM
Originally posted by mango:
I read in the advanced forum that you have got a new job Deiussom so congratulations!

Thanks! http://www.opengl.org/discussion_boards/ubb/smile.gif




I do not think that the pseudo code works without a translation to the next object after the parent object.


Yeah. You're right. I put the code in pretty fast and I guess I wasn't thinking of that. http://www.opengl.org/discussion_boards/ubb/smile.gif I thought later I should also have put a glPushMatrix/glPopMatrix around the whole thing to preserve any "camera" transformations.

Rizo
04-10-2001, 09:16 PM
Originally posted by JiauFoo:
Hi all.

I'm having some trouble modeling the rotational human shoulder joint.

The shoulder (or rather, arm) can rotate in the x, y and z axes. However, after each rotation, the axes are rotated too. Meaning that it's very hard to tell which direction the next rotation is going to occur in.

How do I make the shoulder/arm rotate about a fixed x, y and z axis, regardless of it's current orientation?

Thanks for any help. Need it badly.

I think the problem you are having is called the gimball effect. The problem is with how the OpenGL pipeline works. As you should know, a call to glRotate*() doesn't really rotate the object, it simply post-multiplies the current modelview matrix by a rotation matrix:

[current_model_view_matrix]=[current_model_view_matrix] * [R]

so what happens here that the effect is that some axis gets rotated. In order to avoid this, now you have think whether you want to rotate the object about its own coordinates or about the world coordinates.

How do you implement it?
let's say you have a rotation_matrix which has some value (perhaps it came from a trackball rotation, or its the joint's previous orientation). In the following, MV stands for ModelView matrix and CT is the actual current transformation

glPushMatrix();
glLoadIdentity(); //MV=I
glMultMatrixf(rotation_matrix); //MV=rotation_matrix

glRotatef(angle,xaxis,yaxis,xaxis); //MV=MV*R => MV=rotation_matrix*R
glGetFloatv(GL_MODELVIEW_MATRIX,rotation_matrix);
glPopMatrix();

glMultMatrixf(rotation_matrix);

so what happens when you do another rotation?

1) MV=I*R1 => MV=R1
2) MV=MV*R2 => MV=R1*R2
3) MV=MV*R3 => MV=R1*R2*R3

now remember matrices work from right to left, so when we say pre-multiply, we mean multiply on right. You should easily come up with the post-multiply implementation for a world-centred rotation (but in you case I don't think you need it)


Hope this helps,
Reza

Ps. I think I'm totally confused about this pre/post multiply business myself. The above is correct in the order I've put things, but the notation may be wrong. In particular,

MV = MV * R is a post-multiply
MV = R * MV would be a pre-multiply
(can somebody verify this please?)

In addition, the above is for a body centred rotation and you need world centred rotation, here is the world centred one:

glPushMatrix();
glLoadIdentity; //MV = I
glRotatef(angle,xaxis,yaxis,zaxis); //MV=R
glGetFloatv(GL_MODELVIEW_MATRIX,rotation_matrix); //rotation_matrix = R
glPopMatrix();

glMultMatrixf(rotation_matrix);

By now you should be well confused. http://www.opengl.org/discussion_boards/ubb/smile.gif
Reza

[This message has been edited by Rizo (edited 04-10-2001).]

Rizo
04-10-2001, 09:30 PM
Originally posted by JiauFoo:
Hi all.

I'm having some trouble modeling the rotational human shoulder joint.

The shoulder (or rather, arm) can rotate in the x, y and z axes. However, after each rotation, the axes are rotated too. Meaning that it's very hard to tell which direction the next rotation is going to occur in.

How do I make the shoulder/arm rotate about a fixed x, y and z axis, regardless of it's current orientation?

Thanks for any help. Need it badly.

I think the problem you are having is called the gimball effect. The problem is with how the OpenGL pipeline works. As you should know, a call to glRotate*() doesn't really rotate the object, it simply pre-multiplies the current modelview matrix by a rotation matrix:

[current_model_view_matrix]=current_model_view_matrix] * [rotation_matrix]

so what happens here that the effect is that some axis gets rotated. In order to avoid this, now you have think whether you want to rotate the object about its own coordinates or about the world coordinates. In your case, when you rotate the joint only, you are doing a object coordinate transformation.

How do you implement it?

let's say you have a rotation_matrix which has some value (perhaps it came from a trackball rotation, or its the joint's previous orientation). In the following, MV stands for ModelView matrix


glPushMatrix();
glLoadIdentity(); //MV=I
glMultMatrixf(rotation_matrix); //MV=rotation_matrix

glRotatef(angle,xaxis,yaxis,xaxis); //MV=MV*R => MV=rotation_matrix*R
glGetFloatv(GL_MODELVIEW_MATRIX,rotation_matrix);
glPopMatrix();

glMultMatrixf(rotation_matrix);

so what happens when you do another rotation?

1) MV=I*R1 => MV=R1
2) MV=MV*R2 => MV=R1*R2
3) MV=MV*R3 => MV=R1*R2*R3

now remember matrices work from right to left, so when we say pre-multiply, we mean multiply on right. You should easily come up with the post-multiply implementation for a world-centred rotation (but in you case I don't think you need it)


Hope this helps,
Reza