Following on Vasil Shotarov’s awesome tutorial, I’ve scripted a setup to read angles and have been using it a lot lately. Pretty stable and saves me a lot of time!
def quatTwistReader(name, axis='x'):
# returns grp, reader, quaternionNode
reader = cmds.group(empty=True, name=name+"_twist_reader")
reader_grp = cmds.group(reader, name=reader+"_grp")
mm = cmds.createNode("multMatrix", name=name+"_mm")
cmds.connectAttr(reader+".worldMatrix[0]", mm+".matrixIn[0]")
cmds.connectAttr(reader_grp+".worldInverseMatrix[0]", mm+".matrixIn[1]")
dm = cmds.createNode("decomposeMatrix", name=name+"_dm")
cmds.connectAttr(mm+".matrixSum", dm+".inputMatrix")
qte = cmds.createNode("quatToEuler", name=name+"_qte")
cmds.connectAttr(dm+".outputQuat"+axis.upper(), qte+".inputQuat"+axis.upper())
cmds.connectAttr(dm+".outputQuatW", qte+".inputQuatW")
return reader_grp, reader, qte
Usage example of a wrist twist:
STEP 1
Run quatTwistReader(“l_wrist”, “x”). Double-check your rig for the desired axis you want to extract but it’s usually X as in the axis that goes along a chain.
STEP 2
Parent constrain the top “l_wrist_twist_reader_grp” (reader_grp variable) result to your hierarchy so the reader is always in the correct orientation. For the wrist it should constrained to the last bendy joint of the forearm, right before the hand.
STEP 3
Orient constrain the hand joint to command the “l_wrist_twist_reader” (reader variable).
STEP 4
Use the “outputRotateX” of the “l_wrist_qte” (qte variable – quatToEuler node) for your objective, it should be outputting only the twisting in the X axis.
STEP 5
Profit 😎
Tip: if you’re getting flips before 180 and everything is aligned properly, try changing the inputRotateOrder in the quatToEuler node to match your ctrls/jnts
