[Closed] Fixing transform rotations
I’ve written a tool to help me when using bones. It will calculate an Xform matrix to effectively rotate the bone on X so that either Y or Z will be pointing at a predefined object. I’m doing this in the code below. It’s working great, EXCEPT for the fact that some of the rotation controller values of the bones end up with values like:
[0.1401,1.0996,360.9725]
where the 360 value offset on Z is the problem
and
[179.3479,179.1381,181.3631]
where the multiple 180 value offsets are the problem
whereas I would much prefer those values to be:
[0.1401,1.0996,0.9725]
and
[-0.6521,-0.8619,1.3631]
Is there a known way to deal with this kind of 3-axis 180 or single-axis 360 offset?
I can see a way that I might be able to do it by testing if there are single axis values that are close to multiples of 360, or 3 axis values that are close to multiples of 180, and offsetting these values til they become something more suitable. But that seems quite a fiddly way to go about fixing something like this. I’m hoping there’s a known way to do this elegantly.
alignToPos = selection[1].transform.row4
for i = 2 to selection.count do
(
obj = selection[i]
if obj.children.count > 0 do
(
kidXforms = for kid in obj.children collect kid.transform
)
objPos = obj.transform.row4
x = normalize (obj.transform.row1)
if alignAxis == #y then
(
y = normalize (alignToPos - objPos)
z = normalize ( cross x y)
y = normalize (cross z x)
)
else if alignAxis == #z then
(
z = normalize (alignToPos - objPos)
y = normalize ( cross z x)
z = normalize (cross x y)
)
tm = matrix3 x y z objPos
obj.transform = tm
if obj.children.count > 0 do
(
for j = 1 to kidXforms.count do obj.children[j].transform = kidXforms[j]
)
theRot = obj.transform.controller.rotation.controller
)
)
the following is quoted from maxscript help: quat value chapter, might be helpful…
getEulerQuatAngleRatio <quat1> <quat2> <eulerAngles1> <eulerAngles2> [angle:<eulertype_integer>]
When converting a series of quat values to eulerAngles values, it is possible for sign flips to occur in the eulerAngles values. This is due to the fact that one single quat value can be expressed through many different eulerAngles values. This flip can be detected by based on the eulerAngles/quat ratio. The eulerAngles/quat ratio is the relation of the angle difference in eulerAngles space to the angle difference in quat space. If this ratio is bigger than PI the rotation between the two quat to eulerAngles conversions. This method returns the eulerAngles/quat angle ratio between the two quat to eulerAngles conversions as a float value. The actual detection of the flip is dependent on the amount of rotation in between conversions. The smaller the amount of rotation, the more accurate the detection is. The parameters to this method are:
quat1 and quat2 are the previous and current rotation values.
eulerAngles1 and eulerAngles2 are the previous and current converted rotation angles.
The optional eulertype_integer parameter specifies the order of application of the angles. If not specified, XYZ ordering is used. Its value can be any of the following:
1 – XYZ2 – XZY3 – YZX4 – YXZ5 – ZXY6 – ZYX7 – XYX8 – YZY9 – ZXZ
Hi, thanks for your reply. Can anyone confirm that this information is relevant to my problem? I have read it quite a few times and still don’t understand what it is describing or how this can help me. But if it is relevant, I will endeavor to understand. It mentions comparing a previous and current rotation. But the problem I am having is related to only a current rotation. Still looking for pointers if anyone can shed more light.
Cg.
You might try looking at the Euler Filter code (used in TrackView) in the SDK and try to leverage it to catch your 180/360 flips.
it’s a simple changing euler-bezier controler to TCB and back to euler as i remember. as you can see the keys are losing their in-out custom tangents. so if you OK about it: apply TCB and reapply Euler
[0.1401,1.0996,360.9725]
where the 360 value offset on Z is the problem
and
[179.3479,179.1381,181.3631]
where the multiple 180 value offsets are the problemwhereas I would much prefer those values to be:
[0.1401,1.0996,0.9725]
and
[-0.6521,-0.8619,1.3631]
You could use the mod function which takes two operands a and b and says “what is the remainder when a is divided by b”, for example mod 360.9725 360 = 0.0975. That would work for getting all your rotations values between -360 and 360 but I’m not sure if it would cause any strange behaviour between keyframes. Like previously mentioned the most reliable method would probably be to use Quaternions then convert them to Euler angles the back again.
I’ve attached the Euler Filter.cpp file to which I was referring…