Quaternion Fun!

Started by
29 comments, last by stu2000 13 years, 6 months ago
Hey I have massive problems understanding quaternions, which is a huge problem for me as a programmer here is my problem:

I have two quaternions which represent two orientations of an object in local space:

Quaternion current_orientation
Quaternion desired_orientation

I would like to get from one to the other using something like as follows:

Quaternion offset <- some value that can be added or multiplied or anything to currrent orientation to get to desired orientation
offset_chunk <- equally divisible chunk of the offset quaternion such that adding/multiplying it to current orientation N number of times over N frames/timesteps will result in a smooth rotation from current Orientation to desired_orientation

Could someone please show me how to calculate the offset quaternion from the two provided quaternions current_orientation and desired_orientation. (represented x, y, z, w please i j k etc only if you have to) and also show me how to derive offset_chunk quaternion from that, and how you would apply the offset chunk each frame, ie a multiplication or addition and normalization etc.

Very much apprecitated.
Stu
Advertisement
I suggest looking for "quaternion slerp" in google.
Okay, ive decided to work around the problem by using matrices. I figure once i have the matrix offset i can just multiply the current rotation by the offset each frame to get the final result.

I already have the full rotation i desire. If i divide each of the 9 elements in the totalRotationOffset by N would that produce the 'chunk matrix' i desire to rotate by for each of the N frames?

Stu
You will eventually find out that linear interpolation with matrices is not going to get you the desired result. Which means you will end up having to use quaternion. My advice, learn the mathematical basis behind quaternion or any other concept before blindly using them. Once you have the foundation then its a simple as applying what you have learn. Everyone on the forum can 'show' you, but only you can absorb the knowledge ('learn' ) from what is shown.
Dividing the matrix elements by N will simply scale the matrix by 1/N. Since matrix transformations accumulate by multiplication, you need the N:th root of the matrix, and arbitrary matrix roots are not trivial to compute in general.

I agree with cgrant, doing this with matrices is probably not the best solution. if you have a start and end quaternion, the interpolation between the rotations is trivial.
Hehe...what is going on here!? You posted the same question in the DirectX forum, and SLERP was suggested. You ditched that thread, re-posted here, SLERP was suggested again, and you ignored it, saying you were going to linearly interpolate matrices instead (or something). Do you have something against SLERP? :-)

Remember you can ask follow-up questions - it's allowed ;) If you're not sure what SLERP is or how it relates to your problem, just ask.

Anyway, you can do what you're asking about using SLERP. However, to answer your specific question, you can compute the 'difference value' that you're asking about by multiplying one of the quaternions by the conjugate of the other. Then, you can use quaternion exp() or log() or something (I can't remember off the top of my head and I'm not going to look it up right now) to compute a 'delta' quaternion that you can then use to rotate incrementally from the first orientation to the second. (Basically what this boils down to is converting the 'difference' quaternion to axis-angle form, scaling the angle, and then converting back.) The end result will the same as with SLERP, more or less (although the means of getting there is a little different).

You can do the same sort of thing with matrices but it's both less efficient and (arguably) less elegant.
Quote:Original post by Brother Bob
Dividing the matrix elements by N will simply scale the matrix by 1/N. Since matrix transformations accumulate by multiplication, you need the N:th root of the matrix, and arbitrary matrix roots are not trivial to compute in general.

I agree with cgrant, doing this with matrices is probably not the best solution. if you have a start and end quaternion, the interpolation between the rotations is trivial.


Yes I should have though of that.
Surely a simpler solution would be to Get the two direction vectors from the two rotations, assuming a direction vector of (0,0,1) when no rotation applied, representing say V0. R1 and R2 would represent the two rotation matrices of orientation, then,

V1 = V0 * R1
V2 = V0 * R2

cross product of v1, v2 gets the axis of rotation
angle of rotation (theta) = acos(v1•v2) (since v1 and v2 are already normalised)

then just divide theta by N (the number of frames desired)

Now just derive the rotationOffsetMatrix chunk from the axis of rotation and the new theta

This is EXACTLY the same as Part III: Spherical Linear Interpolations (SLERPS) in this gamedev article: 'Do We Really Need Quaternions?' http://www.gamedev.net/reference/articles/article1199.asp
Yes, that is probably the preferred solution if you have a start and end direction you want to rotate between. As I said, if you start with quaternions though, interpolation with quaternions is probably more convenient. So chose the tool that fits the job.

As the saying goes; if all you have is a hammer, then all problems look like a nail. Don't focus only on solving it with matrices. You said you had quaternions, so solve it with quaternions.
Quote:Original post by jyk
Hehe...what is going on here!? You posted the same question in the DirectX forum, and SLERP was suggested. You ditched that thread, re-posted here, SLERP was suggested again, and you ignored it, saying you were going to linearly interpolate matrices instead (or something). Do you have something against SLERP? :-)

Remember you can ask follow-up questions - it's allowed ;) If you're not sure what SLERP is or how it relates to your problem, just ask.

Anyway, you can do what you're asking about using SLERP. However, to answer your specific question, you can compute the 'difference value' that you're asking about by multiplying one of the quaternions by the conjugate of the other. Then, you can use quaternion exp() or log() or something (I can't remember off the top of my head and I'm not going to look it up right now) to compute a 'delta' quaternion that you can then use to rotate incrementally from the first orientation to the second. (Basically what this boils down to is converting the 'difference' quaternion to axis-angle form, scaling the angle, and then converting back.) The end result will the same as with SLERP, more or less (although the means of getting there is a little different).

You can do the same sort of thing with matrices but it's both less efficient and (arguably) less elegant.


Yes thx for that. I didn't deliberately 'ditch' it. I posted the question, left the forum, and I'd forgotten to put up 'email when someone responds' and then couldnt find it again. Since i had run a search and nothing came up, i had assumed my browser hadn't posted before i had closed the tab window. Many apologies. Dont know why i posted in the DirectX section.
Quote:Original post by Brother Bob
Yes, that is probably the preferred solution if you have a start and end direction you want to rotate between. As I said, if you start with quaternions though, interpolation with quaternions is probably more convenient. So chose the tool that fits the job.

As the saying goes; if all you have is a hammer, then all problems look like a nail. Don't focus only on solving it with matrices. You said you had quaternions, so solve it with quaternions.


Really I have both. Quaternions only pop up because send and receive them over net instead of matrices as it costs less bandwidth, but most of the time dealing with matrices, as all the rotations I get and set in the code are in terms of 3d or 4d Matrix

In terms of speed, isn't performing one matrix multiplication (9 multiplications on 3x3 matrix) cheaper than performing a Slerp every frame? I only have to calculate the offset matrix once roughly every 6.25 frames at worst performance. ie probably more frames pass by than just 6.25 .

This topic is closed to new replies.

Advertisement