def autoFillOffset(self, thisMob, index): """Auto fill offsets attributes.""" allClear = self.checkOutputConnections(thisMob) obj = self.constraintObject if not allClear: if obj.hasFn(om2.MFn.kDagNode): objPath = om2.MFnDagNode(obj).getPath() mOut = objPath.inclusiveMatrix() targetPlug = om2.MPlug(thisMob, SpaceConstraint.inTarget) curTargetPlug = targetPlug.elementByLogicalIndex(index) curTargetObj = curTargetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(curTargetObj) mTarget = mtxDataFn.matrix() mOffset = mOut * mTarget.inverse() offsetPlug = om2.MPlug(thisMob, SpaceConstraint.inOffset) curOffsetPlug = offsetPlug.elementByLogicalIndex(index) curOffsetHdle = curOffsetPlug.asMDataHandle() mCurOffset = curOffsetHdle.asMatrix() if mCurOffset == om2.MMatrix(): curOffsetHdle.setMMatrix(mOffset) curOffsetPlug.setMDataHandle(curOffsetHdle)
def drawArrow(startPnt, endPnt, size, radius, subd, lineW, vp2=False, glFT=None, lineList=None): """Draw an aim arrow Args: startPnt (MFloatVector): The base of the vector. endPnt (MFloatVector): The end of the vector. size (float): The size of the arrow. radius (float): The radius of the arrow. subd (int): The number of subdivisions of the arrow. lineW (float): The width of the lines. vp2 (bool: False [Optional]): Draw inside of drawing override for viewport 2.0. glFT (instance: None [Optional]): The GL Function Table to draw in viewport 1.0. lineList (MPointArray: None [Optional]): The line list to append for drawing override. """ tipSize = 1.0 - size step = 2.0 * math.pi / subd vAim = endPnt - startPnt vBaseOrigin = vAim * tipSize nAim = vAim.normal() nWorld = om2.MFloatVector(0.0, 1.0, 0.0) nBinormal = nWorld ^ nAim nBinormal.normalize() nNormal = nAim ^ nBinormal nNormal.normalize() aim = [ nAim.x, nAim.y, nAim.z, 0.0, nNormal.x, nNormal.y, nNormal.z, 0.0, nBinormal.x, nBinormal.y, nBinormal.z, 0.0, startPnt.x, startPnt.y, startPnt.z, 1.0 ] mBase = om2.MMatrix(aim) mOrigin = om2.MMatrix() mOrigin[12] = vBaseOrigin.length() mBaseOrigin = mOrigin * mBase if vp2: lineList.append(om2.MPoint(startPnt)) lineList.append(om2.MPoint(endPnt)) else: glFT.glLineWidth(lineW) glFT.glBegin(omr1.MGL_LINES) glFT.glVertex3f(startPnt.x, startPnt.y, startPnt.z) glFT.glVertex3f(endPnt.x, endPnt.y, endPnt.z) glFT.glEnd() for i in range(subd): theta = step * i mPoint = om2.MMatrix() mPoint[13] = math.cos(theta) * radius mPoint[14] = math.sin(theta) * radius mArrow = mPoint * mBaseOrigin if vp2: lineList.append( om2.MPoint(mBaseOrigin[12], mBaseOrigin[13], mBaseOrigin[14])) lineList.append(om2.MPoint(mArrow[12], mArrow[13], mArrow[14])) lineList.append(om2.MPoint(mArrow[12], mArrow[13], mArrow[14])) lineList.append(om2.MPoint(endPnt)) else: glFT.glBegin(omr1.MGL_LINES) glFT.glVertex3f(mBaseOrigin[12], mBaseOrigin[13], mBaseOrigin[14]) glFT.glVertex3f(mArrow[12], mArrow[13], mArrow[14]) glFT.glVertex3f(mArrow[12], mArrow[13], mArrow[14]) glFT.glVertex3f(endPnt.x, endPnt.y, endPnt.z) glFT.glEnd() return None
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 ctrlPntsHandle = dataBlock.inputArrayValue( QuadraticCurve.inControlPoints) ctrlPnts = om2.MPointArray() if len(ctrlPntsHandle) < 3: return for i in range(3): ctrlPntsHandle.jumpToLogicalElement(i) mCtrlPnt = ctrlPntsHandle.inputValue().asMatrix() ctrlPnt = om2.MPoint(mCtrlPnt[12], mCtrlPnt[13], mCtrlPnt[14]) ctrlPnts.append(ctrlPnt) crvKnots = om2.MDoubleArray([0, 0, 1, 1]) crvDegree = 2 crvForm = om2.MFnNurbsCurve.kOpen crvIs2d = False crvRational = False crvData = om2.MFnNurbsCurveData().create() crvFn = om2.MFnNurbsCurve(crvData) crvFn.create(ctrlPnts, crvKnots, crvDegree, crvForm, crvIs2d, crvRational, crvData) crvFn.updateCurve() if plug == QuadraticCurve.outCurve: outCurveHandle = dataBlock.outputValue(QuadraticCurve.outCurve) outCurveHandle.setMObject(crvData) outCurveHandle.setClean() elif plug == QuadraticCurve.outTransforms: outTransHandle = dataBlock.outputArrayValue( QuadraticCurve.outTransforms) lockLength = dataBlock.inputValue( QuadraticCurve.inLockLength).asFloat() restLength = dataBlock.inputValue( QuadraticCurve.inRestLength).asFloat() slide = dataBlock.inputValue(QuadraticCurve.inSlide).asFloat() numOutputs = len(outTransHandle) crvLength = crvFn.length() parRejected = crvFn.findParamFromLength(crvLength - restLength) stepFull = 1.0 / (numOutputs - 1) if numOutputs > 1 else 0.0 stepLock = crvFn.findParamFromLength(restLength) / ( numOutputs - 1) if numOutputs > 1 else 0.0 step = (1.0 - lockLength) * stepFull + lockLength * stepLock parSlide = parRejected * slide * lockLength for i in range(numOutputs): parameter = (step * i) # + parSlide pos = crvFn.getPointAtParam(parameter, om2.MSpace.kObject) vPos = om2.MVector(pos.x, pos.y, pos.z) mtx = [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, vPos.x, vPos.y, vPos.z, 1.0 ] mOut = om2.MMatrix(mtx) outTransHandle.jumpToLogicalElement(i) resultHandle = outTransHandle.outputValue() resultHandle.setMMatrix(mOut) outTransHandle.setAllClean() else: return om2.kUnknownParameter
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 != DistributeAlongSurface.outTransform: return om2.kUnknownParameter surfaceHandle = dataBlock.inputValue(DistributeAlongSurface.inSurface) surface = surfaceHandle.asNurbsSurface() distAlong = dataBlock.inputValue(DistributeAlongSurface.inDistributeAlong).asShort() displace = dataBlock.inputValue(DistributeAlongSurface.inDisplace).asFloat() alwaysUniform = dataBlock.inputValue(DistributeAlongSurface.inAlwaysUniform).asBool() outTransHandle = dataBlock.outputArrayValue(DistributeAlongSurface.outTransform) numOutputs = len(outTransHandle) surfaceFn = om2.MFnNurbsSurface(surface) step = 1.0 / (numOutputs - 1) if numOutputs > 1 else 0.0 curveData = om2.MFnNurbsCurveData().create() curveFn = om2.MFnNurbsCurve(curveData) if alwaysUniform: numCVs = surfaceFn.numCVsInU if distAlong == 0 else surfaceFn.numCVsInV curvePnts = om2.MPointArray() curveKnots = surfaceFn.knotsInU() if distAlong == 0 else surfaceFn.knotsInV() curveDegree = surfaceFn.degreeInU if distAlong == 0 else surfaceFn.degreeInV curveForm = surfaceFn.formInU if distAlong == 0 else surfaceFn.formInV curveIs2d = False curveRational = False for i in range(numCVs): if distAlong == 0: curvePnts.append(surfaceFn.cvPosition(i, int(displace))) else: curvePnts.append(surfaceFn.cvPosition(int(displace), i)) curveFn.create(curvePnts, curveKnots, curveDegree, curveForm, curveIs2d, curveRational, curveData) curveLength = curveFn.length() for i in range(numOutputs): if alwaysUniform: parU = curveFn.findParamFromLength(curveLength * step * i) if distAlong == 0 else displace parV = displace if distAlong == 0 else curveFn.findParamFromLength(curveLength * step * i) else: parU = step * i if distAlong == 0 else displace parV = displace if distAlong == 0 else step * i pos = surfaceFn.getPointAtParam(parU, parV, om2.MSpace.kWorld) tangents = surfaceFn.tangents(parU, parV, om2.MSpace.kWorld) aim = tangents[0].normalize() if distAlong == 0 else tangents[1].normalize() normal = surfaceFn.normal(parU, parV, om2.MSpace.kWorld).normalize() binormal = tangents[1].normalize() if distAlong == 0 else tangents[0].normalize() mtx = [ aim.x, aim.y, aim.z, 0.0, normal.x, normal.y, normal.z, 0.0, binormal.x, binormal.y, binormal.z, 0.0, pos.x, pos.y, pos.z, 1.0 ] mOut = om2.MMatrix(mtx) outTransHandle.jumpToLogicalElement(i) resultHandle = outTransHandle.outputValue() resultHandle.setMMatrix(mOut) surfaceHandle.setClean() outTransHandle.setAllClean() cmds.refresh()
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 spaceMatchCallback(msg, plug, otherPlug, clientData): """ The callback function. Note: Attribute Changed messages will not be generated while Maya is either in playback or scrubbing modes. If you need to do something during playback or scrubbing you will have to register a callback for the timeChanged message which is the only message that is sent during those modes. * msg [MNodeMessage::AttributeMessage] is the kind of attribute change triggering the callback. * plug [MPlug] is the node's plug where the connection changed. * otherPlug [MPlug] is the plug opposite the node's plug where the connection changed. * clientData [void*] is the user defined data passed to this callback function. """ # pylint: disable=unused-argument # 6144 = create input array element. # 16385 = connecting output. # 16386 = disconnecting output. # 2052 = change output in compute method. # 2056 = set attribute. # 10240 = delete element plug from array attribute. # 18434 = disconnect input plug. # 18433 = connect input plug. thisMob = clientData.thisMObject() if not isinstance(clientData, SpaceConstraint): # SpaceConstraint *pMesh = static_cast<SpaceConstraint *>(clientData); om2.MGlobal.displayError( "[gfTools] gfSpaceConstraint don't recognize the clientData for space match callback. Callback functionality skiped." ) return match = om2.MPlug(thisMob, SpaceConstraint.inSpaceMatch).asBool() if not match: return if msg == 2056: if plug == SpaceConstraint.inSpace: lastValue = clientData.lastSpace curValue = plug.asShort() # 1- Get the output plug allClear = clientData.checkOutputConnections(thisMob) # 2- Check if the curValue is valid. If it is not, get the last valid. targetPlug = om2.MPlug(thisMob, SpaceConstraint.inTarget) offsetPlug = om2.MPlug(thisMob, SpaceConstraint.inOffset) offsetMatchPlug = om2.MPlug(thisMob, SpaceConstraint.inOffsetMatches) numTarget = targetPlug.numElements() - 1 if curValue > numTarget: curValue = numTarget # 3- If the node have necessary connections... if not allClear and (numTarget + 1) > 0: outObj = clientData.constraintObject if outObj.hasFn(om2.MFn.kDagNode): # 4- Get the last world matrix of the target lastOffsetMatchPlug = offsetMatchPlug.elementByLogicalIndex( lastValue) lastOffsetMatchObj = lastOffsetMatchPlug.asMObject() mtxDataFn = om2.MFnMatrixData(lastOffsetMatchObj) mOffsetMatch = mtxDataFn.matrix() lastOffsetPlug = offsetPlug.elementByLogicalIndex( lastValue) lastOffsetObj = lastOffsetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(lastOffsetObj) mOffset = mtxDataFn.matrix() lastTargetPlug = targetPlug.elementByLogicalIndex( lastValue) lastTargetObj = lastTargetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(lastTargetObj) mTarget = mtxDataFn.matrix() mLastOutputW = mOffsetMatch * mOffset * mTarget # 5- Get the current world matrix of the target curTargetPlug = targetPlug.elementByLogicalIndex( curValue) curTargetObj = curTargetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(curTargetObj) mTarget = mtxDataFn.matrix() curOffsetPlug = offsetPlug.elementByLogicalIndex( curValue) curOffsetObj = curOffsetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(curOffsetObj) mOffset = mtxDataFn.matrix() mCurOutputW = mOffset * mTarget # 6- Get the result of the match and set it into the plug mResult = mLastOutputW * mCurOutputW.inverse() curOffsetMatchPlug = offsetMatchPlug.elementByLogicalIndex( curValue) curOffsetMatchHdle = curOffsetMatchPlug.asMDataHandle() curOffsetMatchHdle.setMMatrix(mResult) curOffsetMatchPlug.setMDataHandle(curOffsetMatchHdle) # 7- Clean the offset match plug from last value lastOffsetMatchHdle = lastOffsetMatchPlug.asMDataHandle( ) lastOffsetMatchHdle.setMMatrix(om2.MMatrix()) lastOffsetMatchPlug.setMDataHandle(lastOffsetMatchHdle) clientData.lastSpace = curValue
def spaceMatchCallback2(node, plug, clientData): """Node dirty callback. Works, but not quite. """ # 1- Check if space plug is dirty. if plug == SpaceConstraint.inSpace: # 2- Check if clientData is valid. thisMob = clientData.thisMObject() if not isinstance(clientData, SpaceConstraint): om2.MGlobal.displayError( "[gfTools] gfSpaceConstraint don't recognize the clientData for space matching. Callback functionality skipped." ) return # 3- Check if automatic space matching is enable. match = om2.MPlug(thisMob, SpaceConstraint.inSpaceMatch).asBool() if not match: return # 4- Check if space attribute changed. lastValue = clientData.lastSpace curValue = plug.asShort() spacePlug = om2.MPlug(thisMob, SpaceConstraint.inSpace) om2.MGlobal.displayInfo("Current space value: %s" % str(spacePlug.asShort())) if curValue == lastValue: return # 5- Check if any output is been used and get the output object. allClear = clientData.checkOutputConnections(thisMob) # 6- Check the inputs. targetPlug = om2.MPlug(thisMob, SpaceConstraint.inTarget) offsetPlug = om2.MPlug(thisMob, SpaceConstraint.inOffset) offsetMatchPlug = om2.MPlug(thisMob, SpaceConstraint.inOffsetMatches) numTarget = targetPlug.numElements() - 1 if curValue > numTarget: curValue = numTarget # 7- If the node have necessary connections... if not allClear and (numTarget + 1) > 0: outObj = clientData.constraintObject if outObj.hasFn(om2.MFn.kDagNode): # 8- Get the last world matrix of the target. lastOffsetMatchPlug = offsetMatchPlug.elementByLogicalIndex( lastValue) lastOffsetMatchObj = lastOffsetMatchPlug.asMObject() mtxDataFn = om2.MFnMatrixData(lastOffsetMatchObj) mOffsetMatch = mtxDataFn.matrix() lastOffsetPlug = offsetPlug.elementByLogicalIndex( lastValue) lastOffsetObj = lastOffsetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(lastOffsetObj) mOffset = mtxDataFn.matrix() lastTargetPlug = targetPlug.elementByLogicalIndex( lastValue) lastTargetObj = lastTargetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(lastTargetObj) mTarget = mtxDataFn.matrix() mLastOutputW = mOffsetMatch * mOffset * mTarget # 9- Get the current world matrix of the target. curTargetPlug = targetPlug.elementByLogicalIndex(curValue) curTargetObj = curTargetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(curTargetObj) mTarget = mtxDataFn.matrix() curOffsetPlug = offsetPlug.elementByLogicalIndex(curValue) curOffsetObj = curOffsetPlug.asMObject() mtxDataFn = om2.MFnMatrixData(curOffsetObj) mOffset = mtxDataFn.matrix() mCurOutputW = mOffset * mTarget # 10- Get the result of the match and set it into the plug. mResult = mLastOutputW * mCurOutputW.inverse() curOffsetMatchPlug = offsetMatchPlug.elementByLogicalIndex( curValue) curOffsetMatchHdle = curOffsetMatchPlug.asMDataHandle() curOffsetMatchHdle.setMMatrix(mResult) curOffsetMatchPlug.setMDataHandle(curOffsetMatchHdle) # 11- Clean the offset match plug from last value. lastOffsetMatchHdle = lastOffsetMatchPlug.asMDataHandle() lastOffsetMatchHdle.setMMatrix(om2.MMatrix()) lastOffsetMatchPlug.setMDataHandle(lastOffsetMatchHdle) om2.MGlobal.displayInfo("Performing space matching...") # 12- Store the current space value in class to be accessed later on. clientData.lastSpace = curValue
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)
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()