Making an object in the game to rotate toward you.

Hi everyone.

I know that gluLookAt is handy for using it from another object’s perspective to look at you and then copying that matrix, inverting it, and using it to multiply against the GL_MODELVIEW matrix to make an object track you, but doing it this way makes it rotate toward you instantly, which is fine for a FPS game where the enemy just needs to turn and look at you. But this isn’t ideal for a drone ship in space flying around in 3D that needs to rotate at it’s own limited maximum rotate speed and slowly turn toward you in a smooth and realistic manner.

I tried the code on a few sites which teach how to convert a rotation matrix to a quaternion so that I can use the quaternion instead of the inverted gluLookAt matrix copy to do the orientation but it’s not duplicating what the inverted matrix does. The code is identical on two different sites that I checked so it “supposedly” has to be right. My gut feeling is that I’m either making an assumption that those sites didn’t explain, or that by some fluke, those formulas work for DirectX or some other GL other than OpenGL.

Has anyone here been able to create a rotation quaternion from a rotation matrix that duplicates what the matrix does perfectly? If so, would you be kind enough to show me the code that you use to get it to work? This is what I’m using now: The rmq_x, rmq_y, rmq_z, rmq_w variables are global GLfloat variables because the function can’t return an array or multiple values. I pass it the rotation matrix that I inverted from the gluLookAt matrix to try and create the quaternion:


void Ship::rotationMatrixToQuaternion(GLfloat inp_mat[16])
{
    GLfloat t = 1 + inp_mat[0] + inp_mat[5] + inp_mat[10];
    GLfloat s = 0.0;
    
    if (t > 0.0)
    {
        s = sqrt(t) * 2;
        rmq_x = (inp_mat[6] - inp_mat[9]) / s;
        rmq_y = (inp_mat[8] - inp_mat[2]) / s;
        rmq_z = (inp_mat[1] - inp_mat[4]) / s;
        rmq_w = 0.25 * s;
    }
    else if ((inp_mat[0] > inp_mat[5]) && (inp_mat[0] > inp_mat[10]))
    {
        s = sqrt(1.0 + inp_mat[0] - inp_mat[5] - inp_mat[10]) * 2;
        rmq_x = 0.25 * s;
        rmq_y = (inp_mat[1] + inp_mat[4] ) / s;
        rmq_z = (inp_mat[8] + inp_mat[2] ) / s;
        rmq_w = (inp_mat[6] - inp_mat[9] ) / s;
    }
    else if (inp_mat[5] > inp_mat[10])
    {
        s = sqrt(1.0 + inp_mat[5] - inp_mat[0] - inp_mat[10]) * 2;
        rmq_x = (inp_mat[1] + inp_mat[4]) / s;
        rmq_y = 0.25 * s;
        rmq_z = (inp_mat[6] + inp_mat[9]) / s;
        rmq_w = (inp_mat[8] - inp_mat[2]) / s;
    }
    else
    {
        s = sqrt(1.0 + inp_mat[10] - inp_mat[0] - inp_mat[5]) * 2;
        rmq_x = (inp_mat[8] + inp_mat[2]) / s;
        rmq_y = (inp_mat[6] + inp_mat[9]) / s;
        rmq_z = 0.25 * s;
        rmq_w = (inp_mat[1] - inp_mat[4]) / s;
    }
}

Any help anyone can give me would be very much appreciated.

I also wanted to add that the reason I want to convert the inverted gluLookAt matrix to a quaternion is because it’s easier to do a slower rotation by using quaternion interpolation. I know that the current function I use for multiplying quaternions work, because I use it for my own personal rotation in first-person view flying every which way in 3D space, and I’m able to create an inverted rotation matrix from my own movement to re-orient my ship to match my view.

I can do all the math on paper from scratch to calculate the dot product of the object’s current look vector with the target vector divided by the lengths of both vectors multiplied together and I get the right angle. I can calculate the cross product to calculate what the arbitrary axis is supposed to be and on paper, that works out fine as well (a 180 degree angle doesn’t work with the cross product because the vectors can’t be parallel for that calculation, but that’s okay because I want the ship to turn slowly, not 180). However, when I create a rotation matrix with the right values plugged into the quaternion, the rotation matrix doesn’t end up doing what would have been done if that ship had been my first person view rather than a 3rd party object in the universe that is trying to track me.

I tried doing the trig such as above from scratch, I tried converting the inverted matrix to a quaternion, and I still can’t solve this problem of having a ship rotate around to match me without “cheating” with the inverted gluLookAt matrix which does what I want to do except it does it instantly instead of gradually. That’s why I want a quaternion so that I can do an interpolation between the rotation quaternion and the current one for the object.

The matrix-to-quaternion code which I have is effectively identical to the code which you posted (albeit slightly simpler, as it doesn’t try to handle the case where t<=0).

About the only scope for variation is row-major versus column-major; but even that would just negate the result (i.e. it would rotate by the same amount about the same axis but in the opposite direction).

So long as you don’t hit any pathological cases (where t is very close to zero, i.e. an axis-aligned transformation), that code should be fine. I’d look elsewhere for the problem.

[QUOTE=GClements;1281276]

About the only scope for variation is row-major versus column-major; but even that would just negate the result (i.e. it would rotate by the same amount about the same axis but in the opposite direction).

So long as you don’t hit any pathological cases (where t is very close to zero, i.e. an axis-aligned transformation), that code should be fine. I’d look elsewhere for the problem.[/QUOTE]

Thank you for the quick reply. Yeah, this is frustrating. :slight_smile: I tried re-arranging from column-major to row-major order and it still didn’t work. I initially tried to do the dot product thing and the cross product thing to give me an angle and an arbitrary axis to turn on with a rotation quaternion and it still didn’t work.

The next thing I’m going to try is using a quaternion to turn on the X-Z plane and then use another one to turn on the Y-Z plane to point to the final target vector. If I can get that to work so that it points where it ultimately is supposed to point to, I can do some sort of quaternion interpolation to smoothen out the rotation in increments so that at least, it will turn as if it was doing it on one arbitrary axis in slow motion rather than just turning all the way on one plane and then all the way on the other. What I can calculate and do on paper, and what ends up happening in the GL_MODELVIEW matrix seems to be two different stories. :slight_smile: