Sign in to follow this  
0v3rloader

Rotations wrong

Recommended Posts

0v3rloader    100
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: Free Image Hosting at www.ImageShack.us 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.

Share this post


Link to post
Share on other sites
shukapi    124
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));

Share this post


Link to post
Share on other sites
0v3rloader    100
Quote:
Original post by shukapi
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));


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.

Share this post


Link to post
Share on other sites
jyk    2094
Another thing you might try is changing this:
qrot.Mul(Vector4f(::g_axis_Y, ry), qrot);	// qrot = qrot * qrotY
qrot.Mul(Vector4f(::g_axis_Z, rz), qrot); // qrot = qrot * qrotZ
To this:
qrot.Mul(Vector4f(::g_axis_Z, rz), qrot);	// qrot = qrot * qrotZ
qrot.Mul(Vector4f(::g_axis_Y, ry), qrot); // qrot = qrot * qrotY
As 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).

Share this post


Link to post
Share on other sites
0v3rloader    100
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 jyk
Another thing you might try is changing this:
qrot.Mul(Vector4f(::g_axis_Y, ry), qrot);	// qrot = qrot * qrotY
qrot.Mul(Vector4f(::g_axis_Z, rz), qrot); // qrot = qrot * qrotZ
To this:
qrot.Mul(Vector4f(::g_axis_Z, rz), qrot);	// qrot = qrot * qrotZ
qrot.Mul(Vector4f(::g_axis_Y, ry), qrot); // qrot = qrot * qrotY
As 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.

Share this post


Link to post
Share on other sites
0v3rloader    100
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);
}

Share this post


Link to post
Share on other sites
0v3rloader    100
SOLUTION FOUND



For 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
}

Share this post


Link to post
Share on other sites
jpetrie    13104
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.

Share this post


Link to post
Share on other sites
0v3rloader    100
Quote:
Original post by jpetrie
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.


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! :)

Share this post


Link to post
Share on other sites
jyk    2094
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).

Share this post


Link to post
Share on other sites
0v3rloader    100
Quote:
Original post by jyk
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).


Thank you very much for that jyk. I'm gonna have a look in my library just to make sure.

Extremely helpful stuff! :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this