Maya orientConstraint algorithm?

I’m trying to replicate the results of an orientConstraint in some of my own code, and I’m wondering if anyone has any clue about what algorithm Maya’s orientConstraint may be using for >2 targets. The problem is that it’s some kind of non-commutative solution (it depends on the target order for its result).

I’m using the slime algorithm as an alternative right now, but hoping to find something that maps 1:1 if anyone has any ideas. If not, I’ll just see if I can reverse engineer it.

I suppose I should clarify: the problem only exists for interpolation types other than average (since average is obviously a commutative operation).

I would guess it’s a regular quaternion slerp for shortest and slerp with no neighborhood check for longest.

The multiplication of quaternions is non-commutative.

In Xna; You rotate with Quaternions by using the * operator which is doing the dirty work for you behind the scenes

Quaternion TargetA, TargetB
Quaternion Source = TargetA * TargetB

I think this should do it and should work for N amount of targets, unless I’m mistaken…

@LoneWolf: the problem is that the it is a weighted blend, rather than a simple composition.

@ShadowM8: while that’s correct and easy enough to reproduce when there are two targets, the question really concerns what happens when there are more than 2 targets.

To see the problem, execute this really quickly in Maya:

import maya.cmds as cmds
cones = []
for i in xrange(4):
    cones.append(cmds.polyCone()[0])
    cmds.setAttr('%s.translate'%cones[i], i*2,0,0)
oc = cmds.orientConstraint([cones[0],cones[1],cones[2],cones[3]])[0]
cmds.setAttr('%s.interpType'%oc, 2)
cmds.setAttr('%s.rotateZ'%cones[0], 90)
cmds.setAttr('%s.rotateZ'%cones[1], 45)
print cmds.getAttr('%s.rotateZ'%cones[3])

You should see the result on the constrained cone is 50.0 degrees. Now run this:

cmds.setAttr('%s.rotateZ'%cones[0], 45)
cmds.setAttr('%s.rotateZ'%cones[1], 90)
print cmds.getAttr('%s.rotateZ'%cones[3])

You should see a result of 40.0. When using e.g., slime, both cases produce the same result (45.0), since it’s a…omnibus? operation.

I’ve tried reproducing Maya’s result in various ways, but for example these forms are incorrect:

Quaternion q= Quaternion.identity;
for (int i=0; i<targets.length; i++)
    q *= Quaternion.Slerp(Quaternion.identity, targets[i].q, targets[i].w;
Quaternion q= Quaternion.identity;
for (int i=0; i<targets.length; i++)
    q *= Quaternion.Slerp(q, targets[i].q, targets[i].w;

I’ve tried a few other variants to no avail, so just hoping someone with more math smarts than I might have a suggestion.

ah yeah true I forgot that maya also has weights for the constraints that you can manipulate…

I found this post. I think the first solution he provides should work. Haven’t used any of them:

http://www.gamedev.net/topic/556211-quaternion-weighting-and-non-linear-interpolation-semi-solved/

why I think it should work? This is the normalize algorithm for quaternions, not different than vector:

magnitude = sqrt(w2 + x2 + y2 + z2)
w = w / magnitude
x = x / magnitude
y = y / magnitude
z = z / magnitude

if we would use the technique he talks about for two quaternions with exactly same value, we would get the same quaternion back. So imagine we have Quaternion A. We multiply A.xyzw with 0.5f… We do A+A and get back the original quaternion. Normalizing would return us back the same value for this but it’s needed in case we pass the 0-1 boundary with the weights like when over weighting

So for 4 quaternions you multiply all the components by 0.25f or the weight you wish to distribute to them. Then add the quaternions together and then normalize! This sounds logical to me but it might not be in practise.

Again I haven’t tested. Just trying to visualize the impossible xD

Thanks for the link Lonewolf. I may see if either of his other options yields the result I’m trying to get, but intuitively they don’t sound like non-commutative operations. Because slerp is not commutative (and because IIRC Maya’s orientConstraint predates e.g., slime and sasquatch interpolation), I am guessing that Maya is using some kind of slerp-based system for the non-average interpolation modes. Just going to be a matter of reverse engineering it :frowning:

Np! If you manage to get ahold of the rest of the algorithms, be sure to post it here, I’m kind of interested in them for learning purposes ^^

Good luck :slight_smile:

It’s been a while since I wrote one but I think I did it sequentially and it matched, so for 3 targets it would be: rq = slerp (slerp (t0, t1), t2). The weight values are remapped into a range of 0 to 1.

Perfect that does it! I owe you a drink!