def blendJoints(self): # for jointA, jointB, joint, count in zip(self.subIKA.jointSystem.pyJoints, # self.subIKB.jointSystem.pyJoints, # self.jointSystem.joints, # range(len(self.jointSystem.joints))): jointRange = range(len(self.jointSystem.jointList[0:self.endJointNumber])) for count in jointRange: jointA = self.subIKA.jointSystem.pyJoints[count] jointB = self.subIKB.jointSystem.pyJoints[count] joint = self.jointSystem.joints[count] pairBlend = core.MetaRig(part=joint.part, side=self.side, endSuffix='PairBlend', nodeType='pairBlend') pairPyNode = pairBlend.pynode connectAttrs = ['Rotate', 'Translate'] if count == jointRange[-1]: connectAttrs.remove('Rotate') for attr in connectAttrs: attrLower = attr.lower() jointA.attr(attrLower) >> pairPyNode.attr('in{}1'.format(attr)) jointB.attr(attrLower) >> pairPyNode.attr('in{}2'.format(attr)) pairPyNode.attr('out{}'.format(attr)) >> joint.pynode.attr(attrLower) self.blendAttr >> pairPyNode.weight
def skinCtrlCurve(self): crvSkinJnts = [] # Iterate through main controls if not self.mainCtrls: self.breakpoint("No Main controls found") for ctrl in self.mainCtrls: # Create Joint and snap and parent to the control curveJoint = joints.Joint(side=ctrl.side, part=ctrl.part, endSuffix="CurveJoint") curveJoint.rotateOrder = self.rotateOrder curveJoint.snap(ctrl.mNode) ctrl.addChild(curveJoint.mNode) ctrl.addSupportNode(curveJoint, "IkSkinJoint") # Connect as support joint crvSkinJnts.append(curveJoint) crvJoints = [jnt.pynode for jnt in crvSkinJnts] skinCluster = libUtilities.skinGeo(self.ikDriveCurve, crvJoints) skinClusterMeta = core.MetaRig(skinCluster.name()) skinClusterMeta.part = self.part self.addSupportNode(skinClusterMeta, "IkSkin") self.transferPropertiesToChild(skinClusterMeta, "IkSkin") skinClusterMeta.resetName() # Help Joint system self.driveJointSystem = joints.JointSystem(side=self.side, part="%sHelpJoints" % self.part) self.driveJointSystem.rigType = "Help" self.driveJointSystem.joints = crvSkinJnts self.driveJointSystem.rebuild_joint_data()
def joints(self, jointList): if not isinstance(jointList[0], basestring): jointList = [joint.mNode for joint in jointList] jointAttr = "SUP_Joints" self.connectChildren(jointList, jointAttr, cleanCurrent=True) if isinstance(jointList[0], core.MetaRig): self.metaCache[jointAttr] = jointList else: self.metaCache[jointAttr] = [ core.MetaRig(joint) for joint in jointList ]
def buildRoll(self, attr, jointTarget): rollName = "{}Roll".format(attr) roll = core.MovableSystem(part=self.part, side=self.side, endSuffix=rollName) roll.addParent(snap=False, endSuffix="{}Prnt".format(rollName)) roll.snap(self.jointSystem.joints[jointTarget].mNode) self.RollSystem.addSupportNode(roll, rollName) inverseMeta = core.MetaRig(part="{}{}".format(self.part, attr), side=self.side, endSuffix="InverseMD", nodeType="multiplyDivide") self.mainIK.pynode.attr(attr) >> inverseMeta.pynode.input1X inverseMeta.pynode.outputX >> roll.pynode.attr("r{}".format(self.bendAxis.lower())) self.RollSystem.addSupportNode(inverseMeta, "{}MD".format(attr)) return roll
def connectTwist(self): # Create plusMinusAverage which control the final twist twistPlusMinus = core.MetaRig(side=self.side, part="%sTwist" % self.part, endSuffix="PMA", nodeType="plusMinusAverage") # Create multiplyDivide which would counter twist for the top control multiplyDivide = core.MetaRig(side=self.side, part="%sCounterTwist" % self.part, endSuffix="MD", nodeType="multiplyDivide") multiplyDivide.input2X = -1 if self.mirrorBehaviour: # This will add one extra MD. So just keep it for now self.mainCtrls[0].addCounterTwist() self.mainCtrls[2].addCounterTwist() # Connect the top control to the twist self.mainCtrls[2].getTwistDriver( self.twistAxis) >> twistPlusMinus.pynode.input1D[0] # Connect to the bottom controller to the counter twist and roll self.mainCtrls[0].getTwistDriver( self.twistAxis) >> multiplyDivide.pynode.input1X multiplyDivide.pynode.outputX >> twistPlusMinus.pynode.input1D[1] # Connect IK Handle twist and roll twistPlusMinus.pynode.output1D >> self.ikHandle.pynode.twist self.mainCtrls[0].getTwistDriver( self.twistAxis) >> self.ikHandle.pynode.roll # Add PMA and MD as supprt node self.ikHandle.rootTwistMode = True self.ikHandle.addSupportNode(twistPlusMinus, "Twist") self.ikHandle.addSupportNode(multiplyDivide, "CounterTwist")
def buildSolver(self): jntSystem = self.ikJointSystem # Build the main single degree curve baseCurve = utils.createCurve(jntSystem.positions, degree=1) baseCurve.rename(utils.nameMe(self.side, self.part, "CtrlCurve")) self.controlCurve = core.MovableSystem(baseCurve.name()) self.controlCurve.part = self.part self.transferPropertiesToChild(self.controlCurve, "CtrlCurve") self.controlCurve.resetName() # Build the bspline ik curve curve_name = utils.nameMe(self.side, self.part, "BaseCurve") # Sometimes bSpline might generate less CVs as the source....Investigate ikCurve, fitNode = pm.fitBspline(baseCurve, ch=1, tol=0.01, n=curve_name) if len(ikCurve.getCVs()) != len(jntSystem.positions): pm.delete(ikCurve) ikCurve = utils.createCurve(jntSystem.positions) ikCurve.rename(curve_name) self.bSpline = False self.ikCurve = core.MovableSystem(ikCurve.name()) self.ikCurve.part = self.part self.transferPropertiesToChild(self.ikCurve, "BaseCurve") if self.bSpline: fitNodeMeta = core.MetaRig(fitNode.name()) fitNodeMeta.part = self.part self.ikCurve.addSupportNode(fitNodeMeta, "BaseDriver") self.ikCurve.transferPropertiesToChild(fitNodeMeta, "FitNode") fitNodeMeta.resetName() # Build the spline IK name = utils.nameMe(self.side, self.part, "IkHandle") startJoint = jntSystem.joints[0].shortName() endJoint = jntSystem.joints[-1].shortName() # noinspection PyArgumentList ikHandle = pm.ikHandle(name=name, sj=startJoint, ee=endJoint, sol="ikSplineSolver", curve=ikCurve, createCurve=False, freezeJoints=False, rootOnCurve=True)[0] ikHandleMeta = core.MovableSystem(ikHandle.name(), nodeType="IkHandle") self.transferPropertiesToChild(ikHandleMeta, "IkHandle") ikHandleMeta.part = "IkHandle" ikHandleMeta.v = False ikHandleMeta.addParent() self.ikHandle = ikHandleMeta
def buildTemplates(templateData): builderDict = {} for info in templateData: info = Info(info) builder = Builder(part=info.part, side=info.side) builder.importData = info builder.rebuild() builderDict[info.part] = builder for builder in builderDict.values(): if builder.importData.parent: if pm.objExists(builder.importData.parent): metaLoc = core.MetaRig(builder.importData.parent) builder.setBuildParent(metaLoc) return builderDict
def buildBlendCtrl(self): # Build Blendcontrol self.blender = self.createCtrlObj('{}Blend'.format(self.part), createXtra=False, addGimbal=False) self.blender.lockDefaultAttributes() # Create reverse node self.inverse = core.MetaRig(side=self.side, part=self.part, endSuffix="Inverse", nodeType="reverse") # Attribute based on the system type libUtilities.addFloatAttr(self.blender.pynode, self.subSystems) # Connect the inverse node self.blendAttr >> self.inverse.pynode.inputX # Add the constraint blend type attr libUtilities.addDivAttr(self.blender.pynode, "Interpolation", "interpType") self.blender.addAttr("type", attrType='enum', enumName="Average:Shortest:Longest:") interpADL = core.MetaRig(side=self.side, part=self.part, endSuffix="InterpADL", nodeType="addDoubleLinear") interpADL.pynode.input2.set(1) self.blender.pynode.attr("type") >> interpADL.pynode.input1 self.blender.addSupportNode(interpADL, "InterpADL")
def _get_joint_twist_average_(jointMeta, axis): pmaHelp = jointMeta.getSupportNode("rotateAverage") # If none are found if not pmaHelp: pmaHelp = core.MetaRig(side=self.side, part=jointMeta.part, endSuffix="RotateAverage", nodeType="plusMinusAverage") jointMeta.addSupportNode(pmaHelp, "rotateAverage") pmaHelp.pynode.attr( "output3D%s" % axis.lower()) >> jointMeta.pynode.attr( "rotate%s" % axis.upper()) currentConnect = pmaHelp.pynode.input3D.numConnectedElements() return pmaHelp.pynode.input3D[currentConnect].attr("input3D%s" % axis.lower())
def buildDevSolver(self): super(SubControlSpine, self).buildSolver() # Blendshape self.controlCurve.select() self.ikCurve.select(add=True) # Give a temporary name as this interferes with the metaConnections currentName = self.controlCurve.shortName() self.ikDriveCurve.rename("SpineDriver") # Blendshape blendShape = pm.blendShape( name=utils.nameMe(self.side, self.part, "BlendShape"))[0] blendShape.setWeight(0, 1) # Rename the control back self.ikDriveCurve.rename(currentName) # Convert a blendnode to meta blendNodeMeta = core.MetaRig(blendShape.name()) self.controlCurve.addSupportNode(blendNodeMeta, "baseDriver") self.controlCurve.transferPropertiesToChild(blendNodeMeta, "BlendShape")
def blendJoints(self): # Replicate the joint based off A self.jointSystem = self.subSystemA.jointSystem.replicate(part=self.part, side=self.side, endSuffix=self.rigType) # Constraints System for i in range(len(self.jointSystem) - 1): # Joint Aliases joint = self.jointSystem.joints[i] jointA = self.subSystemA.jointSystem.joints[i] jointB = self.subSystemB.jointSystem.joints[i] # Hide the SubJoints jointA.v = 0 jointB.v = 0 if i: pairConstraint = pm.PyNode( joint.addConstraint(jointA, "orient", zeroOut=False)) joint.addConstraint(jointB, "orient", zeroOut=False) else: # Constraints the first node pairConstraint = pm.PyNode(joint.addConstraint(jointA, zeroOut=False)) joint.addConstraint(jointB, zeroOut=False) # Reverse node in first self.inverse.pynode.outputX >> pairConstraint.w0 # Connect the interpType self.interpAttr >> pairConstraint.interpType # Direct connection in second self.blendAttr >> pairConstraint.w1 if self.subSystemA.isDeformable: pairBlend = core.MetaRig(part=joint.part, side=self.side, endSuffix='PairBlend', nodeType='pairBlend') pairPyNode = pairBlend.pynode jointA.pynode.attr("scale") >> pairPyNode.attr('inTranslate1') jointB.pynode.attr("scale") >> pairPyNode.attr('inTranslate2') pairPyNode.attr('outTranslate') >> joint.pynode.attr("scale") self.blendAttr >> pairPyNode.weight
def addStretch(self): super(IkSpine, self).addStretch() """ arcMainNode = mc.rename(mc.arclen(IKCrvLenMain, ch=1), self.name + "_" + self.sfx + "_arcLenMain") mc.connectAttr(arcMainNode + ".arcLength", stMD + ".input2X") """ arcLen = pm.arclen(self.mainCurve.pynode, constructionHistory=True) arcLenMeta = core.MetaRig(arcLen) arcLenMeta.part = self.part self.transferPropertiesToChild(arcLenMeta, "ArcLen") arcLenMeta.resetName() self.stretchSystem.setInitialValue(arcLenMeta.pynode.arcLength.get()) self.stretchSystem.connectTrigger(arcLenMeta.pynode.arcLength) # Connect Stretch Joint self.connectStretchJoints() self.mainCtrls[0].addDivAttr("stretch", "strDiv") self.mainCtrls[0].addFloatAttr("Amount", sn="amount") amountAttr = self.mainCtrls[0].pynode.amount self.stretchSystem.connectAmount(amountAttr) amountAttr.set(1)
def connectTwist(self): self.calculateTwistWeights() # JointMeta def _get_joint_twist_average_(jointMeta, axis): pmaHelp = jointMeta.getSupportNode("rotateAverage") # If none are found if not pmaHelp: pmaHelp = core.MetaRig(side=self.side, part=jointMeta.part, endSuffix="RotateAverage", nodeType="plusMinusAverage") jointMeta.addSupportNode(pmaHelp, "rotateAverage") pmaHelp.pynode.attr( "output3D%s" % axis.lower()) >> jointMeta.pynode.attr( "rotate%s" % axis.upper()) currentConnect = pmaHelp.pynode.input3D.numConnectedElements() return pmaHelp.pynode.input3D[currentConnect].attr("input3D%s" % axis.lower()) # Skiplist # skipAxis = [self.rollAxis, self.bendAxis] # for axis in ["x", "y", "z"]: # if axis != self.primaryAxis[0]: # skipAxis.append(axis) # Iterate through the weightMap/Joints for weightMap, joint in zip( self.twistMap, range(len(self.jointSystem) - int(self.evaluateLastJointBool))): # Do not add weight for singleWeight, ctrl in zip(weightMap, self.mainCtrls): if singleWeight == 1: rotateDriver = ctrl.getRotateDriver(self.twistAxis) rotateDriver >> self.jointSystem.joints[joint].pynode.attr( "rotate%s" % self.twistAxis.upper()) elif singleWeight != 0.0: # Get the input PMA for the joint rotateAverage = _get_joint_twist_average_( self.jointSystem.joints[joint], self.twistAxis) # Get Rotate Driver rotateDriver = ctrl.getRotateDriver(self.twistAxis) wm_name = "WeightManager{}".format(self.twistAxis) # Create a Weight MD weightManager = core.MetaRig( side=ctrl.side, part="{0}{1}".format( self.jointSystem.joints[joint].part.capitalize(), ctrl.part.capitalize()), endSuffix=wm_name, nodeType="multiplyDivide") # Add it as support node to joint self.jointSystem.joints[joint].getSupportNode( "rotateAverage").addSupportNode( weightManager, wm_name) # Connect the Rotate Driver rotateDriver >> weightManager.pynode.input1X # Set the weight weightManager.pynode.input2X.set(singleWeight) # Connect to the rotateAverage weightManager.pynode.outputX >> rotateAverage
def buildSubControls(self): if self.devSpine: return subCtrls = [] npc = libUtilities.create_npc_node(self.ikDriveCurve) # Initialise the groups that will stay at the base and metaise them subCtrlGrp = None for newGrp in ["subCtrlGrp", "rideOnLocGrp"]: newGrpMeta = core.MovableSystem(side=self.side, part=self.part, endSuffix=newGrp.capitalize()) newGrpMeta.rotateOrder = self.rotateOrder self.addSupportNode(newGrpMeta, newGrp.capitalize()) newGrpMeta.setParent(self.infoGrp) exec("{} = newGrpMeta".format(newGrp)) # Iterate through all the control curve for i in range(self.ikDriveCurve.numCVs()): ikCV = self.ikCurve.pynode.cv[i] # Set the subpart name SubPart = "{}Sub{}".format(self.part, i) # Get the CV position joint = self.jointSystem.joints[i].pynode npc.inPosition.set(libUtilities.get_world_space_pos(joint)) # Create a new control object subCtrl = self.createCtrlObj(SubPart, shape="Ball", createXtra=False, addGimbal=False) subCtrls.append(subCtrl) # Add a ctrl locator subCtrl.addSpaceLocator(parent=True) subCtrl.locator.v = False subCtrl.addZeroPrnt() # Create the point on curve node poc = core.MetaRig(part=SubPart, side=self.side, endSuffix="POC", nodeType="pointOnCurveInfo") subCtrl.addSupportNode(poc, "PointOnCurve") poc.parameter = npc.parameter.get() self.ikDriveCurve.worldSpace >> poc.pynode.inputCurve poc.pynode.position >> subCtrl.zeroPrnt.pynode.translate # Control to the CV subCtrl.zeroPrnt.snap(self.jointSystem.joints[i], True, False) subCtrl.prnt.snap(self.jointSystem.joints[i], False) # # Apply a cheap point constraint # libUtilities.cheap_point_constraint(rideOnloc.pynode, subCtrl.zeroPrnt.pynode) # Connect the space locator to the IK Curve libUtilities.snap(subCtrl.locator.pynode, ikCV, rotate=False) libUtilities.cheap_point_constraint(subCtrl.locator.pynode, ikCV) # Lock the rotate and scale subCtrl.lockRotate() subCtrl.lockScale() # Add to parent subCtrl.setParent(subCtrlGrp) # Delete the nearest point on curve pm.delete(npc) # Append the control self.subCtrls = subCtrls
def buildHipSpaceSwitch(self, aimJoint): # Create a helper joint pm.select(cl=1) self.aimHelper = core.MovableSystem(part=aimJoint.part, side=self.side, endSuffix="AimHelper") # self.aimHelper.jointOrient = firstJoint.jointOrient self.aimHelper.rotateOrder = aimJoint.rotateOrder # Align with the first joint self.aimHelper.snap(aimJoint.pynode) # Figure out the up vector position. second_joint_position = self.jointSystem.positions[self.hipEndJointNumber] hipIkPoleVector = self.hipIKHandle.poleVector if self.hipIkSolver == "RotatePlane" else None default_pole_vector = libVector.vector(list(hipIkPoleVector or self.ikHandle.poleVector)) # noinspection PyTypeChecker aimPosition = list(((default_pole_vector * [30, 30, 30] * ([self.scaleFactor] * 3)) + second_joint_position)) if hipIkPoleVector: upVector = core.Ctrl(part="{}PV".format(aimJoint.part), side=self.side, endSuffix="HipPV", shape="Locator") upVector.build() self.addRigCtrl(upVector, "HipPV") upVector.constrainedNode.pynode.setTranslation(aimPosition) pvCon = pm.poleVectorConstraint(upVector.mNode, self.hipIKHandle.mNode, weight=1) self.constraintToMetaConstraint(pvCon, "HipPVCon", "poleVectorConstraint") self.secondHipIK.addDivAttr("Show", "showPV") self.secondHipIK.addBoolAttr("PoleVector", "pvVis") self.secondHipIK.pynode.pvVis >> upVector.pynode.getShape().visibility upVector.lockRotate() upVector.lockScale() else: upVector = core.MovableSystem(part=aimJoint.part, side=self.side, endSuffix="UpVector") self.aimHelper.addSupportNode(upVector, "UpVector") upVector.constrainedNode.pynode.setTranslation(aimPosition) # Aim Constraint at mainIk Handle aimConArgs = [self.mainIK.pynode, self.aimHelper.pynode] aimConKwgs = {"mo": False, "wut": "object", "wuo": upVector.mNode} pm.delete(pm.aimConstraint(*aimConArgs, **aimConKwgs)) self.aimHelper.addParent(endSuffix="AimHelperPrnt") aimCon = pm.aimConstraint(*aimConArgs, **aimConKwgs) self.constraintToMetaConstraint(aimCon, "HipAimCon", "HipAim") # Setup the space switching constraintType = 'orient' if self.hipIkSolver != "Single": constraintType = "parent" self.aimHelper.prnt.v = False # Orient Constraint the Hip Constraint ikJoint = joints.Joint(part=self.part, side=self.side, endSuffix="HipIkFollow") ikJoint.v = False ikJoint.rotateOrder = self.rotateOrder ikJoint.setParent(aimJoint) ikJoint.snap(aimJoint) libUtilities.freeze_rotation(ikJoint.pynode) ikJoint.setParent(self.aimHelper) self.hipIK.addConstraint(ikJoint.pynode, constraintType, mo=True, weightAlias="IK") # Create a base joint hipIKCon = getattr(self.hipIK, "{}Constraint".format(constraintType)) hipIKCon.pynode.w0.set(0) homeJoint = joints.Joint(part=self.part, side=self.side, endSuffix="HomeJnt") homeJoint.v = False homeJoint.rotateOrder = self.rotateOrder homeJoint.setParent(aimJoint) homeJoint.snap(aimJoint) libUtilities.freeze_rotation(homeJoint.pynode) homeJoint.setParent(self) # Add another contraint self.hipIK.addConstraint(homeJoint, constraintType, mo=True, weightAlias=self.part) # Blend between the two constraint self.inverse = core.MetaRig(side=self.side, part=self.part, endSuffix="Inverse", nodeType="reverse") # Attribute based on the system type libUtilities.addDivAttr(self.hipIK.pynode, "SpaceSwitch") attrName = "IK_Parent" libUtilities.addFloatAttr(self.hipIK.pynode, attrName) blendAttr = self.hipIK.pynode.attr(attrName) # Connect the inverse node blendAttr >> self.inverse.pynode.inputX self.inverse.pynode.outputX >> hipIKCon.pynode.w0 blendAttr >> hipIKCon.pynode.w1 # Point constrain the first joint aimJoint.addConstraint(self.hipIK, 'point') return upVector