rotating to a normal

Started by
11 comments, last by daniel_i_l 18 years ago
I have a tank whose "base" position is sitting flat on the xz plane (centered at 0,0,0). But the game I have is a on heightmap, and I want the tank to be rotated to fit the terrain, for example I want it to pointing down if it's going downhill). Now I got the normal to the heightmap (x,y,z) were the tank is standing and nomalized it, I also have a normalized vector (x,0,z) that shows the tanks direction(on the xz plane). So how can I use the glRotatef function (1 or more than 1) to both face the tank in the right direction and correctly fit it on the heightmap according to the normal? Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
Advertisement
The best way to solve this problem is by considering the different coordinate frames. When you say "I have a normal and a direction vector", then you have essentially defined a target coordinate system for your tank.

Now, the idea is to directly construct a rotation matrix that will map the old local coordinate system to the new one. First, you would construct a matrix representing the final coordinate system. You do that by filling the columns of a 3x3 matrix with the three base vectors: NxD, D, N (where N is your normal, and D your direction vector). Make sure both N and D are normalized.

Now, you need to find a matrix which maps the old coordinate system to the one you just created. From the matrix FAQ:

Q40. How do I use matrices to convert one coordinate system to another?-----------------------------------------------------------------------  Similar to the previous problem, the requirement is to map one  coordinate system onto another. However, instead of just trying to  map one coordinate axis onto another, all three axii have to be matched.  Both coordinate systems are therefore represented as either 3x3 or  4x4 matrices.  The problem is therefore to find the rotation matrix that will map one  matrix onto another. This can be expressed mathematically:    Mfinal = Mrot . Morig  where Mfinal is the final coordinate system matrix,        Morig  is the original coordinate system and        Mrot   is the desired rotation matrix.  The goal is then to find the matrix Mrot. This can be achieved by  rearranging the equation to give:                  -1    Mfinal . Morig   = Mrot                           -1    Mrot   = Mfinal . Morig  Thus, the desired rotation matrix can be by calculatng the inverse of  the original coordinate system and multiplying it with the final  rotation matrix.  As a check, consider the cases when either the original or final  rotation matrices are the identity matrix. In each case, the rotation  matrix should match the final matrix and the inverse of the final  matrix respectively.


You can make this much easier, if the original coordinate system is the identity (which should be true in your case). Then, the rotation matrix equals the matrix constructed from the three base vectors above.

You can load this matrix into OpenGL using one of the glLoadMatrix or glMultMatrix commands.
Thanks. I have a few questions.
First of all are NxD,D and N columns or rows?
Also, glLoadMatrix gets a 4X4 matrix, what do I fill in for the 4th row and column?
And last of all, I read that glLoadMatrix is passed a pointer to a 4X4 matrix. would I do that like this:
double* m;double matrix[4][4];matrix[0][0] = ......matrix[3][3] = ...m = &matrix;glLoadIdentity();glLoadMatrix(m);DrawTank();glLoadIdentity();DrawEverythingNormally();

Is that correct?
Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
Quote:Original post by Yann L
The best way to solve this problem is by considering the different coordinate frames. When you say "I have a normal and a direction vector", then you have essentially defined a target coordinate system for your tank.

Now, the idea is to directly construct a rotation matrix that will map the old local coordinate system to the new one. First, you would construct a matrix representing the final coordinate system. You do that by filling the columns of a 3x3 matrix with the three base vectors: NxD, D, N (where N is your normal, and D your direction vector). Make sure both N and D are normalized.
One problem the OP may have here is that his D and N are not (necessarily) at right angles, and therefore [ NxD | N | D ] will probably not be orthogonal.

@The OP: In my own code I address this problem using incremental rotations, which I think is the best way to do it. However, this requires having your own math library with the appropriate functionality, and so may not be an option for you at the moment.

If not, here's something you might try. I've never done it this way myself, so I really don't know how well it would work in practice:
Vector3 side = normalize(cross(normal, forwardInXZPlane));Vector3 forward = cross(side, normal);float m[16];m[0] = side[0];m[1] = side[1];m[2] = side[2];m[3] = 0.0f;m[4] = normal[0];m[5] = normal[1];m[6] = normal[2];m[7] = 0.0f;m[8] = forward[0];m[9] = forward[1];m[10] = forward[2];m[11] = 0.0f;m[12] = position[0];m[13] = position[1];m[14] = position[2];m[15] = 1.0f;
You can now send 'm' to OpenGL via glMultMatrixf().

Again, this is just a suggestion, but at least now you have a couple of different ideas to work with.
Quote:Original post by jyk
One problem the OP may have here is that his D and N are not (necessarily) at right angles, and therefore [ NxD | N | D ] will probably not be orthogonal.

If he does his math right, they should be at a right angle (otherwise, the tank would be pointing upwards into the air, or downwards into the ground). You can still ensure orthogonality by using a double cross product. If we assume N to always be a normalized reference vector, we can do:

T = normalize(N x D)
D = N x T

Then the matrix formed by N, D, and NxD will be guaranteed to be orthonormal.

Quote:
First of all are NxD,D and N columns or rows?

In OpenGL, columns.

Quote:
Also, glLoadMatrix gets a 4X4 matrix, what do I fill in for the 4th row and column?

Everything should be zero, except for the bottom right element, which should be one.
Quote:Original post by Yann L
If he does his math right, they should be at a right angle (otherwise, the tank would be pointing upwards into the air, or downwards into the ground).
My comment was based on the following from the original post:
Quote:I also have a normalized vector (x,0,z) that shows the tanks direction(on the xz plane).
Which suggests that N and D will rarely be at right angles to begin with.
Quote:You can still ensure orthogonality by using a double cross product. If we assume N to always be a normalized reference vector, we can do:

T = normalize(N x D)
D = N x T

Then the matrix formed by N, D, and NxD will be guaranteed to be orthonormal.
And this is (almost) exactly what the code sample I posted does (the only difference being that, I think, it should be D = T x N).
Yep, true. I'm tired, and should probably go to bed :)
Thanks everyone, I think I'll try that.
And one other thing, should I translate to the position of the tank with glTranslatef() before calling glMultMatrix or after?
Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky
Quote:Original post by daniel_i_l
And one other thing, should I translate to the position of the tank with glTranslatef() before calling glMultMatrix or after?
Most likely the glTranslatef() call should come before the glMultMatrix() call; this corresponds to the transformation order rotate->translate, which is usually what you want for rendering models.
But isn't the glMultMatrix like a rotation call, if that is true then the glTranslate should come after (like you said, rotation then translation)?
Thanks.
"We've all heard that a million monkeys banging on a million typewriters will eventually reproduce the entire works of Shakespeare. Now, thanks to the internet, we know this is not true." -- Professor Robert Silensky

This topic is closed to new replies.

Advertisement