def addConstraintMap(node, driven, utilities, kwargsMap=None): """Adds a mapping of drivers and utilities to the constraint compound array attribute :param node: The node to add or has the constraint map , typically this would be the driver node \ of the constraint. :type node: om2.MObject :param driven: a list of driven transform nodes. :type driven: tuple(om2.MObject) :param utilities: a list of utilities/support nodes that make up the constraint, this could be the \ constraint node itself or any math node etc. :type utilities: tuple(om2.MObject) """ kwargsmap = kwargsMap or "" mfn = om2.MFnDependencyNode(node) if not mfn.hasAttribute("constraints"): compoundPlug = addConstraintAttribute(node) else: compoundPlug = mfn.findPlug("constraints", False) availPlug = plugs.nextAvailableElementPlug(compoundPlug) drivenPlug = availPlug.child(0) # lets add the driven nodes to the xth of the element compound for drive in iter(driven): if drive is None: continue drivenFn = om2.MFnDependencyNode(drive) if drivenFn.hasAttribute("constraint"): p = drivenFn.findPlug("constraint", False) elementP = plugs.nextAvailableElementPlug(p) plugs.connectPlugs(drivenPlug, elementP) continue attr = nodes.addAttribute(drive, "constraint", "constraint", attrtypes.kMFnMessageAttribute, isArray=True) attrP = om2.MPlug(drive, attr.object()) plugs.connectPlugs(drivenPlug, attrP.elementByLogicalIndex(0)) utilPlug = availPlug.child(1) # add all the utilities for i in iter(utilities): if i is None: continue utilFn = om2.MFnDependencyNode(i) if utilFn.hasAttribute("constraint"): p = utilFn.findPlug("constraint", False) if p.isDestination: continue plugs.connectPlugs(utilPlug, p) continue attr = nodes.addAttribute(i, "constraint", "constraint", attrtypes.kMFnMessageAttribute) plugs.connectPlugs(utilPlug, om2.MPlug(i, attr.object())) # set the kwargs map plug, so we know how the constraint was created plugs.setPlugValue(availPlug.child(2), kwargsmap) return compoundPlug
def connectToByPlug(self, sourcePlug, node, nodeAttributeName=None): nodeAttributeName = nodeAttributeName or "metaNode" dep = om2.MFnDependencyNode(node) if not dep.hasAttribute(nodeAttributeName): destinationPlug = dep.findPlug( nodes.addAttribute(node, nodeAttributeName, nodeAttributeName, attrtypes.kMFnMessageAttribute).object(), False) else: destinationPlug = dep.findPlug(nodeAttributeName, False) plugs.disconnectPlug(destinationPlug) with plugs.setLockedContext(sourcePlug): destIsLock = False sourceIsLock = False if destinationPlug.isLocked: destinationPlug.isLocked = False destIsLock = True if sourcePlug.isLocked: sourcePlug.isLocked = False sourceIsLock = True plugs.connectPlugs(sourcePlug, destinationPlug) if sourceIsLock: sourcePlug.isLocked = True if destIsLock: destinationPlug.isLocked = True return destinationPlug
def addAttribute(self, name, value, Type, isArray=False, lock=True): mfn = self._mfn mobj = mfn.object() if mfn.hasAttribute(name): return mfn.findPlug(name, False) try: attr = nodes.addAttribute(mobj, name, name, Type, isArray=isArray, apply=True) except RuntimeError: raise ValueError( "Failed to create attribute with name: {}".format(name)) newPlug = None if attr is not None: newPlug = om2.MPlug(mobj, attr.object()) if value is not None and newPlug is not None: # if mobject expect it to be a node if isinstance(value, om2.MObject): self.connectTo(name, value) else: plugs.setPlugValue(newPlug, value) newPlug.isLocked = lock return newPlug
def addTarget(self, driver): """Adds the given driver transform to the constraint :param driver: The driver mobject transform :type driver: MObject @note having to use maya commands here due to api not able to resize the plugs array outside the datablock """ driven = self.drivenObject() driverName = nodes.nameFromMObject(driver) # so we have the fullPath driverShortName = om2.MNamespace.stripNamespaceFromName(driverName).split("|")[-1] nextWeightIndex = self.numTargets() # starts at zero so the return is the next element drivenFn = om2.MFnDependencyNode(driven) offsetMatrix = om2.MTransformationMatrix(nodes.getOffsetMatrix(driver, driven)) translation = offsetMatrix.translation(om2.MSpace.kTransform) rotation = generic.eulerToDegrees( offsetMatrix.rotation().reorder(plugs.getPlugValue(drivenFn.findPlug("rotateOrder", False)))) # create the weight attribute weightName = "W".join([driverShortName, str(nextWeightIndex)]) weightAttr = nodes.addAttribute(self.node.object(), weightName, weightName, attrType=attrtypes.kMFnNumericDouble) weightAttr.setMin(0.0) weightAttr.setMax(1.0) weightAttr.default = 1.0 weightAttr.keyable = True driverFn = om2.MFnDependencyNode(driver) targetPlug = self.mfn.findPlug("target", False).elementByLogicalIndex(nextWeightIndex) cmds.connectAttr(driverFn.findPlug("parentMatrix", False).elementByPhysicalIndex(0).name(), targetPlug.child(0).name()) # targetParentMatrix cmds.connectAttr(driverFn.findPlug("scale", False).name(), targetPlug.child(13).name()) # targetScale cmds.connectAttr(driverFn.findPlug("rotateOrder", False).name(), targetPlug.child(8).name()) # targetRotateOrder cmds.connectAttr(driverFn.findPlug("rotate", False).name(), targetPlug.child(7).name()) # targetRotate cmds.connectAttr(driverFn.findPlug("rotatePivotTranslate", False).name(), targetPlug.child(5).name()) # targetRotateTranslate cmds.connectAttr(driverFn.findPlug("rotatePivot", False).name(), targetPlug.child(4).name()) # targetRotatePivot cmds.connectAttr(driverFn.findPlug("translate", False).name(), targetPlug.child(3).name()) # targetTranslate cmds.connectAttr(om2.MPlug(self.mfn.object(), weightAttr.object()).name(), targetPlug.child(1).name()) # targetWeight # setting offset value plugs.setPlugValue(targetPlug.child(6), translation) # targetOffsetTranslate plugs.setPlugValue(targetPlug.child(10), rotation) # targetOffsetRotate
def connectTo(self, attributeName, node, nodeAttributeName=None): """Connects one plug to another by attribute name :param attributeName: the meta attribute name to connect from, if it doesn't exist it will be created :type attributeName: str :param node: the destination node :type node: MObject :param nodeAttributeName: the destination node attribute name, if one doesn't exist one will be created :type nodeAttributeName: str :return: the destination plug :rtype: om2.MPlug """ nodeAttributeName = nodeAttributeName or "metaNode" dep = om2.MFnDependencyNode(node) self.disconnectFromNode(node) if not dep.hasAttribute(nodeAttributeName): destinationPlug = dep.findPlug( nodes.addAttribute(node, nodeAttributeName, nodeAttributeName, attrtypes.kMFnMessageAttribute).object(), False) else: destinationPlug = dep.findPlug(nodeAttributeName, False) plugs.disconnectPlug(destinationPlug) if self._mfn.hasAttribute(attributeName): # we should have been disconnected from the destination control above sourcePlug = self._mfn.findPlug(attributeName, False) else: newAttr = self.addAttribute(attributeName, None, attrtypes.kMFnMessageAttribute) if newAttr is not None: sourcePlug = newAttr else: sourcePlug = self._mfn.findPlug(attributeName, False) with plugs.setLockedContext(sourcePlug): if destinationPlug.isLocked: destinationPlug.isLocked = False plugs.connectPlugs(sourcePlug, destinationPlug) destinationPlug.isLocked = True return destinationPlug
def addAttribute(self, name, value, Type, isArray=False, lock=True): mobj = self._handle.object() mfn = om2.MFnDependencyNode(mobj) if mfn.hasAttribute(name): return try: attr = nodes.addAttribute(mobj, name, name, Type) attr.array = isArray except RuntimeError: return newPlug = None if attr is not None: newPlug = om2.MPlug(mobj, attr.object()) if value is not None and newPlug is not None: # if mobject expect it to be a node if isinstance(value, om2.MObject): self.connectTo(name, value) else: plugs.setPlugValue(newPlug, value) newPlug.isLocked = lock return attr
def buildConstraint(source, targets, maintainOffset=False, constraintType=om2.MFn.kParentConstraint, **kwargs): """This Function build a space switching constraint. Currently Supporting types of kParentConstraint kPointConstraint kOrientConstraint :param source: The transform to drive :param source: om2.MObject :param targets: A dict containing the target information(see below example) :param targets: dict or None :param: maintainOffset: whether or not the constraint should maintain offset :type maintainOffset: bool :param constraintType: The maya api kType eg. om2.MFn.kParentConstraint, defaults to kParentConstraint :type constraintType: om2.MFn.kType :param kwargs: The cmds.kconstraintType extra arguments to use :type kwargs: dict .. code-block: python targets = [] for n in ("locator1", "locator2", "locator3"): targets.append((n, nodes.createDagNode(n, "locator"))) spaceNode =nodes.createDagNode("control", "locator") drivenNode = nodes.createDagNode("driven", "locator") spaces = {"spaceNode": spaceNode, "attributeName": "parentSpace", "targets": targets} constraint, conditions = build(drivenNode, targets=spaces) # lets add to the existing system spaces = {"spaceNode": spaceNode, "attributeName": "parentSpace", "targets": ( ("locator8", nodes.createDagNode("locator8", "locator")),)} constraint, conditions = build(drivenNode, targets=spaces) ) """ # make sure we support the constrainttype the user wants assert constraintType in APITOCMDS_CONSTRAINT_MAP, "No Constraint of type: {}, supported".format(constraintType) spaceNode = targets.get("spaceNode") attrName = targets.get("attributeName", "parent") targetInfo = targets["targets"] targetLabels, targetNodes = zip(*targetInfo) # first try to find an existing constraint existingConstraint = findConstraint(source, constraintType, includeReferenced=False) # if we found existing constraint then check to see if the target is already # constraining, if so just excluded it. targetList = targetNodes if existingConstraint: existingTargets = list(iterTargetsFromConstraint(existingConstraint)) targetList = [t for t in targetNodes if t not in existingTargets] # in the case that all target already exist just early out if not targetList: return None, [] # create the constraint constraintMap = APITOCMDS_CONSTRAINT_MAP[constraintType] cmdsFunc = getattr(cmds, constraintMap["type"]) arguments = {"maintainOffset": maintainOffset} arguments.update(kwargs) constraint = cmdsFunc(map(nodes.nameFromMObject, targetList), nodes.nameFromMObject(source), **arguments)[0] # if we have been provided a spaceNode, which will contain our switch, otherwise ignore the setup of a switch # and just return the constraint constraintMObject = nodes.asMObject(constraint) if spaceNode is None: return constraintMObject, [] spaceFn = om2.MFnDependencyNode(spaceNode) if spaceFn.hasAttribute(attrName): spacePlug = spaceFn.findPlug(attrName, False) existingFieldNames = plugs.enumNames(spacePlug) spaceAttr = om2.MFnEnumAttribute(spacePlug.attribute()) # add any missing fields to enumAttribute for field in targetLabels: if field not in existingFieldNames: spaceAttr.addField(field, len(existingFieldNames)) else: spaceAttr = nodes.addAttribute(spaceNode, attrName, attrName, attrType=attrtypes.kMFnkEnumAttribute, keyable=True, channelBox=True, locked=False, enums=targetLabels) spacePlug = om2.MPlug(spaceNode, spaceAttr.object()) constraintFn = om2.MFnDependencyNode(constraintMObject) targetArray = constraintFn.findPlug("target", False) sourceShortName = nodes.nameFromMObject(source, partialName=True, includeNamespace=False) conditions = [] constraintTargetWeightIndex = constraintMap["targetPlugIndex"] # first iterate over the target array on the constraint for index in targetArray.getExistingArrayAttributeIndices(): targetElement = targetArray.elementByLogicalIndex(index) targetElementWeight = targetElement.child(constraintTargetWeightIndex) targetWeightSource = targetElementWeight.source() # just in case the target weight plug is disconnected if targetWeightSource is None: targetWeightSource = targetElementWeight else: # lets make sure that we're not already connected to a condition node # if so skip weightSourceNode = targetWeightSource.node() # if we connected to the constraint i.e spaceWO1 if weightSourceNode == constraintMObject: upstreamWeight = targetWeightSource.source() if upstreamWeight and upstreamWeight.node().apiType() == om2.MFn.kCondition: continue else: if weightSourceNode.apiType() == om2.MFn.kCondition: continue targetNode = targetElement.child(0).source().node() targetShortName = nodes.nameFromMObject(targetNode, partialName=True, includeNamespace=False) # create the condition node and do the connections conditionNode = creation.conditionVector(firstTerm=spacePlug, secondTerm=float(targetElement.logicalIndex()), colorIfTrue=(1.0, 0.0, 0.0), colorIfFalse=(0.0, 0.0, 0.0), operation=0, name="_".join([targetShortName, sourceShortName, "space"])) condFn = om2.MFnDependencyNode(conditionNode) plugs.connectPlugs(condFn.findPlug("outColorR", False), targetWeightSource) conditions.append(conditionNode) return constraintMObject, conditions