[Closed] Slerp function
Hi guys,
I’m seeing some unexpected behaviour with the slerp function in max script (3ds Max 2010) and I would be really grateful if anyone in here would spare a few minutes to enlighten me a bit.
I’m using the slerp function in a rotation script controller to calculate the intermediate rotation between two object’s rotations:
slerp rot1 rot2 0.5
This works like a charm until the angle between rot1 and rot2 reaches ca. 120 degress – then the result quaternion flips 180 degress. I wouldn’t expect the flip to occur until the angle between rot1 and rot2 reaches a value of 180 degrees. I tried to normalize the quarternions but it didn’t do any difference.
Can this really be intentional behaviour of the slerp function, or am I messing it up with my controllers?
Regards,
Benny the rabbit…
…from the rabbit hole…
Very odd, I’m seeing the same issue. The simplest test is failing with it. Two point helpers and using (quat 0 0 0 1) as the base. I have used this in the past in Max with out a problem and even remember way back learning about quat with it and only saw the flip at 180. Been along time since those tests but I know that I have used this function in the last couple of years.
It seems the input quat values causes the problem and not the slerp function itself.
If i create a teapot and rotate it around the Z-axis while printing the rotation(or just checking the values in the “Rotate Transform Type-In floater”), the quat value changes from positive to negative (and vica versa) at 120 degrees and -240 degrees.
I’ve tried to make a workaround to interpolate between two rotation controllers. If the rotation controllers are read as separate eulerangles, then made into angleaxis and then converted to quats, it kind of works, but only on one axis at a time, combining x,y,z rotation is not stable in the attached example, but it can probably be done better and easier than this
to get right interpolation of two quats you have to calculate first the sign of their dot product…
fn dotQuat q q_prev =
(
(q.w * q_prev.w + q.x * q_prev.x + q.y * q_prev.y + q.z * q_prev.z) < 0
)
fn blendMatrix m1: m2: weight:0.5 =
(
r1 = m1.rotationpart
r2 = m2.rotationpart
if (dotQuat r1 r2) do r1 *=-1
r = slerp (normalize r1) (normalize r2) weight
t = m1.translationpart + (m2.translationpart - m1.translationpart) * weight
s = m1.scalepart
translate (rotate (scale (matrix3 1) s true) r) t -- ignores scale
)
Why would you have to do this Denis if slerp is supposed to do this for you? Or is the work around you are suggesting?
slerp (quat 1) (rotateXMatrix 180).rotation .5
(quat -0.707107 0 0 0.707107) as eulerangles
(eulerAngles 90 0 0)
fn blendMatrix
(matrix3 [1,0,0] [0,0,-1] [0,1,0] [0,0,0]) as eulerangles
(eulerAngles -90 0 0)
for i=0 to 10 do
print ((slerp (quat 1) (rotateXMatrix 180).rotation (i/10.))as eulerangles)
I can’t recreate the problem… seems fine
Hi Ruramuq
This scene setup with a script controller at the middle node shows the problem:
node1 = teapot pos:[-100,0,0] ; node2 = teapot pos:[100,0,0] ; node3 = teapot()
node3.rotation.controller = (scr = rotation_script()) ; scr.addtarget "rot1" node1.rotation.controller ; scr.addtarget "rot2" node2.rotation.controller ; scr.script = "slerp rot1 rot2 0.5"
This shows where the problem occurs at the 120 deg. sign flip:
node1 = teapot(); for i = 1 to 360 do (node1.rotation.controller[3].value = i; redrawViews(); print node1.rotation; print i)
and at 240 deg. the other way:
node1 = teapot(); for i = 1 to 360 do (node1.rotation.controller[3].value = i; redrawViews(); print node1.rotation; print i)
The Slerp function is working ok, the problem is even outside the script controller.
its because of the teapot’s rotation controllers
it reads those x,y,z subanims and compose the quaternion,
a quat rotation can be interpreted in different ways using an euler
simple solution: replace euler with TCB controller
Exactly – slerp works fine. It’s the input that causes the problem. Unfortunately TCB controllers are no good for character anim, at least in my opinion. (I know Bennyrabbit, it’s for a rigsystem we’re working on). But it’s nice that the rotation doesn’t flip at all
In the attached scene I’ve tried to avoid the TCB controller, but tried getting the same behavior by sending the rotation information through an orientation constraint. Now the axis flip at 180 degrees!
By the way – I think Denis solution might be sufficient for this specific problem, since it gives the same result as the above workaround = 180 deg. flip. But if there is an even more simple way that also avoids flipping I would be really happy to know.
I’m still thinking this is a bug. Since an Euler controller converts to a Quat be for it is passed to the matrix the Quat should work as a Quat. I wonder if some one has done some updates to how Eulers work and didn’t take that into consideration.
krestenandersen, what is wrong with using the orientation constraints? Why do you have to go with a script controller on this node?