3
$\begingroup$

I'm working with OpenGL to try to rotate / translate my 3d object : a cow.

The requirement is simple :

  1. If I toggle key 'r'. The cow spinning around and random axis.
  2. If I drag the cow with mouse, it translate along its own x axis which means +x directions is for cow's head
  3. Rotation and translation need not execute at the same time.
  4. Rotation and translation is done is modeling space.

To implement first requirement, I used timer function like this :

void rotateCow(int value) {
    //rotation ended
    if (!rotate_flag)
        return;

    printf("rotateCow\n");

    angle = (angle + 5) % 360;
    glutPostRedisplay();
    glutTimerFunc(30, rotateCow, 1);
}

and for rotation and translation : (some of codes are skipped)

void dragCow() {
    glPushMatrix();
    //some codes are skipped..

    //rotation start
    if (rotate_flag == 1) {
        rotate_flag = 2;
        glutTimerFunc(30, rotateCow, 1);
    }

    glTranslatef(trans_x, trans_y, trans_z);
    glRotatef(angle, rotate_x, rotate_y, rotate_z);

    glCallList( cowID ); // Draw cow.
    glPopMatrix();
}

void onMouseDrag( int x, int y ) {
    y = height - y - 1;
    if (trans_flag == DIR_X) {
        trans_x = ((x - oldX) / DRAG) + old_trans_x;
    }

    glutPostRedisplay();
}

If I run as above(rotate and then translate) rotation is as expected.

However, the translation is done in global x-axis not towards head direction of cow.

If I change the order like this :

glRotatef(angle, rotate_x, rotate_y, rotate_z);
glTranslatef(trans_x, trans_y, trans_z);

It shows that translation is as expected(towards head direction of cow).

However, the rotations not works - the rotation-axis made on global x-axis and the cow revolve around that line.

So how can I solve this problem??

$\endgroup$
1
$\begingroup$

You can put the translation first, and then the rotation, but have the translation happen in the direction of the cow's head. To do that, you need a vector from the center of the cow to its head. Then you need the length of the translation. You can then do the translation in that direction. Like this:

float direction_x;
float direction_y;
float direction_z;
direction_x = cow_head_x - cow_center_x;
direction_y = cow_head_y - cow_center_y;
direction_z = cow_head_z - cow_center_z;

// find the length of the direction vector
float dir_length = sqrt(direction_x * direction_x + direction_y * direction_y + direction_z * direction_z);

// normalize the direction vector by dividing by the length
direction_x /= dir_length;
direction_y /= dir_length;
direction_z /= dir_length;

// Create a new vector pointing in the correct direction with the same
// length as the drag
float cow_translate_x = direction_x * drag_length;
float cow_translate_y = direction_y * drag_length;
float cow_translate_z = direction_z * drag_length;

// Do the transformation
glTranslatef(cow_translate_x, cow_translate_y, cow_translate_z);
glRotate(angle, rotate_x, rotate_y, rotate_z);

You could also get the direction vector by converting the angles to a direction. For example, if the rotation is only around the Y-axis, you could calculate it by doing the following:

float direction_x;
float direction_y;
float direction_z;
direction_x = cos(angle);
direction_y = 0.0; // since we're rotating around the Y axis
direction_z = sin(angle);

In this case, the direction vector is already normalized.

If you do have rotations around all 3 axes, you can calculate the direction vector using spherical coordinates:

direction_x = sin(angle) * cos(phi);
direction_y = sin(angle) * sin(phi);
direction_z = cos(angle);

where angle is the rotation around the y axis and phi is the angle above/below the x/z plane. The direction should already be normalized in this case, too.

$\endgroup$
  • $\begingroup$ How to calculate angle and phi when rotate around all 3 axes? I've read wikipedia you linked, and try to calculate it... but still don't know how to calculate those with rotation angle used on glRotate(angle, rotate_x, rotate_y, rotate_z); $\endgroup$ – BlakStar Oct 16 '17 at 5:22
  • $\begingroup$ The easiest way is to take a unit vector, like <0, 0, 1>, run it through the Euler rotation matrix, then convert the point at the end of the resulting vector to spherical coordinates. You can use this formula to get the cartesian rotation matrix from your Euler angles. $\endgroup$ – user1118321 Oct 16 '17 at 14:55
  • $\begingroup$ Thx. This works perfectly good. However, I'm still curious that how to calculate 'angle' and 'phi' that for spherical coordinates with Euler angle. $\endgroup$ – BlakStar Oct 17 '17 at 7:32
  • $\begingroup$ A quick search didn't turn up any obvious answers, and my linear algebra is somewhat limited, so unfortunately, I don't know of another way. $\endgroup$ – user1118321 Oct 17 '17 at 16:37
  • 1
    $\begingroup$ note that $angle$ here is called the polar angle and $phi$ here is called the azimuth angle. how you translate between spherical coordinates and euler angles depends on the way your euler angles are defined, since there are multiple ways to use them. if you have access to these books, they have information about coordinate conversions and euler angles: Real-Time Rendering 3rd Edition (in the fourth chapter there is information about Euler Angles) Mathematics for 3D Game Programming and Computer Graphics 3rd Edition (in the appendix there is a lot about cartesian and spherical coordinates) $\endgroup$ – Tare Nov 15 '17 at 7:52

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.