   Rotating a vector INTO another
  Hi !I need to compute a matrix M that rotates a vector <0, 0, 1> into another arbitrary normalized vector V = <Nx, Ny, Nz>.We suppose both vectors start at the origin.Does anyone know how to achieve it ?I tried various things, but none worked:1. the first attempt was to compute the angles between V and each axis. Then use a rotation matrix from those angles, but this should be mathematically incorrect.2. I tried retrieving spherical coordinates from V. Then use 'tetha' and 'phi' to build a rotation matrix around X-Z axis.3. Lastly I tried to build a rotation matrix with V as the last row. But I'm not sure in how to compute the other two rows.Can anyone help me ?THANKS !   
Quote:Original post by NiGoeaHi !I need to compute a matrix M that rotates a vector <0, 0, 1> into another arbitrary normalized vector V = <Nx, Ny, Nz>.We suppose both vectors start at the origin.Does anyone know how to achieve it ?I tried various things, but none worked:1. the first attempt was to compute the angles between V and each axis. Then use a rotation matrix from those angles, but this should be mathematically incorrect.2. I tried retrieving spherical coordinates from V. Then use 'tetha' and 'phi' to build a rotation matrix around X-Z axis.3. Lastly I tried to build a rotation matrix with V as the last row. But I'm not sure in how to compute the other two rows.Can anyone help me ?THANKS !This is a classic question. There should be dozens and dozens of topics on that specific problem.First, compute the cross product of "Z"(0,0,1) and V. The vector obtained is the axis of rotation.Vector3 axis = cross_product( Z, V );Compute the dot product of "Z" and V. "Z" and V being unit-length vectors, their dot product is equal to the cosine of the angle they make. The angle of rotation is then:angle = std::acos( dot_product( Z, V ) );You build the rotation matrix from the axis and angle obtained.    //"Real" is a type definition    //The columns of the matrix form an orthonormal basis    void to_rotation_matrix(   Vector3 const & src_1,   Real src_2,   Matrix3 & dest    )    { Real const eps = 1.0e-12;Real c = std::cos( src_2 );Real s = std::sin( src_2 );Real t = 1 - std::cos( src_2 );Real tXY = t * src_1.get_x() * src_1.get_y();Real tXZ = t * src_1.get_x() * src_1.get_z();Real tYZ = t * src_1.get_y() * src_1.get_z();Real sX = s * src_1.get_x();Real sY = s * src_1.get_y();Real sZ = s * src_1.get_z();dest.set_00( t * src_1.get_x() * src_1.get_x() + c );dest.set_01( tXY - sZ );dest.set_02( tXZ + sY );dest.set_10( tXY + sZ );dest.set_11( t * src_1.get_y() * src_1.get_y() + c );dest.set_12( tYZ - sX );dest.set_20( tXZ - sY );dest.set_21( tYZ + sX );dest.set_22( t * src_1.get_z() * src_1.get_z() + c );    }Matrix3 rotation;to_rotation_matrix( axis, angle, rotation ); [Edited by - johnstanp on May 18, 2010 10:17:34 AM];  If all you want is any matrix that will rotate one vector into another, it's really simple. All you have to do is use0, 0, nx0, 0, ny0, 0, nzObviously, if you want an orthogonal matrix, it's much more complicated. The easiest way to generate an orthogonal matrix is to take the cross product with any other linearly independent vector, and then take the cross product again and use those as your other two columns.By the way, a single rotation is not enough to uniquely specify a matrix. Assuming you want an orthogonal matrix, it takes two destination vectors to uniquely specify. For a general matrix, it takes three.   ;Quote:Original post by StoryyellerIf all you want is any matrix that will rotate one vector into another, it's really simple. All you have to do is use0, 0, nx0, 0, ny0, 0, nzObviously, if you want an orthogonal matrix, it's much more complicated. The easiest way to generate an orthogonal matrix is to take the cross product with any other linearly independent vector, and then take the cross product again and use those as your other two columns.By the way, a single rotation is not enough to uniquely specify a matrix. Assuming you want an orthogonal matrix, it takes two destination vectors to uniquely specify. For a general matrix, it takes three.I had already considered that method, but I wasn't able to find a correct orthogonal matrix, mainly because I couldn't find the second column vector.Quote:Original post by johnstanpThis is a classic question. There should be dozens and dozens of topics on that specific problem.Yes it is. In fact, the first thing I did was in vain trying to search some topics.So thank you for your reply.Quote:First, compute the cross product of "Z"(0,0,1) and V. The vector obtained is the axis of rotation.*** Source Snippet Removed ***Compute the dot product of "Z" and V. "Z" and V being unit-length vectors, their dot product is equal to the cosine of the angle they make. The angle of rotation is then:*** Source Snippet Removed ***You build the rotation matrix from the axis and angle obtained.*** Source Snippet Removed ****** Source Snippet Removed ***Unfortunatly, I did understand exactly what your code does. Could you explain me ?---- Today I find a solution by myself using polar coordinates. You compute tetha and phi and then make a rotation matrix about X and Y axis.Seems to work.If it would happen to give wrong results, I will try your methods for sure !THANKS !;Quote:Original post by NiGoeaUnfortunatly, I did understand exactly what your code does. Could you explain me ?You meant "I didn't understand"?You just need to understand what are an axis and an angle of rotation: simply put, what is a rotation, actually. Quote:Original post by NiGoeaToday I find a solution by myself using polar coordinates. You compute tetha and phi and then make a rotation matrix about X and Y axis.Seems to work.If it would happen to give wrong results, I will try your methods for sure !THANKS !Polar coordinates only exist in 2 dimensions: these are "rho" and "theta". In three dimensions, you can use spherical coordinates to locate a point: "rho", "theta" and "phi".   ;For future reference this here piece of code might be useful. After messing around with the approach johnstanp described and wrestling the common atan2 alternative, I stumbled across this code in Ogre3D to compute a quaternion describing the rotation needed to go from one vector to another. I've been using it ever since [smile] ;Quote:Original post by remigiusFor future reference this here piece of code might be useful. After messing around with the approach johnstanp...[smile]Well, I should have written that I've never tested the code I posted, mostly because I'm more interested in applying forces and/or torques to make a rigid body move( translation or rotation ), than in computing a specific matrix. What went wrong?;Quote:Original post by johnstanpWhat went wrong?Ow, I guess that got across wrong. There's nothing wrong with your description. I was just using the same approach as you described for some older projects, but I always seemed to run into edge cases where the rotations were not behaving. ACos returning the wrong angle out of the two possible ones, interpolations not working out, that sort of thing. The quaternion approach isn't a magical cure to all this, but somehow it works out smoother for me.;Quote:Original post by remigiusQuote:Original post by johnstanpWhat went wrong?Ow, I guess that got across wrong. There's nothing wrong with your description. I was just using the same approach as you described for some older projects, but I always seemed to run into edge cases where the rotations were not behaving. ACos returning the wrong angle out of the two possible ones, interpolations not working out, that sort of thing. The quaternion approach isn't a magical cure to all this, but somehow it works out smoother for me.Ah okay.Actually, I always test if the axis has a magnitude equal, in absolute value, to 1.0 or a little less. For the angle, being computed from the dot product of two vectors, I also check that those two vectors have a magnitude equal, in absolute value, to 1.0 or a little less, in order to have an argument for acos, that is relevant. But I guess that you already do that. For the acos returning the wrong angle out of two: acos should normally return a value between 0.0 and pi. That's the interval where the cosine is a bijection. There can only exist one value for acos(x), ie, you should only expect one value. Of course, cos(x) = cos(-x) for any real x, meaning that there are two possible "x"s, that verify cos(x) = y, y being given.I had a little concern with the angle: shouldn't one consider the case when acos returns "angle" when one "would" expect its opposite? angle( v1, v2 ) = angle( v1, v3 ) with v2 != v3, but cross( v1, v2 ) = opposite( cross( v1, v3 ) ). So two different situations shouldn't yield the same outcome( rotation matrix ), as long as, to_rotation_matrix( cross( v1, v2 ), angle( v1, v2 ) ) != to_rotation_matrix( opposite( cross( v1, v2 ) ), angle( v1, v2 ) )P.S: Matrix3 to_rotation_matrix( Vector3 const & axis, Real angle );[Edited by - johnstanp on May 20, 2010 8:25:14 AM];Quote:Original post by johnstanp For the acos returning the wrong angle out of two: acos should normally return a value between 0.0 and pi. That's the interval where the cosine is a bijection. There can only exist one value for acos(x), ie, you should only expect one value. Of course, cos(x) = cos(-x) for any real x, meaning that there are two possible "x"s, that verify cos(x) = y, y being given.Yep, that's the problem, especially for angles close to 0 and Pi. When x crosses -1 or 1, the derivate of the returned angles will flip sign. I found this to be particularly troublesome when interpolating between the returned angles and things only turn halfway and subsequently return to their original orientation.Quote:I had a little concern with the angle: shouldn't one consider the case when acos returns "angle" when one "would" expect its opposite?One should I think. If the actual angle between two vectors is steadily increasing from say 0 to 2Pi, the acos approach will start returning increasingly smaller angles as the actual angle goes past Pi. Aside from keeping track of the previous angle (or effectively the derivate) I'm not aware of an easy fix for this behaviour.Quote: angle( v1, v2 ) = angle( v1, v3 ) with v2 != v3, but cross( v1, v2 ) = opposite( cross( v1, v3 ) ). So two different situations shouldn't yield the same outcome( rotation matrix ), as long as, to_rotation_matrix( cross( v1, v2 ), angle( v1, v2 ) ) != to_rotation_matrix( opposite( cross( v1, v2 ) ), angle( v1, v2 ) )P.S: Matrix3 to_rotation_matrix( Vector3 const & axis, Real angle );I think I understand what you mean here, but the switch to the opposite cross product actually adds to the problem when interpolating. Especially when you're working with larger time steps, the behavior of meshes can get pretty exotic. I'm pretty sure this could somehow be fixed and I just lack the math insights to do so, but since the quaternion worked out I just stuck with that. Rethinking the particular case where acos was being troublesome for me, I think it might have been a bad idea in the first place to store baseHeading (as defined by the model) and currentHeading and compute the rotation matrix from those. Having currentHeading around made it pretty easy to do simple 'euler' movement (pos += dt * speed * heading) and it was easier to align projectile headings to 'home in' on targets, but in retrospect it would probably have been a better idea to store rotation properly and just compute the heading from that. Ah well, live and learn [smile]