def bdBuildSplineSolverScale(self,condition): print 'asdas' self.splineCurve = pm.listConnections(self.ikSpline, type = 'nurbsCurve')[0] effector = pm.listConnections(self.ikSpline ,source=True, type='ikEffector')[0] endJoint = pm.listConnections(effector,source=True, type='joint')[0] startJointChild = pm.listRelatives(self.startJoint,c=True, type='joint')[0] self.jointChain = [] self.jointChain.append(self.startJoint) self.jointChain.append(startJointChild) while startJointChild.name() != endJoint.name(): startJointChild = pm.listRelatives(startJointChild,c=True, type='joint')[0] self.jointChain.append(startJointChild) self.splineCurveScl = pm.duplicate(self.splineCurve,name = self.splineCurve.name().replace('crv','crv_scl')) strArclenSCL = pm.arclen(self.splineCurveScl,ch=True) strArclenCRV = pm.arclen(self.splineCurve,ch=True) arclenSCL = pm.ls( strArclenSCL ) [0] arclenCRV = pm.ls( strArclenCRV ) [0] arclenSCL.rename(self.splineCurveScl[0].name() + '_length') arclenCRV.rename(self.splineCurve.name() + '_length') mdScaleFactor = pm.createNode('multiplyDivide', name = self.splineCurve.name().replace('crv','crv_scaleFactor_md')) arclenCRV.arcLength.connect(mdScaleFactor.input1X) arclenSCL.arcLength.connect(mdScaleFactor.input2X) mdScaleFactor.operation.set(2) for jnt in self.jointChain: mdScaleFactor.outputX.connect(jnt.scaleX)
def gear_curveslide2_op(outcrv, incrv, position=0, maxstretch=1, maxsquash=1, softness=0): """Apply a sn_curveslide2_op operator Arguments: outcrv (NurbsCurve): Out Curve. incrv (NurbsCurve): In Curve. position (float): Default position value (from 0 to 1). maxstretch (float): Default maxstretch value (from 1 to infinite). maxsquash (float): Default maxsquash value (from 0 to 1). softness (float): Default softness value (from 0 to 1). Returns: pyNode: The newly created operator. """ pm.select(outcrv) node = pm.deformer(type="mgear_slideCurve2")[0] pm.connectAttr(incrv + ".local", node + ".master_crv") pm.connectAttr(incrv + ".worldMatrix", node + ".master_mat") pm.setAttr(node + ".master_length", pm.arclen(incrv)) pm.setAttr(node + ".slave_length", pm.arclen(incrv)) pm.setAttr(node + ".position", 0) pm.setAttr(node + ".maxstretch", 1) pm.setAttr(node + ".maxsquash", 1) pm.setAttr(node + ".softness", 0) return node
def bdBuildSplineSolverScale(): selection = pm.ls(sl=1, type='transform') startJoint = '' if selection: startJoint = selection[0] else: return print startJoint ikSpline = pm.listConnections(startJoint, type='ikHandle')[0] print ikSpline solver = ikSpline.ikSolver.inputs()[0] if 'ikSplineSolver' in solver.name(): sclChain = pm.duplicate(startJoint, name=startJoint.name() + '_SCL')[0] sclChainAll = sclChain.listRelatives(f=True, ad=True, type='joint') print sclChainAll for sclJnt in sclChainAll: pm.rename(sclJnt, sclJnt + '_SCL') splineCurve = pm.listConnections(ikSpline, type='nurbsCurve')[0] effector = pm.listConnections(ikSpline, source=True, type='ikEffector')[0] endJoint = pm.listConnections(effector, source=True, type='joint')[0] jointChain = startJoint.listRelatives(f=True, ad=True, type='joint') jointChain = jointChain + [startJoint] jointChain.reverse() print jointChain splineCurveScl = pm.duplicate(splineCurve, name=splineCurve.name().replace( 'crv', 'crv_scl')) strArclenSCL = pm.arclen(splineCurveScl, ch=True) strArclenCRV = pm.arclen(splineCurve, ch=True) arclenSCL = pm.ls(strArclenSCL)[0] arclenCRV = pm.ls(strArclenCRV)[0] arclenSCL.rename(splineCurveScl[0].name() + '_length') arclenCRV.rename(splineCurve.name() + '_length') mdScaleFactor = pm.createNode('multiplyDivide', name=splineCurve.name().replace( 'crv', 'crv_scaleFactor_md')) arclenCRV.arcLength.connect(mdScaleFactor.input1X) arclenSCL.arcLength.connect(mdScaleFactor.input2X) mdScaleFactor.operation.set(2) for jnt in jointChain[1:]: mdJntTr = pm.createNode('multiplyDivide', name=jnt + '_trX_MD') #mdJntTr.operation.set(2) sclJnt = pm.ls(jnt + '_SCL')[0] mdScaleFactor.outputX.connect(mdJntTr.input2X) sclJnt.translateX.connect(mdJntTr.input1X) mdJntTr.outputX.connect(jnt.translateX)
def bdBuildSplineSolverScale(): selection = pm.ls(sl=1,type='transform') startJoint = '' if selection: startJoint = selection[0] else: return print startJoint ikSpline = pm.listConnections(startJoint,type='ikHandle')[0] print ikSpline solver = ikSpline.ikSolver.inputs()[0] if 'ikSplineSolver' in solver.name(): sclChain = pm.duplicate(startJoint,name = startJoint.name() + '_SCL')[0] sclChainAll = sclChain.listRelatives(f=True, ad=True,type='joint') print sclChainAll for sclJnt in sclChainAll: pm.rename(sclJnt,sclJnt+'_SCL') splineCurve = pm.listConnections(ikSpline, type = 'nurbsCurve')[0] effector = pm.listConnections(ikSpline ,source=True, type='ikEffector')[0] endJoint = pm.listConnections(effector,source=True, type='joint')[0] jointChain = startJoint.listRelatives(f=True, ad=True,type='joint') jointChain = jointChain + [startJoint] jointChain.reverse() print jointChain splineCurveScl = pm.duplicate(splineCurve,name = splineCurve.name().replace('crv','crv_scl')) strArclenSCL = pm.arclen(splineCurveScl,ch=True) strArclenCRV = pm.arclen(splineCurve,ch=True) arclenSCL = pm.ls( strArclenSCL ) [0] arclenCRV = pm.ls( strArclenCRV ) [0] arclenSCL.rename(splineCurveScl[0].name() + '_length') arclenCRV.rename(splineCurve.name() + '_length') mdScaleFactor = pm.createNode('multiplyDivide', name = splineCurve.name().replace('crv','crv_scaleFactor_md')) arclenCRV.arcLength.connect(mdScaleFactor.input1X) arclenSCL.arcLength.connect(mdScaleFactor.input2X) mdScaleFactor.operation.set(2) for jnt in jointChain[1:]: mdJntTr = pm.createNode('multiplyDivide', name = jnt + '_trX_MD') #mdJntTr.operation.set(2) sclJnt = pm.ls(jnt + '_SCL')[0] mdScaleFactor.outputX.connect(mdJntTr.input2X) sclJnt.translateX.connect(mdJntTr.input1X) mdJntTr.outputX.connect(jnt.translateX)
def _build(self, *args): """ Builds the joints on the curve. """ # naming convention asset = self.asset side = self.side part = self.part joints = self.joints suffix = self.suffix if self.gui: asset = self.asset_name.text() side = self.side.currentText() part = self.part_name.text() joints = self.joints_box.value() suffix = self.suffix.currentText() try: curve = pm.ls(sl=True)[0] curve_name = NameUtils.get_unique_name(asset, side, part, "crv") self.curve = pm.rename(curve, curve_name) except IndexError: pm.warning("Please select a curve") return length_of_curve = pm.arclen(self.curve) equal_spacing = length_of_curve / float(joints) # clear the selection pm.select(cl=True) # # create the joints curve_joints = list() for x in xrange(int(joints) + 1): name = NameUtils.get_unique_name(asset, side, part, suffix) joint = pm.joint(n=name) curve_joints.append(joint) joint_position = (x * equal_spacing) pm.move(0, joint_position, 0) # rename last joint last_joint = curve_joints[-1] pm.rename(last_joint, last_joint + "End") root_joint = pm.selected()[0].root() end_joint = pm.ls(sl=True)[0] solver = 'ikSplineSolver' # attach joints to curve ik_name = NameUtils.get_unique_name(asset, side, part, "ikHandle") self.ikHandle = pm.ikHandle(sj=root_joint, ee=end_joint, sol=solver, c=self.curve, pcv=True, roc=True, ccv=False, n=ik_name) joint_chain = pm.ls(root_joint, dag=True) # delete history pm.makeIdentity(root_joint, apply=True) # cleanup self._cleanup()
def make_spline_streatch(ikHandle): ''' ''' joints = pm.ikHandle(ikHandle, q=True, jl=True) curve = pm.PyNode(pm.ikHandle(ikHandle, q=True, c=True)).getParent() if not curve.hasAttr('global_scale'): pm.addAttr(curve, ln='global_scale', dv=1, k=True) arcn = pm.arclen(curve, ch=True) mult = pm.createNode('multDoubleLinear') devi = pm.createNode('multiplyDivide') arcn.al >> devi.i1x curve.global_scale >> mult.i1 arcn.al >> mult.i2 arcn.al // mult.i2 mult.o >> devi.i2x devi.op.set(2) for jnt in joints: devi.ox >> pm.PyNode('{0}.s{1}'.format(jnt, get_joint_axis(jnt))) return True
def stretchyBack(ikHandleTorso, jntList): pymelLogger.debug('Starting: stretchyBack()...') #Stretchy process # ArcLen to create curveInfo curveInfoNodeBack = pm.arclen(ikHandleTorso[2], ch=True) # add attr to curveinfo Node (normalizedScale) # this will have a value coming from a multiply divide node that will be # dividing the current length by the initial length of the curve # this will be used later to scale the joints pm.addAttr(curveInfoNodeBack, longName='normalizedScale', attributeType='double') # get initial length of the curve iniLen = pm.getAttr(curveInfoNodeBack + '.arcLength') # create a node multiplydivide, operation set to division MDCurveBack = pm.shadingNode('multiplyDivide', asUtility=True) pm.setAttr(MDCurveBack + '.operation', 2) # divide # Connect curve arcLength to input1X pm.connectAttr(curveInfoNodeBack + '.arcLength', MDCurveBack + '.input1X', force=True) # Set input2X to initial length of the curve pm.setAttr(MDCurveBack + '.input2X', iniLen) # connect outpux x from multiplydivide to normalized scale of the curve info pm.connectAttr(MDCurveBack + '.outputX', curveInfoNodeBack + '.normalizedScale', force=True) returnList = [curveInfoNodeBack, MDCurveBack] pymelLogger.debug('End: stretchyBack()...') return returnList
def addScale(self): self.splineCurveScl = pm.duplicate(self.crv, name=self.crv.replace('crv', 'crv_ori'))[0] strArclenSCL = pm.arclen(self.splineCurveScl, ch=True) strArclenCRV = pm.arclen(self.crv, ch=True) arclenSCL = pm.ls(strArclenSCL)[0] arclenCRV = pm.ls(strArclenCRV)[0] arclenSCL.rename(self.splineCurveScl[0].name() + '_length') arclenCRV.rename(self.crv + '_length') mdScaleFactor = pm.createNode('multiplyDivide', name=self.crv + '_scaleFactor_md') arclenCRV.arcLength.connect(mdScaleFactor.input1X) arclenSCL.arcLength.connect(mdScaleFactor.input2X) mdScaleFactor.operation.set(2) for jnt in self.ikJntList: mdScaleFactor.outputX.connect(jnt.scaleX)
def addScale(self): self.splineCurveScl = pm.duplicate(self.crv,name = self.crv.replace('crv','crv_ori'))[0] strArclenSCL = pm.arclen(self.splineCurveScl,ch=True) strArclenCRV = pm.arclen(self.crv,ch=True) arclenSCL = pm.ls( strArclenSCL ) [0] arclenCRV = pm.ls( strArclenCRV ) [0] arclenSCL.rename(self.splineCurveScl[0].name() + '_length') arclenCRV.rename(self.crv + '_length') mdScaleFactor = pm.createNode('multiplyDivide', name = self.crv + '_scaleFactor_md') arclenCRV.arcLength.connect(mdScaleFactor.input1X) arclenSCL.arcLength.connect(mdScaleFactor.input2X) mdScaleFactor.operation.set(2) for jnt in self.ikJntList: mdScaleFactor.outputX.connect(jnt.scaleX)
def stretchyBack( ikHandleTorso, jntList ): pymelLogger.debug('Starting: stretchyBack()...') #Stretchy process # ArcLen to create curveInfo curveInfoNodeBack = pm.arclen( ikHandleTorso[2], ch=True ) # add attr to curveinfo Node (normalizedScale) # this will have a value coming from a multiply divide node that will be # dividing the current length by the initial length of the curve # this will be used later to scale the joints pm.addAttr(curveInfoNodeBack, longName='normalizedScale', attributeType='double') # get initial length of the curve iniLen = pm.getAttr( curveInfoNodeBack + '.arcLength' ) # create a node multiplydivide, operation set to division MDCurveBack = pm.shadingNode( 'multiplyDivide', asUtility=True ) pm.setAttr( MDCurveBack+'.operation', 2 ) # divide # Connect curve arcLength to input1X pm.connectAttr( curveInfoNodeBack + '.arcLength', MDCurveBack + '.input1X', force=True ) # Set input2X to initial length of the curve pm.setAttr(MDCurveBack+'.input2X', iniLen) # connect outpux x from multiplydivide to normalized scale of the curve info pm.connectAttr(MDCurveBack + '.outputX', curveInfoNodeBack + '.normalizedScale', force=True) returnList = [curveInfoNodeBack,MDCurveBack] pymelLogger.debug('End: stretchyBack()...') return returnList
def bdBuildRPSolverScale(self,condition): print 'RP Solver' #self.splineCurve = pm.listConnections(self.ikSpline, type = 'nurbsCurve')[0] pm.select(cl=True) ikGrp = pm.group(n=self.ikSpline.name() + '_GRP') ikParent = self.ikSpline.getParent() ikPos = self.ikSpline.getTranslation(space= 'world') ikGrp.setTranslation(ikPos) pm.parent(ikGrp,ikParent) pm.parent(self.ikSpline,ikGrp) sclJnt = pm.duplicate(self.startJoint, parentOnly = True , name = self.startJoint.name().replace('JNT','SCL'))[0] effector = pm.listConnections(self.ikSpline ,source=True, type='ikEffector')[0] endJoint = pm.listConnections(effector,source=True, type='joint')[0] startJointChild = pm.listRelatives(self.startJoint,c=True, type='joint')[0] self.jointChain = [] self.jointChain.append(self.startJoint) self.jointChain.append(startJointChild) while startJointChild.name() != endJoint.name(): startJointChild = pm.listRelatives(startJointChild,c=True, type='joint')[0] self.jointChain.append(startJointChild) jntPos = [] for jnt in self.jointChain: pos = jnt.getTranslation(space= 'world') jntPos.append(pos) self.splineCurveScl = pm.curve(p=jntPos, degree =1, n = self.startJoint.name().replace('01_JNT','CRV_SCL')) self.splineCurveScl.setPivots(jntPos[0]) pm.parent(self.splineCurveScl, sclJnt) strArclenSCL = pm.arclen(self.splineCurveScl,ch=True) arclenSCL = pm.ls( strArclenSCL ) [0] arclenSCL.rename(self.splineCurveScl.name() + '_length') distanceNode = pm.createNode('distanceBetween',name = self.startJoint.name().replace('_01_JNT','distance')) sclJnt.rotatePivotTranslate.connect(distanceNode.point1) ikGrp.rotatePivotTranslate.connect(distanceNode.point2) sclJnt.worldMatrix.connect(distanceNode.inMatrix1) ikGrp.worldMatrix.connect(distanceNode.inMatrix2) mdScaleFactor = pm.createNode('multiplyDivide', name = self.splineCurveScl.name().replace('CRV_SCL','CRV_scaleFactor_MD')) distanceNode.distance.connect(mdScaleFactor.input1X) arclenSCL.arcLength.connect(mdScaleFactor.input2X) mdScaleFactor.operation.set(2) cndScaleFactor = pm.createNode('condition', name = self.splineCurveScl.name().replace('CRV_SCL','CRV_scaleFactor_CND')) distanceNode.distance.connect(cndScaleFactor.firstTerm) arclenSCL.arcLength.connect(cndScaleFactor.secondTerm) mdScaleFactor.outputX.connect(cndScaleFactor.colorIfTrueR) cndScaleFactor.operation.set(2) for jnt in self.jointChain: cndScaleFactor.outColorR.connect(jnt.scaleX)
def add_squash_n_stretch(self, follicles): """ Args: None Returns (None) Usage: """ base_name = '%s_flexiPlane' % self.flexiPlaneNameField.getText() wire_name = '%s_wire_CRV' % base_name main_crv_name = '%s_main_CTRL' % base_name wire = pm.PyNode(wire_name) arc_len = pm.arclen(wire, ch = True) pm.rename( arc_len, wire_name + 'info' ) arc_len_val = pm.getAttr( wire_name + 'info.arcLength') multDiv_length = pm.shadingNode( 'multiplyDivide', asUtility = True ) pm.rename( multDiv_length, base_name + '_div_squashStretch_length' ) pm.setAttr( base_name + '_div_squashStretch_length.operation', 2 ) pm.connectAttr( wire_name + 'info.arcLength', base_name + '_div_squashStretch_length.input1X' ) pm.setAttr( base_name + '_div_squashStretch_length.input2X', arc_len_val ) multDiv_volume = pm.shadingNode( 'multiplyDivide', asUtility = True ) pm.rename( multDiv_volume, base_name + '_div_volume' ) pm.setAttr( base_name + '_div_volume.operation', 2 ) pm.setAttr( base_name + '_div_volume.input1X', 1 ) pm.connectAttr( base_name + '_div_squashStretch_length.outputX', base_name + '_div_volume.input2X', f = True ) conditional_volume = pm.shadingNode( 'condition', asUtility = True ) pm.rename( conditional_volume, base_name + '_cond_volume' ) pm.setAttr( base_name + '_cond_volume.secondTerm', 1 ) pm.connectAttr( main_crv_name + '.squashN_stretch', base_name + '_cond_volume.firstTerm' ) multDiv_globelScale = pm.shadingNode( 'multiplyDivide', asUtility = True ) pm.rename( multDiv_globelScale, base_name + '_mult_globalScale' ) pm.connectAttr( base_name + '_div_volume.outputX', base_name + '_mult_globalScale.input1X' ) pm.connectAttr( main_crv_name + '.scaleX', base_name + '_mult_globalScale.input2X' ) pm.connectAttr( base_name + '_mult_globalScale.outputX', base_name + '_cond_volume.colorIfTrueR' ) for index,follicle in enumerate(follicles): jnt_name = self.format_string.format(PREFIX = self.flexiPlaneNameField.getText(), INDEX = 'flexiPlane_jnt%03d' % (index+1), SUFFIX = 'JNT') jnt_offset_name = jnt_name.replace('_JNT','Offset_GRP') tweek_crv_name = self.format_string.format(PREFIX = self.flexiPlaneNameField.getText(), INDEX = 'flexiPlane_tweak%03d' % (index+1), SUFFIX = 'CTRL') pm.scaleConstraint( tweek_crv_name + 'Con_GRP', jnt_offset_name ) pm.connectAttr( base_name + '_cond_volume.outColorR', jnt_name + '.scaleX') pm.connectAttr( base_name + '_cond_volume.outColorR', jnt_name + '.scaleZ') pm.select( clear = True )
def duplicateAlongPath(self, *args): ''' ------------------------------------------ position along curve ------------------------------------------ ''' inputX = pm.intField(self.widgets['numberOfDuplicates'], q=True, v=True) GOD_object = pm.ls(sl=True)[0] curve = pm.textFieldButtonGrp(self.widgets['curvePath'], q=True, tx=True) pathLength = pm.arclen(curve, ch=False) randomON = pm.checkBox(self.widgets['RandomPathDistance'], q=True, v=True) n = 0 pathIncrement = 1.0 / inputX for increment in range(inputX): object = pm.duplicate(GOD_object, rc=True) objGroup = pm.group(object) motionPath = pm.pathAnimation(objGroup, fm=True, f=True, fa='x', ua='y', wut='scene', c=curve) pm.delete(pm.listConnections(motionPath + '.uValue')) value = rand.uniform(n, (n + pathIncrement)) if randomON == True: pm.setAttr(motionPath + '.uValue', value) randomRotate = rand.randint(0, 360) randomScale = rand.uniform( (pm.floatField(self.widgets['randomizeScaleMINPath'], q=True, v=True)), (pm.floatField(self.widgets['randomizeScaleMAXPath'], q=True, v=True))) print object pm.setAttr(object[0] + '.ry', randomRotate) pm.setAttr(object[0] + '.sx', randomScale) pm.setAttr(object[0] + '.sy', randomScale) pm.setAttr(object[0] + '.sz', randomScale) else: pm.setAttr(motionPath + '.uValue', n) n = n + pathIncrement pm.parent(objGroup, 'ROOT_enviroment_01')
def IK_createAveObj(cur, number, s="group"): newCur = pm.duplicate(cur, rr=1, n=cur + "_copyCurve1") curInfo = pm.arclen(cur, ch=1) ns = int(curInfo.arcLength.get()) pm.delete(curInfo) pm.rebuildCurve(newCur, ch=1, rpo=1, rt=0, end=1, kr=0, kcp=0, kep=1, kt=0, s=ns * 100, d=3, tol=0.01) allNewInfo = [] aimObj = [] p = 1.0 / float((number - 1)) prF = 0.0 if s == "position": allPoistion = [] for i in range(number): if i == number - 1: NewInfo = pm.pointOnCurve(newCur, ch=1, top=1, pr=1) else: NewInfo = pm.pointOnCurve(newCur, ch=1, top=1, pr=prF) prF += p allNewInfo.append(NewInfo) t = pm.getAttr(NewInfo + ".position") if s == "position": allPoistion.append(t) if s == "group": obj = pm.group(em=1, n=cur + "_AimGrp" + str(i + 1)) aimObj.append(obj) pm.setAttr(obj + ".translate", t) cmds.select(cl=1) pm.delete(allNewInfo, newCur) if s == "position": return allPoistion if s == "group": return aimObj
def bdBuildSplineSolverScale(self, condition): print 'asdas' self.splineCurve = pm.listConnections(self.ikSpline, type='nurbsCurve')[0] effector = pm.listConnections(self.ikSpline, source=True, type='ikEffector')[0] endJoint = pm.listConnections(effector, source=True, type='joint')[0] startJointChild = pm.listRelatives(self.startJoint, c=True, type='joint')[0] self.jointChain = [] self.jointChain.append(self.startJoint) self.jointChain.append(startJointChild) while startJointChild.name() != endJoint.name(): startJointChild = pm.listRelatives(startJointChild, c=True, type='joint')[0] self.jointChain.append(startJointChild) self.splineCurveScl = pm.duplicate( self.splineCurve, name=self.splineCurve.name().replace('crv', 'crv_scl')) strArclenSCL = pm.arclen(self.splineCurveScl, ch=True) strArclenCRV = pm.arclen(self.splineCurve, ch=True) arclenSCL = pm.ls(strArclenSCL)[0] arclenCRV = pm.ls(strArclenCRV)[0] arclenSCL.rename(self.splineCurveScl[0].name() + '_length') arclenCRV.rename(self.splineCurve.name() + '_length') mdScaleFactor = pm.createNode('multiplyDivide', name=self.splineCurve.name().replace( 'crv', 'crv_scaleFactor_md')) arclenCRV.arcLength.connect(mdScaleFactor.input1X) arclenSCL.arcLength.connect(mdScaleFactor.input2X) mdScaleFactor.operation.set(2) for jnt in self.jointChain: mdScaleFactor.outputX.connect(jnt.scaleX)
def create_ik_spline(self, *args): """ Creates an ik spline with ik ctrls from the start and end locators, with the given selection the names will be neck,head and else. This uses the crv type, crv color, locator scale for the ctrl crvs. This uses joints from the create_jnt_chain, and makes a spline ik handle with advanced twist attributes for every rotation. :param args: :return: None """ # create ik handle spline solver pm.ikHandle(n='{}_iks'.format(self.name), sj=self.jnt_chain[0], ee=self.jnt_chain[int(self.number)], sol='ikSplineSolver', ns=1, ccv=True) # get the name for crv ik_crv = '{}_ik_crv'.format(self.name) # rename the ik spline handle crv pm.rename(pm.listConnections('{}_iks'.format(self.name), t='shape'), ik_crv) # select the ik crv pm.select(ik_crv, r=True) # create a curve info crv_info = pm.arclen(ik_crv, ch=True) # rename the curve info pm.rename(crv_info, '{}_ik_crv_info'.format(self.name)) # enable advanced twist controls in ik handle pm.setAttr('{}_iks.dTwistControlEnable'.format(self.name), 1) # more advanced twist option changes pm.setAttr('{}_iks.dWorldUpType'.format(self.name), 4) # creating the ik ctrls by using the ik_ctrl_wloc module start_loc_name, start_ctrl_name, self.top_start_grp = ik_ctrl_wloc( self.name, self.ik_ctrl_s_scale, self.jnt_chain[0], self.crv_type, self.color_index) end_loc_name, end_ctrl_name, self.top_end_grp = ik_ctrl_wloc( self.name_end, self.ik_ctrl_e_scale, self.jnt_chain[int(self.number)], self.crv_type, self.color_index) pm.connectAttr('{}.worldMatrix[0]'.format(start_loc_name), '{}_iks.dWorldUpMatrix'.format(self.name)) pm.connectAttr('{}.worldMatrix[0]'.format(end_loc_name), '{}_iks.dWorldUpMatrixEnd'.format(self.name)) # get the span number form the ik crv spans and degrees crv_cv = pm.getAttr(ik_crv + '.spans') + pm.getAttr(ik_crv + '.degree') # get the position and create a locator to that position for x in range(crv_cv): source_node = pm.pointPosition(ik_crv + '.cv[{:d}]'.format(x)) target_loc = '{}_ik_{:d}_loc'.format(self.name, x) loc_grp = create_loc(source_node, target_loc) pm.connectAttr(('{}Shape.worldPosition[0]'.format(target_loc)), ('{}Shape.controlPoints[{}]'.format(ik_crv, x))) if x < 2: loc_grp.setParent(start_ctrl_name) else: loc_grp.setParent(end_ctrl_name)
def makeStretchySpline(controller, ik, stretchDefault=1): start, chain, jointAxis, switcher = _makeStretchyPrep( controller, ik, stretchDefault) crv = ik.inCurve.listConnections()[0] length = arclen(crv, ch=1).arcLength lengthMax = arclen(crv, ch=1).arcLength.get() # Spline squashes and stretches multiplier = core.math.divide(length, lengthMax) jointLenMultiplier = switcher.output multiplier >> switcher.input[1] for i, j in enumerate(chain[1:], 1): #util.recordFloat(j, 'restLength', j.attr('t' + jointAxis).get() ) saveRestLength(j, jointAxis) core.math.multiply(jointLenMultiplier, j.restLength) >> j.attr('t' + jointAxis) return controller.attr('stretch'), jointLenMultiplier
def curveInfo(): sel = pm.ls(sl = True)[0] curve = pm.arclen(sel, ch = True) print pm.rename(curve, (sel.name() + "_info")) print curve pm.addAttr( sel, longName = "part", attributeType = 'double' ) pm.setAttr( (sel + ".part") , keyable = True ) str =(sel + ".part = " + curve + ".arcLength/8 ;") print str pm.expression(s = str, o = sel, ae = True, uc = "all" , n = (sel + "_part"))
def bdBuildMotionPathRbn(self): self.mpCrv = pm.ls(sl=1)[0] if self.mpType == 'closed': startU = self.bdFindStart() self.mpLength = pm.arclen(self.mpCrv) print self.mpLength # oriCrv = self.bdGetOriCrv(self.mpCrv) # bdGetUPos(oriCrv) allCtrlGrp = pm.group(name=self.mpCrv.name().replace('crv', 'loc_grp'), empty=1) allCtrlGrp.setScalePivot(self.mpCrv.boundingBox().center()) allCtrlGrp.setRotatePivot(self.mpCrv.boundingBox().center()) for i in range(0, self.numLocs, 1): ctrl = pm.circle( n=self.mpCrv.name().replace('crv', 'ctrl_' + str(i)))[0] ctrl.ry.set(90) ctrl.setScale([0.2, 0.2, 0.2]) ctrl.overrideEnabled.set(1) ctrl.overrideColor.set(18) pm.makeIdentity(ctrl, a=1) ctrlGrp = pm.group(name=ctrl.name() + '_grp') if self.mpType == 'closed': self.bdFindStart() if self.mpType == 'closed': uPos = startU + i / (self.numLocs * 1.0) else: uPos = startU + i / (self.numLocs - 1.0) if uPos > 1: uPos = uPos - 1 print uPos mp = pm.pathAnimation(ctrlGrp, c=self.mpCrv.name(), su=uPos, follow=1, followAxis='x', upAxis='y', worldUpType="vector") uAnimCrv = pm.listConnections('%s.uValue' % mp) pm.delete(uAnimCrv) pm.select(cl=1) jnt = pm.joint(n=ctrl.name().replace('ctrl', 'JNT')) pm.select(cl=1) pm.parent(jnt, ctrl) for axis in ['X', 'Y', 'Z']: jnt.attr('translate' + axis).set(0) pm.parent(ctrlGrp, allCtrlGrp)
def bdGetUPos(self,crv): crv = pm.ls(crv)[0] length = pm.arclen(crv) print length cvs = crv.getCVs() numCvs = crv.numCVs() uPos = [] l=0 for i in range(numCvs-1): p1 = crv.getCV(i) p2 = crv.getCV(i+1) p3 = p2.distanceTo(p1) l = l + p3 print l print uPos return uPos
def bdGetUPos(self, crv): crv = pm.ls(crv)[0] length = pm.arclen(crv) print length cvs = crv.getCVs() numCvs = crv.numCVs() uPos = [] l = 0 for i in range(numCvs - 1): p1 = crv.getCV(i) p2 = crv.getCV(i + 1) p3 = p2.distanceTo(p1) l = l + p3 print l print uPos return uPos
def bdBuildMotionPathRbn(self): self.mpCrv = pm.ls(sl=1)[0] if self.mpType == 'closed': startU = self.bdFindStart() self.mpLength = pm.arclen(self.mpCrv) print self.mpLength #oriCrv = self.bdGetOriCrv(self.mpCrv) #bdGetUPos(oriCrv) allCtrlGrp = pm.group(name = self.mpCrv.name().replace('crv','loc_grp'),empty=1) allCtrlGrp.setScalePivot(self.mpCrv.boundingBox().center()) allCtrlGrp.setRotatePivot(self.mpCrv.boundingBox().center()) for i in range(0,self.numLocs,1): ctrl = pm.circle(n=self.mpCrv.name().replace('crv','ctrl_' + str(i)))[0] ctrl.ry.set(90) ctrl.setScale([0.2,0.2,0.2]) ctrl.overrideEnabled.set(1) ctrl.overrideColor.set(18) pm.makeIdentity(ctrl,a=1) ctrlGrp = pm.group(name = ctrl.name() + '_grp') if self.mpType == 'closed': self.bdFindStart() if self.mpType == 'closed': uPos = startU + i/(self.numLocs*1.0) else: uPos = startU + i/(self.numLocs-1.0) if uPos > 1: uPos = uPos - 1 print uPos mp = pm.pathAnimation(ctrlGrp,c = self.mpCrv.name(),su = uPos,follow = 1,followAxis = 'x', upAxis='y',worldUpType="vector") uAnimCrv = pm.listConnections('%s.uValue'%mp) pm.delete(uAnimCrv) pm.select(cl=1) jnt = pm.joint(n=ctrl.name().replace('ctrl','JNT')) pm.select(cl=1) pm.parent(jnt,ctrl) for axis in ['X','Y','Z']: jnt.attr('translate'+axis).set(0) pm.parent(ctrlGrp,allCtrlGrp)
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 rig_ikChainSpline(name, rootJnt, ctrlSize=1.0, **kwds): numIkControls = defaultReturn(5, 'numIkControls', param=kwds) numFkControls = defaultReturn(5, 'numFkControls', param=kwds) dWorldUpAxis = defaultReturn(6, 'dWorldUpAxis', param=kwds) parentRoot = defaultReturn('spineJA_JNT', 'parent', param=kwds) lockBase = defaultReturn(1, 'lockBase', param=kwds) module = rig_module(name) ctrlSizeHalf = [ctrlSize / 2.0, ctrlSize / 2.0, ctrlSize / 2.0] ctrlSizeQuarter = [ctrlSize / 4.0, ctrlSize / 4.0, ctrlSize / 4.0] ctrlSize = [ctrlSize, ctrlSize, ctrlSize] chainList = rig_chain(rootJnt).chain numJoints = len(chainList) ''' ctrlPos = [] for i in range(0, numJoints): if i % numFkControls == 0: ctrlPos.append(chainList[i]) ''' endJnt = defaultReturn(rootJnt.replace('JA_JNT', 'JEnd_JNT'), 'endJnt', param=kwds) ctrlPos = mm.eval('rig_chainBetweenTwoPoints("' + name + 'Pos", "' + rootJnt + '", "' + endJnt + '",' + str(numIkControls) + ');') #for jnt in ctrlPos: pm.parent(ctrlPos, w=True) for jnt in ctrlPos: pm.delete(pm.orientConstraint(rootJnt, jnt)) # make ik driver controls/joints fkControls = [] ikControls = [] driverJntList = [] fkScale = 1.5 for i in range(0, len(ctrlPos)): driverJnt = rig_transform(0, name=name + 'DriverJ' + ABC[i], type='joint', target=ctrlPos[i], parent=module.parts, rotateOrder=2).object driverJntList.append(driverJnt) driverCtrl = rig_control(name=name + 'Driver' + ABC[i], shape='box', modify=1, scale=ctrlSizeHalf, colour='green', parentOffset=module.controlsSec, rotateOrder=2) ikControls.append(driverCtrl) pm.delete(pm.parentConstraint(driverJnt, driverCtrl.offset)) pm.parentConstraint(driverCtrl.con, driverJnt, mo=True) lockTranslate = [] ctrlShape = 'circle' if i == 0: lockTranslate = ['tx', 'ty', 'tz'] ctrlShape = 'pyramid' else: lockTranslate = [] fkCtrl = rig_control(name=name + 'FK' + ABC[i], shape=ctrlShape, modify=2, targetOffset=ctrlPos[i], parentOffset=module.controls, lockHideAttrs=lockTranslate, scale=((ctrlSize[0]) * fkScale, (ctrlSize[1]) * fkScale, (ctrlSize[2]) * fkScale)) if i == 0: if pm.objExists(parentRoot): pm.parentConstraint(parentRoot, fkCtrl.offset, mo=True) if pm.objExists(parentRoot) and pm.objExists('worldSpace_GRP'): constrainObject(fkCtrl.modify[0], [fkCtrl.offset, 'worldSpace_GRP'], fkCtrl.ctrl, ['parent', 'world'], type='orientConstraint') pm.parentConstraint(fkCtrl.con, driverCtrl.offset, mo=True) if i > 0: parentOffset = fkControls[i - 1].con pm.parent(fkCtrl.offset, parentOffset) fkControls.append(fkCtrl) fkScale = fkScale - 0.1 pm.delete(ctrlPos) # shape controls rootCtrl = fkControls[0] pm.addAttr(rootCtrl.ctrl, ln='SHAPE', at='enum', enumName='___________', k=True) rootCtrl.ctrl.SHAPE.setLocked(True) pm.addAttr(rootCtrl.ctrl, longName='curl', at='float', k=True, min=-10, max=10, dv=0) pm.addAttr(rootCtrl.ctrl, longName='curlSide', at='float', k=True, min=-10, max=10, dv=0) for i in range(1, numIkControls): rig_animDrivenKey(rootCtrl.ctrl.curl, (-10, 0, 10), fkControls[i].modify[0] + '.rotateX', (-90, 0, 90)) rig_animDrivenKey(rootCtrl.ctrl.curlSide, (-10, 0, 10), fkControls[i].modify[0] + '.rotateZ', (-90, 0, 90)) ik = rig_ik(name, rootJnt, chainList[-1], 'ikSplineSolver', numSpans=numIkControls) pm.parent(ik.handle, ik.curve, module.parts) lowerAim = rig_transform(0, name=name + 'LowerAim', type='locator', parent=module.parts, target=ikControls[1].con).object upperAim = rig_transform(0, name=name + 'UpperAim', type='locator', parent=module.parts, target=ikControls[-2].con).object pm.rotate(lowerAim, 0, 0, -90, r=True, os=True) pm.rotate(upperAim, 0, 0, -90, r=True, os=True) pm.parentConstraint(ikControls[1].con, lowerAim, mo=True) pm.parentConstraint(ikControls[-2].con, upperAim, mo=True) aimTop = mm.eval('rig_makePiston("' + lowerAim + '", "' + upperAim + '", "' + name + 'Aim");') pm.move(upperAim + 'Up', 0, 30 * ctrlSize[0], 0, r=True, os=True) pm.move(lowerAim + 'Up', 0, 20 * ctrlSize[0], 0, r=True, os=True) # advanced twist pm.setAttr(ik.handle + '.dTwistControlEnable', 1) pm.setAttr(ik.handle + '.dWorldUpType', 2) # object up start and end pm.setAttr(ik.handle + '.dForwardAxis', 2) # positive y pm.setAttr(ik.handle + '.dWorldUpAxis', dWorldUpAxis) # positive x pm.connectAttr(upperAim + 'Up.worldMatrix[0]', ik.handle.dWorldUpMatrixEnd, f=True) pm.connectAttr(lowerAim + 'Up.worldMatrix[0]', ik.handle.dWorldUpMatrix, f=True) pm.parent(aimTop, module.parts) pm.select(ik.curve) curveShape = pm.pickWalk(direction='down') curveInfoNode = pm.arclen(curveShape[0], ch=True) curveInfo = pm.rename(curveInfoNode, name + '_splineIk_curveInfo') globalCurve = pm.duplicate(ik.curve) globalCurve = pm.rename(globalCurve, name + 'global_splineIk_curve') pm.select(globalCurve) globalCurveShape = pm.pickWalk(direction='down') globalCurveInfoNode = pm.arclen(globalCurveShape[0], ch=True) globalCurveInfo = pm.rename(globalCurveInfoNode, name + 'global_splineIk_curveInfo') pm.parent(globalCurve, module.parts) pm.setAttr(globalCurve + '.inheritsTransform', 1) distanceToStretch_PM = plusMinusNode(name + '_distanceToStretch', 'subtract', curveInfo, 'arcLength', globalCurveInfo, 'arcLength') correctAdd_Minus_MD = multiplyDivideNode( name + '_correctAdd_Minus', 'multiply', input1=[-1, 0, 0], input2=[distanceToStretch_PM + '.output1D', 0, 0], output=[]) toggleStretch_ctrl_MD = multiplyDivideNode( name + '_toggleStretch_ctrl', 'multiply', input1=[0, 0, 0], input2=[correctAdd_Minus_MD + '.outputX', 0, 0], output=[]) distanceStretchCurve_PM = plusMinusNode(name + '_distanceStretchCurve', 'sum', curveInfo, 'arcLength', toggleStretch_ctrl_MD, 'outputX') globalCurveStretchyFix_MD = multiplyDivideNode( name + '_globalCurveStretchyFix', 'divide', input1=[distanceStretchCurve_PM + '.output1D', 0, 0], input2=[globalCurveInfo + '.arcLength', 1, 1], output=[]) pm.addAttr(fkControls[0].ctrl, longName='stretch', shortName='ts', attributeType="double", min=0, max=1, defaultValue=0, keyable=True) connectReverse(input=(fkControls[0].ctrl + '.stretch', 0, 0), output=(toggleStretch_ctrl_MD + '.input1X', 0, 0)) for i in range(0, len(chainList) - 1): pm.connectAttr(globalCurveStretchyFix_MD + '.outputX', chainList[i] + '.scaleY', f=True) pm.skinCluster(driverJntList, ik.curve, tsb=True) return module
def rope(DEF_nb=10, ropeName="rope", keepRatio=False, lvlType="transform", oSel=None): """ Create rope rig based in 2 parallel curves. Args: DEF_nb (int): Number of deformer joints. ropeName (str): Name for the rope rig. keepRatio (bool): If True, the deformers will keep the length position when the curve is stretched. """ if oSel and len(oSel) == 2 and isinstance(oSel, list): oCrv = oSel[0] if isinstance(oCrv, str): oCrv = pm.PyNode(oCrv) oCrvUpV = oSel[1] if isinstance(oCrvUpV, str): oCrvUpV = pm.PyNode(oCrvUpV) else: if len( pm.selected()) !=2: print "You need to select 2 nurbsCurve" return oCrv = pm.selected()[0] oCrvUpV = pm.selected()[1] if oCrv.getShape().type() != "nurbsCurve" or oCrvUpV.getShape().type() != "nurbsCurve": print "One of the selected objects is not of type: 'nurbsCurve'" print oCrv.getShape().type() print oCrvUpV.getShape().type() return if keepRatio: arclen_node = pm.arclen(oCrv, ch=True) alAttr = pm.getAttr(arclen_node + ".arcLength") muldiv_node = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node+".arcLength", muldiv_node+".input1X") pm.setAttr(muldiv_node+".input2X", alAttr) pm.setAttr(muldiv_node+".operation", 2) pm.addAttr(oCrv, ln="length_ratio", k=True, w=True) pm.connectAttr(muldiv_node+".outputX", oCrv+".length_ratio") root = pm.PyNode(pm.createNode(lvlType, n= ropeName + "_root", ss=True)) step = 1.000/(DEF_nb -1) i = 0.000 shds = [] for x in range(DEF_nb): oTransUpV = pm.PyNode(pm.createNode(lvlType, n= ropeName + str(x).zfill(3) + "_upv", p=root, ss=True)) oTrans = pm.PyNode(pm.createNode(lvlType, n= ropeName + str(x).zfill(3) + "_lvl", p=root, ss=True)) cnsUpv = aop.pathCns(oTransUpV, oCrvUpV, cnsType=False, u=i, tangent=False) cns = aop.pathCns(oTrans, oCrv, cnsType=False, u=i, tangent=False) if keepRatio: muldiv_node2 = pm.createNode("multiplyDivide") condition_node = pm.createNode("condition") pm.setAttr(muldiv_node2+".operation", 2) pm.setAttr(muldiv_node2+".input1X", i) pm.connectAttr(oCrv+".length_ratio", muldiv_node2+".input2X") pm.connectAttr(muldiv_node2+".outputX", condition_node+".colorIfFalseR") pm.connectAttr(muldiv_node2+".outputX", condition_node+".secondTerm") pm.connectAttr(muldiv_node2+".input1X", condition_node+".colorIfTrueR") pm.connectAttr(muldiv_node2+".input1X", condition_node+".firstTerm") pm.setAttr(condition_node+".operation", 4) pm.connectAttr(condition_node+".outColorR", cnsUpv+".uValue") pm.connectAttr(condition_node+".outColorR", cns+".uValue") cns.setAttr("worldUpType", 1) cns.setAttr("frontAxis", 0) cns.setAttr("upAxis", 1) pm.connectAttr(oTransUpV.attr("worldMatrix[0]"),cns.attr("worldUpMatrix")) shd = rt.addJnt(oTrans) shds.append(shd[0]) i += step return shds
def createStretchSpline(curveObj, volume, worldScale, worldScaleObj, worldScaleAttr, disable=0, disableObj='', disableAttr=''): """ Script: js_createStretchSpline.mel Author: Jason Schleifer Descr: Given the selected curve, it will tell the joints to stretch. It's easiest to use with the js_createStretchSplineUI.mel script Inputs: $curveObj => The nurbs curve that will be stretched $maintainVolume => Whether or not to maintain volume on the joints if this is on, then it will be made with an expression, if not then we'll use nodes. $worldScale => Whether or not to take worldScale into account $worldScaleObj => The object that will be used for world scale $worldScaleAttr => The attribute to be used for world scale $disable => Option to control and disable stretch with control $disableObj => The object that will be used for disable $disableAttr => The attribute to be used for disable Req: getStretchAxis createCurveControl """ node = pm.arclen(curveObj, n= '%s_curveInfo'%curveObj, ch=1) # based on the given curve, tell the joints to stretch # create a curveInfo node # get the ikhandle shape = pm.listRelatives(curveObj, s=1, f=1) con = pm.listConnections((shape[0] + ".worldSpace[0]"), type='ikHandle') ikHandle = con[0] # find out what joints are in the list joints = pm.ikHandle(ikHandle, q=1, jl=1) # we need to figure out which direction the curve should be scaling. # do to that, we'll look at the translate values of the second joint. Whichever translate has the # highest value, that'll be the first one and the other two axis will be the shrinking one stretchAxis = getStretchAxis(joints[1]) # create a normalizedScale attr on the curveInfo node pm.addAttr(node, ln="normalizedScale", at="double") length = pm.getAttr(str(node) + ".arcLength") # create blend node for on/off blendStretch = pm.shadingNode('blendColors', asUtility=1, name='%s_stretchBlend'%curveObj) pm.setAttr(str(blendStretch) + '.color1R', length) pm.connectAttr((str(node) + ".arcLength"), str(blendStretch) + '.color2R') # create a NormalizedScale node to connect to everything. multDivide = pm.createNode('multiplyDivide') multDivide = pm.rename(multDivide, (curveObj + "_normalizedScale")) # set the multiplyDivide node to division pm.setAttr((str(multDivide) + ".operation"), 2) pm.connectAttr("%s.outputR"%blendStretch, "%s.input1X"%multDivide) pm.setAttr((str(multDivide) + ".input2X"), length) pm.connectAttr((str(multDivide) + ".outputX"), (str(node) + ".normalizedScale")) if disable: pm.connectAttr('%s.%s'%(disableObj, disableAttr), '%s.blender'%blendStretch ) else: pm.setAttr('%s.blender'%blendStretch, 1 ) # if worldscale is off, and volume deformation is off, we can just connect directly to the joints if (worldScale == 0) and (volume == 0): for joint in joints: print "connecting to " + str(joint) + "." + stretchAxis[0] + "\n" pm.connectAttr((str(node) + ".normalizedScale"), (str(joint) + "." + stretchAxis[0]), f=1) elif (worldScale == 1) and (volume == 0): md2 = pm.createNode('multiplyDivide', n=(curveObj + "_worldScale")) # if $worldScale is on, but volume is off we can just add another multiply divide node # and connect to that # create a multiplyDivide node pm.setAttr((str(md2) + ".operation"), 2) pm.connectAttr((str(node) + ".normalizedScale"), (str(md2) + ".input1X")) pm.connectAttr((worldScaleObj + "." + worldScaleAttr), (str(md2) + ".input2X")) for joint in joints: pm.connectAttr((str(md2) + ".outputX"), (str(joint) + "." + stretchAxis[0]), f=1) else: pm.select(joints) # also create an anim curve which we can use to connnect to the joints to help # determine the scaling power in X and Z. This will be attached to the curve itself utils.createCurveControl(curveObj, "scalePower", "pow") # start creating an expression expr = "" # for each joint, connect the scaleX to the normalizedScale # if worldScale and disable: # expr += ("$scale = " + str(node) + ".normalizedScale *" + worldScaleObj + "." + worldScaleAttr + " * " + disableObj + "." + disableAttr + ";\n") if worldScale: expr += ("$scale = " + str(node) + ".normalizedScale *" + worldScaleObj + "." + worldScaleAttr + ";\n") # elif disable: # expr += ("$scale = " + str(node) + ".normalizedScale *" + disableObj + "." + disableAttr + ";\n") else: expr += ("$scale = " + str(node) + ".normalizedScale;\n") expr += ("$sqrt = 1/sqrt($scale);\n") size = len(joints) for x in range(0, size): item = joints[x] # set a powPosition based on the number of joints which will be scaling, from 0 to 1 expr = (expr + str(item) + "." + stretchAxis[0] + " = $scale;\n") expr = (expr + str(item) + "." + stretchAxis[1] + " = pow($sqrt," + str(item) + ".pow);\n") expr = (expr + str(item) + "." + stretchAxis[2] + " = pow($sqrt," + str(item) + ".pow);\n") pm.expression(s=expr, n=(curveObj + "_expr")) pm.select(curveObj) return joints
def _cerateCurveIkHandle(self , frontBackList = None): ''' @frontBackList : list , This is the frontBackList of is List ''' if frontBackList is None : OpenMaya.MGlobal_displayError('@frontBackList : This is the jointList is None : frontBackList = %s'%(frontBackList)) return frontBackClusterList = [] for jointList in frontBackList: swapName = jointList[0].name().split('_')[-1] name = jointList[0].name().replace('_'+swapName , '_cruve') jointList1 = [jointList[0] , jointList[-1]] pointList = [a.getTranslation(space = 'world') for a in jointList1] knotList = range(len(jointList1)) curve = pm.curve(n = name , d = 1 , p = pointList , k = knotList ) #pm.rebuildCurve(curve ,d = 3) ikHandleName = jointList[0].name().replace('_'+swapName , '_ikHandle') handle , effector = pm.ikHandle( n = ikHandleName , sj = jointList[0] , ee = jointList[-1] , c = curve , sol="ikSplineSolver" , ccv = 0, pcv = 0 , ns = 3) jointListGroup = self._objectGroup(jointList[0]) handleGroup = self._objectGroup(handle) curveGroup = self._objectGroup(curve) curve.getParent().inheritsTransform.set(0) curveGroup.setParent(handleGroup) handleGroup.setParent(jointListGroup) jointListGroup.setParent(self.featherIkCurGroup) jointList[0].getParent().v.set(0) handle.getParent().v.set(0) curveInfo = pm.arclen(curve , ch = 1) curveInfoName = curveInfo.rename(curve.name().replace('_cruve' , '_curveInfo')) MDName1 = pm.shadingNode("multiplyDivide",asUtility=True,n=jointList[0].name().replace('_'+swapName , '_MD1')) MDName1.operation.set(1) MDName2 = pm.shadingNode("multiplyDivide",asUtility=True,n=jointList[0].name().replace('_'+swapName , '_MD2')) MDName2.operation.set(2) self.globalScaleMD.input1X.set(1) MDName1.input1X.set(curveInfoName.arcLength.get()) curveInfoName.arcLength.connect(MDName2.input1X) MDName1.outputX.connect(MDName2.input2X) self.globalScaleMD.outputX.connect(MDName1.input2X) for x in jointList: MDName2.outputX.connect(x.scaleX) ClusterList = self._createCurveCluster(curve) frontBackClusterList.append(ClusterList) OpenMaya.MGlobal_clearSelectionList() return frontBackClusterList
def generateFollowPlane(self, *args): startTime = pm.playbackOptions(q=1, min=1) endTime = pm.playbackOptions(q=1, max=1) sel_list = pm.ls(sl=1, ni=1, type="transform") if not sel_list: pm.confirmDialog(message='请选择物体', button=['确定']) return for sel in sel_list: # snapshot = pm.snapshot(sel,st=startTime,et=endTime)[1] snapshot = pm.createNode("snapshot") sel.selectHandle.connect(snapshot.localPosition) sel.worldMatrix[0].connect(snapshot.inputMatrix) snapshot.startTime.set(startTime) snapshot.endTime.set(endTime) snapshot.increment.set(1) anim_curve = pm.curve(n=sel + "_follow_curve", d=3, p=snapshot.pts.get()) pm.delete(snapshot) curve_length = pm.arclen(anim_curve, ch=0) plane, plane_node = pm.polyPlane(n=sel + "_follow_plane", sx=20, sy=3, w=curve_length, h=20) plane_grp = pm.group(plane, n=plane + "_grp") # NOTE 创建运动路径跟随 motion_path = pm.pathAnimation( plane_grp, anim_curve, fractionMode=1, follow=1, followAxis="x", upAxis="y", worldUpType="vector", worldUpVector=(0, 1, 0), inverseUp=0, inverseFront=0, bank=0, startTimeU=startTime, endTimeU=endTime, ) motion_path = pm.PyNode(motion_path) flow_node, ffd_node, lattice_node, ffd_base = pm.flow(plane_grp, dv=(100, 2, 2)) # NOTE 设置外部影响 ffd_node.outsideLattice.set(1) ffd_node.local.set(1) plane_node.width.set(50) lattice_node.v.set(0) ffd_base.v.set(0) # NOTE 设置 Parametric Length 匹配位置 motion_path.fractionMode.set(0) # NOTE 设置为 normal 朝向确保不会翻转 motion_path.worldUpType.set(4) animCurve = motion_path.listConnections(type="animCurve")[0] # NOTE 关键帧设置为线性 animCurve.setTangentTypes(range(animCurve.numKeys()), inTangentType="linear", outTangentType="linear") # NOTE 打组 pm.group(lattice_node, ffd_base, plane_grp, anim_curve, n=sel + "_follow_grp") pm.select(plane)
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # 1 bone chain Upv ref ============================== self.ikHandleUpvRef = primitive.addIkHandle( self.root, self.getName("ikHandleLegChainUpvRef"), self.legChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.legChainUpvRef[0], self.ik_ctl, self.upv_cns, mo=True) # Visibilities ------------------------------------- # shape.dispGeometry # fk fkvis_node = node.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.line_ref.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] o_node = applyop.gear_ikfk2bone_op(out, self.root_ctl, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, o_node + ".blend") if self.negate: mulVal = -1 else: mulVal = 1 node.createMulNode(self.roll_att, mulVal, o_node + ".roll") # pm.connectAttr(self.roll_att, o_node+".roll") pm.connectAttr(self.scale_att, o_node + ".scaleA") pm.connectAttr(self.scale_att, o_node + ".scaleB") pm.connectAttr(self.maxstretch_att, o_node + ".maxstretch") pm.connectAttr(self.slide_att, o_node + ".slide") pm.connectAttr(self.softness_att, o_node + ".softness") pm.connectAttr(self.reverse_att, o_node + ".reverse") # Twist references --------------------------------- o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) # spline IK for twist jnts self.ikhUpLegTwist, self.uplegTwistCrv = applyop.splineIK( self.getName("uplegTwist"), self.uplegTwistChain, parent=self.root, cParent=self.bone0) self.ikhLowLegTwist, self.lowlegTwistCrv = applyop.splineIK( self.getName("lowlegTwist"), self.lowlegTwistChain, parent=self.root, cParent=self.bone1) # references self.ikhUpLegRef, self.tmpCrv = applyop.splineIK( self.getName("uplegRollRef"), self.uplegRollRef, parent=self.root, cParent=self.bone0) self.ikhLowLegRef, self.tmpCrv = applyop.splineIK( self.getName("lowlegRollRef"), self.lowlegRollRef, parent=self.root, cParent=self.eff_loc) self.ikhAuxTwist, self.tmpCrv = applyop.splineIK( self.getName("auxTwist"), self.auxTwistChain, parent=self.root, cParent=self.eff_loc) # setting connexions for ikhUpLegTwist self.ikhUpLegTwist.attr("dTwistControlEnable").set(True) self.ikhUpLegTwist.attr("dWorldUpType").set(4) self.ikhUpLegTwist.attr("dWorldUpAxis").set(3) self.ikhUpLegTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhUpLegTwist.attr("dWorldUpVectorY").set(0.0) self.ikhUpLegTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhUpLegTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.uplegRollRef[0].attr("worldMatrix[0]"), self.ikhUpLegTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.bone0.attr("worldMatrix[0]"), self.ikhUpLegTwist.attr("dWorldUpMatrixEnd")) # setting connexions for ikhAuxTwist self.ikhAuxTwist.attr("dTwistControlEnable").set(True) self.ikhAuxTwist.attr("dWorldUpType").set(4) self.ikhAuxTwist.attr("dWorldUpAxis").set(3) self.ikhAuxTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhAuxTwist.attr("dWorldUpVectorY").set(0.0) self.ikhAuxTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhAuxTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.lowlegRollRef[0].attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.tws_ref.attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrixEnd")) pm.connectAttr(self.auxTwistChain[1].attr("rx"), self.ikhLowLegTwist.attr("twist")) pm.parentConstraint(self.bone1, self.aux_npo, maintainOffset=True) # scale arm length for twist chain (not the squash and stretch) arclen_node = pm.arclen(self.uplegTwistCrv, ch=True) alAttrUpLeg = arclen_node.attr("arcLength") muldiv_nodeArm = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeArm.attr("input1X")) muldiv_nodeArm.attr("input2X").set(alAttrUpLeg.get()) muldiv_nodeArm.attr("operation").set(2) for jnt in self.uplegTwistChain: pm.connectAttr(muldiv_nodeArm.attr("outputX"), jnt.attr("sx")) # scale forearm length for twist chain (not the squash and stretch) arclen_node = pm.arclen(self.lowlegTwistCrv, ch=True) alAttrLowLeg = arclen_node.attr("arcLength") muldiv_nodeLowLeg = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeLowLeg.attr("input1X")) muldiv_nodeLowLeg.attr("input2X").set(alAttrLowLeg.get()) muldiv_nodeLowLeg.attr("operation").set(2) for jnt in self.lowlegTwistChain: pm.connectAttr(muldiv_nodeLowLeg.attr("outputX"), jnt.attr("sx")) # scale compensation for the first twist join dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix[0]"), dm_node.attr("inputMatrix")) pm.connectAttr(dm_node.attr("outputScale"), self.uplegTwistChain[0].attr("inverseScale")) pm.connectAttr(dm_node.attr("outputScale"), self.lowlegTwistChain[0].attr("inverseScale")) # tangent controls muldiv_node = pm.createNode("multiplyDivide") muldiv_node.attr("input2X").set(-1) pm.connectAttr(self.tws1A_npo.attr("rz"), muldiv_node.attr("input1X")) muldiv_nodeBias = pm.createNode("multiplyDivide") pm.connectAttr(muldiv_node.attr("outputX"), muldiv_nodeBias.attr("input1X")) pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X")) pm.connectAttr(muldiv_nodeBias.attr("outputX"), self.tws1A_loc.attr("rz")) if self.negate: axis = "xz" else: axis = "-xz" applyop.aimCns(self.tws1A_npo, self.tws0_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.lowlegTangentB_loc, self.lowlegTangentA_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) pm.pointConstraint(self.eff_loc, self.lowlegTangentB_loc) muldiv_node = pm.createNode("multiplyDivide") muldiv_node.attr("input2X").set(-1) pm.connectAttr(self.tws1B_npo.attr("rz"), muldiv_node.attr("input1X")) muldiv_nodeBias = pm.createNode("multiplyDivide") pm.connectAttr(muldiv_node.attr("outputX"), muldiv_nodeBias.attr("input1X")) pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X")) pm.connectAttr(muldiv_nodeBias.attr("outputX"), self.tws1B_loc.attr("rz")) if self.negate: axis = "-xz" else: axis = "xz" applyop.aimCns(self.tws1B_npo, self.tws2_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) applyop.aimCns(self.uplegTangentA_loc, self.uplegTangentB_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) # Volume ------------------------------------------- distA_node = node.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = node.createDistNode(self.tws1_loc, self.tws2_loc) add_node = node.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = node.createDivNode(add_node + ".output", self.root_ctl.attr("sx")) # comp scaling issue dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = node.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # connecting tangent scaele compensation after volume to # avoid duplicate some nodes distA_node = node.createDistNode(self.tws0_loc, self.mid_ctl) distB_node = node.createDistNode(self.mid_ctl, self.tws2_loc) div_nodeUpLeg = node.createDivNode(distA_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = node.createDivNode(div_nodeUpLeg + ".outputX", distA_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1A_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.uplegTangentA_loc.attr("sx")) div_nodeLowLeg = node.createDivNode(distB_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = node.createDivNode(div_nodeLowLeg + ".outputX", distB_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1B_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.lowlegTangentB_loc.attr("sx")) # conection curve cnts = [ self.uplegTangentA_loc, self.uplegTangentA_ctl, self.uplegTangentB_ctl, self.kneeTangent_ctl ] applyop.gear_curvecns_op(self.uplegTwistCrv, cnts) cnts = [ self.kneeTangent_ctl, self.lowlegTangentA_ctl, self.lowlegTangentB_ctl, self.lowlegTangentB_loc ] applyop.gear_curvecns_op(self.lowlegTwistCrv, cnts) # Tangent controls vis for shp in self.uplegTangentA_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.uplegTangentB_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.lowlegTangentA_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.lowlegTangentB_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) for shp in self.kneeTangent_ctl.getShapes(): pm.connectAttr(self.tangentVis_att, shp.attr("visibility")) # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the # controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if i < (self.settings["div0"] + 2): mulmat_node = applyop.gear_mulmatrix_op( self.uplegTwistChain[i] + ".worldMatrix", div_cns + ".parentInverseMatrix") lastUpLegDiv = div_cns else: o_node = self.lowlegTwistChain[i - (self.settings["div0"] + 2)] mulmat_node = applyop.gear_mulmatrix_op( o_node + ".worldMatrix", div_cns + ".parentInverseMatrix") lastLowLegDiv = div_cns dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", div_cns + ".t") pm.connectAttr(dm_node + ".outputRotate", div_cns + ".r") # Squash n Stretch o_node = applyop.gear_squashstretch2_op( div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, o_node + ".blend") pm.connectAttr(self.volDriver_att, o_node + ".driver") pm.connectAttr(self.st_att[i], o_node + ".stretch") pm.connectAttr(self.sq_att[i], o_node + ".squash") # force translation for last loc arm and foreamr applyop.gear_mulmatrix_op(self.kneeTangent_ctl.worldMatrix, lastUpLegDiv.parentInverseMatrix, lastUpLegDiv, "t") applyop.gear_mulmatrix_op(self.tws2_loc.worldMatrix, lastLowLegDiv.parentInverseMatrix, lastLowLegDiv, "t") # NOTE: next line fix the issue on meters. # This is special case becasuse the IK solver from mGear use the # scale as lenght and we have shear # TODO: check for a more clean and elegant solution instead of # re-match the world matrix again transform.matchWorldTransform(self.fk_ctl[0], self.match_fk0_off) transform.matchWorldTransform(self.fk_ctl[1], self.match_fk1_off) transform.matchWorldTransform(self.fk_ctl[0], self.match_fk0) transform.matchWorldTransform(self.fk_ctl[1], self.match_fk1) # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) return
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # Curves ------------------------------------------- op = applyop.gear_curveslide2_op( self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) pm.connectAttr(self.position_att, op + ".position") pm.connectAttr(self.lenght_att, op + ".maxstretch") op = applyop.gear_curveslide2_op( self.slv_upv_crv, self.upv_crv, 0, 1.5, .5, .5) pm.connectAttr(self.position_att, op + ".position") pm.connectAttr(self.lenght_att, op + ".maxstretch") for tang in self.tangentsCtl: for shp in tang.getShapes(): pm.connectAttr(self.tangentsVis_att, shp.attr("visibility")) for twnpo, fkctl in zip(self.tweak_npo, self.fk_ctl): intMatrix = applyop.gear_intmatrix_op( fkctl.attr("worldMatrix"), fkctl.getParent().attr("worldMatrix"), .5) applyop.gear_mulmatrix_op(intMatrix.attr("output"), twnpo.attr("parentInverseMatrix[0]"), twnpo) dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix) if self.settings["keepLength"]: arclen_node = pm.arclen(self.slv_crv, ch=True) alAttr = pm.getAttr(arclen_node + ".arcLength") pm.addAttr(self.slv_crv, ln="length_ratio", k=True, w=True) node.createDivNode(arclen_node.arcLength, alAttr, self.slv_crv.length_ratio) div_node_scl = node.createDivNode(self.slv_crv.length_ratio, dm_node_scl.outputScaleX) step = 1.000 / (self.def_number - 1) u = 0.000 for i in range(self.def_number): mult_node = node.createMulNode(u, self.lenght_att) cnsUpv = applyop.pathCns(self.upv_cns[i], self.slv_upv_crv, cnsType=False, u=u, tangent=False) pm.connectAttr(mult_node.outputX, cnsUpv.uValue) cns = applyop.pathCns( self.div_cns[i], self.slv_crv, False, u, True) pm.connectAttr(mult_node.outputX, cns.uValue) # Connectiong the scale for scaling compensation for axis, AX in zip("xyz", "XYZ"): pm.connectAttr(dm_node_scl.attr("outputScale{}".format(AX)), self.div_cns[i].attr("s{}".format(axis))) if self.settings["keepLength"]: div_node2 = node.createDivNode(u, div_node_scl.outputX) cond_node = node.createConditionNode(div_node2.input1X, div_node2.outputX, 4, div_node2.input1X, div_node2.outputX) # pm.connectAttr(cond_node + ".outColorR", # cnsUpv + ".uValue") # pm.connectAttr(cond_node + ".outColorR", # cns + ".uValue") pm.connectAttr(cond_node + ".outColorR", mult_node + ".input1X", f=True) # Connect the scaling for self.Extra_tweak_npo et_npo = self.Extra_tweak_npo[i] pm.connectAttr(self.spin_att, et_npo + ".rz") base_node = node.createMulNode(self.baseSize_att, 1.00000 - u, output=None) tip_node = node.createMulNode(self.tipSize_att, u, output=None) sum_node = node.createPlusMinusAverage1D([base_node.outputX, tip_node.outputX]) # print et_npo pm.connectAttr(sum_node.output1D, et_npo.scaleX, f=True) pm.connectAttr(sum_node.output1D, et_npo.scaleY, f=True) pm.connectAttr(sum_node.output1D, et_npo.scaleZ, f=True) cns.setAttr("worldUpType", 1) cns.setAttr("frontAxis", 0) cns.setAttr("upAxis", 1) pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"), cns.attr("worldUpMatrix")) u += step for et in self.Extra_tweak_ctl: for shp in et.getShapes(): pm.connectAttr(self.tweakVis_att, shp.attr("visibility")) if self.settings["keepLength"]: # add the safty distance offset self.tweakTip_npo.attr("tx").set(self.off_dist) # connect vis line ref for shp in self.line_ref.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) for ctl in self.tweak_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) for ctl in self.fk_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.fkVis_att, shp.attr("visibility"))
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # setup out channels. This channels are pass through for stack node.createPlusMinusAverage1D( [self.mid_wide_att, self.mid_wide_in_att, -1.0], 1, self.mid_wide_out_att) node.createPlusMinusAverage1D( [self.mid_depth_att, self.mid_depth_in_att, -1.0], 1, self.mid_depth_out_att) node.createPlusMinusAverage1D( [self.tip_wide_att, self.tip_wide_in_att, -1.0], 1, self.tip_wide_out_att) node.createPlusMinusAverage1D( [self.tip_depth_att, self.tip_depth_in_att, -1.0], 1, self.tip_depth_out_att) node.createPlusMinusAverage1D( [self.mid_twist_att, self.mid_twist_in_att], 1, self.mid_twist_out_att) node.createPlusMinusAverage1D( [self.tip_twist_att, self.tip_twist_in_att], 1, self.tip_twist_out_att) if not self.settings["simpleFK"]: dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix) if self.settings["keepLength"]: arclen_node = pm.arclen(self.mst_crv, ch=True) alAttr = pm.getAttr(arclen_node + ".arcLength") ration_node = node.createMulNode(self.length_ratio_att, alAttr) pm.addAttr(self.mst_crv, ln="length_ratio", k=True, w=True) node.createDivNode(arclen_node.arcLength, ration_node.outputX, self.mst_crv.length_ratio) div_node_scl = node.createDivNode(self.mst_crv.length_ratio, dm_node_scl.outputScaleX) step = 1.000 / (self.def_number - 1) step_mid = 1.000 / ((self.def_number - 1) / 2.0) u = 0.000 u_mid = 0.000 pass_mid = False for i in range(self.def_number): cnsUpv = applyop.pathCns(self.upv_cns[i], self.upv_crv, cnsType=False, u=u, tangent=False) cns = applyop.pathCns(self.div_cns[i], self.mst_crv, False, u, True) # Connecting the scale for scaling compensation # for axis, AX in zip("xyz", "XYZ"): for axis, AX in zip("x", "X"): pm.connectAttr( dm_node_scl.attr("outputScale{}".format(AX)), self.div_cns[i].attr("s{}".format(axis))) if self.settings["keepLength"]: div_node2 = node.createDivNode(u, div_node_scl.outputX) cond_node = node.createConditionNode( div_node2.input1X, div_node2.outputX, 4, div_node2.input1X, div_node2.outputX) pm.connectAttr(cond_node + ".outColorR", cnsUpv + ".uValue") pm.connectAttr(cond_node + ".outColorR", cns + ".uValue") cns.setAttr("worldUpType", 1) cns.setAttr("frontAxis", 0) cns.setAttr("upAxis", 1) pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"), cns.attr("worldUpMatrix")) # Connect scale Wide and Depth # wide and Depth mid_mul_node = node.createMulNode( [self.mid_wide_att, self.mid_depth_att], [self.mid_wide_in_att, self.mid_depth_in_att]) mid_mul_node2 = node.createMulNode( [mid_mul_node.outputX, mid_mul_node.outputY], [u_mid, u_mid]) mid_mul_node3 = node.createMulNode( [mid_mul_node2.outputX, mid_mul_node2.outputY], [ dm_node_scl.attr("outputScaleX"), dm_node_scl.attr("outputScaleY") ]) tip_mul_node = node.createMulNode( [self.tip_wide_att, self.tip_depth_att], [self.tip_wide_in_att, self.tip_depth_in_att]) tip_mul_node2 = node.createMulNode( [tip_mul_node.outputX, tip_mul_node.outputY], [u, u]) node.createPlusMinusAverage1D([ mid_mul_node3.outputX, 1.0 - u_mid, tip_mul_node2.outputX, 1.0 - u, -1.0 ], 1, self.div_cns[i].attr("sy")) node.createPlusMinusAverage1D([ mid_mul_node3.outputY, 1.0 - u_mid, tip_mul_node2.outputY, 1.0 - u, -1.0 ], 1, self.div_cns[i].attr("sz")) # Connect Twist "cns.frontTwist" twist_mul_node = node.createMulNode( [self.mid_twist_att, self.tip_twist_att], [u_mid, u]) twist_mul_node2 = node.createMulNode( [self.mid_twist_in_att, self.tip_twist_in_att], [u_mid, u]) node.createPlusMinusAverage1D([ twist_mul_node.outputX, twist_mul_node.outputY, twist_mul_node2.outputX, twist_mul_node2.outputY, ], 1, cns.frontTwist) # u_mid calc if u_mid >= 1.0 or pass_mid: u_mid -= step_mid pass_mid = True else: u_mid += step_mid if u_mid > 1.0: u_mid = 1.0 # ensure the tip is never affected byt the mid if i == (self.def_number - 1): u_mid = 0.0 u += step if self.settings["keepLength"]: # add the safty distance offset self.tweakTip_npo.attr("tx").set(self.off_dist) # connect vis line ref for shp in self.line_ref.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) # CONNECT STACK # master components mstr_global = self.settings["masterChainGlobal"] mstr_local = self.settings["masterChainLocal"] if mstr_global: mstr_global = self.rig.components[mstr_global] if mstr_local: mstr_local = self.rig.components[mstr_local] # connect twist and scale if mstr_global and mstr_local: node.createPlusMinusAverage1D([ mstr_global.root.mid_twist_out, mstr_local.root.mid_twist_out ], 1, self.mid_twist_in_att) node.createPlusMinusAverage1D([ mstr_global.root.tip_twist_out, mstr_local.root.tip_twist_out ], 1, self.tip_twist_in_att) node.createPlusMinusAverage1D([ mstr_global.root.mid_wide_out, mstr_local.root.mid_wide_out, -1 ], 1, self.mid_wide_in_att) node.createPlusMinusAverage1D([ mstr_global.root.tip_wide_out, mstr_local.root.tip_wide_out, -1 ], 1, self.tip_wide_in_att) node.createPlusMinusAverage1D([ mstr_global.root.mid_depth_out, mstr_local.root.mid_depth_out, -1 ], 1, self.mid_depth_in_att) node.createPlusMinusAverage1D([ mstr_global.root.tip_depth_out, mstr_local.root.tip_depth_out, -1 ], 1, self.tip_depth_in_att) elif mstr_local or mstr_global: for master_chain in [mstr_local, mstr_global]: if master_chain: pm.connectAttr(master_chain.root.mid_twist_out, self.mid_twist_in_att) pm.connectAttr(master_chain.root.tip_twist_out, self.tip_twist_in_att) pm.connectAttr(master_chain.root.mid_wide_out, self.mid_wide_in_att) pm.connectAttr(master_chain.root.tip_wide_out, self.tip_wide_in_att) pm.connectAttr(master_chain.root.mid_depth_out, self.mid_depth_in_att) pm.connectAttr(master_chain.root.tip_depth_out, self.tip_depth_in_att) # connect the fk chain ctls for e, ctl in enumerate(self.fk_ctl): # connect out out_loc = self.fk_local_out[e] applyop.gear_mulmatrix_op(ctl.attr("worldMatrix"), out_loc.attr("parentInverseMatrix[0]"), out_loc) out_glob = self.fk_global_out[e] out_ref = self.fk_global_ref[e] applyop.gear_mulmatrix_op(out_ref.attr("worldMatrix"), out_glob.attr("parentInverseMatrix[0]"), out_glob) # connect in global if mstr_global: self.connect_master(mstr_global.fk_global_out, self.fk_global_in, e, self.settings["cnxOffset"]) # connect in local if mstr_local: self.connect_master(mstr_local.fk_local_out, self.fk_local_in, e, self.settings["cnxOffset"]) for shp in ctl.getShapes(): pm.connectAttr(self.fkVis_att, shp.attr("visibility")) for ctl in self.tweak_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) if self.settings["extraTweak"]: for tweak_ctl in self.extratweak_ctl: for shp in tweak_ctl.getShapes(): pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))
def bdBuildRPSolverScale(self, condition): print 'RP Solver' #self.splineCurve = pm.listConnections(self.ikSpline, type = 'nurbsCurve')[0] pm.select(cl=True) ikGrp = pm.group(n=self.ikSpline.name() + '_GRP') ikParent = self.ikSpline.getParent() ikPos = self.ikSpline.getTranslation(space='world') ikGrp.setTranslation(ikPos) pm.parent(ikGrp, ikParent) pm.parent(self.ikSpline, ikGrp) sclJnt = pm.duplicate(self.startJoint, parentOnly=True, name=self.startJoint.name().replace( 'JNT', 'SCL'))[0] effector = pm.listConnections(self.ikSpline, source=True, type='ikEffector')[0] endJoint = pm.listConnections(effector, source=True, type='joint')[0] startJointChild = pm.listRelatives(self.startJoint, c=True, type='joint')[0] self.jointChain = [] self.jointChain.append(self.startJoint) self.jointChain.append(startJointChild) while startJointChild.name() != endJoint.name(): startJointChild = pm.listRelatives(startJointChild, c=True, type='joint')[0] self.jointChain.append(startJointChild) jntPos = [] for jnt in self.jointChain: pos = jnt.getTranslation(space='world') jntPos.append(pos) self.splineCurveScl = pm.curve(p=jntPos, degree=1, n=self.startJoint.name().replace( '01_JNT', 'CRV_SCL')) self.splineCurveScl.setPivots(jntPos[0]) pm.parent(self.splineCurveScl, sclJnt) strArclenSCL = pm.arclen(self.splineCurveScl, ch=True) arclenSCL = pm.ls(strArclenSCL)[0] arclenSCL.rename(self.splineCurveScl.name() + '_length') distanceNode = pm.createNode('distanceBetween', name=self.startJoint.name().replace( '_01_JNT', 'distance')) sclJnt.rotatePivotTranslate.connect(distanceNode.point1) ikGrp.rotatePivotTranslate.connect(distanceNode.point2) sclJnt.worldMatrix.connect(distanceNode.inMatrix1) ikGrp.worldMatrix.connect(distanceNode.inMatrix2) mdScaleFactor = pm.createNode('multiplyDivide', name=self.splineCurveScl.name().replace( 'CRV_SCL', 'CRV_scaleFactor_MD')) distanceNode.distance.connect(mdScaleFactor.input1X) arclenSCL.arcLength.connect(mdScaleFactor.input2X) mdScaleFactor.operation.set(2) cndScaleFactor = pm.createNode('condition', name=self.splineCurveScl.name().replace( 'CRV_SCL', 'CRV_scaleFactor_CND')) distanceNode.distance.connect(cndScaleFactor.firstTerm) arclenSCL.arcLength.connect(cndScaleFactor.secondTerm) mdScaleFactor.outputX.connect(cndScaleFactor.colorIfTrueR) cndScaleFactor.operation.set(2) for jnt in self.jointChain: cndScaleFactor.outColorR.connect(jnt.scaleX)
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # Tangent position --------------------------------- # common part d = vector.getDistance(self.guide.pos["root"], self.guide.pos["neck"]) dist_node = node.createDistNode(self.root, self.ik_ctl) rootWorld_node = node.createDecomposeMatrixNode( self.root.attr("worldMatrix")) div_node = node.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleX") div_node = node.createDivNode(div_node + ".outputX", d) # tan0 mul_node = node.createMulNode(self.tan0_att, self.tan0_loc.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan0_loc + ".ty") # tan1 mul_node = node.createMulNode(self.tan1_att, self.tan1_loc.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan1_loc.attr("ty")) # Curves ------------------------------------------- op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) pm.connectAttr(self.maxstretch_att, op + ".maxstretch") pm.connectAttr(self.maxsquash_att, op + ".maxsquash") pm.connectAttr(self.softness_att, op + ".softness") # Volume driver ------------------------------------ crv_node = node.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 2) # front axis is 'Z' # Roll intMatrix = applyop.gear_intmatrix_op( self.intMRef + ".worldMatrix", self.ik_ctl + ".worldMatrix", u) dm_node = node.createDecomposeMatrixNode(intMatrix + ".output") pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate")) pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True) pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector") # Squash n Stretch op = applyop.gear_squashstretch2_op(self.fk_npo[i], self.root, pm.arclen(self.slv_crv), "y") pm.connectAttr(self.volume_att, op + ".blend") pm.connectAttr(crv_node + ".arcLength", op + ".driver") pm.connectAttr(self.st_att[i], op + ".stretch") pm.connectAttr(self.sq_att[i], op + ".squash") op.setAttr("driver_min", .1) # scl compas if i != 0: div_node = node.createDivNode([1, 1, 1], [ self.fk_npo[i - 1] + ".sx", self.fk_npo[i - 1] + ".sy", self.fk_npo[i - 1] + ".sz" ]) pm.connectAttr(div_node + ".output", self.scl_npo[i] + ".scale") # Controlers if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) else: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) # Orientation Lock if i == self.settings["division"] - 1: dm_node = node.createDecomposeMatrixNode(self.ik_ctl + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") # Head --------------------------------------------- self.fk_ctl[-1].addChild(self.head_cns) # scale compensation dm_node = node.createDecomposeMatrixNode(self.scl_npo[0] + ".parentInverseMatrix") pm.connectAttr(dm_node + ".outputScale", self.scl_npo[0] + ".scale")
def createStretchSpline( ctrl=None, curve=None, maintainVolume=True, globalScaleAttr=None ): # PyNode 캐스팅 if not curve: sel = pm.selected() if sel: curve = sel[0] else: curve = pm.PyNode( curve ) # 컨트롤러 캐스팅 node = curve if ctrl: node = pm.PyNode(ctrl) # ikhandle 알아옴. ikHandle = curve.getShape().worldSpace.outputs( type='ikHandle') if not ikHandle: pm.mel.error(u'select curve for splineIK') ikHandle = ikHandle[0] # 연결된 조인트 알아옴 joints = ikHandle.getJointList() # ctrl node node.addAttr('globalScale', keyable=True, dv=1 ) node.addAttr('stretch', keyable=True, dv=1 ) node.addAttr('maintainVolumne', keyable=False, dv=1 ) node.addAttr('currentCurveLength', keyable=True ) node.addAttr('initCurveLength', keyable=True ) node.addAttr('aimAxisScale', nn='Aim Axis Scale', keyable=True ) node.addAttr('sideAxisScale', keyable=False ) node.addAttr('sideAxisScaleShape', keyable=False ) node.setAttr('currentCurveLength', keyable=False, channelBox=True) node.setAttr('initCurveLength', keyable=True, channelBox=True) #node.setAttr('aimAxisScale', keyable=False, channelBox=True) # curveInfo node 생성 crvInfo = pm.arclen( curve, ch=True ) crvInfo.setAttr('arcLength', keyable=True) initCurveLength = crvInfo.arcLength.get() crvInfo.arcLength >> node.currentCurveLength node.initCurveLength.set( initCurveLength ) # we need to figure out which direction the curve should be scaling. # do to that, we'll look at the translate values of the second joint. Whichever translate has the # highest value, that'll be the first one and the other two axis will be the shrinking one stretchAxis = getStretchAxisAttr( joints[-1] ) # # 노드 계산 # # # aimAxisScale = currentCurveLength / initCurveLength md1 = pm.createNode( 'multiplyDivide', n=curve.name()+'_initCurveLength' ) md1.setAttr('operation', keyable=True) md1.operation.set(2) # Divide node.currentCurveLength >> md1.input1X node.initCurveLength >> md1.input2X md1.outputX >> node.aimAxisScale # aimAxisScale = ( currentCurveLength / initCurveLength ) / globalScale md2 = pm.createNode( 'multiplyDivide', n=curve.name()+'_multGlobalScale' ) md2.setAttr('operation', keyable=True) md2.operation.set(2) # Divide md1.outputX >> md2.input1X node.globalScale >> md2.input2X md2.outputX >> node.aimAxisScale # node.stretch 로 stretch가 되고 안되게~ # aimAxisScale = pow( [ (currentCurveLength / initCurveLength) / globalScale ], stretch ) stretchable = pm.createNode( 'multiplyDivide', n=curve.name()+'_stretchable_switchPow' ) stretchable.operation.set(3) # pow stretchable.setAttr('operation', keyable=True) md2.outputX >> stretchable.input1X node.stretch >> stretchable.input2X stretchable.outputX >> node.aimAxisScale for jnt in joints: attr = jnt.attr( stretchAxis[0] ) print 'connecting to "%s"'%attr node.aimAxisScale >> attr if globalScaleAttr: pm.Attribute( globalScaleAttr ) >> node.globalScale # maintain Volume Option이 설정 되어 있으면~~ if maintainVolume: node.setAttr('maintainVolumne', keyable=True, channelBox=False) node.setAttr('sideAxisScale', keyable=True, channelBox=False) node.setAttr('sideAxisScaleShape', keyable=True, channelBox=False) # # sideAxisScale = 1/sqrt( scale ) # sqrtNode = pm.createNode( 'multiplyDivide', n=curve.name()+'_volumnPreserve_sqrt' ) sqrtNode.operation.set(3) # pow(sqrt) sqrtNode.setAttr('operation', keyable=True) node.aimAxisScale >> sqrtNode.input1X sqrtNode.input2.set(0.5,0.5,0.5) # sqrtNode.outputX >> ---> divNode = pm.createNode( 'multiplyDivide', n=curve.name()+'_volumnPreserve_div' ) divNode.operation.set(2) # division divNode.setAttr('operation', keyable=True) divNode.input1.set(1,1,1) sqrtNode.outputX >> divNode.input2X divNode.outputX >> node.sideAxisScale # node.maintainVolumne 로 볼륨 유지가 되고 안되게~ maintainVolumneAble = pm.createNode( 'multiplyDivide', n=curve.name()+'_maintainVolumne_switchPow' ) maintainVolumneAble.operation.set(3) # pow maintainVolumneAble.setAttr('operation', keyable=True) divNode.outputX >> maintainVolumneAble.input1X node.maintainVolumne >> maintainVolumneAble.input2X maintainVolumneAble.outputX >> node.sideAxisScale powAttr = rigCurveShapeControl( ctrl=node, attr='sideAxisScaleShape', sampleParams=range( len(joints) ) ) for i in range( len(joints) ): Jnt = joints[i] Pow = powAttr[i] # pow( 1/sqrt( Scale ), 2 ) powNode = pm.createNode( 'multiplyDivide', n=curve.name()+'_volumnPreserve_pow' ) powNode.operation.set(3) # pow powNode.setAttr('operation', keyable=True) node.sideAxisScale >> powNode.input1X Pow >> powNode.input2X powNode.outputX >> Jnt.attr( stretchAxis[1] ) powNode.outputX >> Jnt.attr( stretchAxis[2] )
#select ikSpline Handle import pymel.core as pm ik = pm.selected()[0] joints = ik.getJointList() curve = ik.getCurve() curveInfo = pm.arclen(curve, ch=True) md = pm.createNode('multiplyDivide') md.operation.set(2) length = curveInfo.arcLength.get() md.input2X.set(length) curveInfo.arcLength >> md.input1X for j in joints: md.outputX >> j.sx import pymel.core as pm for bind_joint in pm.selected(): rig_joint = pm.PyNode(bind_joint.name().replace('dst', 'src')) dMatrix = pm.createNode('decomposeMatrix') rig_joint.worldMatrix[0] >> dMatrix.inputMatrix dMatrix.outputRotate >> bind_joint.jointOrient dMatrix.outputTranslate >> bind_joint.translate
def addFkOperator(self, i, rootWorld_node, crv_node): fk_local_npo_xfoms = [] if i not in [len(self.guide.apos), 0]: xform = getTransform(self.fk_local_npo[i]) fk_local_npo_xfoms.append(xform) # break FK hierarchical orient if i not in [len(self.guide.apos), 0]: s = self.fk_ctl[i - 1] s2 = self.fk_npo[i] d = self.fk_local_npo[i] mulmat_node = applyop.gear_mulmatrix_op(s2.attr("matrix"), s.attr("matrix")) mulmat_node2 = applyop.gear_mulmatrix_op(mulmat_node.attr("output"), s2.attr("inverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node2 + ".output") pm.connectAttr(dm_node + ".outputTranslate", d.attr("t")) check_list = (pm.Attribute, unicode, str) # noqa cond = pm.createNode("condition") pm.setAttr(cond + ".operation", 4) # greater attribute.connectSet(self.fk_collapsed_att, cond + ".secondTerm", check_list) attribute.connectSet(dm_node + ".outputRotate", cond + ".colorIfTrue", check_list) pm.setAttr(cond + ".colorIfFalseR", 0.) pm.setAttr(cond + ".colorIfFalseG", 0.) pm.setAttr(cond + ".colorIfFalseB", 0.) pm.connectAttr(cond + ".outColor", d.attr("r")) # References if i == 0: # we add extra 10% to the first position u = (1.0 / (len(self.guide.apos) - 1.0)) / 10000 else: u = getCurveUAtPoint(self.slv_crv, self.guide.apos[i]) tmp_div_npo_transform = getTransform(self.div_cns_npo[i]) # to fix mismatch before/after later cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 0) # front axis is 'X' # Roll # choose ik_ctls for _i, uv in enumerate(self.ik_uv_param): if u < uv: ik_a = self.ik_ctl[_i - 1] ik_b = self.ik_ctl[_i] roll_a = self.ik_decompose_rot[_i - 1] roll_b = self.ik_decompose_rot[_i] ratio = (uv - u) * (self.settings["ikNb"] - 1) break else: ik_a = self.ik_ctl[-2] ik_b = self.ik_ctl[-1] roll_a = self.ik_decompose_rot[-2] roll_b = self.ik_decompose_rot[-1] ratio = 1. intMatrix = applyop.gear_intmatrix_op( ik_a + ".worldMatrix", ik_b + ".worldMatrix", ratio) dm_node = node.createDecomposeMatrixNode(intMatrix + ".output") # pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate")) pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True) pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector") self.div_cns_npo[i].setMatrix(tmp_div_npo_transform, worldSpace=True) # rotationdriver roll_ratio = (i + 1.00) / len(self.fk_ctl) mul1 = pm.createNode("multDoubleLinear") pm.connectAttr(roll_a.attr("outRoll"), mul1.attr("input1")) pm.setAttr(mul1.attr("input2"), ratio) mul2 = pm.createNode("multDoubleLinear") pm.connectAttr(roll_b.attr("outRoll"), mul2.attr("input1")) pm.setAttr(mul2.attr("input2"), (1. - ratio)) add = pm.createNode("addDoubleLinear") pm.connectAttr(mul1.attr("output"), add.attr("input1")) pm.connectAttr(mul2.attr("output"), add.attr("input2")) compose_rot = pm.createNode("composeRotate") pm.setAttr(compose_rot.attr("axisOrientX"), 90.0) pm.setAttr(compose_rot.attr("axisOrientZ"), 90.0) pm.connectAttr(add.attr("output"), compose_rot.attr("roll")) pm.connectAttr(compose_rot.attr("outRotate"), self.div_roll_npo[i].attr("rotate")) # compensate scale reference div_node = node.createDivNode( [1, 1, 1], [rootWorld_node + ".outputScaleX", rootWorld_node + ".outputScaleY", rootWorld_node + ".outputScaleZ"]) # Squash n Stretch op = applyop.gear_squashstretch2_op(self.scl_transforms[i], self.root, pm.arclen(self.slv_crv), "y", div_node + ".output") pm.connectAttr(self.volume_att, op + ".blend") pm.connectAttr(crv_node + ".arcLength", op + ".driver") # pm.connectAttr(self.st_att[i], op + ".stretch") # pm.connectAttr(self.sq_att[i], op + ".squash") # Controlers tmp_local_npo_transform = getTransform(self.fk_local_npo[i]) # to fix mismatch before/after later if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_roll_npo[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) elif i != len(self.guide.apos) - 1: mulmat_node = applyop.gear_mulmatrix_op( self.div_roll_npo[i].attr("worldMatrix"), self.div_roll_npo[i - 1].attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") mul_node = node.createMulNode(div_node + ".output", dm_node + ".outputTranslate") pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t")) else: pass if i == len(self.guide.apos) - 1: # pm.connectAttr(dm_node + ".outputRotate", self.fk_local_npo2.attr("r")) _ = pm.parentConstraint(self.ik_ctl[-1], self.fk_local_npo2, skipTranslate=("x", "y", "z"), maintainOffset=True) else: pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) # self.addOperatorsOrientationLock(i, cns) self.fk_local_npo[i].setMatrix(tmp_local_npo_transform, worldSpace=True) # References if i < (len(self.fk_ctl) - 1): if self.negate: aim = (0., 1., 0.) upv = (0., 0., 1.) else: aim = (0., -1., 0.) upv = (0., 0., -1.) pm.aimConstraint(self.div_cns_npo[i + 1], self.div_cns_npo[i], mo=True, worldUpType="object", worldUpObject=self.fk_upvectors[i], worldUpVector=(0., 1., 0.), aimVector=aim, upVector=upv, )
def createIKspline(IK_chain = None, ikSpineGrp = None): """ maj: x-- add pelvis control -- add follow on mid ctrl debug: -- orient ik mid ctrl in the same orientation then other controllers """ # insert joints # global IKjointList, dwCtrl,upCtrl IKjointList = [] jointIt = 3 for jnt in IK_chain: IKjointList.append(jnt) child = jnt.getChildren() if len(child)>0: num = jointIt rad = pm.joint(jnt, query = True , radius = True)[0] dist = pm.joint(child[0], query = True , relative = True, position = True)[0] gap = dist/(num) for i in range((num-1),0,-1): newJnt = pm.insertJoint(jnt) pm.joint( newJnt, edit = True,component = True, relative = True, radius = rad, position = ((gap*i),0,0)) IKjointList.append(newJnt) # create ikhandle IKspine = pm.ikHandle(solver = "ikSplineSolver", name = "IKspine", simplifyCurve = True, startJoint = IK_chain[0], endEffector = IK_chain[(len(IK_chain)-1)], createCurve = True, numSpans = 4) IKhandle = IKspine[0] IKcurve = IKspine[2] IKhandle.setParent(ikSpineGrp) curveJointList = pm.ikHandle(IKhandle, query = True, jointList = True) # create clusters on point cvsList = (IKcurve.getShape()).getCVs() clusterGrp = pm.group(name = "cluster_grp", empty = True) clusterGrp.setParent(ikSpineGrp) ctrlGrp = pm.group(name = "IK_ctrls_grp", empty = True) ctrlGrp.setParent(ikSpineGrp) # parent cluster to sphere ctrlList = [] clusterList = [] for i,cv in enumerate(cvsList): cluster = pm.cluster("curve1.cv[%s]" % i) cluster[0].setAttr("relative", 1) tmpCluster = cluster[1] tmpCluster.setParent(clusterGrp) clusterList.append(tmpCluster) oneCtrl = helpers.createNurbsSphere(rad = 0.5) ctrlList.append(oneCtrl) # oneCtrl.setParent(ctrlGrp) tmpPoint = pm.pointConstraint(tmpCluster, oneCtrl) pm.delete(tmpPoint) pm.pointConstraint(oneCtrl, tmpCluster) for c in ctrlList: c.setParent(ctrlGrp) ctrlListGrp = helpers.insertGroups(ctrlList) # create main ctrls # orient up and down ctrls as joint selection upCtrlGrp, upCtrl = helpers.createOneCircle([1,0,0], sel = sel[0], rad = 4, suf= "_IK_ctrl") dwCtrlGrp, dwCtrl = helpers.createOneCircle([1,0,0], sel = sel[len(sel)-1], rad = 4, suf= "_IK_ctrl") idMid = int((pm.datatypes.round(float(len(ctrlListGrp))/2)) - 1) midCtrlGrp, midCtrl = helpers.createOneCircle([0,1,0], sel = ctrlList[idMid], rad = 4, suf= "_IK_ctrl") upCtrlGrp.setParent(ctrlGrp) dwCtrlGrp.setParent(ctrlGrp) midCtrlGrp.setParent(ctrlGrp) upLoc = helpers.createOneLoc(parentToWorld = False, s = upCtrl) dwLoc = helpers.createOneLoc(parentToWorld = False, s = dwCtrl) upLoc.setAttr("tz", 2) dwLoc.setAttr("tz", 2) # parent sphere ctrls to main ctrls ctrlListGrp[0].setParent(upCtrl) ctrlListGrp[1].setParent(upCtrl) ctrlListGrp[idMid - 1].setParent(midCtrl) ctrlListGrp[idMid].setParent(midCtrl) ctrlListGrp[idMid + 1].setParent(midCtrl) ctrlListGrp[(len(ctrlListGrp)-2)].setParent(dwCtrl) ctrlListGrp[(len(ctrlListGrp)-1)].setParent(dwCtrl) # add twist IKhandle.setAttr("dTwistControlEnable", 1) IKhandle.setAttr("dWorldUpType", 2) IKhandle.setAttr("dWorldUpAxis", 3) pm.connectAttr(upLoc.worldMatrix, IKhandle.dWorldUpMatrix, force = True) pm.connectAttr(dwLoc.worldMatrix, IKhandle.dWorldUpMatrixEnd, force = True) #### add stretch # add parameters on upper control pm.addAttr(dwCtrl, longName = "________", attributeType = "enum", enumName = "CTRLS:") pm.setAttr(dwCtrl.________, keyable = True, lock = True) # make stretch editable pm.addAttr(dwCtrl, longName = "stretch", attributeType = "double", min = 0, max = 1, dv = 0) # pm.addAttr(dwCtrl, longName = "squash", attributeType = "double", min = 0, max = 1, dv = 0) pm.addAttr(dwCtrl, longName = "followJoint", attributeType = "double", min = 0, max = 1, dv = 1) pm.addAttr(dwCtrl, longName = "followCtrl", attributeType = "double", min = 0, max = 1, dv = 0) pm.setAttr(dwCtrl.stretch, keyable = True) # pm.setAttr(dwCtrl.squash, keyable = True) pm.setAttr(dwCtrl.followJoint, keyable = True) pm.setAttr(dwCtrl.followCtrl, keyable = True) subFollowNode = pm.createNode('plusMinusAverage', name = "follow_mode_compense") subFollowNode.setAttr("input1D[0]", 1) subFollowNode.setAttr('operation', 2) pm.connectAttr(dwCtrl.followJoint, subFollowNode.input1D[1], f = True) pm.connectAttr(subFollowNode.output1D, dwCtrl.followCtrl, f = True) newJointsNum = (len(IKjointList)) # add arclenght on curve arcLenNode = pm.arclen(IKcurve, ch = True) defaultSize = arcLenNode.getAttr("arcLength") # multiply/divide default size by current size mdNode = pm.createNode("multiplyDivide") mdNode.setAttr("operation", 2 ) mdNode.setAttr("input2X", arcLenNode.getAttr("arcLength") ) pm.connectAttr(arcLenNode.arcLength, mdNode.input1X) # average to calculate stretch addition : stretch - 1 addStretchNode = pm.createNode("plusMinusAverage", name = "add_stretch") addStretchNode.setAttr("operation", 2) pm.connectAttr(mdNode.outputX, addStretchNode.input1D[0]) addStretchNode.setAttr("input1D[1]", 1) # multiplydivide to mutiply stretch addition by strecth parameter stretchMultiplyNode = pm.createNode("multiplyDivide", name = "multiply_stretch") pm.connectAttr(addStretchNode.output1D, stretchMultiplyNode.input1X) pm.connectAttr(dwCtrl.stretch, stretchMultiplyNode.input2X) # average to addition 1 + stretch addition addStretchFinalNode = pm.createNode("plusMinusAverage", name = "add_stretch") addStretchFinalNode.setAttr("operation", 1) pm.connectAttr(stretchMultiplyNode.outputX, addStretchFinalNode.input1D[0]) addStretchFinalNode.setAttr("input1D[1]", 1) for jnt in IKjointList: jntNode = (pm.PyNode(jnt)) try: pm.connectAttr(addStretchFinalNode.output1D, jntNode.scaleX) except: print(Exception) ## add parametrable squash ## follow control on neck lastJoint = IKjointList[-1] IKfollowJnt = pm.duplicate(lastJoint, name = (lastJoint.nodeName() + "_follow"))[0] IKfollowJnt.setAttr("scaleX", 1) IKfollowJnt.setParent(ikSpineGrp) """ tmp = IKfollowJnt.getParent() if tmp: tmp.setAttr("scaleX", 1) IKfollowJnt.setParent(world = True) pm.delete(tmp) """ constrain = pm.parentConstraint(dwCtrl, IK_chain[len(IK_chain)-1], IKfollowJnt) for attr in pm.listAttr(constrain, visible = True, keyable= True): if 'IKW' in attr: # print(attr) pm.connectAttr(dwCtrl.followJoint, '%s.%s' % (constrain,attr)) ikFound = True elif 'ctrl' in attr: # print(attr) pm.connectAttr(dwCtrl.followCtrl, '%s.%s' % (constrain,attr)) ##### ik pelvis # follow control on pelvis # duplicate first joint as follow_pelvis_joint pelvisIKjoint = pm.duplicate(IKjointList[0], parentOnly = True, name = (IKjointList[0].nodeName() + "_pelvis_follow_joint"))[0] pelvisIKjoint.jointOrient.set([0,0,0]) # duplicate down ctrl as pelvis ctrl pelvisIKctrlList = pm.duplicate(upCtrl, name = (upCtrl.nodeName() + "_pelvis")) pelvisIKctrl = pelvisIKctrlList[0] toDel = pm.listRelatives(pelvisIKctrl, children = True, type = "transform") pm.delete(toDel) manageCtrl.scaleShape(sel = pelvisIKctrl, scalX = True, scalY = True, scalZ = True, scale = 0.9) # parent pelvis ctrl under down ctrl pm.parent(pelvisIKctrl, upCtrl) helpers.createOneHelper(sel = pelvisIKctrl, freezeGrp = False, hierarchyParent = "insert") # add loc on IKjointList[0] IKpelvisJointLocGrp, IKpelvisJointLoc = helpers.createOneHelper(type = "loc", sel = IKjointList[0], freezeGrp = False, hierarchyParent = "child") # add loc on pelvis ctrl IKpelvisCtrlLocGrp, IKpelvisCtrlLoc = helpers.createOneHelper(type = "loc", sel = pelvisIKctrl, freezeGrp = False, hierarchyParent = "child") # parent constraint follow_pelvis_joint to locs IKpelvisConstraint = pm.parentConstraint(IKpelvisJointLoc, IKpelvisCtrlLoc, pelvisIKjoint) # add attributes on base controller pm.addAttr(upCtrl, ln = "_______" , attributeType = "enum", enumName = "CTRLS:") pm.addAttr(upCtrl, ln = "followJoint" , at = 'double', min = 0, max = 1, dv = 0) pm.addAttr(upCtrl, ln = "followCtrl" , at = 'double', min = 0, max = 1) pm.setAttr(upCtrl._______ , keyable = True, lock = True) pm.setAttr(upCtrl.followJoint, keyable = True) pm.setAttr(upCtrl.followCtrl, keyable = True) pelvisSubFollowNode = pm.createNode('plusMinusAverage', name = "pelvis_follow_mode_compense") pelvisSubFollowNode.setAttr("input1D[0]", 1) pelvisSubFollowNode.setAttr('operation', 2) pm.connectAttr(upCtrl.followJoint, pelvisSubFollowNode.input1D[1], f = True) pm.connectAttr(pelvisSubFollowNode.output1D, upCtrl.followCtrl, f = True) # connect attributes to constraint parent contraintList = pm.parentConstraint(IKpelvisConstraint, query = True, targetList = True ) # pprint(contraintList) weightAliasList = pm.parentConstraint(IKpelvisConstraint, query = True, weightAliasList = True ) # pprint(weightAliasList) # pprint(IKpelvisJointLoc) for i,c in enumerate(contraintList): if c == IKpelvisJointLoc: pm.connectAttr(upCtrl.followJoint, weightAliasList[i] ) elif c == IKpelvisCtrlLoc: pm.connectAttr(upCtrl.followCtrl, weightAliasList[i] ) ## constraint deformation system to follow ik # return good array of ik joint to parent on return IKfollowJnt, pelvisIKjoint
def addOperators(self): # Visibilities ------------------------------------- # fk fkvis_node = nod.createReverseNode(self.blend_att) for shp in self.fk0_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk1_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) for shp in self.fk2_ctl.getShapes(): pm.connectAttr(fkvis_node + ".outputX", shp.attr("visibility")) # ik for shp in self.upv_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ikcns_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.ik_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- att.setRotOrder(self.fk0_ctl, "XZY") att.setRotOrder(self.fk1_ctl, "XYZ") att.setRotOrder(self.fk2_ctl, "YZX") att.setRotOrder(self.ik_ctl, "ZYX") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.gear_ikfk2bone_op(out, self.root, self.ik_ref, self.upv_ctl, self.fk_ctl[0], self.fk_ctl[1], self.fk_ref, self.length0, self.length1, self.negate) pm.connectAttr(self.blend_att, node + ".blend") pm.connectAttr(self.roll_att, node + ".roll") pm.connectAttr(self.scale_att, node + ".scaleA") pm.connectAttr(self.scale_att, node + ".scaleB") pm.connectAttr(self.maxstretch_att, node + ".maxstretch") pm.connectAttr(self.slide_att, node + ".slide") pm.connectAttr(self.softness_att, node + ".softness") pm.connectAttr(self.reverse_att, node + ".reverse") # Twist references --------------------------------- node = aop.gear_mulmatrix_op(self.eff_loc.attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputTranslate", self.tws2_npo.attr("translate")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(node + ".output", dm_node + ".inputMatrix") pm.connectAttr(dm_node + ".outputRotate", self.tws2_npo.attr("rotate")) #spline IK for twist jnts self.ikhArmTwist, self.armTwistCrv = aop.splineIK( self.getName("armTwist"), self.armTwistChain, parent=self.root, cParent=self.bone0) self.ikhForearmTwist, self.forearmTwistCrv = aop.splineIK( self.getName("forearmTwist"), self.forearmTwistChain, parent=self.root, cParent=self.bone1) #references self.ikhArmRef, self.tmpCrv = aop.splineIK(self.getName("armRollRef"), self.armRollRef, parent=self.root, cParent=self.bone0) self.ikhForearmRef, self.tmpCrv = aop.splineIK( self.getName("forearmRollRef"), self.forearmRollRef, parent=self.root, cParent=self.eff_loc) self.ikhAuxTwist, self.tmpCrv = aop.splineIK(self.getName("auxTwist"), self.auxTwistChain, parent=self.root, cParent=self.eff_loc) #setting connexions for ikhArmTwist self.ikhArmTwist.attr("dTwistControlEnable").set(True) self.ikhArmTwist.attr("dWorldUpType").set(4) self.ikhArmTwist.attr("dWorldUpAxis").set(3) self.ikhArmTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhArmTwist.attr("dWorldUpVectorY").set(0.0) self.ikhArmTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhArmTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.armRollRef[0].attr("worldMatrix[0]"), self.ikhArmTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.bone0.attr("worldMatrix[0]"), self.ikhArmTwist.attr("dWorldUpMatrixEnd")) #setting connexions for ikhAuxTwist self.ikhAuxTwist.attr("dTwistControlEnable").set(True) self.ikhAuxTwist.attr("dWorldUpType").set(4) self.ikhAuxTwist.attr("dWorldUpAxis").set(3) self.ikhAuxTwist.attr("dWorldUpVectorZ").set(1.0) self.ikhAuxTwist.attr("dWorldUpVectorY").set(0.0) self.ikhAuxTwist.attr("dWorldUpVectorEndZ").set(1.0) self.ikhAuxTwist.attr("dWorldUpVectorEndY").set(0.0) pm.connectAttr(self.forearmRollRef[0].attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrix")) pm.connectAttr(self.eff_loc.attr("worldMatrix[0]"), self.ikhAuxTwist.attr("dWorldUpMatrixEnd")) pm.connectAttr(self.auxTwistChain[1].attr("rx"), self.ikhForearmTwist.attr("twist")) pm.parentConstraint(self.bone1, self.aux_npo, maintainOffset=True) #scale arm length for twist chain (not the squash and stretch) arclen_node = pm.arclen(self.armTwistCrv, ch=True) alAttrArm = arclen_node.attr("arcLength") muldiv_nodeArm = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeArm.attr("input1X")) muldiv_nodeArm.attr("input2X").set(alAttrArm.get()) muldiv_nodeArm.attr("operation").set(2) for jnt in self.armTwistChain: pm.connectAttr(muldiv_nodeArm.attr("outputX"), jnt.attr("sx")) #scale forearm length for twist chain (not the squash and stretch) arclen_node = pm.arclen(self.forearmTwistCrv, ch=True) alAttrForearm = arclen_node.attr("arcLength") muldiv_nodeForearm = pm.createNode("multiplyDivide") pm.connectAttr(arclen_node.attr("arcLength"), muldiv_nodeForearm.attr("input1X")) muldiv_nodeForearm.attr("input2X").set(alAttrForearm.get()) muldiv_nodeForearm.attr("operation").set(2) for jnt in self.forearmTwistChain: pm.connectAttr(muldiv_nodeForearm.attr("outputX"), jnt.attr("sx")) #scale compensation for the first twist join dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix[0]"), dm_node.attr("inputMatrix")) pm.connectAttr(dm_node.attr("outputScale"), self.armTwistChain[0].attr("inverseScale")) pm.connectAttr(dm_node.attr("outputScale"), self.forearmTwistChain[0].attr("inverseScale")) #tangent controls muldiv_node = pm.createNode("multiplyDivide") muldiv_node.attr("input2X").set(-1) pm.connectAttr(self.tws1A_npo.attr("rz"), muldiv_node.attr("input1X")) muldiv_nodeBias = pm.createNode("multiplyDivide") pm.connectAttr(muldiv_node.attr("outputX"), muldiv_nodeBias.attr("input1X")) pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X")) pm.connectAttr(muldiv_nodeBias.attr("outputX"), self.tws1A_loc.attr("rz")) if self.negate: axis = "xz" else: axis = "-xz" aop.aimCns(self.tws1A_npo, self.tws0_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) aop.aimCns(self.forearmTangentB_loc, self.forearmTangentA_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) pm.pointConstraint(self.eff_loc, self.forearmTangentB_loc) muldiv_node = pm.createNode("multiplyDivide") muldiv_node.attr("input2X").set(-1) pm.connectAttr(self.tws1B_npo.attr("rz"), muldiv_node.attr("input1X")) muldiv_nodeBias = pm.createNode("multiplyDivide") pm.connectAttr(muldiv_node.attr("outputX"), muldiv_nodeBias.attr("input1X")) pm.connectAttr(self.roundness_att, muldiv_nodeBias.attr("input2X")) pm.connectAttr(muldiv_nodeBias.attr("outputX"), self.tws1B_loc.attr("rz")) if self.negate: axis = "-xz" else: axis = "xz" aop.aimCns(self.tws1B_npo, self.tws2_loc, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) aop.aimCns(self.armTangentA_loc, self.armTangentB_npo, axis=axis, wupType=2, wupVector=[0, 0, 1], wupObject=self.mid_ctl, maintainOffset=False) # Volume ------------------------------------------- distA_node = nod.createDistNode(self.tws0_loc, self.tws1_loc) distB_node = nod.createDistNode(self.tws1_loc, self.tws2_loc) add_node = nod.createAddNode(distA_node + ".distance", distB_node + ".distance") div_node = nod.createDivNode(add_node + ".output", self.root.attr("sx")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(self.root.attr("worldMatrix"), dm_node + ".inputMatrix") div_node2 = nod.createDivNode(div_node + ".outputX", dm_node + ".outputScaleX") self.volDriver_att = div_node2 + ".outputX" # connecting tangent scaele compensation after volume to aboid duplicate some nodes ------------------------------ distA_node = nod.createDistNode(self.tws0_loc, self.mid_ctl) distB_node = nod.createDistNode(self.mid_ctl, self.tws2_loc) div_nodeArm = nod.createDivNode(distA_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = nod.createDivNode(div_nodeArm + ".outputX", distA_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1A_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.armTangentA_loc.attr("sx")) div_nodeForearm = nod.createDivNode(distB_node + ".distance", dm_node.attr("outputScaleX")) div_node2 = nod.createDivNode(div_nodeForearm + ".outputX", distB_node.attr("distance").get()) pm.connectAttr(div_node2.attr("outputX"), self.tws1B_loc.attr("sx")) pm.connectAttr(div_node2.attr("outputX"), self.forearmTangentB_loc.attr("sx")) #conection curve aop.gear_curvecns_op(self.armTwistCrv, [ self.armTangentA_loc, self.armTangentA_ctl, self.armTangentB_ctl, self.elbowTangent_ctl ]) aop.gear_curvecns_op(self.forearmTwistCrv, [ self.elbowTangent_ctl, self.forearmTangentA_ctl, self.forearmTangentB_ctl, self.forearmTangentB_loc ]) #Tangent controls vis pm.connectAttr(self.tangentVis_att, self.armTangentA_ctl.attr("visibility")) pm.connectAttr(self.tangentVis_att, self.armTangentB_ctl.attr("visibility")) pm.connectAttr(self.tangentVis_att, self.forearmTangentA_ctl.attr("visibility")) pm.connectAttr(self.tangentVis_att, self.forearmTangentB_ctl.attr("visibility")) pm.connectAttr(self.tangentVis_att, self.elbowTangent_ctl.attr("visibility")) # Divisions ---------------------------------------- # at 0 or 1 the division will follow exactly the rotation of the controler.. and we wont have this nice tangent + roll for i, div_cns in enumerate(self.div_cns): if i < (self.settings["div0"] + 2): mulmat_node = aop.gear_mulmatrix_op( self.armTwistChain[i] + ".worldMatrix", div_cns + ".parentInverseMatrix") else: mulmat_node = aop.gear_mulmatrix_op( self.forearmTwistChain[i - (self.settings["div0"] + 2)] + ".worldMatrix", div_cns + ".parentInverseMatrix") dm_node = nod.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", div_cns + ".t") pm.connectAttr(dm_node + ".outputRotate", div_cns + ".r") # Squash n Stretch node = aop.gear_squashstretch2_op(div_cns, None, pm.getAttr(self.volDriver_att), "x") pm.connectAttr(self.volume_att, node + ".blend") pm.connectAttr(self.volDriver_att, node + ".driver") pm.connectAttr(self.st_att[i], node + ".stretch") pm.connectAttr(self.sq_att[i], node + ".squash") # return # NOTE: next line fix the issue on meters. # This is special case becasuse the IK solver from mGear use the scale as lenght and we have shear # TODO: check for a more clean and elegant solution instead of re-match the world matrix again tra.matchWorldTransform(self.fk_ctl[0], self.match_fk0_off) tra.matchWorldTransform(self.fk_ctl[1], self.match_fk1_off) tra.matchWorldTransform(self.fk_ctl[0], self.match_fk0) tra.matchWorldTransform(self.fk_ctl[1], self.match_fk1) # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True)
def build_joint_chain(name=None, crv=None, order=None, num=None, loc=None, reg_node=None, log=False): '''Given a valid curve, build joint chain along curve, num joints long Attributes: name -- Prefix name for plane. Str crv -- Curve to use as build guide. pm.nt.Transform order -- ['xyz','xzy','yxz','yzx','zxy','zyx'] num -- Number of joints. 3 - 50, Int loc -- Used to set aim of secondary axis nt.Transform reg_node -- Registratioin node. nt.Transform log -- Output logging messages. Bool ''' general.check_type(name, 'name', [str]) general.check_type(crv, 'crv', [pm.nt.Transform]) general.check_type(order, 'order', [str]) general.check_type(num, 'num', [int]) general.check_type(loc, 'loc', [pm.nt.Transform]) orders = ['xyz', 'xzy', 'yxz', 'yzx', 'zxy', 'zyx'] if order not in orders: raise errors.InputError('order', order, orders) if num < 3 or num > 50: raise errors.InputError('num', num, 'Range: 3 - 50') loc = loc.duplicate()[0] chain = [] loc_v = None incr = float(1.0/num) if log: str_1 = 'Curve Length: ', pm.arclen(crv) str_2 = 'Increment: ', incr general.logging.debug(str_1) general.logging.debug(str_2) param = 0 pm.select(clear=1) for i in range(num): pos = pm.pointOnCurve(crv, pr=param, p=True, top=True) if i == 0: # Get vector to locator pos_v = pm.dt.Vector(pos) loc_pos = pm.dt.Vector(pm.xform(loc, q=1, ws=1, rp=1)) loc_v = loc_pos - pos_v if log: str_1 = 'Jnt Pos: ', pos_v str_2 = 'Loc Pos: ', loc_pos str_3 = 'Loc Vec: ', loc_v general.logging.debug(str_1) general.logging.debug(str_2) general.logging.debug(str_3) j = pm.joint(p=pos, name='%s_Jnt_%s' % (name, (i+1))) chain.append(j) if log: str_1 = 'Created Joint: ', j str_2 = 'Parameter: ', param str_3 = 'Pos: ', pos str_4 = 'Curve: ', crv general.logging.debug(str_1) general.logging.debug(str_2) general.logging.debug(str_3) general.logging.debug(str_4) param += incr if log: str_1 = 'Chain: ', str(chain) general.logging.debug(str_1) # aim vector aim_v = [] if order[0].lower() == 'x': aim_v = [1, 0, 0] if order[0].lower() == 'y': aim_v = [0, 1, 0] if order[0].lower() == 'z': aim_v = [0, 0, 1] # up vector up_v = [] if order[1].lower() == 'x': up_v = [1, 0, 0] if order[1].lower() == 'y': up_v = [0, 1, 0] if order[1].lower() == 'z': up_v = [0, 0, 1] for jnt in chain[:-1]: # Snap/parent locator to jnt pm.parent(loc, jnt) loc.setTranslation(0) loc.setRotation([0, 0, 0]) # move by loc_v pm.move(loc_v[0], loc_v[1], loc_v[2], loc, r=1) pm.parent(loc, w=1) # Remove joint from hierarchy p = jnt.getParent() c = jnt.getChildren() try: pm.parent(jnt, w=1) except: pass pm.parent(c, w=1) # Aim to child pm.delete(pm.aimConstraint(c, jnt, aim=aim_v, wu=up_v, wut='object', wuo=loc, mo=0)) # Reinsert to heirarchy if c: pm.parent(c, jnt) if p: pm.parent(jnt, p) # Oreint last joint to none pm.joint(chain[-1], e=1, oj='none', zso=True) if not reg_node: reg_node = control.create_register_node(name) control.register_object(reg_node, '%s_chain_root' % name, chain[0]) pm.select(clear=1) pm.delete(loc) return reg_node, chain
def flexiplane(self, prefix=''): """ Build FlexiPlane :param index: number of flexiplane in scene (auto managed by maya) :return: FlexiPlane group node """ fp_name = '%sflexiPlane' % prefix fp_name = nameCheck.nameCheck(fp_name + '*_GRP').replace( '_GRP', '', 1) # flexiPlane_GRP fp_surf = self.create_plane('%s_NURBS' % (fp_name))[0] fp_surf.overrideEnabled.set(1) fp_surf.overrideDisplayType.set(2) # Assign Material self.create_lambret(fp_surf, color=(0.067, 0.737, 0.749), transparency=(0.75, 0.75, 0.75)) # Create Follicles # flc_name = 'flexiPlane' v = 0.1 # 1/width flcs = [] how_many_flc = 5 # width/2 for i in range(0, how_many_flc): ofoll = self.create_follicle( fp_surf, '%s_flc_%s_FLC' % (fp_name, letters[i + 26]), v, 0.5) flcs.append(ofoll) v += 0.2 # (1/width)*2 # Group Follicles flc_grp = pm.group(flcs, name='%s_flcs_GRP' % (fp_name)) # creates flexiPlane controls curves at each end self.ctrl_a = self.ctrl_square(name='%s_ctrl_a_CTRL' % (fp_name), pos=[-5, 0, 0]) ctrl_ashape = self.ctrl_a.getShape() pm.rename(ctrl_ashape, '%sShape' % self.ctrl_a) self.ctrl_b = self.ctrl_square(name='%s_ctrl_b_CTRL' % (fp_name), pos=[5, 0, 0]) ctrl_bshape = self.ctrl_b.getShape() pm.rename(ctrl_bshape, '%sShape' % self.ctrl_b) pm.select(cl=True) # creates flexiPlane blendshape # blendshape suffix: _bShp_ fp_bshp = pm.duplicate(fp_surf, n='%s_bshp_NURBS' % (fp_name))[0] pm.move(0, 0, -5, fp_bshp) fps_bshp_node = pm.blendShape(fp_bshp, fp_surf, n='%s_BSHP' % (fp_name))[0] pm.setAttr('%s.%s' % (fps_bshp_node, fp_bshp), 1) # pm.rename('tweak1', '%sbshp_%stweak_01' % (fp_name, sur)) # creates curve for wire deformer fp_curve = pm.curve(d=2, p=[(-5, 0, -5), (0, 0, -5), (5, 0, -5)], k=[0, 0, 1, 1], n='%s_wire_CV' % (fp_name)) cl_a, cl_b, cl_mid = self.cluster_curve(fp_curve, fp_name) # create and place twist deformer pm.select(fp_bshp) fp_twist = pm.nonLinear(type='twist', lowBound=-1, highBound=1) # displays warning: pymel.core.general : could not create desired mfn. Defaulting MfnDependencyNode. # doesn't seem to affect anything though pm.rename(fp_twist[0], '%s_twistAttr_surface_NURBS' % (fp_name)) pm.rename(fp_twist[1], '%s_twist_Handle_DEFORMER' % (fp_name)) fp_twist[1].rz.set(90) # connect start and end angle to their respective control connect = self.ctrl_b.rx >> fp_twist[0].startAngle connect = self.ctrl_a.rx >> fp_twist[0].endAngle # skins wire to blendshape fp_wire = pm.wire( fp_bshp, w=fp_curve, gw=False, en=1, ce=0, li=0, # dds=(0, 20), n='%s_wireAttrs_DEFORMER' % (fp_name)) fp_wire[0].dropoffDistance[0].set(20) hist = pm.listHistory(fp_surf) tweaks = [t for t in hist if 'tweak' in t.nodeName()] pm.rename(tweaks[2], '%s_cl_cluster_tweak' % (fp_name)) pm.rename(tweaks[0], '%s_wireAttrs_tweak' % (fp_name)) pm.rename(tweaks[1], '%s_extra_tweak' % (fp_name)) # group clusters cl_grp = pm.group(cl_a[1], cl_b[1], cl_mid[1], n='%s_cls_GRP' % (fp_name)) util.lock_and_hide_all(cl_grp) # creates mid control self.ctrl_mid = self.flexiplane_mid_ctrl(name='%s_ctrl_mid_CTRL' % (fp_name)) ctrl_mid_grp = pm.group(self.ctrl_mid, n='%s_grp_midBend_GRP' % (fp_name)) pm.pointConstraint(self.ctrl_a, self.ctrl_b, ctrl_mid_grp, o=[0, 0, 0], w=1) # groups controls together and locks and hides group attributes ctrl_grp = pm.group(self.ctrl_a, self.ctrl_b, ctrl_mid_grp, n='%s_ctrl_GRP' % (fp_name)) util.lock_and_hide_all(ctrl_grp) # connecting translate attrs of control curves for to the clusters connect = [] connect.append(self.ctrl_a.t >> cl_a[1].t) connect.append(self.ctrl_b.t >> cl_b[1].t) connect.append(self.ctrl_mid.t >> cl_mid[1].t) # makes mid_ctrl, flexiPlane and blendShape surfaces non renderable util.no_render(fp_surf) util.no_render(fp_bshp) util.no_render(self.ctrl_mid) # groups everything under 1 group then locks and hides the transform attrs of that group #flexiPlane_wire_surface0101BaseWire self.fp_grp = pm.group( fp_surf, flc_grp, fp_bshp, fp_wire, # '%s_wire_%s_BaseWire_GRP' % (fp_name, self.surfaceSuffix), cl_grp, ctrl_grp, n='%s_GRP' % (fp_name)) util.lock_and_hide_all(self.fp_grp) # creates global move group and extraNodes fp_gm_grp = pm.group(fp_surf, ctrl_grp, n='%s_globalMove_GRP' % (fp_name)) fp_xnodes_grp = pm.group(flc_grp, fp_bshp, fp_wire, '%s_wire_CVBaseWire' % (fp_name), cl_grp, n='%s_extraNodes_GRP' % (fp_name)) pm.parent(fp_twist, fp_xnodes_grp) pm.parent(fp_xnodes_grp, self.fp_grp) fp_xnodes_grp.overrideEnabled.set(1) fp_xnodes_grp.overrideDisplayType.set(2) # scale constrains follicles to global move group for follicle in flcs: mparent = follicle.getParent() pm.scaleConstraint(fp_gm_grp, mparent) # creates global move control self.fp_gm_ctrl = self.global_ctrl(name=fp_name) # moves global control into flexiPlane group then parent global move group to global move control. pm.parent(self.fp_gm_ctrl, self.fp_grp) pm.parent(fp_gm_grp, self.fp_gm_ctrl) # joints placement jnts = [] for i in range(0, len(flcs)): posx = round(flcs[i].getParent().translateX.get(), 4) jnt = pm.joint(p=(posx, 0, 0), rad=0.5, n='%sbind_%s_JNT' % (fp_name, letters[i + 26])) jnts.append(jnt) # parent joint under follicle pm.parent(jnt, flcs[i].getParent()) # locks and hides transformNodes flexiPlane surface util.lock_and_hide_all(fp_surf) # hides blendShape, clusters and twist Deformer fp_twist[1].visibility.set(0) cl_grp.visibility.set(0) fp_bshp.visibility.set(0) fp_curve.visibility.set(0) # selects the wire deformer and creates a curve info node... # ...to get the wire deformers length pm.select(fp_curve, r=True) length = pm.arclen(ch=1) length.rename('%scurveInfo_DEFORMER' % (fp_name)) # creates a multiplyDivideNode for squashStretch length... # ...and sets it operation to divide fp_div = pm.createNode('multiplyDivide', n='%sdiv_squashStretch_length' % (fp_name)) fp_div.operation.set(2) # secondary multDivNode for volume, sets input1X to 1 fp_div_vol = pm.createNode('multiplyDivide', n='%sdiv_volume' % (fp_name)) fp_div_vol.operation.set(2) fp_div_vol.input1X.set(1) # creates a conditionNode for global_ctrl enable attr fp_cond = pm.createNode('condition', n='%scond_volume' % (fp_name)) fp_cond.secondTerm.set(1) # connects curve all the nodes connect = length.arcLength >> fp_div.input1.input1X fp_div.input2.input2X.set(10) connect = fp_div.outputX >> fp_div_vol.input2.input2X connect = self.fp_gm_ctrl.enable >> fp_cond.firstTerm connect = fp_div_vol.outputX >> fp_cond.colorIfTrueR fp_ctrl_global = self.fp_gm_ctrl.getShape() for i in range(0, len(flcs)): connect = fp_cond.outColorR >> jnts[i].sy connect = fp_cond.outColorR >> jnts[i].sz flcs[i].visibility.set(0) # hides blendShape, clusters and twist Deformer fp_twist[1].visibility.set(0) cl_grp.visibility.set(0) fp_bshp.visibility.set(0) fp_curve.visibility.set(0) pm.select(self.fp_gm_ctrl, r=True) return self.fp_gm_ctrl
def create_stretchy_ik(ik_handle, prefix): prefix = "%s_stretchy" % prefix joints = ik_handle.getJointList() joints.extend(joints[-1].getChildren(type="joint")) spline_curve = ik_handle.getCurve() stretchy_grp = pm.group(name="%s_grp" % prefix, empty=True) pm.addAttr(stretchy_grp, k=1, at="double", ln="global_scale", dv=1) pm.addAttr(stretchy_grp, k=1, at="double", ln="stretch_toggle", min=0, max=1) pm.addAttr(stretchy_grp, k=1, at="double", ln="extend", min=0.10, dv=1) md = pm.createNode("multiplyDivide", name="%s_scale_md" % prefix) md.operation.set(2) # determine if it's a spline ik if spline_curve: print "spilne ik detected" curveInfo = pm.arclen(spline_curve, name="%s_arcLen" % prefix, ch=True) curveInfo.arcLength >> md.input1X distance = curveInfo.arcLength.get() else: print "ik detected" distance = 0.00 for joint in joints[1::]: distance = distance + joint.tx.get() ik_handle.snapEnable.set(0) ik_handle.stickiness.set(1) distanceBetween = pm.createNode("distanceBetween", name="%s_distanceBetween" % prefix) joints[0].worldMatrix[0] >> distanceBetween.inMatrix1 ik_handle.worldMatrix[0] >> distanceBetween.inMatrix2 condition = pm.createNode("condition", name="%s_condition" % prefix) condition.operation.set(5) # less or equal condition.secondTerm.set(distance) condition.colorIfTrueR.set(distance) distanceBetween.distance >> condition.firstTerm distanceBetween.distance >> condition.colorIfFalseR condition.outColorR >> md.input1X gMd = pm.createNode("multiplyDivide", name="%s_globalScale_mdl" % prefix) gMd.input1X.set(distance) stretchy_grp.global_scale >> gMd.input2X gMd.outputX >> md.input2X bta = pm.createNode("blendTwoAttr", name="%s_toggle_bta" % prefix) bta.input[0].set(1) md.outputX >> bta.input[1] stretchy_grp.stretch_toggle >> bta.attributesBlender tMd = pm.createNode("multiplyDivide", name="%s_tweakScale_md" % prefix) bta.output >> tMd.input1X stretchy_grp.extend >> tMd.input2X for joint in joints[1::]: mdl = pm.createNode("multiplyDivide", name="%s_stretchy_mdl" % joint) mdl.input1X.set(joint.tx.get()) tMd.outputX >> mdl.input2X mdl.outputX >> joint.tx
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ # Auto bend ---------------------------- if self.settings["autoBend"]: mul_node = node.createMulNode( [self.autoBendChain[0].ry, self.autoBendChain[0].rz], [self.sideBend_att, self.frontBend_att]) mul_node.outputX >> self.ik1autoRot_lvl.rz mul_node.outputY >> self.ik1autoRot_lvl.rx self.ikHandleAutoBend = primitive.addIkHandle( self.autoBend_ctl, self.getName("ikHandleAutoBend"), self.autoBendChain, "ikSCsolver") # Tangent position --------------------------------- # common part d = vector.getDistance(self.guide.apos[0], self.guide.apos[-1]) dist_node = node.createDistNode(self.ik0_ctl, self.ik1_ctl) rootWorld_node = node.createDecomposeMatrixNode( self.root.attr("worldMatrix")) div_node = node.createDivNode(dist_node + ".distance", rootWorld_node + ".outputScaleX") div_node = node.createDivNode(div_node + ".outputX", d) # tan0 mul_node = node.createMulNode(self.tan0_att, self.tan0_npo.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan0_npo.attr("ty")) # tan1 mul_node = node.createMulNode(self.tan1_att, self.tan1_npo.getAttr("ty")) res_node = node.createMulNode(mul_node + ".outputX", div_node + ".outputX") pm.connectAttr(res_node + ".outputX", self.tan1_npo.attr("ty")) # Tangent Mid -------------------------------------- if self.settings["centralTangent"]: tanIntMat = applyop.gear_intmatrix_op( self.tan0_npo.attr("worldMatrix"), self.tan1_npo.attr("worldMatrix"), .5) applyop.gear_mulmatrix_op( tanIntMat.attr("output"), self.tan_npo.attr("parentInverseMatrix[0]"), self.tan_npo) pm.connectAttr(self.tan_ctl.attr("translate"), self.tan0_off.attr("translate")) pm.connectAttr(self.tan_ctl.attr("translate"), self.tan1_off.attr("translate")) # Curves ------------------------------------------- op = applyop.gear_curveslide2_op(self.slv_crv, self.mst_crv, 0, 1.5, .5, .5) pm.connectAttr(self.position_att, op + ".position") pm.connectAttr(self.maxstretch_att, op + ".maxstretch") pm.connectAttr(self.maxsquash_att, op + ".maxsquash") pm.connectAttr(self.softness_att, op + ".softness") # Volume driver ------------------------------------ crv_node = node.createCurveInfoNode(self.slv_crv) # Division ----------------------------------------- for i in range(self.settings["division"]): # References u = i / (self.settings["division"] - 1.0) if i == 0: # we add extra 10% to the first vertebra u = (1.0 / (self.settings["division"] - 1.0)) / 10 cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 0) # front axis is 'X' # Roll intMatrix = applyop.gear_intmatrix_op( self.ik0_ctl + ".worldMatrix", self.ik1_ctl + ".worldMatrix", u) dm_node = node.createDecomposeMatrixNode(intMatrix + ".output") pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate")) pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True) pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector") # compensate scale reference div_node = node.createDivNode([1, 1, 1], [ rootWorld_node + ".outputScaleX", rootWorld_node + ".outputScaleY", rootWorld_node + ".outputScaleZ" ]) # Squash n Stretch op = applyop.gear_squashstretch2_op(self.scl_transforms[i], self.root, pm.arclen(self.slv_crv), "y", div_node + ".output") pm.connectAttr(self.volume_att, op + ".blend") pm.connectAttr(crv_node + ".arcLength", op + ".driver") pm.connectAttr(self.st_att[i], op + ".stretch") pm.connectAttr(self.sq_att[i], op + ".squash") # Controlers if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) else: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns[i].attr("worldMatrix"), self.div_cns[i - 1].attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") mul_node = node.createMulNode(div_node + ".output", dm_node + ".outputTranslate") pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t")) pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) # Orientation Lock if i == 0: dm_node = node.createDecomposeMatrixNode(self.ik0_ctl + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori0_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") elif i == self.settings["division"] - 1: dm_node = node.createDecomposeMatrixNode(self.ik1_ctl + ".worldMatrix") blend_node = node.createBlendNode( [dm_node + ".outputRotate%s" % s for s in "XYZ"], [cns + ".rotate%s" % s for s in "XYZ"], self.lock_ori1_att) self.div_cns[i].attr("rotate").disconnect() pm.connectAttr(blend_node + ".output", self.div_cns[i] + ".rotate") # Connections (Hooks) ------------------------------ pm.parentConstraint(self.hip_lvl, self.cnx0) pm.scaleConstraint(self.hip_lvl, self.cnx0) pm.parentConstraint(self.scl_transforms[-1], self.cnx1) pm.scaleConstraint(self.scl_transforms[-1], self.cnx1)
def addOperators(self): """Create operators and set the relations for the component rig Apply operators, constraints, expressions to the hierarchy. In order to keep the code clean and easier to debug, we shouldn't create any new object in this method. """ dm_node_scl = node.createDecomposeMatrixNode(self.root.worldMatrix) if self.settings["keepLength"]: arclen_node = pm.arclen(self.mst_crv, ch=True) alAttr = pm.getAttr(arclen_node + ".arcLength") ration_node = node.createMulNode(self.length_ratio_att, alAttr) pm.addAttr(self.mst_crv, ln="length_ratio", k=True, w=True) node.createDivNode(arclen_node.arcLength, ration_node.outputX, self.mst_crv.length_ratio) div_node_scl = node.createDivNode(self.mst_crv.length_ratio, dm_node_scl.outputScaleX) step = 1.000 / (self.def_number - 1) u = 0.000 for i in range(self.def_number): cnsUpv = applyop.pathCns(self.upv_cns[i], self.upv_crv, cnsType=False, u=u, tangent=False) cns = applyop.pathCns(self.div_cns[i], self.mst_crv, False, u, True) # Connectiong the scale for scaling compensation for axis, AX in zip("xyz", "XYZ"): pm.connectAttr(dm_node_scl.attr("outputScale{}".format(AX)), self.div_cns[i].attr("s{}".format(axis))) if self.settings["keepLength"]: div_node2 = node.createDivNode(u, div_node_scl.outputX) cond_node = node.createConditionNode(div_node2.input1X, div_node2.outputX, 4, div_node2.input1X, div_node2.outputX) pm.connectAttr(cond_node + ".outColorR", cnsUpv + ".uValue") pm.connectAttr(cond_node + ".outColorR", cns + ".uValue") cns.setAttr("worldUpType", 1) cns.setAttr("frontAxis", 0) cns.setAttr("upAxis", 1) pm.connectAttr(self.upv_cns[i].attr("worldMatrix[0]"), cns.attr("worldUpMatrix")) u += step if self.settings["keepLength"]: # add the safty distance offset self.tweakTip_npo.attr("tx").set(self.off_dist) # connect vis line ref for shp in self.line_ref.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) for ctl in self.tweak_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.ikVis_att, shp.attr("visibility")) for ctl in self.fk_ctl: for shp in ctl.getShapes(): pm.connectAttr(self.fkVis_att, shp.attr("visibility")) if self.settings["extraTweak"]: for tweak_ctl in self.extratweak_ctl: for shp in tweak_ctl.getShapes(): pm.connectAttr(self.tweakVis_att, shp.attr("visibility"))
def addFkOperator(self, i, rootWorld_node, crv_node): if i == 0 and self.settings["isSplitHip"]: s = self.fk_hip_ctl d = self.fk_local_npo[0], # maintainOffset, skipRotate, skipTranslate _ = pm.parentConstraint(s, d, mo=True, sr=("x", "y", "z"), st=()) s = self.ik_global_out[0] d = self.hip_fk_local_in, # maintainOffset, skipRotate, skipTranslate pm.parentConstraint(s, d, mo=True) # break FK hierarchical orient if i not in [len(self.guide.apos), 0]: s = self.fk_ctl[i - 1] s2 = self.fk_npo[i] d = self.fk_local_npo[i] mulmat_node = applyop.gear_mulmatrix_op(s2.attr("matrix"), s.attr("matrix")) mulmat_node2 = applyop.gear_mulmatrix_op(mulmat_node.attr("output"), s2.attr("inverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node2 + ".output") pm.connectAttr(dm_node + ".outputTranslate", d.attr("t")) check_list = (pm.Attribute, unicode, str) # noqa cond = pm.createNode("condition") pm.setAttr(cond + ".operation", 4) # greater attribute.connectSet(self.fk_collapsed_att, cond + ".secondTerm", check_list) attribute.connectSet(dm_node + ".outputRotate", cond + ".colorIfTrue", check_list) pm.setAttr(cond + ".colorIfFalseR", 0.) pm.setAttr(cond + ".colorIfFalseG", 0.) pm.setAttr(cond + ".colorIfFalseB", 0.) pm.connectAttr(cond + ".outColor", d.attr("r")) # References if i == 0: # we add extra 10% to the first position u = (1.0 / (len(self.guide.apos) - 1.0)) / 1000 else: u = getCurveUAtPoint(self.slv_crv, self.guide.apos[i]) tmp_div_npo_transform = getTransform(self.div_cns_npo[i]) # to fix mismatch before/after later cns = applyop.pathCns(self.div_cns[i], self.slv_crv, False, u, True) cns.setAttr("frontAxis", 1) # front axis is 'Y' cns.setAttr("upAxis", 0) # front axis is 'X' # Roll # choose ik_ctls for _i, uv in enumerate(self.ik_uv_param): if u < uv: ik_a = self.ik_ctl[_i - 1] ik_b = self.ik_ctl[_i] if self.settings["isSplitHip"] and i == 0: u = (i + 1) / (len(self.guide.apos) - 1.0) ratio = u / uv * .5 else: ratio = u / uv break else: ik_a = self.ik_ctl[-2] ik_b = self.ik_ctl[-1] ratio = 1. intMatrix = applyop.gear_intmatrix_op( ik_a + ".worldMatrix", ik_b + ".worldMatrix", ratio) dm_node = node.createDecomposeMatrixNode(intMatrix + ".output") pm.connectAttr(dm_node + ".outputRotate", self.twister[i].attr("rotate")) pm.parentConstraint(self.twister[i], self.ref_twist[i], maintainOffset=True) pm.connectAttr(self.ref_twist[i] + ".translate", cns + ".worldUpVector") self.div_cns_npo[i].setMatrix(tmp_div_npo_transform, worldSpace=True) # compensate scale reference div_node = node.createDivNode( [1, 1, 1], [rootWorld_node + ".outputScaleX", rootWorld_node + ".outputScaleY", rootWorld_node + ".outputScaleZ"]) # Squash n Stretch op = applyop.gear_squashstretch2_op(self.scl_transforms[i], self.root, pm.arclen(self.slv_crv), "y", div_node + ".output") pm.connectAttr(self.volume_att, op + ".blend") pm.connectAttr(crv_node + ".arcLength", op + ".driver") pm.connectAttr(self.st_att[i], op + ".stretch") pm.connectAttr(self.sq_att[i], op + ".squash") # Controlers tmp_local_npo_transform = getTransform(self.fk_local_npo[i]) # to fix mismatch before/after later if i == 0: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns_npo[i].attr("worldMatrix"), self.root.attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") pm.connectAttr(dm_node + ".outputTranslate", self.fk_npo[i].attr("t")) else: mulmat_node = applyop.gear_mulmatrix_op( self.div_cns_npo[i].attr("worldMatrix"), self.div_cns_npo[i - 1].attr("worldInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") mul_node = node.createMulNode(div_node + ".output", dm_node + ".outputTranslate") pm.connectAttr(mul_node + ".output", self.fk_npo[i].attr("t")) pm.connectAttr(dm_node + ".outputRotate", self.fk_npo[i].attr("r")) self.addOperatorsOrientationLock(i, cns) self.fk_local_npo[i].setMatrix(tmp_local_npo_transform, worldSpace=True) # References if i < (len(self.fk_ctl) - 1): aim = pm.aimConstraint(self.div_cns_npo[i + 1], self.div_cns_npo[i], maintainOffset=False) pm.setAttr(aim + ".aimVectorX", 0) pm.setAttr(aim + ".aimVectorY", 1) pm.setAttr(aim + ".aimVectorZ", 0) pm.setAttr(aim + ".upVectorX", 0) pm.setAttr(aim + ".upVectorY", 1) pm.setAttr(aim + ".upVectorZ", 0)
def add_stretchy_ik(ik_handle): """ create stretchy IK""" logger.debug("Running function.. (%s.add_strectchy_ik)" %__name__) prefix = "%s_stretchy" %ik_handle.name() joints = ik_handle.getJointList() joints.extend(joints[-1].getChildren(type='joint')) spline_curve = ik_handle.getCurve() ik_handle.add_separator_attr("stretchy_ik") pm.addAttr(ik_handle, k=1, at='double', ln='global_scale', dv=1) pm.addAttr(ik_handle, k=1, at='double', ln='stretch_toggle', min=0, max=1) pm.addAttr(ik_handle, k=1, at='double', ln='extend', min=0.10, dv=1) md = pm.createNode('multiplyDivide', name = "%s_scale_md" %prefix) md.operation.set(2) #determine if it's a spline ik if spline_curve: logger.debug("spilne ik detected") curveInfo = pm.arclen(spline_curve, name = "%s_arcLen" %prefix, ch=True) curveInfo.arcLength >> md.input1X distance = curveInfo.arcLength.get() else: logger.debug("ik detected") distance = 0.00 for joint in joints[1::]: distance = distance + joint.tx.get() ik_handle.snapEnable.set(0) ik_handle.stickiness.set(1) distanceBetween = pm.createNode('distanceBetween', name='%s_distanceBetween'%prefix) joints[0].worldMatrix[0] >> distanceBetween.inMatrix1 ik_handle.worldMatrix[0] >> distanceBetween.inMatrix2 condition = pm.createNode('condition', name="%s_condition"%prefix) condition.operation.set(5) # less or equal condition.secondTerm.set(distance) condition.colorIfTrueR.set(distance) distanceBetween.distance >> condition.firstTerm distanceBetween.distance >> condition.colorIfFalseR condition.outColorR >> md.input1X gMd = pm.createNode("multiplyDivide", name = "%s_globalScale_mdl" %prefix) gMd.input1X.set(distance) ik_handle.global_scale >> gMd.input2X gMd.outputX >> md.input2X bta = pm.createNode('blendTwoAttr', name = "%s_toggle_bta" %prefix) bta.input[0].set(1) md.outputX >> bta.input[1] ik_handle.stretch_toggle >> bta.attributesBlender tMd = pm.createNode("multiplyDivide", name = "%s_tweakScale_md" %prefix) bta.output >> tMd.input1X ik_handle.extend >> tMd.input2X for joint in joints[1::]: mdl = pm.createNode('multiplyDivide', name = "%s_stretchy_mdl" %joint) mdl.input1X.set(joint.tx.get()) tMd.outputX >> mdl.input2X mdl.outputX >> joint.tx