PDA

View Full Version : How to "extract" a rotation



DrGonzo
09-15-2010, 01:05 PM
Hey all,

I suspect this problem to be quite trivial, but I just don't see it.

The main idea is that the code below connects 2 points by means of a beam (a square through both points, with the point as the center of the 'top' and 'bottom', perpendicular to the direction) and 4 quads to complete the beam.

This works well, but now I need the world coordinates of the vertices that make up the corners of my quads. (because I built my collision detection around them).

The translation (glTranslated) can be 'compensated' by adding the value of the transX, transY and transZ to the corresponding X,Y and Z element (and in case of the second quad, v also needs to be added).

But how would one 'compensate' the rotation (glRotated), given that I know the angle and the axis it rotates around?

I was thinking that I needed to create my own rotation matrix, and use that to multiply my points with, but I don't get how I do that. Wikipedia suggested that I should use a certain matrix when using an arbitrary axis, but that it should rotate around a unit vector. But where does this unit vector come from?

In the code below transX,transY and transZ and transX2,transY2, transZ2 are values of two points in space in WORLD coordinates. They originate from a member matrix that holds the global transformation of a certain joint.
TransX..Z contains the 3 translation values from the current joint TransX2..Z2 contains the 3 translation values from the next joint.

The rest of the code is then used to calculate the angle and axis to rotate about, and afterwards the 8 points of the 2 quads (which form the top and bottom cap of the beam) are calculated.

*I make use of a custom vector library, plMath.



double vx = transX2-transX;
double vy = transY2-transY;
double vz = transZ2-transZ;

//handle the degenerate case of z1 == z2 with an approximation
if(vz == 0.0)
vz = .0001;

double v = sqrt( vx*vx + vy*vy + vz*vz );
double ax = (180 / M_PI) * acos( vz/v );
if ( vz < 0.0 )
ax = -ax;
double rx = -vy*vz;
double ry = vx*vz;
glPushMatrix();

//draw the beam
glTranslated( transX,transY,transZ );
glRotated(ax, rx, ry, 0.0);

//with sides
plVector3d p11 = plVector3d(-0.01, 0.01, 0.0);
plVector3d p12 = plVector3d(0.01, 0.01, 0.0);
plVector3d p13 = plVector3d(0.01, -0.01, 0.0);
plVector3d p14 = plVector3d(-0.01, -0.01, 0.0);

plVector3d p21 = plVector3d(-0.01, 0.01, v);
plVector3d p22 = plVector3d(0.01, 0.01, v);
plVector3d p23 = plVector3d(0.01, -0.01, v);
plVector3d p24 = plVector3d(-0.01, -0.01, v);
glPopMatrix();

Rosario Leonardi
09-16-2010, 12:30 PM
Let me understand...
You have two points, A and B, in world coordinate.
You want to draw a vertical quad that connect the two points.

You can't simply send the quad vertex in world space? I don't understand why you need a matrix.

MaxH
09-16-2010, 07:09 PM
I would put your untransformed tube coordinates into an array and apply the rotation and translation transformations myself, i.e. with my own rotation routines. Rotation is a simple matrix multiplication. So - don't use GL Rotate and Translate - write your own.

DrGonzo
09-17-2010, 04:55 AM
Thanks for the suggestions, seems the figure is indeed called a 'tube' and not a 'beam'. To take away any confusion, perhaps this drawing might help: http://img835.imageshack.us/img835/263/opengl.jpg

I've looked up transformation matrices, and it's clear to me the top 3 values of the 4th column describe the translation and that the top left 3x3 matrix describes the rotation.

The glTranslate call can be easily replaced.
However, it is not clear to me how I am to convert the glRotate call into a 3x3 Rotation matrix, (which I would then also place in the transformation matrix).

As this is no rotation about the X,Y or Z axis, I need to create a rotation matrix around an arbitrary axis, which I guess is (vx, vy, 0.0) with an angle theta of ax.

Hmm, seems I implemented a rotation about the origin, while I in fact seem to need a rotation about an arbitrary axis:

I'll try to implement this:
http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.html (Rotation about an arbitrary line)

MaxH
09-17-2010, 01:00 PM
There are different ways to solve your problem. My suggestion (as mentioned above) is very basic. Do the scaling, translation, and orientation transformations yourself. Then use OpenGL to display the results. This way you never use glRotate or glTranslate. It's easier than it sounds. I've put a basic example of this at < http://www.mfwweb.com/OpenGL/tube.c >

Don't be put off by the fact that it's 330 lines of code. Most of those lines are supporting math and graphics routines. All of the transformation calculations are done in a 20 line subroutine called 'Transform_Tube'. It computes a new tube that stretches from points A to B. You will need to link this demo with OpenGL and GLUT. The new tube coordinates are put into array 'Q' which you can print out or use for collision calculations. The routine 'Draw_Tube' draws the new tube between points A and B.

DrGonzo
09-20-2010, 02:16 AM
Woops, you missed a capital 'T' in you link, and that gives me a 404. I did find this: http://www.mfwweb.com/OpenGL/Tube.c ;)

On-Topic: Thanks, that's just what I need, I've studied it a little, and it is clear what each function does.

The coding seems very neatly written, I could pick up a thing or two about that as well.

Thanks for this very detailed example!

MaxH
09-20-2010, 01:13 PM
... that's just what I need, I've studied it a little, and it is clear what each function does. I just loaded a cleaned up version of that code. The indents were messed up in the original. Hopefully, you were able to compile and run it too. It does what you want, but in a slightly different way than you asked for.