btQuaternion clamping values and slerp question

Please don't post Bullet support questions here, use the above forums instead.
androiders
Posts: 2
Joined: Wed Oct 27, 2010 7:25 pm

btQuaternion clamping values and slerp question

Post by androiders »

Hi!

Okay, this is my first post here. Must say the forum, what i have read and seen so far, is great :) The library itself is of course also great. Even if i am yet beginner.

Anyways, i have a question about the quaternions and if they clamp, or recalculates, the angle value if it reaches > 180 degrees? I looked at the code but found nothing obvious...

What i am doing is that i have a camera that follows behind a space ship. The ship can move pretty freely around in space. The camera aligns itself with the ships orientation using slerp between the cameras orientation and the ships in order to get a nice delay effect. The cameras orientation lags so to speak. When the spaceship has rotated a full circle the camera jumps or jerks a bit and then all is normal for another full circle and so on.
This led me to believe that the values are clamped and the space ships orientation is clamped before the camera has rotated a full circle and this makes slerp " go the other way".

now, is there something i can make bullet do about it or do i have to work around it in some way?

Thanks in advance
--Anders
Kanttori
Posts: 38
Joined: Thu Jul 08, 2010 12:52 am

Re: btQuaternion clamping values and slerp question

Post by Kanttori »

If the problem happens at 180 degrees it's probably because slerp can't decide which way to rotate, there is no shortest route from pole to pole since all routes are equal. Imho:
- you could have an angle range where the camera follow constraint would softly increase to 100% to match the ships rotation so as not to get this situation.
- check for the 180 degrees and if found, use the previous working ships rotation quaternion as the target.
- (I'm not a mathwizz:) code a slerp which would take an extra parameter to hold the last sane (length above 0) "cross-product" between quaternions because it would give you the axis/direction to do the slerp.
androiders
Posts: 2
Joined: Wed Oct 27, 2010 7:25 pm

Re: btQuaternion clamping values and slerp question

Post by androiders »

thanks for your reply.

I found something odd actually. The slerp function checks if the angle between the quaternions, theta, is zero. But then it divides by btSin( theta ) which is zero at every multiple of Pi. A bug?
This leads to strange values of the w variable of the calculated quaternion.

And this is what is going on :)

--Anders
paul.dubois
Posts: 10
Joined: Thu May 20, 2010 10:45 pm

Re: btQuaternion clamping values and slerp question

Post by paul.dubois »

btQuat::angle actually measures the angle between the two 4d quaternions, not the angle you'd get if you converted the quat to an axis-angle format. An odd feature of quaternions is that every orientation is specified by two distinct quaternions: (x,y,z,w) and (-x,-y,-z,-w). These two quaternions are "180 degrees" apart (in the sense that acos(q1 dot q2) is 180 degrees).

A straightforward consequence of this is that the "angle between quaternions" is half the "angle between orientations". I believe there is a bug in the tracker about btQuat::angle() confusion; it returns the former where some thought it should have returned the latter.

Anyway, if you try to slerp 180 degrees between q and -q (and your slerp is robust enough not to blow up in that case) then your object will spin 360 degrees about some arbitrary axis.

So it turns out that what Kanttori says is almost correct if the "poles" are actually the 4d poles of the quaternion hypersphere. But typically you don't care about that. The easiest thing to do is to make sure your inputs to quat::slerp() are in the same hemisphere -- if the dot product is negative, invert one of them. This makes the slerp always take the short route between your two orientations, instead of the long way around -- think of the difference between rotating 1 degree clockwise and 359 degrees counterclockwise.

btQuat::slerp should probably also be fixed to be robust when slerping between q and -q, but typically that case doesn't come up because very few people would want to interpolate between two identical orientations by spinning 360 degrees in place. A bigger issue with the slerp as written is that it looks unstable when q1 ~= q2