rotating to a normal
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.
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:
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.
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:
Is that correct?
Thanks.
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.
Quote:Original post by Yann LOne 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 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.
@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 LMy comment was based on the following from the original post:
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).
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: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).
T = normalize(N x D)
D = N x T
Then the matrix formed by N, D, and NxD will be guaranteed to be orthonormal.
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.
And one other thing, should I translate to the position of the tank with glTranslatef() before calling glMultMatrix or after?
Thanks.
Quote:Original post by daniel_i_lMost 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.
And one other thing, should I translate to the position of the tank with glTranslatef() before calling glMultMatrix or after?
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement