using opengl's function glRotate for rotations

Post questions, comments and feedback to our 3Dconnexion Windows Development Team.

Moderator: Moderators

Post Reply
tomkirk
Posts: 7
Joined: Wed Mar 19, 2008 7:34 am

using opengl's function glRotate for rotations

Post by tomkirk »

We use the mouse for 3D navigation in Catia V5 and it works great. We are now trying to apply it to an in house application. I have the SDK and can read the translation and rotation values in the new program with no problem. The device sends the normalized x,y,z rotation vector and angle about the vector fine. We use opengl and thought we would use the function glRotatef (a, x, y, z). However, when you reverse the mouse rotation, about Y for example, the direction changes immediately (+ or -) causing the 3D model to rotate abruptly. Can you reference an example
showing how to handle the data correctly for this function. An exhaustive search has turned up nothing. Thank you.
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

Hello tomkirk,

I've never used that function, but reading its doc, it looks like it should work fine. It applies a small rotation delta to the existing transformation. You will have to scale the angle to get something appropriate for degrees.

What exactly are you seeing? The rotation should change direction immediately when you start twisting the device in a different direction.

Jim
3Dx Software Development
tomkirk
Posts: 7
Joined: Wed Mar 19, 2008 7:34 am

Post by tomkirk »

I have scaled the angle so that the rotation works great initially. The problem comes when reversing the cap which changes the axis value from +1 to -1 for example on the Y axis. The accumulated angle remains the same at that point but the object immediately rotates to the opposite direction because the rotation vector is now 180 deg. different. So, If I first rotate 30 deg. in one direction, the model rotates fine, then rotate the cap in the opposite direction, the model instantly rotates as if I had initially rotated it in the opposite direction and I have a rotation of -30 deg. Thanks for your help.
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

The part jumps?
It should only be getting small delta rotation matrices out of glrotatef.

How are the rotations being accumulated? You can't accumulate the angle, RX, RY & RZ from the device. You must use those values to create a rotation matrix (glrotatef appears to do that for you). That rotation matrix must be applied to another accumulation matrix. Then small deltas from glrotatef(angle, rx, ry, rz) can be used to update that matrix.

How does that compare to what you are doing?

Print out the resulting matrices & look at the numbers. The numbers don't lie. You'll see a flip if it is happening.

Jim
3Dx Software Development
tomkirk
Posts: 7
Joined: Wed Mar 19, 2008 7:34 am

Post by tomkirk »

I read the values from the device and assign to local values in the function as seen here.

ra3 = pRotation->Angle * 60.0;
rx3 = pRotation->X;
ry3 = pRotation->Y;
rz3 = pRotation->Z;

If I use ra3 in the function directly, the model rotates fine except that
when I let go of the cap, the model recenters (since ra3 goes back to 0)

glRotatef (ra3, rx3, ry3, rz3);

I accumulate the angle in "accum" and then use it in the function and rotation works great in 1 direction and holds the rotation. Then when the cap is reversed, I get the value of "accum" applied all at once in the opposite direction.

accum += ra3;
glRotatef (accum, rx3, ry3, rz3);

It's like I need to set accum back to 0 when the direction reverses, but that would only work for 1 axis.
jwick
Moderator
Moderator
Posts: 3341
Joined: Wed Dec 20, 2006 2:25 pm
Location: USA
Contact:

Post by jwick »

I see. You can't do that. You have to accumulate in a matrix, not the rotation angle value.

You have to do something like this (of course you also have to do your usual GL projection/perspective & pushmatrix, popmatrix calls) :

Matrix accumulatedTransformation;
MakeIdentityMatrix( accumulatedTransformation );
...

while(1) {

...

// Load your accumulated transformations onto the GL matrix stack
LoadMatrixOntoGLStack( accumulatedTransformation );

// Add in the small rotation from the 3Dx device
glRotatef( pRotation->Angle * 60.0, pRotation->X, pRotation->Y, pRotation->Z );

// Add in the small translation from the 3Dx device (the order of this may be wrong)
glTranslatef( pTranslation->X, pTranslation->Y, pTranslation->Z );

GetMatrixOnTopOfStack( accumulatedTransformation );

... draw the part

}
tomkirk
Posts: 7
Joined: Wed Mar 19, 2008 7:34 am

Post by tomkirk »

You were correct. I created a matrix to accumulate the rotations from the 3d device and apply it during each redaw and it works great. I have also implemented the panning and zooming using the translation parameters. Thank you for your assistance.

Tom
Manicat
Posts: 3
Joined: Fri Mar 06, 2009 3:13 am

Post by Manicat »

Hello Tomkirk

I'm writing a simulation program that I can use to visualize rollercoaster and dark ride attractions. I also apply OpenGL and i face exactly the same problem as you indicated: translations are easy to implement, but I get the same program interaction with rotations as you described.

Unfortunately jwick's hint was apparently clear to you, but I am stil in the dark.

Would you be be willing to post your solution in code ?
tomkirk
Posts: 7
Joined: Wed Mar 19, 2008 7:34 am

Post by tomkirk »

define these:
float accumMatrix[16];
float m3dx[16];
float m3dxNew[16];

1. initialize accumMatrix to identity

2. generate a rotation matrix (m3dxNew) from the pRotation data that comes
from the sensor.

3. multiply m3dxNew and accumMatrix to produce m3dx

4. assign m3dx to accumMatrix

5. use the accumMatrix in the rendering loop to cause the rotation
like this: glMultMatrixf ((float*) accumMatrix);

hope this helps
Manicat
Posts: 3
Joined: Fri Mar 06, 2009 3:13 am

Post by Manicat »

Thanks tomkirk, I have implemented the rotation issue as following:

A (global)rotation matrix RotMat[4][4] is declared.
This matrix is used to perform a rotation on the display item in the following way:

=================

glLoadIdentity(); // Reset The Current Modelview Matrix
glScaled(scale,scale,scale); // Scaling
glTranslated(translx,transly,0.); // Translate according to user input
glMultMatrixd(&RotMat[0][0]); // Rotate in correct direction as instructed by 3d Trackball

=================

At program start and after a reset RotMat is initialized as Identity matrix.

for (i=0;i<4;i++) {
for (j=0;j<4;j++) {
RotMat[j] = (i-j ? 0.0 : 1.0);
}
}

Furthermore a timer callback function _3DxTimerProc() is used to poll the 3D input device for change of keystates and the cap displacement values. In this routine a matrix M[3][3] is use to store an incremental rotation matrix as following:

=================
VOID CALLBACK _3DxTimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
double transsens = 1.E7;
double A[3][3],M[3][3];
double u,v,w,angle;
double c,s,t;
int i,j;
BOOL update;

/*
..... (handling of keystrokes)
*/

update = FALSE;
if (g3DSensor) {
CComPtr<IVector3D> pTranslation = g3DSensor->Translation;
CComPtr<IAngleAxis> pRotation = g3DSensor->Rotation;

if (pTranslation->Length > NEARZERO) {
update = TRUE;

translx += (pTranslation->X * (transsens / rsphere));
transly += (pTranslation->Y * (transsens / rsphere));
scale += (pTranslation->Z / (10.*pTranslation->Length));
scale = max(scale,1.E-2);
}

if (pRotation->Angle > NEARZERO) {
update = TRUE;

angle = -1.E-1 * pRotation->Angle;
c = cos(angle);
s = sin(angle);
t = 1.-c;

u = pRotation->X;
v = pRotation->Y;
w = pRotation->Z;

M[0][0] = u*u + (v*v + w*w)*c;
M[0][1] = u*v*t - w*s;
M[0][2] = u*w*t + v*s;
M[1][0] = u*v*t + w*s;
M[1][1] = v*v + (u*u + w*w)*c;
M[1][2] = v*w*t - u*s;
M[2][0] = u*w*t - v*s;
M[2][1] = v*w*t + u*s;
M[2][2] = w*w + (u*u + v*v)*c;

/*
=================
Then this incremental matrix is multiplied with the previously accumulated matrix RotMat. For this matter a temporary storage matrix A is used.
=================
*/
for (i=0; i<3; i++) {
for (j=0; j<3; j++) A[j] = RotMat[0]*M[0][j] + RotMat[1]*M[1][j] + RotMat[2]*M[2][j];
}
/*
=================
Then the old rotation matrix RotMat is overwritten with matrix A:
=================
*/
for (i=0; i<3; i++) {
for (j=0; j<3; j++) RotMat[j] = A[j];
}
}

/*
=================
Finally the display is forced to be updated (rendered again) if this is necessary because the cap input has changed:
=================
*/

if (update) {
// Force screen update
InvalidateRect(hWnd,NULL,FALSE);
}
}
}

=================
That's indeed all there is to. Works like a charm.

One other remark: the order of matrix multiplation is important.
The correct multiplication order is RotMat = RotMat * M

When it is implemented as RotMat = M * RotMat then the display item rotates around its own local coordinate system (as tomkirk experienced and reported in another post) rather than around a fixed coordinate system
Post Reply