0v3rloader 100 Report post Posted August 1, 2007 Hi, I'm having a real tough time trying to apply correct rotations to an object. I'll illustrate what's happening... Here's how the model looks after rotating it on the Z axis: And here's how it looks after rotating it on the Y axis: In the last image you can clearly see the model is rotating around the global Y axis and not the rotated Y local axis (to the right.) The colored lines represent the axes being red for x, green for y and blue for z. I'm using the following method to apply the transformations: Matrix4f mx(false); // false = don't load identity Vector4f qrot(::g_axis_X, rx); // quat from axis-angle qrot.Mul(Vector4f(::g_axis_Y, ry), qrot); // qrot = qrot * qrotY qrot.Mul(Vector4f(::g_axis_Z, rz), qrot); // qrot = qrot * qrotZ mx.FromOrientation(qrot); // quatf to matrix4f ::glLoadMatrixf(*GetScene()->GetCamera()); // load model view matrix ::glMultMatrixf(mx); // transform! ::glCallList(O3D_SWORD); // render model FYI, I'm getting the same results using OpenGL's own set of methods (glTranslate/Rotate.) How can I rotate an object around its set of local axes? PS: I've started a thread in Math's forum covering this same topic, however I don't think I was very clear and nobody replied, hence I started this thread here in the Beginner's forum hoping to get an answer. Apologies to anyone I may have annoyed by cross-posting. 0 Share this post Link to post Share on other sites
shukapi 124 Report post Posted August 1, 2007 Not sure what library you're using but:Try switching the order of the arguments to Mul()qrot.Mul(Vector4f(::g_axis_Z, rz), qrot);qrot.Mul(qrot, Vector4f(::g_axis_Z, rz)); 0 Share this post Link to post Share on other sites
0v3rloader 100 Report post Posted August 1, 2007 Quote:Original post by shukapiNot sure what library you're using but:Try switching the order of the arguments to Mul()qrot.Mul(Vector4f(::g_axis_Z, rz), qrot);qrot.Mul(qrot, Vector4f(::g_axis_Z, rz));Thanks for that! I'm using my own lib.I don't really know what you mean by switching the order of the args?Prototype of Mul:Vector4f::Mul(Vector4f& quatMultiplyBy, Vector4f& quatResult);Also, as I mentioned in my post, I'm getting the same results using glTranslate and glRotatef, which means my quaternion class is working well...I'm really desperate as I don't have a clue why this is happening and how to solve it. 0 Share this post Link to post Share on other sites
jyk 2095 Report post Posted August 1, 2007 Another thing you might try is changing this:qrot.Mul(Vector4f(::g_axis_Y, ry), qrot); // qrot = qrot * qrotYqrot.Mul(Vector4f(::g_axis_Z, rz), qrot); // qrot = qrot * qrotZTo this:qrot.Mul(Vector4f(::g_axis_Z, rz), qrot); // qrot = qrot * qrotZqrot.Mul(Vector4f(::g_axis_Y, ry), qrot); // qrot = qrot * qrotYAs it's possible that changing the order in which the rotations are applied will give you the effect you're looking for (then again, it may not). 0 Share this post Link to post Share on other sites
0v3rloader 100 Report post Posted August 1, 2007 Quote:Original post by jyk Quote: Original post by 0v3rloader Anyway, I've read that incremental rotations might just sort out my problem and so I was wondering if you guys know of any other method, perhaps one which is simpler?If what you want is incremental rotations, then you'll have to use incremental rotations.Fortunately, it's really not all that complicated. Basically, you:1. Store the orientation of your object as a quaternion (in your case, at least - another option would be a 3x3 rotation matrix).2. Update it incrementally via local- or global-axis rotations (this involves multiplying the orientation quaternion on one side or the other by the appropriate global-axis quaternions).3. Normalize the quaternion periodically (it's probably easiest just to do it after each update).(Also, this is a bit of a cross-post; more info - and screenshots - here.)But, is incremental rotations what I need? This is what I'm not too sure about you see?Quote:Original post by jykAnother thing you might try is changing this:qrot.Mul(Vector4f(::g_axis_Y, ry), qrot); // qrot = qrot * qrotYqrot.Mul(Vector4f(::g_axis_Z, rz), qrot); // qrot = qrot * qrotZTo this:qrot.Mul(Vector4f(::g_axis_Z, rz), qrot); // qrot = qrot * qrotZqrot.Mul(Vector4f(::g_axis_Y, ry), qrot); // qrot = qrot * qrotYAs it's possible that changing the order in which the rotations are applied will give you the effect you're looking for (then again, it may not).It does actually! Having tested a few different combinations yields interesting results. It turns out that the first rotation transforms the model correctly, but then the remaining ones affect its global axes. Weird stuff...However, the model I'm using will have to be able to rotate freely in the 3d space in all axes depending on the user input, so it's not really a matter of changing the combination in which the rotations are applied. 0 Share this post Link to post Share on other sites
0v3rloader 100 Report post Posted August 1, 2007 Implemented the following code which is called whenever the model is to be rotated:void GModel::Rotate(float rx, float ry, float rz) throw(){ _qrot.Mul(Vector4f(::g_axis_X, rx)); _qrot.Mul(Vector4f(::g_axis_Y, ry)); _qrot.Mul(Vector4f(::g_axis_Z, rz));}In essence, this bit of code, should increment the object's rotation, however, that isn't happening... Now all rotations apply to the global axes. I don't get this.I'm at a loss again.EDIT: You might also want to have a look at the following bit of code:void GModel::Update() throw(){ ::glMatrixMode(GL_MODELVIEW); Matrix4f _mx(false); // Now load the matrix directly ::glLoadMatrixf(*_pScene->GetCamera()); _mx.FromOrientation(_pos, _qrot); ::glMultMatrixf(_mx);}void GModel::Translate(float x, float y, float z, float distance = 1.f) throw(){ _pos.Translate(x, y, z);} 0 Share this post Link to post Share on other sites
0v3rloader 100 Report post Posted August 1, 2007 SOLUTION FOUNDFor those of you having the same sort of issues as I did the trick was switch the operands in the quaternion multiplication and also to employ incremental rotation, as given:class G3dObject{ . : .protected: Vector4f _qrot; // orientation of object};void G3dObject::Rotate(float rx, float ry, float rz) throw(){ Vector4f qx(::g_axis_X, rx); Vector4f qy(::g_axis_Y, ry); Vector4f qz(::g_axis_Z, rz); qx.Mul(_qrot, _qrot); // _qrot = qx * _qrot qy.Mul(_qrot, _qrot); // _qrot = qy * _qrot qz.Mul(_qrot, _qrot); // _qrot = qz * _qrot} 0 Share this post Link to post Share on other sites
jpetrie 13199 Report post Posted August 1, 2007 Quote:switch the operands in the quaternion multiplication Be careful! Q1*Q2 != Q2*Q1. If switching the multiplication order "fixes" your problem you're going to want to make a serious investigation into your underlying math routines to make sure you don't have a bug in them. It's surprisingly common to find yourself in a situation where you have a bug, and then elsewhere erroneously correct for the bug, making it look like there is no bug at all. So you want to be absolutely sure that your mistake was really that you accidentally performed the quaternion multiplication in the wrong order, rather than accidentally writing the quaternion multiplication function incorrectly. 0 Share this post Link to post Share on other sites
0v3rloader 100 Report post Posted August 1, 2007 Quote:Original post by jpetrieQuote:switch the operands in the quaternion multiplication Be careful! Q1*Q2 != Q2*Q1. If switching the multiplication order "fixes" your problem you're going to want to make a serious investigation into your underlying math routines to make sure you don't have a bug in them. It's surprisingly common to find yourself in a situation where you have a bug, and then elsewhere erroneously correct for the bug, making it look like there is no bug at all. So you want to be absolutely sure that your mistake was really that you accidentally performed the quaternion multiplication in the wrong order, rather than accidentally writing the quaternion multiplication function incorrectly.I'm 100% sure the multiplication method in my quaternion class is working flawlessly; no probs there!I actually took a peek inside Ogre's source code and was surprised to find that Ogre does three different types of rotations: on parent node, local and world. It so happens that parent node and local rotations are similar and only differ in the quaternion multiplication operands being switched.But I understand where you're coming from, as I could easily be suffering from a hidden bug in my quaternion class. Thanks for pointing that out jpetrie! :) 0 Share this post Link to post Share on other sites
jyk 2095 Report post Posted August 1, 2007 Just a couple of comments on quaternions and multiplication order...One thing you have to watch out for is that, in some math libraries and references, quaternion multiplication is actually re-defined such that the sign of the cross product term is reversed. This is done, for example, in the DirectX math library, so that concatenation of rotations in quaternion form mirrors the use of row-basis matrices.I don't know which form of quaternion multiplication your library uses, but I'm guessing it's the 'standard' form. In any case, with both quaternions and matrices, if you multiply a rotation on one side of a target orientation (i.e. A*B), the rotation will be applied in the local space of the target orientation, whereas if you multiply it on the other side (i.e. B*A), it will be applied in world/parent space. Which side does which depends on whether you're using column-vector notation (or standard quaternion multiplication order) or row-vector notation (or 'reversed' quaternion multiplication order). 0 Share this post Link to post Share on other sites
0v3rloader 100 Report post Posted August 1, 2007 Quote:Original post by jykJust a couple of comments on quaternions and multiplication order...One thing you have to watch out for is that, in some math libraries and references, quaternion multiplication is actually re-defined such that the sign of the cross product term is reversed. This is done, for example, in the DirectX math library, so that concatenation of rotations in quaternion form mirrors the use of row-basis matrices.I don't know which form of quaternion multiplication your library uses, but I'm guessing it's the 'standard' form. In any case, with both quaternions and matrices, if you multiply a rotation on one side of a target orientation (i.e. A*B), the rotation will be applied in the local space of the target orientation, whereas if you multiply it on the other side (i.e. B*A), it will be applied in world/parent space. Which side does which depends on whether you're using column-vector notation (or standard quaternion multiplication order) or row-vector notation (or 'reversed' quaternion multiplication order).Thank you very much for that jyk. I'm gonna have a look in my library just to make sure.Extremely helpful stuff! :) 0 Share this post Link to post Share on other sites