PDA

View Full Version : gluLookAt unwanted rotation\spining



MaximV
01-10-2010, 09:59 PM
I've been programming for a while now on OpenGL and after implementing the gluLookAt function I found out that if the target goes 90 degrees sideways of the viewer (turn 90 degrees from original location) the camera spins sideways. If I were to change the Y axis the entire scene just rotates!

I'm well aware that this is a basic problem yet I've been unable to find on the web (and on this forum) any solution, and switching to rotation matrixes cant be a solution here.

I think there must be a solution involving the up vector, but I've got no idea as to the calculations needed to perform in order to "neutralize" the spining effect.

Thanks for the help

Dark Photon
01-11-2010, 06:01 AM
...after implementing the gluLookAt function I found out that if the target goes 90 degrees sideways of the viewer (turn 90 degrees from original location) the camera spins sideways. If I were to change the Y axis the entire scene just rotates!
Well, sure sounds like gimbal lock (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=208925). But you're just trying to track a target with gluLookAt? Not sure why that would cause a problem, assuming you use pure vector math to compute the gluLookAt parameters.

The basic gluLookAt algorithm for determining the vector basis is:

back = (eye-center).normalize();
right = cross( up, back ).normalize();
up = cross( back, right );

AFAIK, there is nothing inherently in this that's gonna cause any weird sort of angle locking if you provide reasonable values for eye, center, and up. It's just plain vector math.

So I'd suspect how you're computing eye, center, and up.

Disconnect your math and try a test: for a given eye and up, rotate the center point around the eyepoint in a circle on a plane perpendicular to the up vector. You should see no weird effects.

MaximV
01-11-2010, 10:04 AM
thanks to your comment on how these things dont go this way on gluLookAt (second time you save me) I've checked the gluLookAt version I took:

GLfloat x[3], y[3], z[3];
GLfloat mag;

// Make rotation matrix

// Z vector
z[0] = cameraLocation.x - cameraTarget.x;
z[1] = cameraLocation.y - cameraTarget.y;
z[2] = cameraLocation.z - cameraTarget.z;
mag = sqrt(z[0] * z[0] + z[1] * z[1] + z[2] * z[2]);
if (mag) { // mpichler, 19950515
z[0] /= mag;
z[1] /= mag;
z[2] /= mag;
}

// Y vector
y[0] = upx;
y[1] = upy;
y[2] = upz;

// X vector = Y cross Z
x[0] = y[1] * z[2] - y[2] * z[1];
x[1] = -y[0] * z[2] + y[2] * z[0];
x[2] = y[0] * z[1] - y[1] * z[0];

// Recompute Y = Z cross X
y[0] = z[1] * x[2] - z[2] * x[1];
y[1] = -z[0] * x[2] + z[2] * x[0];
y[2] = z[0] * x[1] - z[1] * x[0];

// mpichler, 19950515
// cross product gives area of parallelogram, which is < 1.0 for
//non-perpendicular unit-length vectors; so normalize x, y here


mag = sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
if (mag) {
x[0] /= mag;
x[1] /= mag;
x[2] /= mag;
}

mag = sqrt(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);
if (mag) {
y[0] /= mag;
y[1] /= mag;
y[2] /= mag;
}

cameraMatrix.m[0][0] = x[0];
cameraMatrix.m[0][1] = x[1];
cameraMatrix.m[0][2] = x[2];
cameraMatrix.m[0][3] = 0.0;
cameraMatrix.m[1][0] = y[0];
cameraMatrix.m[1][1] = y[1];
cameraMatrix.m[1][2] = y[2];
cameraMatrix.m[1][3] = 0.0;
cameraMatrix.m[2][0] = z[0];
cameraMatrix.m[2][1] = z[1];
cameraMatrix.m[2][2] = z[2];
cameraMatrix.m[2][3] = 0.0;
cameraMatrix.m[3][0] = 0.0;
cameraMatrix.m[3][1] = 0.0;
cameraMatrix.m[3][2] = 0.0;
cameraMatrix.m[3][3] = 1.0;


and switched it to this:

forward[0] = cameraTarget.x - cameraLocation.x;
forward[1] = cameraTarget.y - cameraLocation.y;
forward[2] = cameraTarget.z - cameraLocation.z;

up[0] = upx;
up[1] = upy;
up[2] = upz;

// Normalize Forward
r = sqrt( forward[0]*forward[0] + forward[1]*forward[1] + forward[2]*forward[2] );
if (r)
{
forward[0] /= r;
forward[1] /= r;
forward[2] /= r;
}

/* Side = forward x up */

side[0] = forward[1]*up[2] - forward[2]*up[1];
side[1] = forward[2]*up[0] - forward[0]*up[2];
side[2] = forward[0]*up[1] - forward[1]*up[0];


// Normalize Side
r = sqrt( side[0]*side[0] + side[1]*side[1] + side[2]*side[2] );
if (r)
{
side[0] /= r;
side[1] /= r;
side[2] /= r;
}


/* Recompute up as: up = side x forward */
up[0] = side[1]*forward[2] - side[2]*forward[1];
up[1] = side[2]*forward[0] - side[0]*forward[2];
up[2] = side[0]*forward[1] - side[1]*forward[0];

cameraMatrix.m[0][0] = side[0];
cameraMatrix.m[1][0] = side[1];
cameraMatrix.m[2][0] = side[2];

cameraMatrix.m[0][1] = up[0];
cameraMatrix.m[1][1] = up[1];
cameraMatrix.m[2][1] = up[2];

cameraMatrix.m[0][2] = -forward[0];
cameraMatrix.m[1][2] = -forward[1];
cameraMatrix.m[2][2] = -forward[2];


works perfect! (I know I should get normalize and cross to a function but I want to save unnecessary header here)

Thank you again :)