Get model to face direction of movement - SOLVED - Printable Version +- iDevGames Forums (http://www.idevgames.com/forums) +-- Forum: Development Zone (/forum-3.html) +--- Forum: iPhone, iPad & iPod Game Development (/forum-11.html) +--- Thread: Get model to face direction of movement - SOLVED (/thread-8073.html) Get model to face direction of movement - SOLVED - MikeD - Sep 5, 2010 02:49 PM This is a question that has been asked in MANY forums on the web as I've been reading most of them :s That said, I'm still confused as to how to orient my 3D model to face the direction of travel. I have a normalized 3D vector that is pointing in the direction of travel and I want to orient my model to face that direction. I'm thinking I need to create a 3D matrix from that vector, but all the examples I've been trying cause the model to rotate in all sorts of ways, but never face the direction I expect. At the moment I'm trying to create a matrix from a vector using code that was inside the gluLookAt function. This code looks like this: Code: ```static inline void SSMatrixFromVector(float* mtx, const SSVector3D v, const float upx, const float upy, const float upz) { //    GLfloat m[16];     GLfloat x[3], y[3], z[3];     GLfloat mag;          /* Make rotation matrix */          /* Z vector */     z[0] = 0 - v.x;     z[1] = 0 - v.y;     z[2] = 0 - v.z;     mag = sqrtf(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 = sqrtf(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);     if (mag) {         x[0] /= mag;         x[1] /= mag;         x[2] /= mag;     }          mag = sqrtf(y[0] * y[0] + y[1] * y[1] + y[2] * y[2]);     if (mag) {         y[0] /= mag;         y[1] /= mag;         y[2] /= mag;     }      #define M(row,col)  mtx[col*4+row]     M(0, 0) = x[0];     M(0, 1) = x[1];     M(0, 2) = x[2];     M(0, 3) = 0.0;     M(1, 0) = y[0];     M(1, 1) = y[1];     M(1, 2) = y[2];     M(1, 3) = 0.0;     M(2, 0) = z[0];     M(2, 1) = z[1];     M(2, 2) = z[2];     M(2, 3) = 0.0;     M(3, 0) = 0.0;     M(3, 1) = 0.0;     M(3, 2) = 0.0;     M(3, 3) = 1.0; #undef M     }``` The model is rotating, but not in a way that keeps the front of the shop oriented toward the direction of travel. The models rolls and banks as the direction changes but not in the correct way. I hope that has made some sense. If anyone has any pointers or suggestions that would be great. Cheers MikeD RE: Get model to face direction of movement - OneSadCookie - Sep 5, 2010 03:16 PM This is what gluLookAt does -- given a forward vector and an up vector: normalize both cross forward and up to get right/left (depending on handedness and order of cross product) cross forward and right/left to get new up use forward, right/left and new up as a rotation matrix Of course, there are two cross products that you can change the order of to get the wrong answer, several stages that may or may not need renormalization, and you'll have to fight the fact that OpenGL's matrices aren't the same way round as your linear algebra text. Your code would be a lot easier to read if you defined some functions like "normalize" and "cross". RE: Get model to face direction of movement - AnotherJake - Sep 5, 2010 03:38 PM If you're having difficulty doing this via gluLookAt, or your own UVN rotation code isn't working, you could also just go brute-force on it and use some trig, as long as you aren't using it for anything particularly performance critical. This is assuming up is toward the zenith, so roll isn't taken into account here. I don't know if this code works or not. I just butchered it together for some ideas of how to approach it brute-force style. I put in two functions, one for y being the zenith and one for z being the zenith. Code: ```enum {     RHO,    // distance from origin to point     THETA,    // similar to longitude (azimuth)     PHI        // similar to latitude (altitude, elevation, or inclination) }; enum { X, Y, Z }; #define RAD_TO_DEG    57.295779513082f #define EPSILON        1e-6f void tqPointToSphericalZenithYDeg(float *point, float *sph) {     // north pointing toward positive y axis          float x = point[X];     float y = point[Z];     float z = point[Y];          // distance     sph[RHO] = sqrtf((x * x) + (y * y) + (z * z));          // longitude     sph[THETA] = atan2f(y, x) * RAD_TO_DEG;     while (sph[THETA] < 0.0f)         sph[THETA] += 360.0f;          // latitude     if (sph[RHO] < EPSILON)         sph[PHI] = 0.0f;     else         sph[PHI] = acosf(z / sph[RHO]) * RAD_TO_DEG; } void tqPointToSphericalZenithZDeg(float *point, float *sph) {     // north pointing toward positive z axis          float x = point[X];     float y = point[Y];     float z = point[Z];          // distance     sph[RHO] = sqrtf((x * x) + (y * y) + (z * z));          // longitude     sph[THETA] = atan2f(y, x) * RAD_TO_DEG;     while (sph[THETA] < 0.0f)         sph[THETA] += 360.0f;          // latitude     if (sph[RHO] < EPSILON)         sph[PHI] = 0.0f;     else         sph[PHI] = acosf(z / sph[RHO]) * RAD_TO_DEG; }``` You'd use it, something like this, where myPoint would be your movement vector and mySphereCoords would be filled in with angles you can use to rotate your object with to match the direction vector (theoretically anyway, like I said, I don't know if this works or not ): Code: ```// init to demo values (not normalized, but not necessary in this situation) float myPoint[3] = { 2.1f, 1.1f, -5.4f }; float mySphereCoords[3]; // assuming Y axis is north pole (the zenith) tqPointToSphericalZenithYDeg(myPoint, mySphereCoords); // rotate azimuth around Y glRotatef(mySphereCoords[THETA], 0.0f, 1.0f, 0.0f); // tilt up/down glRotatef(mySphereCoords[PHI], 1.0f, 0.0f, 0.0f);``` It works by imagining you're at the center of the earth and know the cartesian point where something is located on the surface (your direction vector), and then converts that to lat/lon. RE: Get model to face direction of movement - SOLVED - MikeD - Sep 6, 2010 12:37 PM Thanks for the help guys. Based on your info and so more reading I've created a function that will create a matrix that can be used to orientate my model in the direction they are travelling, or any direction I pass in. I've put the function below in case anyone else goes hunting for something similar. Code: ```static inline void SSMatrixFaceVector(float* mtx, const SSVector3D dir, const SSVector3D up) {     SSVector3D d = SSVector3DNormalize(dir);     SSVector3D right = SSVector3DNormalize(SSVector3DCross(up, d));     SSVector3D newUp = SSVector3DNormalize(SSVector3DCross(d, right));     SSVector3D backwards = SSVector3DNormalize(SSVector3DCross(right, newUp));     // Construct a matrix from the new values     mtx[0] =  right.x;        mtx[1] =  right.y;        mtx[2] =  right.z;        mtx[3] =  0;     mtx[4] =  newUp.x;        mtx[5] =  newUp.y;        mtx[6] =  newUp.z;        mtx[7] =  0;     mtx[8] =  backwards.x;    mtx[9] =  backwards.y;    mtx[10] = backwards.z;    mtx[11] = 0;     mtx[12] = 0;              mtx[13] = 0;              mtx[14] = 0;              mtx[15] = 1; }``` Thanks again for the quick response and the help Cheers MikeD