def __init__(self, transform=None): logger.debug('Initializing: {}'.format(self)) self._transform = om2.MTransformationMatrix() if transform is None \ else om2.MTransformationMatrix(transform) self._preCallbacks = list() self._postCallbacks = list() self._parent = None # `isDirty` sets whether or not the primitive needs to be updated # before drawing. self.isDirty = False
def compute(self, plug, dataBlock): """ Node computation method: * plug is a connection point related to one of our node attributes (either an input or an output). * dataBlock contains the data on which we will base our computations. """ rotation = dataBlock.inputValue(TwistExtractor.inRotation).asDouble3() rotOrder = dataBlock.inputValue( TwistExtractor.inRotationOrder).asShort() eRoll = om2.MEulerRotation(rotation, rotOrder) useUpObj = dataBlock.inputValue(TwistExtractor.inUseUpVec).asBool() revTwist = dataBlock.inputValue(TwistExtractor.inInvTwist).asBool() # Non flip ROO = XYZ # Not working = XZY twistOrder = om2.MEulerRotation.kXYZ eRoll.reorderIt(twistOrder) # Non-Roll orientation mtxFn = om2.MTransformationMatrix() mtxFn.rotateBy(eRoll, om2.MSpace.kWorld) mRoll = mtxFn.asMatrix() qNonRoll = om2.MQuaternion() nAim = om2.MVector(mRoll[0], mRoll[1], mRoll[2]) nAim.normalize() nAimAxis = om2.MVector.kXaxisVector qAim = om2.MQuaternion(nAimAxis, nAim) qNonRoll *= qAim if useUpObj: vUp = om2.MVector( dataBlock.inputValue(TwistExtractor.inUpVec).asFloat3()) nNormal = vUp - ((vUp * nAim) * nAim) nNormal.normalize() nUp = om2.MVector.kYaxisVector.rotateBy(qAim) angle = nUp.angle(nNormal) qNormal = om2.MQuaternion(angle, nAim) if not nNormal.isEquivalent(nUp.rotateBy(qNormal), 1.0e-5): angle = 2.0 * kPI - angle qNormal = om2.MQuaternion(angle, nAim) qNonRoll *= qNormal eNonRoll = qNonRoll.asEulerRotation() eNonRoll = om2.MEulerRotation(eNonRoll.x, eNonRoll.y, eNonRoll.z, twistOrder) # Extract Twist from orientations qRoll = eRoll.asQuaternion() qExtract180 = qNonRoll * qRoll.inverse() eExtract180 = qExtract180.asEulerRotation() twist = -eExtract180.x if revTwist: twist *= -1.0 # Output Twist if plug == TwistExtractor.outTwist: outTwistHdle = dataBlock.outputValue(TwistExtractor.outTwist) outTwistHdle.setMAngle(om2.MAngle(twist)) outTwistHdle.setClean() # Output Twist Distribution if plug == TwistExtractor.outTwistDist: invDist = dataBlock.inputValue(TwistExtractor.inRevDist).asBool() outTwistDistHdle = dataBlock.outputArrayValue( TwistExtractor.outTwistDist) outputs = len(outTwistDistHdle) step = twist / (outputs - 1) if outputs > 1 else twist outList = [] outList.extend(range(outputs)) if not invDist: outList.reverse() # pylint: disable=consider-using-enumerate for i in range(len(outList)): outTwistDistHdle.jumpToLogicalElement(i) resultHdle = outTwistDistHdle.outputValue() result = step * outList[i] if outputs > 1 else twist resultHdle.setMAngle(om2.MAngle(result)) outTwistDistHdle.setAllClean() return
def compute(self, plug, dataBlock): """ Node computation method: * plug is a connection point related to one of our node attributes (either an input or an output). * dataBlock contains the data on which we will base our computations. """ # pylint: disable=no-self-use # if not dataBlock.isClean(SpaceConstraint.inSpace): # om2.MGlobal.displayInfo("\tSpace attribute is dirty.") # om2.MUserEventMessage.postUserEvent("preCompute", self) curSpace = dataBlock.inputValue(SpaceConstraint.inSpace).asShort() offsetMatchHdle = dataBlock.inputArrayValue( SpaceConstraint.inOffsetMatches) offsetHdle = dataBlock.inputArrayValue(SpaceConstraint.inOffset) targetHdle = dataBlock.inputArrayValue(SpaceConstraint.inTarget) offsetMatchList = [] offsetList = [] targetList = [] for i in range(len(offsetMatchHdle)): offsetMatchHdle.jumpToLogicalElement(i) mOffMatch = offsetMatchHdle.inputValue().asMatrix() offsetMatchList.append(mOffMatch) for i in range(len(offsetHdle)): offsetHdle.jumpToLogicalElement(i) mOff = offsetHdle.inputValue().asMatrix() offsetList.append(mOff) for i in range(len(targetHdle)): targetHdle.jumpToLogicalElement(i) mTgt = targetHdle.inputValue().asMatrix() targetList.append(mTgt) if len(offsetList) == 0 or len(targetList) == 0: mResult = om2.MMatrix() else: minRequired = min(len(offsetList), len(targetList)) - 1 if curSpace > minRequired: curSpace = minRequired mResult = offsetMatchList[curSpace] * offsetList[ curSpace] * targetList[curSpace] mtxFn = om2.MTransformationMatrix(mResult) if plug == SpaceConstraint.outConstTrans: vTransD = om2.MVector(mResult[12], mResult[13], mResult[14]) vTrans = om2.MFloatVector(vTransD) outTransHdle = dataBlock.outputValue(SpaceConstraint.outConstTrans) outTransHdle.setMFloatVector(vTrans) outTransHdle.setClean() if plug == SpaceConstraint.outConstRot: eRot = mtxFn.rotation(asQuaternion=False) outRotHdle = dataBlock.outputValue(SpaceConstraint.outConstRot) outRotHdle.setMVector(eRot.asVector()) outRotHdle.setClean() if plug == SpaceConstraint.outConstSca: outSca = mtxFn.scale(om2.MSpace.kWorld) outScaHdle = dataBlock.outputValue(SpaceConstraint.outConstSca) outScaHdle.set3Float(outSca[0], outSca[1], outSca[2]) outScaHdle.setClean()
def transform(self, value): value = om2.MTransformationMatrix(value) # copy if self._transform != value: self._transform = value self.isDirty = True
def compute(self, plug, dataBlock): """ Node computation method: * plug is a connection point related to one of our node attributes (either an input or an output). * dataBlock contains the data on which we will base our computations. """ # pylint: disable=no-self-use if plug != HelperJoint.outTransform: return om2.kUnknownParameter mSource = dataBlock.inputValue(HelperJoint.inSource).asMatrix() mtxFn = om2.MTransformationMatrix(mSource) mtxFn.setScale([1.0, 1.0, 1.0], om2.MSpace.kTransform) mSource = mtxFn.asMatrix() mSourceParent = dataBlock.inputValue(HelperJoint.inSourceParent).asMatrix() mParInv = dataBlock.inputValue(HelperJoint.inParInvMtx).asMatrix() sourceParSca = dataBlock.inputValue(HelperJoint.inSourceParSca).asFloat3() mtxFn = om2.MTransformationMatrix() mtxFn.scaleBy(sourceParSca, om2.MSpace.kTransform) mInvSca = mtxFn.asMatrix() targetListHandle = dataBlock.inputArrayValue(HelperJoint.inTargetList) outputList = [] for i in range(len(targetListHandle)): targetListHandle.jumpToLogicalElement(i) targetHandle = targetListHandle.inputValue() vPosOffset = om2.MVector(targetHandle.child(HelperJoint.inPositionOffset).asFloat3()) eRotOffset = om2.MEulerRotation(targetHandle.child(HelperJoint.inRotationOffset).asDouble3()) angle = targetHandle.child(HelperJoint.inRotAngle).asAngle().asRadians() restAngle = targetHandle.child(HelperJoint.inRestAngle).asAngle().asRadians() rotInterp = targetHandle.child(HelperJoint.inRotInterp).asFloat() posMult = targetHandle.child(HelperJoint.inPosMult).asFloat() negMult = targetHandle.child(HelperJoint.inNegMult).asFloat() mPositionOffset = om2.MMatrix() mPositionOffset[12] = vPosOffset.x mPositionOffset[13] = vPosOffset.y mPositionOffset[14] = vPosOffset.z multTranslation = abs(angle) * posMult if angle < restAngle: multTranslation = abs(angle) * negMult vPosOffset.normalize() mMultiplier = om2.MMatrix() mMultiplier[12] = vPosOffset.x * multTranslation mMultiplier[13] = vPosOffset.y * multTranslation mMultiplier[14] = vPosOffset.z * multTranslation mTargetPoint = mMultiplier * mPositionOffset * mSource mTargetOrient = mInvSca * (mSource * (1.0 - rotInterp)) + (mSourceParent * rotInterp) vResultPos = om2.MVector(mTargetPoint[12], mTargetPoint[13], mTargetPoint[14]) mtxFn = om2.MTransformationMatrix(mTargetOrient) eResultOri = eRotOffset + mtxFn.rotation(asQuaternion=False) mtxFn = om2.MTransformationMatrix() mtxFn.setRotation(eResultOri) mtxFn.setTranslation(vResultPos, om2.MSpace.kTransform) mResult = mtxFn.asMatrix() * mParInv outputList.append(mResult) outTransHandle = dataBlock.outputArrayValue(HelperJoint.outTransform) for i in range(len(outTransHandle)): outTransHandle.jumpToLogicalElement(i) resultHandle = outTransHandle.outputValue() if i < len(outTransHandle) and i < len(outputList): resultHandle.setMMatrix(outputList[i]) else: resultHandle.setMMatrix(om2.MMatrix.kIdentity)
_MAYA_OUTPUT_ATTRIBUTE_NAME = 'output' def getMRotFromNodeOutput(node_mob, rotOrder=om2.MEulerRotation.kXYZ): """ finds the angular output of the argument node and returns it as a Euler rotation where that angle is the X element :param node_mob: [MObject] the node to get the output port from :param rotOrder: [int] the factory constant for the desired rotation order the returned Euler rotation should be set to :return: [MEulerRotation] the Euler rotation composition where the angular output on the argument node is the X value """ mfn_dep = om2.MFnDependencyNode(node_mob) angle = om2.MAngle(0.0) if node_mob.hasFn(om2.MFn.kAnimBlend) and mfn_dep.hasAttribute( _MAYA_OUTPUT_ATTRIBUTE_NAME): plug = mfn_dep.findPlug(_MAYA_OUTPUT_ATTRIBUTE_NAME, False) angle = plug.asMAngle() rot = om2.MEulerRotation(angle.asRadians(), 0.0, 0.0, rotOrder) return rot mobTuple = tuple(iterSelection()) if len(mobTuple) >= 2: if mobTuple[0] is not None: srtWMtx = om2.MTransformationMatrix(wMtxFromMob(mobTuple[0])) srtWMtx.rotateBy(getMRotFromNodeOutput(mobTuple[1]), om2.MSpace.kWorld)
def compute(self, plug, dataBlock): """ Node computation method: * plug is a connection point related to one of our node attributes (either an input or an output). * dataBlock contains the data on which we will base our computations. """ # pylint: disable=no-self-use if plug != AimConstraint.outConstraint: return om2.kUnknownParameter upVecType = dataBlock.inputValue(AimConstraint.inUpVecType).asShort() eOffset = om2.MEulerRotation( dataBlock.inputValue(AimConstraint.inOffset).asDouble3()) qOffset = eOffset.asQuaternion() mTargetW = dataBlock.inputValue(AimConstraint.inTargetWMtx).asMatrix() targetWeight = dataBlock.inputValue( AimConstraint.inTargetWeight).asDouble() mConstW = dataBlock.inputValue(AimConstraint.inConstWMtx).asMatrix() mConstParInv = dataBlock.inputValue( AimConstraint.inConstParInvMtx).asMatrix() eConstJntOri = om2.MEulerRotation( dataBlock.inputValue(AimConstraint.inConstJntOri).asDouble3()) qConstJntOri = eConstJntOri.asQuaternion() constRotOrder = dataBlock.inputValue( AimConstraint.inConstRotOrder).asShort() vTarget = om2.MVector(mTargetW[12], mTargetW[13], mTargetW[14]) vConst = om2.MVector(mConstW[12], mConstW[13], mConstW[14]) mtxFn = om2.MTransformationMatrix(mConstParInv) qConstParInv = mtxFn.rotation(asQuaternion=True) primAxis = om2.MVector.kXaxisVector secAxis = om2.MVector.kYaxisVector qAimConst = om2.MQuaternion() nAim = vTarget - vConst nAim.normalize() qAim = om2.MQuaternion(primAxis, nAim) qAimConst *= qAim if upVecType != 0: if upVecType == 1: # World Up nWorldUp = om2.MVector( dataBlock.inputValue( AimConstraint.inWorldUpVector).asFloat3()) nWorldUp.normalize() vUp = nWorldUp elif upVecType == 2: # Object Up mWorldUp = dataBlock.inputValue( AimConstraint.inWorldUpMtx).asMatrix() vWorldUp = om2.MVector(mWorldUp[12], mWorldUp[13], mWorldUp[14]) vUp = vWorldUp - vConst elif upVecType == 3: # Angle Up angleUp = dataBlock.inputValue( AimConstraint.inAngleUp).asAngle().asRadians() qTwist = om2.MQuaternion(angleUp, nAim) vUp = secAxis.rotateBy(qTwist) nNormal = vUp - ((vUp * nAim) * nAim) nNormal.normalize() nUp = secAxis.rotateBy(qAim) angle = nUp.angle(nNormal) qNormal = om2.MQuaternion(angle, nAim) if not nNormal.isEquivalent(nUp.rotateBy(qNormal), 1.0e-5): angle = 2.0 * math.pi - angle qNormal = om2.MQuaternion(angle, nAim) qAimConst *= qNormal qResult = om2.MQuaternion() qResult *= qOffset.invertIt() qResult *= qAimConst qResult *= qConstParInv qResult *= qConstJntOri.invertIt() eResult = qResult.asEulerRotation() eResult.reorderIt(constRotOrder) eResult *= targetWeight vResult = eResult.asVector() outConstraintHandle = dataBlock.outputValue( AimConstraint.outConstraint) outConstraintHandle.setMVector(vResult) outConstraintHandle.setClean()
def compute(self, plug, dataBlock): """ Node computation method: * plug is a connection point related to one of our node attributes (either an input or an output). * dataBlock contains the data on which we will base our computations. """ if plug != IKVChainSolver.outChain: return om2.kUnknownParameter # Get Basis Quaternion mRoot = dataBlock.inputValue(IKVChainSolver.inRoot).asMatrix() mHandle = dataBlock.inputValue(IKVChainSolver.inHandle).asMatrix() mPoleVector = dataBlock.inputValue( IKVChainSolver.inPoleVector).asMatrix() pvMode = dataBlock.inputValue(IKVChainSolver.inPvMode).asShort() prefAngle = dataBlock.inputValue( IKVChainSolver.inPreferredAngle).asAngle().asRadians() twist = dataBlock.inputValue( IKVChainSolver.inTwist).asAngle().asRadians() snap = dataBlock.inputValue(IKVChainSolver.inSnapUpVector).asFloat() mSnap = dataBlock.inputValue(IKVChainSolver.inSnap).asMatrix() flip = dataBlock.inputValue(IKVChainSolver.inFlip).asBool() vRoot = om2.MVector(mRoot[12], mRoot[13], mRoot[14]) vHandle = om2.MVector(mHandle[12], mHandle[13], mHandle[14]) vPoleVector = om2.MVector(mPoleVector[12], mPoleVector[13], mPoleVector[14]) vSnap = om2.MVector(mSnap[12], mSnap[13], mSnap[14]) primAxis = om2.MVector.kXaxisVector secAxis = om2.MVector.kYaxisVector if flip: primAxis = -om2.MVector.kXaxisVector secAxis = -om2.MVector.kYaxisVector binAxis = primAxis ^ secAxis qBasis = om2.MQuaternion() vAim = vHandle - vRoot nAim = vAim.normal() qAim = om2.MQuaternion(primAxis, nAim) qBasis *= qAim vStartSnap = vSnap - vRoot vEndSnap = vSnap - vHandle if pvMode == 0: vUp = vPoleVector - vRoot else: qTwist = om2.MQuaternion(prefAngle + twist, nAim) vUp = secAxis.rotateBy(qTwist) nNormalPole = vUp - ((vUp * nAim) * nAim) nNormalPole.normalize() if snap > 0.0: nNormalSnap = vStartSnap - ((vStartSnap * nAim) * nAim) nNormalSnap.normalize() nNormal = (1.0 - snap) * nNormalPole + snap * nNormalSnap else: nNormal = nNormalPole nUp = secAxis.rotateBy(qAim) angle = nUp.angle(nNormal) qNormal = om2.MQuaternion(angle, nAim) if not nNormal.isEquivalent(nUp.rotateBy(qNormal), 1.0e-5): angle = 2.0 * math.pi - angle qNormal = om2.MQuaternion(angle, nAim) qBasis *= qNormal # Solver Triangle restStartLen = dataBlock.inputValue( IKVChainSolver.inRestLenStart).asFloat() restEndLen = dataBlock.inputValue( IKVChainSolver.inRestLenEnd).asFloat() compressionLimit = dataBlock.inputValue( IKVChainSolver.inCompressionLimit).asFloat() softVal = dataBlock.inputValue(IKVChainSolver.inSoftness).asFloat() startSnapLen = vStartSnap.length() endSnapLen = vEndSnap.length() startLen = (1.0 - snap) * restStartLen + snap * startSnapLen endLen = (1.0 - snap) * restEndLen + snap * endSnapLen chainLen = (1.0 - snap) * (restStartLen + restEndLen) + snap * ( startSnapLen + endSnapLen) handleLen = vAim.length() rigidLen = max(min(handleLen, chainLen), chainLen * compressionLimit) dc = chainLen da = (1.0 - softVal) * dc if handleLen > da and softVal > 0.0: ds = dc - da softLen = ds * (1.0 - math.pow(math.e, (da - handleLen) / ds)) + da solverLen = (1.0 - snap) * softLen + snap * rigidLen else: solverLen = rigidLen # Pre Calculations startLenSquared = math.pow(startLen, 2.0) endLenSquared = math.pow(endLen, 2.0) solverLenSquared = math.pow(solverLen, 2.0) stretch = dataBlock.inputValue(IKVChainSolver.inStretch).asDouble() squashMultStart = dataBlock.inputValue( IKVChainSolver.inSquashMultStart).asFloat2() squashMultEnd = dataBlock.inputValue( IKVChainSolver.inSquashMultEnd).asFloat2() if stretch > 0.0: clampStretch = dataBlock.inputValue( IKVChainSolver.inClampStretch).asDouble() clampValue = dataBlock.inputValue( IKVChainSolver.inClampValue).asDouble() squash = dataBlock.inputValue(IKVChainSolver.inSquash).asDouble() if handleLen > da and softVal > 0.0: scaleFactor = handleLen / solverLen else: scaleFactor = handleLen / chainLen if handleLen >= da: clampFactor = ( 1.0 - clampStretch) * scaleFactor + clampStretch * min( scaleFactor, clampValue) stretchFactor = (1.0 - stretch) + stretch * clampFactor else: stretchFactor = 1.0 squashFactor = (1.0 - squash) + squash * (1.0 / math.sqrt(stretchFactor)) else: stretchFactor = 1.0 squashFactor = 1.0 hierarchyMode = dataBlock.inputValue( IKVChainSolver.inHierarchyMode).asBool() useScale = dataBlock.inputValue(IKVChainSolver.inUseScale).asBool() outChainHandle = dataBlock.outputArrayValue(IKVChainSolver.outChain) offsetHandle = dataBlock.inputArrayValue(IKVChainSolver.inOffset) jntOriHandle = dataBlock.inputArrayValue(IKVChainSolver.inJntOri) mParInv = dataBlock.inputValue(IKVChainSolver.inParInvMtx).asMatrix() srtList = [] offsetList = [] jntOriList = [] for i in range(len(offsetHandle)): offsetHandle.jumpToLogicalElement(i) eOff = om2.MEulerRotation(offsetHandle.inputValue().asDouble3()) qOff = eOff.asQuaternion() offsetList.append(qOff) for i in range(len(jntOriHandle)): jntOriHandle.jumpToLogicalElement(i) eOri = om2.MEulerRotation(jntOriHandle.inputValue().asDouble3()) qOri = eOri.asQuaternion() jntOriList.append(qOri) # First Output # Scale firstStretch = stretchFactor firstScaX = firstStretch if not useScale: firstStretch = 1.0 firstSquash = [ squashFactor * squashMultStart[0], squashFactor * squashMultStart[1] ] firstSca = [firstStretch, firstSquash[0], firstSquash[1]] # Rotation betaCosPure = (startLenSquared + solverLenSquared - endLenSquared) / (2.0 * startLen * solverLen) betaCos = min(max(betaCosPure, -1.0), 1.0) beta = math.acos(betaCos) qBeta = om2.MQuaternion(beta, binAxis) qFirstRotW = qBeta * qBasis qFirstRot = om2.MQuaternion() if len(offsetList) >= 1: qFirstRot *= offsetList[0].invertIt() qFirstRot *= qFirstRotW if len(jntOriList) >= 1: qFirstRot *= jntOriList[0].invertIt() # Translation vFirstPos = vRoot # Matrix Output mtxFn = om2.MTransformationMatrix() mtxFn.setScale(firstSca, om2.MSpace.kTransform) mtxFn.setRotation(qFirstRot) mtxFn.setTranslation(vFirstPos, om2.MSpace.kTransform) mFirst = mtxFn.asMatrix() mFirst *= mParInv srtList.append(mFirst) # Second Output # Scale secondStretch = stretchFactor secondScaX = secondStretch if not useScale: secondStretch = 1.0 secondSquash = [ squashFactor * squashMultEnd[0], squashFactor * squashMultEnd[1] ] secondSca = [secondStretch, secondSquash[0], secondSquash[1]] # Rotation gammaCosPure = (startLenSquared + endLenSquared - solverLenSquared) / (2.0 * startLen * endLen) gammaCos = min(max(gammaCosPure, -1.0), 1.0) gamma = math.acos(gammaCos) gammaCmp = gamma + beta - math.pi qGamma = om2.MQuaternion(gammaCmp, binAxis) qSecondRotW = qGamma * qBasis qSecondRot = om2.MQuaternion() if len(offsetList) >= 2: qSecondRot *= offsetList[1].invertIt() qSecondRot *= qSecondRotW if hierarchyMode: qSecondRot *= qFirstRotW.invertIt() if len(offsetList) >= 1: qSecondRot *= offsetList[0].invertIt() if len(jntOriList) >= 2: qSecondRot *= jntOriList[1].invertIt() # Translation if hierarchyMode: vSecondPos = primAxis * startLen if not useScale: vSecondPos *= firstScaX else: vSecondOri = nAim.rotateBy(om2.MQuaternion( beta, nAim ^ nNormal)) * startLen if not useScale: vSecondOri *= firstScaX vSecondPos = vRoot + vSecondOri # Matrix Output mtxFn = om2.MTransformationMatrix() mtxFn.setScale(secondSca, om2.MSpace.kTransform) mtxFn.setRotation(qSecondRot) mtxFn.setTranslation(vSecondPos, om2.MSpace.kTransform) mSecond = mtxFn.asMatrix() if not hierarchyMode: mSecond *= mParInv srtList.append(mSecond) # Third Output # Rotation qThirdRot = qBasis if hierarchyMode: qThirdRot *= qSecondRotW.invertIt() if len(offsetList) >= 2: qThirdRot *= offsetList[1].invertIt() # Translation if hierarchyMode: vThirdPos = primAxis * endLen if not useScale: vThirdPos *= secondScaX else: vThirdPos = vRoot + nAim * solverLen if not useScale: vThirdPos = vRoot + nAim * solverLen * stretchFactor # Matrix Output mtxFn = om2.MTransformationMatrix() mtxFn.setRotation(qThirdRot) mtxFn.setTranslation(vThirdPos, om2.MSpace.kTransform) mThird = mtxFn.asMatrix() if not hierarchyMode: mThird *= mParInv srtList.append(mThird) # Set outputs for i in range(len(outChainHandle)): outChainHandle.jumpToLogicalElement(i) resultHandle = outChainHandle.outputValue() if i < len(outChainHandle) and i < len(srtList): resultHandle.setMMatrix(srtList[i]) else: resultHandle.setMMatrix(om2.MMatrix.kIdentity) outChainHandle.setAllClean()
def compute(self, plug, dataBlock): """ Node computation method: * plug is a connection point related to one of our node attributes (either an input or an output). * dataBlock contains the data on which we will base our computations. """ # pylint: disable=no-self-use eConstJntOri = om2.MEulerRotation( dataBlock.inputValue( ParentConstraint.inConstraintJntOri).asDouble3()) mConstParInv = dataBlock.inputValue( ParentConstraint.inConstraintParInvMtx).asMatrix() constRotOrder = dataBlock.inputValue( ParentConstraint.inConstraintRotOrder).asShort() constParSca = dataBlock.inputValue( ParentConstraint.inConstraintParSca).asFloat3() targetListHandle = dataBlock.inputArrayValue( ParentConstraint.inTargetList) mTargetsAdded = om2.MMatrix() mtxFn = om2.MTransformationMatrix() mtxFn.scaleBy(constParSca, om2.MSpace.kTransform) mInvSca = mtxFn.asMatrix() for i in range(len(targetListHandle)): targetListHandle.jumpToLogicalElement(i) targetHandle = targetListHandle.inputValue() # targetJntOri = om2.MEulerRotation(targetHandle.child(ParentConstraint.inTargetJntOri).asDouble3()) # targetRotOrder = targetHandle.child(ParentConstraint.inTargetRotOrder).asShort() mTargetW = targetHandle.child( ParentConstraint.inTargetWorldMatrix).asMatrix() mOffset = targetHandle.child( ParentConstraint.inTargetOffset).asMatrix() targetWeight = targetHandle.child( ParentConstraint.inTargetWeight).asFloat() mTarget = mOffset * (mTargetW * targetWeight) if mTargetsAdded == om2.MMatrix(): mTargetsAdded = mTarget else: mTargetsAdded += mTarget mResult = mTargetsAdded * mConstParInv * mInvSca if plug == ParentConstraint.outConstTrans: outTransHandle = dataBlock.outputValue( ParentConstraint.outConstTrans) outTrans = om2.MFloatVector(mResult[12], mResult[13], mResult[14]) outTransHandle.setMFloatVector(outTrans) outTransHandle.setClean() if plug == ParentConstraint.outConstRot: outRotHandle = dataBlock.outputValue(ParentConstraint.outConstRot) mtxFn = om2.MTransformationMatrix(mResult) eRotMtx = mtxFn.rotation(asQuaternion=False) qRotMtx = eRotMtx.asQuaternion() qConstJntOri = eConstJntOri.asQuaternion() qOutRot = qRotMtx * qConstJntOri.invertIt() outRot = qOutRot.asEulerRotation().reorderIt(constRotOrder) outRotHandle.setMVector(outRot.asVector()) outRotHandle.setClean() if plug == ParentConstraint.outConstSca: outScaHandle = dataBlock.outputValue(ParentConstraint.outConstSca) mtxFn = om2.MTransformationMatrix(mResult) outSca = mtxFn.scale(om2.MSpace.kWorld) outScaHandle.set3Float(outSca[0], outSca[1], outSca[2]) outScaHandle.setClean()