OpenGL vector rotation (I've spent 6 hours now)
Mike Farrell

I am really upset and burnt out. I don't think I've ever been more frustrated in my entire life of programming. I'm about ready to slam my keyboard up against the wall. >:(>:(>:(>:(>:(>:(>:(>:(>:(>:(>:(

Please someone help me out if you can. (If you can't or you don't understand the question please don't flood the thread with meaningless attempts). I've figured this out once before but it will not work in my new situation.

Keep in mind I am using OpenGL's matrix routines and NOOOOOOT allegro's.

I have an vehicle that can drive over a SCENE filled with polygons. Most of the polygons are flat surfaced (normal vector 0, 1, 0) but a number of them are slanted. I want it so that when the vehicle is over the slanted polygons that the vehicle will rotate itself around the normal of the surface it's on. When I tell glRotate to rotate around the normal vector. I got a very strange and incorrect result. Basically I want the object to rotate on it's OWN y axis (the poly normal), and not the WORLD axis, (and it will not work).

I would draw an illustration but I'm way too tired. Bob started to help me with this on irc and when it didn't work he had to leave which left me stuck for 3 hours trying things that didn't work.

Here is some code that worked with allegro's matrix routines but wont' work when I use them in openGL (probably because of the order of application or whatever I dont' know).

world->get_normal_vector(i, QUAD, &a1, &a2, &a3);
normalize_vector_f(&a1, &a2, &a3);
cross_product_f(a1, a2, a3, 0, -1.0, 0, &b1, &b2, &b3);

//(then inside of my poly drawing function)
//I get this matrix and apply it to the vertices
get_vector_rotation_matrix_f(&trans, b1, b2, b3, rx);

I have done what feels like 25 different cases of the exact same operation above in OpenGL and get the same annoying and incorrect results.

Can someone please help me???

Elias

I sent you something similiar in IRC, this is the function i used when i tried to start with opengl some time ago: It's just conceptual, so you have to adjust it to work. In my code i'm using it as the camera matrix, so i'm not even completely sure it works :)

The idea of it is, to just convert the allegro-like orientation into an OpenGL matrix.

It uses vector_up, which would be your surface normal. And it uses a vector_heading, which is a unit vector in the direction the vehicle is heading. pos is the position of the vehicle.

1void orient_to_GL() {
2 GLfloat m[16];
3
4 Vector vector_right;
5
6 glLoadIdentity();
7
8 cross_product_f(vector_up->x, vector_up->y, vector_up->z,
9 vector_heading->x, vector_heading->y, vector_heading->z,
10 &vector_right->x, vector_right->y, &vector_right->z);
11
12 m[0]=vector_right->x;
13 m[4]=vector_right->y;
14 m[8]=vector_right->z;
15 m[12]=0;
16
17 m[1]=vector_up->x;
18 m[5]=vector_up->y;
19 m[9]=vector_up->z;
20 m[13]=0;
21
22 m[2]=vector_front->x;
23 m[6]=vector_front->y;
24 m[10]=vector_front->z;
25 m[14]=0;
26
27 m[3]=pos->x;
28 m[7]=pos->y;
29 m[11]=pos->z;
30 m[15]=1.0f;
31
32 glMultMatrixf(m);
33}

The code to draw the vehicle should go right after a call to this function.

Thomas Harte

I offer a completely different solution to korval, which might also be worth investigating.

Bear in mind that what you pass to the gl rotation stuff is the vector you want to rotate around, not the vector you want to line up with. So, if the normal vector were (0,1,0) (a flat polygon, normal heading straight up), and I rotated around that, I'd get a car that looked like it was turning.

So, the question is, what do you want to rotate around, and by how much? Well, the answer is easy!

Your car has some upward vector, call that vector A. You want the upward vector A to become equal to the normal vector of some polygon, call that vector B. And you want to move from A to B using a rotation matrix.

First of all, how many degrees do you want to rotate by? Well, that is easy. If you calculate A.B (i.e. the dot product), you get (length of A)*(length of B)*(cosine of angle inbetween). So you can easily use inverse cosine (acos in libc talk) & a quick radians->degrees conversion to get the genuine angle.

This is very good, but around what vector do you want to rotate? This too is easy - you want to rotate around AxB (i.e. the cross product). Think about it geometrically for a second and it'll become obvious why. The cross product of two vectors gives a vector perpendicular to both. Therefore any rotation of any vector on the plane containing the original two vectors around the vector that resulted from the cross product will still be on the plane. And clearly that is exactly what you want.

Mike Farrell

Hey guys I got it myself! Man that was crazy. I'm too lazy to paste it in words so I'll just paste the code :-)

1void VEHICLE::draw()
2{
3 glPushMatrix();
4 glTranslatef(x, y, z);
5
6// if(surface_normal.y <= -1.05 || surface_normal.y >= -0.95)
7 if(up_vector.y <= -1.01 || up_vector.y >= -0.99)
8 {
9 MATRIX_f matrix;
10 GLfloat rot[16];
11 float rot_x, rot_y, rot_z;
12
13 cross_product_f(up_vector.x, -up_vector.y, up_vector.z, 0, 1.0, 0, &rot_x, &rot_y, &rot_z);
14 normalize_vector_f(&rot_x, &rot_y, &rot_z);
15
16 get_vector_rotation_matrix_f(&matrix, rot_x, rot_y, rot_z, DEG(acos(-up_vector.y))*0.711111111111111111111111111111111);
17 allegro_gl_MATRIX_f_to_GLfloat(&matrix, rot);
18 glMultMatrixf(rot);
19 }
20 glRotatef(-ang_deg, 0, 1, 0);
21
22
23 glScalef(2.5, 2.5, 2.5);
24 model->draw();
25
26 glPopMatrix();
27}

Damn that's about the hardest thing yet. Thanks for trying to help me though.

Thomas Harte

Well, thats the solution I suggested give or take some assumptions about the dot product between (0,1,0) and your plane normal. But one thing, with respect to this code :

normalize_vector_f(&rot_x, &rot_y, &rot_z);
get_vector_rotation_matrix_f(&matrix, rot_x, rot_y, rot_z, DEG(acos(-up_vector.y))*0.711111111111111111111111111111111);
allegro_gl_MATRIX_f_to_GLfloat(&matrix, rot);
glMultMatrixf(rot);

Do you have serious problems with the much simpler and infinitely more prone to hardware acceleration :

glRotatef(DEG(acos(-up_vector.y))*0.711111111111111111111111111111111, rot_x, rot_y, rot_z);

?

Mike Farrell

Thomas: indeed you are right. The reason I was using get_vector_rotation matrix is because I thought glRotate wasn't doing the operation properly. I'll change the code later thanks..

Thread #199643. Printed from Allegro.cc