daniel_i_l 295 Report post Posted April 17, 2006 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. 0 Share this post Link to post Share on other sites
Yann L 1802 Report post Posted April 17, 2006 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. 0 Share this post Link to post Share on other sites
daniel_i_l 295 Report post Posted April 17, 2006 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. 0 Share this post Link to post Share on other sites
jyk 2094 Report post Posted April 17, 2006 Quote:Original post by Yann LThe 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. 0 Share this post Link to post Share on other sites
Yann L 1802 Report post Posted April 17, 2006 Quote:Original post by jykOne 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 TThen 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. 0 Share this post Link to post Share on other sites
jyk 2094 Report post Posted April 17, 2006 Quote:Original post by Yann LIf 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 TThen 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). 0 Share this post Link to post Share on other sites
Yann L 1802 Report post Posted April 17, 2006 Yep, true. I'm tired, and should probably go to bed :) 0 Share this post Link to post Share on other sites
daniel_i_l 295 Report post Posted April 18, 2006 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. 0 Share this post Link to post Share on other sites
jyk 2094 Report post Posted April 18, 2006 Quote:Original post by daniel_i_lAnd 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. 0 Share this post Link to post Share on other sites
daniel_i_l 295 Report post Posted April 18, 2006 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. 0 Share this post Link to post Share on other sites
jyk 2094 Report post Posted April 18, 2006 Quote:Original post by daniel_i_lBut isn't the glMultMatrix like a rotation call, if that is true then the glTranslate should come after (like you said, rotation then translation)?OpenGL uses column vectors, which is reflected in the fact that OpenGL transform function calls must be issued 'backwards' from the order in which you want them to be applied. So if you want rotate->translate, you call glTranslate() first, and the rotation function second. 0 Share this post Link to post Share on other sites
daniel_i_l 295 Report post Posted April 18, 2006 Thanks for clearing that up:) 0 Share this post Link to post Share on other sites
daniel_i_l 295 Report post Posted April 21, 2006 I implemented it like this:glLoadIdentity(); Camera.Look(); glColor3f(0.5,1,0.5); CVector3 vForward2D = {1,0,0}; CVector3 vNormal; vNormal = NormalToMap(g_HeightMap, ((Map.BestPoint.x)/SCALE_SIDE), ((Map.BestPoint.z)/SCALE_SIDE)); CVector3 vSide = Normalize(Cross(vNormal, vForward2D)); CVector3 vForward = Cross(vSide, vNormal); CVector3 vPosition = Map.BestPoint; float m[16]; m[0] = vSide.x; m[1] = vSide.y; m[2] = vSide.z; m[3] = 0.0f; m[4] = vNormal.x; m[5] = vNormal.y; m[6] = vNormal.z; m[7] = 0.0f; m[8] = vForward.x; m[9] = vForward.y; m[10] = vForward.z; m[11] = 0.0f; m[12] = vPosition.x; m[13] = vPosition.y; m[14] = vPosition.z; m[15] = 1.0f; glMultMatrixf(m); glLineWidth(2); glBegin(GL_TRIANGLES); glVertex3f(-15, 1, 15); glVertex3f( 20, 1, 20); glVertex3f( 0, 1, -20); glEnd(); glLineWidth(1);And it worked Great! I don't even have to translate cause of the vPosition input. I just have a little question, when I set the forward to CVector3 vForward2D = {1,0,0};the triangle points to the left instead of to the right, only when I set the x to -1 it points right. Also, when the z is set to 1 it point into the screen instead of out of it? Why does this happen?Thanks. 0 Share this post Link to post Share on other sites