def _visualizer_setup(self): """Add a shader to visualize the outValue and the coneAngle.""" visualize_sdr = pm.shadingNode('surfaceShader', asShader=True, n='visualize') sets = pm.sets(renderable=True, noSurfaceShader=True, empty=True, n='visualize') visualize_sdr.outColor >> sets.surfaceShader vis_ramp = pm.createNode('ramp', n='visualize') vis_ramp.setAttr('type', 1) vis_ramp.setAttr('colorEntryList[0].color', 0, 0, 0) vis_ramp.setAttr('colorEntryList[1].position', 1) vis_ramp.setAttr('colorEntryList[1].color', 0, 0, 0) vis_ramp.setAttr('colorEntryList[2].position', 0) cmds.setAttr('%s.colorEntryList[2].color' % vis_ramp, 0, 0, 0, type='double3') vis_ramp.setAttr('colorEntryList[3].color', 0, 0, 0) self.ramp.outColorR >> vis_ramp.colorEntryList[1].color.colorG rmv = pm.createNode('remapValue', n='visualize') rmv.setAttr('inputMin', -1) rmv.setAttr('inputMax', 0) rmv.setAttr('outputMin', 1) rmv.setAttr('outputMax', 0) self.ramp.outColorR >> rmv.inputValue rmv.outValue >> vis_ramp.colorEntryList[2].color.colorR (self.ramp.colorEntryList[0].position >> vis_ramp.colorEntryList[0].position) (self.ramp.colorEntryList[3].position >> vis_ramp.colorEntryList[3].position) vis_ramp.outColor >> visualize_sdr.outColor pm.defaultNavigation(source=visualize_sdr, destination=self.sphere.getShape().instObjGroups[0], connectToExisting=True)
def createEtWorldPosRE(self): #create etWorldPosRE etWorldPosRE = self.createRenderElement('ExtraTexElement') pm.rename(etWorldPosRE, 'rbEtWorldPos') #SetAttrs on etWorldPosRE pm.setAttr(etWorldPosRE.vray_name_extratex, 'rbEtWorldPos') pm.setAttr(etWorldPosRE.vray_explicit_name_extratex, 'rbEtWorldPos') pm.setAttr(etWorldPosRE.vray_affectmattes_extratex, 0) pm.setAttr(etWorldPosRE.vray_filtering_extratex, 0) #Create vrayfresnel tex and setAttrs pm.select(cl = True) vrayFresnelTex = pm.createNode('VRayFresnel') pm.rename(vrayFresnelTex, 'rbVRayFresnelWorldPos') pm.setAttr(vrayFresnelTex.IOR, 1) pm.select(cl = True) #Create sampler Info Node samplerInfoWorldPos = pm.createNode('samplerInfo') pm.rename(samplerInfoWorldPos, 'rbSamplerInfoWorldPos') #connections samplerInfoWorldPos.pointWorld >> vrayFresnelTex.frontColor samplerInfoWorldPos.pointWorld >> vrayFresnelTex.sideColor vrayFresnelTex.outColor >> etWorldPosRE.vray_texture_extratex pm.select(cl = True) #verbose if(self.verbose): print('Extra Tex World Pos RE created')
def bdCreateDistanceCnd(): jnt = pm.ls(sl=1)[0] #loc1,loc2,jnt = pm.ls(sl=1) jntCnstr = jnt.listRelatives(type='pointConstraint')[0] loc1,loc2 = pm.pointConstraint(jntCnstr,q=1,tl=1) matrixLoc1 = pm.createNode('decomposeMatrix',name = loc1.name().replace('_loc','_dm')) matrixLoc2 = pm.createNode('decomposeMatrix',name = loc2.name().replace('_loc','_dm')) pma = pm.createNode('plusMinusAverage',name = loc1.name().replace('_loc','_pma')) pma.operation.set(2) rv = pm.createNode('remapValue',name = loc1.name().replace('_loc','_rv')) rv.inputMin.set(0.1) rev = pm.createNode('reverse',name = loc1.name().replace('_loc','_rev')) loc1.worldMatrix[0].connect(matrixLoc1.inputMatrix) loc2.worldMatrix[0].connect(matrixLoc2.inputMatrix) matrixLoc1.outputTranslateY.connect(pma.input1D[0]) matrixLoc2.outputTranslateY.connect(pma.input1D[1]) pma.output1D.connect(rv.inputValue) rv.outValue.connect(jntCnstr.attr(loc1.name() + 'W0')) rv.outValue.connect(rev.inputX) rev.outputX.connect(jntCnstr.attr(loc2.name() + 'W1'))
def build(self, no_subdiv=False, num_ctrl=None, degree=3, create_ctrl=True, constraint=False, rot_fol=True, *args, **kwargs): super(Ribbon, self).build(create_grp_anm=create_ctrl, *args, **kwargs) if num_ctrl is not None: self.num_ctrl = num_ctrl nomenclature_rig = self.get_nomenclature_rig() # Create the plane and align it with the selected bones plane_tran = next( (input for input in self.input if libPymel.isinstance_of_shape(input, pymel.nodetypes.NurbsSurface)), None) if plane_tran is None: plane_name = nomenclature_rig.resolve("ribbonPlane") if no_subdiv: # We don't want any subdivision in the plane, so use only 2 bones to create it no_subdiv_degree = 2 if degree < 2: no_subdiv_degree = degree plane_tran = libRigging.create_nurbs_plane_from_joints([self.chain_jnt[0], self.chain_jnt[-1]], degree=no_subdiv_degree, width=self.width) else: plane_tran = libRigging.create_nurbs_plane_from_joints(self.chain_jnt, degree=degree, width=self.width) plane_tran.rename(plane_name) plane_tran.setParent(self.grp_rig) self._ribbon_shape = plane_tran.getShape() # Create the follicule needed for the system on the skinned bones self.attach_to_plane(rot_fol) # TODO : Support aim constraint for bones instead of follicle rotation? follicles_grp = pymel.createNode("transform") follicle_grp_name = nomenclature_rig.resolve("follicleGrp") follicles_grp.rename(follicle_grp_name) follicles_grp.setParent(self.grp_rig) for n in self._follicles: n.setParent(follicles_grp) # Create the joints that will drive the ribbon. # TODO: Support other shapes than straight lines... self._ribbon_jnts = libRigging.create_chain_between_objects( self.chain_jnt.start, self.chain_jnt.end, self.num_ctrl, parented=False) # Group all the joints ribbon_chain_grp_name = nomenclature_rig.resolve('ribbonChainGrp') self.ribbon_chain_grp = pymel.createNode('transform', name=ribbon_chain_grp_name, parent=self.grp_rig) align_chain = True if len(self.chain_jnt) == len(self._ribbon_jnts) else False for i, jnt in enumerate(self._ribbon_jnts): # Align the ribbon joints with the real joint to have a better rotation ctrl ribbon_jnt_name = nomenclature_rig.resolve('ribbonJnt{0:02d}'.format(i)) jnt.rename(ribbon_jnt_name) jnt.setParent(self.ribbon_chain_grp) if align_chain: matrix = self.chain_jnt[i].getMatrix(worldSpace=True) jnt.setMatrix(matrix, worldSpace=True) # TODO - Improve skinning smoothing by setting manually the skin... pymel.skinCluster(list(self._ribbon_jnts), plane_tran, dr=1.0, mi=2.0, omi=True) try: libSkinning.assign_weights_from_segments(self._ribbon_shape, self._ribbon_jnts, dropoff=1.0) except ZeroDivisionError, e: pass
def finalize_boxes(): # collect weights boxes = collect_proxy_boxes() jnts = [box.getParent() for box in boxes] weights = [] for i, box in enumerate(boxes): weights.extend([i] * len(box.vtx)) # mergeboxes polyUnite = pymel.createNode('polyUnite') itt = 0 for box in boxes: for shape in box.getShapes(): pymel.connectAttr(shape.worldMatrix, polyUnite.inputMat[itt]) pymel.connectAttr(shape.outMesh, polyUnite.inputPoly[itt]) itt += 1 outputMesh = pymel.createNode('mesh') pymel.connectAttr(polyUnite.output, outputMesh.inMesh) #pymel.delete(boxes) # set skin weights pymel.skinCluster(jnts, outputMesh.getParent(), toSelectedBones=True) skinCluster = next((hist for hist in outputMesh.listHistory() if isinstance(hist, pymel.nodetypes.SkinCluster)), None) for vtx, inf in zip(iter(outputMesh.vtx), weights): skinCluster.setWeights(vtx, [inf], [1])
def _parentSurfaceFLCL(self, constrained_obj, geo, deleteCPOMS=1): """ Parents object to follicle at closest point on surface. Select child transform, then select mesh to hold parent follicle. """ cpos = pmc.createNode('closestPointOnSurface', n='cpos_flcl_' + geo) mc.connectAttr(pmc.listRelatives(geo, shapes=True, children=True)[0] + '.local', cpos + '.inputSurface') obj_mtx = pmc.xform(constrained_obj, q=True, m=True) pmc.setAttr(cpos + '.inPosition', [obj_mtx[12], obj_mtx[13], obj_mtx[14]]) flclShape = pmc.createNode('follicle', n='flclShape' + geo) flcl = pmc.listRelatives(flclShape, type='transform', parent=True) pmc.rename(flcl, 'flcl_' + geo + '_1') mc.connectAttr(flclShape + '.outRotate', flcl[0] + '.rotate') mc.connectAttr(flclShape + '.outTranslate', flcl[0] + '.translate') mc.connectAttr(geo + '.worldMatrix', flclShape + '.inputWorldMatrix') mc.connectAttr(geo + '.local', flclShape + '.inputSurface') mc.setAttr(flclShape + '.simulationMethod', 0) u = mc.getAttr(cpos + '.result.parameterU') v = mc.getAttr(cpos + '.result.parameterV') pmc.setAttr(flclShape + '.parameterU', u) pmc.setAttr(flclShape + '.parameterV', v) pmc.parent(constrained_obj, flcl) if deleteCPOMS == 1: pmc.delete(cpos) return flcl
def _attachRenderProxy( self, objects ): path = self.fileInput.text() proxy = [] if os.path.isdir(path): for file in glob.glob(path+"/*.mib"): bipx = pm.createNode('mip_binaryproxy',n=file.split('/').pop().split('.')[0]+'_BINARYPROXY') bipx.object_filename.set(file) proxy.append(bipx) else: bipx = pm.createNode('mip_binaryproxy',n=path.split('/').pop().split('.')[0]+'_BINARYPROXY') bipx.object_filename.set(path) proxy.append( bipx ) if not objects: for prx in proxy: objects.append(pm.polyCube()) for arg in objects: if len(proxy)==0: pm.error('No proxies found in folder. Womp Womp.') elif len(proxy)>1: print 'more than one proxy' #turn the lo geometry shader on arg.miExportGeoShader.set(1) #connect the proxy to the lo's geo shader proxy[random.randint(0,len(proxy)-1)].outValue.connect(arg.miGeoShader, f=True) else: print 'one proxy' #turn the lo geometry shader on arg.miExportGeoShader.set(1) #connect the proxy to the lo's geo shader proxy.pop().outValue.connect(arg.miGeoShader, f=True)
def makeNodeSet(pointValueList, transNodeType): for x in pointValueList: if transNodeType == 'locator': pm.spaceLocator().t.set(x) else: pm.createNode(transNodeType).t.set(x)
def createSubdivApproxNode(): ''' copy of createApproxNode from mentalrayApproxEditor.mel node will be named "mathildaSubdivApprox" ''' # delete existing node if exists nodeName = 'mathildaSubdivApprox' # make sure mental ray is loaded first if not pm.pluginInfo('Mayatomr', q=True, loaded=True): pm.loadPlugin('Mayatomr', qt=True) # create approx node approxNode = pm.createNode('mentalraySubdivApprox', n=nodeName) # get listNode try: mrItemsListNode = pm.ls(type='mentalrayItemsList')[0] except IndexError: mrItemsListNode = pm.createNode('mentalrayItemsList', n='mentalrayItemsList') # connect approx to list pm.connectAttr(approxNode.message, mrItemsListNode.subdivApproxs, na=True) return approxNode
def _create_custom(self): self.pos_x_remap.outputMin.set(1) self.pos_x_remap.outputMax.set(0) self.neg_x_remap.outputMin.set(0) self.neg_x_remap.outputMax.set(1) NL_mult = pm.createNode("multDoubleLinear", name="%s_NL_mult" % self.prefix) NR_mult = pm.createNode("multDoubleLinear", name="%s_NR_mult" % self.prefix) SL_mult = pm.createNode("multDoubleLinear", name="%s_SL_mult" % self.prefix) SR_mult = pm.createNode("multDoubleLinear", name="%s_SR_mult" % self.prefix) self.pos_x_remap.outValue >> NR_mult.input1 self.pos_y_remap.outValue >> NR_mult.input2 NR_mult.output >> self.control_group.nShapeR self.neg_x_remap.outValue >> NL_mult.input1 self.pos_y_remap.outValue >> NL_mult.input2 NL_mult.output >> self.control_group.nShapeL self.pos_x_remap.outValue >> SR_mult.input1 self.neg_y_remap.outValue >> SR_mult.input2 SR_mult.output >> self.control_group.sShapeR self.neg_x_remap.outValue >> SL_mult.input1 self.neg_y_remap.outValue >> SL_mult.input2 SL_mult.output >> self.control_group.sShapeL
def createFresnel(out = None): #创建菲涅尔节点组合 # #参数out: 属性输出给哪个节点, 连接属性 # #创建节点 samplerInfo = pm.createNode('samplerInfo', name = 'Fre_samplerInfo_arnold') ramp = pm.createNode('ramp', name = 'Fre_ramp_arnold') aiUtility, SG = pm.createSurfaceShader('aiUtility', name = 'Fresnel_arnold') #修改属性 ramp.interpolation.set("Exponential Down") ramp.colorEntryList[2].remove(b=1) ramp.colorEntryList[1].position.set(1) ramp.colorEntryList[0].color.set(1,1,1) ramp.colorEntryList[1].color.set(0,0,0) aiUtility.shadeMode.set(2) #链接属性 samplerInfo.facingRatio >> ramp.uvCoord.uCoord samplerInfo.facingRatio >> ramp.uvCoord.vCoord ramp.outColor >> aiUtility.color if out : aiUtility.outColor >> out else : pass return aiUtility, SG
def createZ(out = None): #创建Z通道节点组合 # #参数out: 属性输出给哪个节点, 连接属性 # #创建节点 samplerInfo = pm.createNode('samplerInfo', name = 'z_samplerInfo_arnold') multiplyDivide = pm.createNode('multiplyDivide', name = 'z_multiplyDivide_arnold') setRange = pm.createNode('setRange', name = 'z_setRange_arnold') aiUtility, SG = pm.createSurfaceShader('aiUtility', name = 'zdp_arnold') #修改属性 multiplyDivide.input2X.set(-1) setRange.minX.set(1) setRange.oldMinX.set(0.1) setRange.oldMaxX.set(500) aiUtility.shadeMode.set(2) #属性链接 samplerInfo.pointCameraZ >> multiplyDivide.input1X multiplyDivide.outputX >> setRange.valueX setRange.message >> aiUtility.colorR setRange.message >> aiUtility.colorG setRange.message >> aiUtility.colorB if out : aiUtility.outColor >> out else : pass return aiUtility, SG
def wiggleJointChain(strPnt, endPnt, side='FL', chainPos='Upper'): ''' create joint chain between two points (strPnt & endPnt). require name string of strPnt & endPnt ''' strPos = pm.xform( strPnt, q=True, ws=True, translation=True ) endPos = pm.xform( endPnt, q=True, ws=True, translation=True ) if side.endswith('L'): sideLabel = 1 elif side.endswith('R'): sideLabel = 2 ikSpCrv = pm.curve( degree=2, editPoint=( strPos, endPos) ) ikSpCrv.rename( 'wiggle_%s_%s_CRV'%(side, chainPos) ) ikSpCrvShp = ikSpCrv.listRelatives(shapes=True)[0] pm.select(clear=True) jnt2pos = pm.pointOnCurve( ikSpCrv, pr=0.3333, turnOnPercentage=True) jnt3pos = pm.pointOnCurve( ikSpCrv, pr=0.6667, turnOnPercentage=True ) jntPos = ( strPos, jnt2pos, jnt3pos, endPos ) jntList = [] for pnt in jntPos: jName = 'Wiggle_%s_%s_%02d'%(side, chainPos, jntPos.index(pnt)+1) newJoint = pm.joint(name=jName, p=pnt) newJoint.side.set(sideLabel) newJoint.__getattr__('type').set(18) newJoint.otherType.set(jName) jntList.append(newJoint) pm.joint( jntList[0], edit=True, orientJoint='xyz', secondaryAxisOrient='xup', children=True, zeroScaleOrient=True ) ikHandle = pm.ikHandle( name='Wiggle_%s_%s_ikHandle'%(side, chainPos), solver='ikSplineSolver', createCurve=False, curve=ikSpCrvShp, startJoint=jntList[0].name(), endEffector=jntList[-1].name(), rootOnCurve=False, createRootAxis=True, parentCurve=False ) jntGrp = jntList[0].listRelatives(parent=True)[0] jntGrp.rename('Wiggle_%s_%s'%(side, chainPos)) crvInfo = pm.createNode('curveInfo', name='crvInf_wiggle_%s_%s'%(side, chainPos)) multDiv1 = pm.createNode('multiplyDivide', name='md_wiggle_%s_%s_01'%(side, chainPos)) multDiv2 = pm.createNode('multiplyDivide', name='md_wiggle_%s_%s_02'%(side, chainPos)) ikSpCrvShp.worldSpace >> crvInfo.inputCurve arcLgt = crvInfo.arcLength.get() multDiv1.input2X.set(arcLgt) multDiv1.operation.set(2) spacing = jntList[1].tx.get() multDiv2.input2X.set(spacing) multDiv1.outputX >> multDiv2.input1X crvInfo.arcLength >> multDiv1.input1X for jnt in jntList[1:]: multDiv2.outputX >> jnt.tx return ikSpCrvShp, ikSpCrv, ikHandle[0], jntGrp
def symmetryLayer(): allCtrls = pm.PyNode('CT_face_ctrl').getChildren(ad=True, type='nurbsCurve') allCtrls = set([crv.getParent() for crv in allCtrls]) # new group to hold mirrored locs symLocGrp = pm.group(em=True, n='RT_symmetryLoc_grp') allRightCtrls = [crv for crv in allCtrls if 'RT_' in crv.name()] symMatrix = pm.createNode('fourByFourMatrix', n='CT_symmetryMatrix_mat') symMatrix.in00.set(-1) for rightCtl in allRightCtrls: leftCtl = pm.PyNode(rightCtl.replace('RT_', 'LT_')) loc = pm.spaceLocator(n=rightCtl+'_symLoc') symLocGrp | loc # connect to left side mm = pm.createNode('multMatrix', n=rightCtl+'_sym_mm') symMatrix.output >> mm.matrixIn[0] leftCtl.worldMatrix >> mm.matrixIn[1] symMatrix.output >> mm.matrixIn[2] dcm = pm.createNode('decomposeMatrix', n=rightCtl+'_sym_dcm') mm.matrixSum >> dcm.inputMatrix dcm.ot >> loc.t dcm.outputRotate >> loc.r # constrain on anim layer pm.parentConstraint(loc, rightCtl, l='Symmetry', weight=1)
def connectLocRotate(): ''' ''' locGrpNames = ['_back', '_left', '_front', '_right', '_leftBack', '_rightBack', '_rightFront', '_leftFront'] # create one nurb circle for all groups circ = pm.createNode('makeNurbCircle', n='CT_jacketLocsAlign_circle') circ.normal.set(0,1,0) # use the same root ctrl for all groups rootCtl = pm.PyNode('Mathilda_root_ctrl') # create one motionpath for each group for grpName in locGrpNames: mp = pm.createNode('motionPath', n='CT_jacketLocsAlign'+grpName+'_mp') circ.outputCurve >> mp.gp # use paramater from lowest npc pm.PyNode('torsoReader_3'+grpName+'_npc').parameter >> mp.uValue rootCtl.worldMatrix >> mp.worldUpMatrix mp.worldUpType.set(2) mp.worldUpVector.set(0,1,0) mp.frontAxis.set(0) mp.upAxis.set(1) # connect to all locs in grp for locId in range(1,10): mp.rotate >> pm.PyNode('torsoReader_%d%s_loc.r' % (locId, grpName))
def addAOV(self, aovName, aovType=None): ''' add an AOV to the active list for this AOV node returns the created AOV node ''' if aovType is None: aovType = getAOVTypeMap().get(aovName, 'rgba') if not isinstance(aovType, int): aovType = dict(TYPES)[aovType] aovNode = pm.createNode('aiAOV', name='aiAOV_' + aovName, skipSelect=True) out = aovNode.attr('outputs')[0] pm.connectAttr('defaultArnoldDriver.message', out.driver) filter = defaultFiltersByName.get(aovName, None) if filter: node = pm.createNode('aiAOVFilter', skipSelect=True) node.aiTranslator.set(filter) filterAttr = node.attr('message') import mtoa.hooks as hooks hooks.setupFilter(filter, aovName) else: filterAttr = 'defaultArnoldFilter.message' pm.connectAttr(filterAttr, out.filter) aovNode.attr('name').set(aovName) aovNode.attr('type').set(aovType) nextPlug = self.nextAvailableAttr() aovNode.message.connect(nextPlug) aov = SceneAOV(aovNode, nextPlug) addAliases([aov]) return aov
def connectJacketLoc(twistCrv, untwistCrv, param, name='', addCrvs=[]): ''' ''' mp = pm.createNode('motionPath', n=twistCrv+name+'_mp') untwistCrv.worldSpace >> mp.geometryPath mp.u.set(param) npc = pm.createNode('nearestPointOnCurve', n=twistCrv+name+'_npc') mp.allCoordinates >> npc.inPosition twistCrv.worldSpace >> npc.inputCurve allLocs = [] loc = pm.spaceLocator(n=twistCrv+name+'_loc') npc.position >> loc.translate allLocs.append(loc) for crv in addCrvs: pci = pm.createNode('pointOnCurveInfo', n=crv+name+'_pci') npc.parameter >> pci.parameter crv.worldSpace >> pci.inputCurve loc = pm.spaceLocator(n=crv+name+'_loc') pci.position >> loc.translate allLocs.append(loc) pm.select(allLocs)
def connectEyelidLocsToBlinkAttr(): ''' ''' blinkAttr = pm.PyNode('LT_eye_ctl.blink') locA, locB = pm.ls(sl=True)[:2] # get center pt between two locs (from their pocis) pociA = locA.t.inputs(type='pointOnCurveInfo', p=True)[0] pociB = locB.t.inputs(type='pointOnCurveInfo', p=True)[0] pma = pm.createNode('plusMinusAverage', n=locA+'_avgPos_pma') pma.operation.set(3) pociA >> pma.input3D[0] pociB >> pma.input3D[1] # blend positions blendA = pm.createNode('blendColors', n=locA+'_blendPos_bld') pma.output3D >> blendA.color1 pociA >> blendA.color2 blinkAttr >> blendA.blender blendA.output >> locA.t blendB = pm.createNode('blendColors', n=locB+'_blendPos_bld') pma.output3D >> blendB.color1 pociB >> blendB.color2 blinkAttr >> blendB.blender blendB.output >> locB.t
def test_export_network(self, epsilon=0.00001): pynode_a = pymel.createNode('transform') pynode_b = pymel.createNode('transform') old_instance = A() old_instance.ex_int = 42 old_instance.ex_float = 3.14159 old_instance.ex_str = 'Hello World' old_instance.ex_None = None old_instance.ex_list_pynode = [None, pynode_a, None, pynode_b] # # Ensure consistency when exporting to network # n = libSerialization.export_network(old_instance) network_ex_int = n.ex_int.get() network_ex_float = n.ex_float.get() network_ex_str = n.ex_str.get() self.assertTrue(network_ex_int == old_instance.ex_int) self.assertTrue(abs(network_ex_float- old_instance.ex_float) < epsilon) self.assertTrue(network_ex_str == old_instance.ex_str) # Note: libSerialization will NEVER export a None value since the type cannot be resolved. self.assertTrue(not n.hasAttr('ex_None')) # # Ensure consistency when importing from network # new_instance = libSerialization.import_network(n) self.assertTrue(network_ex_int == new_instance.ex_int) self.assertTrue(abs(network_ex_float- new_instance.ex_float) < epsilon) self.assertTrue(network_ex_str == new_instance.ex_str)
def transfer_shape(source, target, flip=True): """it will replace the shape of selected number 2 with the shapes of selected number 1""" target_shape = target.getShape(noIntermediate=True) target_shape_orig = get_orig_shape(target_shape) dup = pymel.duplicate(source, rc=1)[0] tmp = pymel.createNode('transform') pymel.parent(tmp, dup) pymel.xform(tmp, t=(0, 0, 0), ro=(0, 0, 0), scale=(1, 1, 1)) pymel.parent(tmp, w=1) for sh in dup.getShapes(noIntermediate=True): pymel.parent(sh, tmp, r=1, s=1) pymel.delete(dup) temp_grp_negScale = pymel.createNode('transform') pymel.parent(tmp, temp_grp_negScale) if flip: temp_grp_negScale.scaleX.set(-1) pymel.parent(tmp, target) pymel.delete(temp_grp_negScale) pymel.makeIdentity(tmp, t=True) # this brings translate values at 0 before scale freezing pymel.makeIdentity(tmp, apply=True, t=True, r=True, s=True) pymel.parent(tmp, w=1) color_info, vis_master = get_previous_controller_info(target) shapes_has_been_deleted = False for sh in tmp.getShapes(): if target_shape_orig: adapt_to_orig_shape(sh, target.getShape()) else: if not shapes_has_been_deleted: shapesDel = target.getShapes() if shapesDel: pymel.delete(shapesDel) shapes_has_been_deleted = True pymel.parent(sh, target, r=1, s=1) pymel.rename(sh.name(), target.name() + "Shape") if color_info[0]: if color_info[1]: sh.overrideEnabled.set(True) sh.overrideRGBColors.set(1) sh.overrideColorRGB.set(color_info[2]) else: sh.overrideEnabled.set(True) sh.overrideRGBColors.set(0) sh.overrideColor.set(color_info[2]) else: sh.overrideEnabled.set(False) if vis_master: vis_master.connect(sh.visibility) pymel.delete(tmp)
def create_copier(in_meshes, name='out_geo#', in_array=None, rotate=True): # Create output mesh out_shape = pm.createNode('mesh') out_xform = out_shape.getParent() out_xform.rename(name) # Create copier node copier = pm.createNode('copier') copier.orient.set(1) copier.toggleUV.set(1) copier.outputMesh.connect(out_shape.inMesh) # Connect input meshes for i, mesh in enumerate(in_meshes): shape = mesh.getShape(noIntermediate=True) shape.worldMesh[0].connect(copier.inputMesh[i]) if not in_array: # Connect input transforms array = pm.createNode('transformsToArrays') else: array = in_array array.outPositionPP.connect(copier.posArray) if rotate: array.outRotationPP.connect(copier.rotArray) return out_xform, copier, array
def addAOV( aovName, aovType = None ): """docstring for addAov""" if aovType is None: aovType = aovs.getAOVTypeMap().get(aovName, 'rgba') if not isinstance(aovType, int): aovType = dict(aovs.TYPES)[aovType] aovNode = pm.createNode('aiAOV', name='aiAOV_' + aovName, skipSelect=True) out = aovNode.attr('outputs')[0] pm.connectAttr('defaultArnoldDriver.message', out.driver) filter = aovs.defaultFiltersByName.get(aovName, None) if filter: node = pm.createNode('aiAOVFilter', skipSelect=True) node.aiTranslator.set(filter) filterAttr = node.attr('message') import mtoa.hooks as hooks hooks.setupFilter(filter, aovName) else: filterAttr = 'defaultArnoldFilter.message' pm.connectAttr(filterAttr, out.filter) aovNode.attr('name').set(aovName) aovNode.attr('type').set(aovType) base = pm.PyNode('defaultArnoldRenderOptions') aovAttr = base.aovs nextPlug = aovAttr.elementByLogicalIndex(aovAttr.numElements()) aovNode.message.connect(nextPlug) aov = aovs.SceneAOV(aovNode, nextPlug) return aov
def closestEndOrStartVertToSurface(targetSurface, transforms): ''' Usage: closestEndOrStartVertToSurface(pm.PyNode('r_hand_GEO'), pm.ls(sl=True)) ''' cpom = pm.createNode('closestPointOnMesh') distBet = pm.createNode('distanceBetween') targetSurface.outMesh.connect(cpom.inMesh) for transform in transforms: closestPointAndVert = {} loc = pm.spaceLocator(n=transform.name().replace('GEO','LOC')) loc.translate.set( transform.getShape().vtx[-1].getPosition() ) cpom.inPosition.set(loc.translate.get()) closestVert = cpom.closestVertexIndex.get() closestPosEnd = targetSurface.vtx[cpom.closestVertexIndex.get()].getPosition() distBet.point1.set( closestPosEnd ) distBet.point2.set( loc.translate.get() ) distToEnd = distBet.distance.get() closestPointAndVert[distToEnd] = [closestVert, closestPosEnd] loc.translate.set( transform.getShape().vtx[0].getPosition() ) cpom.inPosition.set(loc.translate.get()) closestVert = cpom.closestVertexIndex.get() closestPosStart = targetSurface.vtx[cpom.closestVertexIndex.get()].getPosition() distBet.point1.set( closestPosStart ) distBet.point2.set( loc.translate.get() ) distToStart = distBet.distance.get() closestPointAndVert[distToStart] = [closestVert, closestPosEnd] loc.translate.set( closestPointAndVert[ min(distToStart, distToEnd) ][1] )
def _gather_exported_alembic_info_(): cmds.loadPlugin("AbcImport.mll", quiet=True) template_obj, fields, tk = _get_shotgun_fields_from_file_name_() if not pm.objExists("animatedAlembicGroup"): pm.createNode("transform", name="animatedAlembicGroup") temp, fields, tk = _get_shotgun_fields_from_file_name_() masterAlembicTemplate = tk.templates["master_alembic_cache"] alembicFolder = libFile.get_parent_folder(masterAlembicTemplate.apply_fields(fields)) # Get all the abc files exported_alemblic_info = {} if libFile.exists(alembicFolder): for alembicFile in libFile.listfiles(alembicFolder, "abc"): alembicFilePath = libFile.join(alembicFolder, alembicFile) # Edited by Chet # Project Kitten Witch 25 May 2016 # ======================================================== # Old code that was causing the list of alembics to build # niceName = alembicFile.split(".")[0].split("_")[] niceName = alembicFile.split(".")[0] niceName = niceName.split("_") niceName = " ".join(niceName[1:]) exported_alemblic_info[niceName] = alembicFilePath return exported_alemblic_info
def _setup_node(self, *args, **kwargs): """Setup and return the node @param args <list> Storing args from config file as list @param kwargs <dict> Storing keyword args from config file as dict @DONE use logging instead of printing """ node = None if args: if args[0] == help: msg = "\nValid parameters for the %s node:" % self._nodename logging.debug(msg) for n in self._nodes[self._nodename].items(): if not n[0] == '__ABBREVIATION__': logging.debug('-- %s : <%s>' % (n[0], n[1])) # end if exclude abbreviation # end for print parameters and types return # end if help or set name if not self.suffix: self.suffix = self._nodes[self._nodename]['__ABBREVIATION__'] # end if not suffix given use abbreviation list name = '%s_%s_%s' % (self.side, args[0], self.suffix) node = pm.createNode(self._nodename, n=name) else: node = pm.createNode(self._nodename) # end if args exists self._setup_attribute(node, **kwargs) self.suffix = None return node
def orientPlacerOnLoop(pLoc, beforeObj=None, afterObj=None): """ assume pLocs are all in the same space! so we don't need to calc worldspace positions! at this time, aimVec is always +y-axis and upVec is always +x-axis """ # create vectors pmas if beforeObj: beforePma = getVectorBetweenTwoPlacers(beforeObj, pLoc) xAxis = beforePma.output3D if afterObj: afterPma = getVectorBetweenTwoPlacers(pLoc, afterObj) xAxis = afterPma.output3D # calculate vectors if blend is needed if beforeObj and afterObj: # slerp blend between the two vectors slerp = pm.createNode("animBlendNodeAdditiveRotation", n=pLoc + "_blendBeforeAndAfterVec_slerp") beforePma.output3D >> slerp.inputA afterPma.output3D >> slerp.inputB xAxis = slerp.output # yAxis is always (0,1,0) # now we also know xAxis # calculate zAxis zAxisVpd = pm.createNode("vectorProduct", n=pLoc + "_calcZAxis_vpd") xAxis >> zAxisVpd.input1 zAxisVpd.input2.set(0, 1, 0) zAxisVpd.operation.set(2) zAxis = zAxisVpd.output # construct a matrix in worldSpace wsMat = pm.createNode("fourByFourMatrix", n=pLoc + "_wsFbfm") # x-vector try: xAxis.outputX >> wsMat.in00 wsMat.in01.set(0) xAxis.outputZ >> wsMat.in02 except AttributeError: xAxis.output3Dx >> wsMat.in00 wsMat.in01.set(0) xAxis.output3Dz >> wsMat.in02 # y-vector wsMat.in10.set(0) wsMat.in11.set(1) wsMat.in12.set(0) # z-vector zAxis.outputX >> wsMat.in20 zAxis.outputY >> wsMat.in21 zAxis.outputZ >> wsMat.in22 # decompose dcm = pm.createNode("decomposeMatrix", n=pLoc + "_orientMat_dcm") wsMat.output >> dcm.inputMatrix dcm.outputRotate >> pLoc.r
def createOptions(): """ override this with your own function to set defaults """ import mtoa.aovs as aovs import mtoa.hooks as hooks # the shared option ensures that it is only created if it does not exist options = pm.createNode('aiOptions', skipSelect=True, shared=True, name='defaultArnoldRenderOptions') filterNode = pm.createNode('aiAOVFilter', name='defaultArnoldFilter', skipSelect=True, shared=True) driverNode = pm.createNode('aiAOVDriver', name='defaultArnoldDriver', skipSelect=True, shared=True) displayDriverNode = pm.createNode('aiAOVDriver', name='defaultArnoldDisplayDriver', skipSelect=True, shared=True) if (filterNode or driverNode) and not options: options = pm.PyNode('defaultArnoldRenderOptions') # options previously existed, so we need to upgrade upgradeAOVOutput(options, filterNode, driverNode) # if we're just creating the options node, then be sure to connect up the driver and filter if filterNode: # newly created default filter hooks.setupFilter(filterNode) else: filterNode = pm.PyNode('defaultArnoldFilter') if driverNode: # newly created default driver hooks.setupDriver(driverNode) else: driverNode = pm.PyNode('defaultArnoldDriver') if options: # newly created options hooks.setupDefaultAOVs(aovs.AOVInterface(options)) hooks.setupOptions(options) pm.setAttr('defaultArnoldRenderOptions.version', str(cmds.pluginInfo( 'mtoa', query=True, version=True))) else: options = pm.PyNode('defaultArnoldRenderOptions') if displayDriverNode: # options exist, but not display driver: upgrade from older version of mtoa hooks.setupDefaultAOVs(aovs.AOVInterface(options)) if displayDriverNode: # newly created default driver displayDriverNode.aiTranslator.set('maya') # GUI only displayDriverNode.outputMode.set(0) hooks.setupDriver(displayDriverNode) displayDriverNode.message.connect(options.drivers, nextAvailable=True) elif not options.drivers.inputs(): pm.connectAttr('defaultArnoldDisplayDriver.message', options.drivers, nextAvailable=True) try: pm.connectAttr('%s.message' % filterNode.name(), '%s.filter' % options.name(), force=True) except: pass try: pm.connectAttr('%s.message' % driverNode.name(), '%s.driver' % options.name(), force=True) except: pass
def loadStandins(self): meshName = self.path.split("/")[-1].replace(".binarymesh", "") standInMesh = pm.createNode("mesh") standInMesh.getParent().rename(meshName + "_standIn") standInMeshNode = pm.createNode("mtap_standinMeshNode") standInMeshNode.rename(meshName + "_standInCreator") standInMeshNode.binMeshFile.set(self.path) standInMeshNode.outputMesh >> standInMesh.inMesh
def _ctrlDBL(self, controls): pmc.undoInfo(openChunk=True) if controls == []: controls = pmc.ls(sl=True) for control in controls: control_roo = pmc.xform(control, q=True, roo=True) control_mtx = pmc.xform(control, q=True, m=True, ws=True) control_parent = pmc.listRelatives(control, p=True) pmc.select(cl=True) locdbl_parent = pmc.spaceLocator(n='locDBL_parent_' + control) locdbl_offset = pmc.spaceLocator(n='locDBL_offset_' + control) pmc.xform(locdbl_parent, ws=True, m=control_mtx) pmc.xform(locdbl_offset, ws=True, m=control_mtx) pmc.parent(locdbl_offset, locdbl_parent) pmc.parent(locdbl_parent, control_parent) pmc.parent(control, locdbl_offset) if control_roo == 'xyz': pmc.xform(locdbl_offset, roo='zyx') if control_roo == 'yzx': pmc.xform(locdbl_offset, roo='xzy') if control_roo == 'zxy': pmc.xform(locdbl_offset, roo='yxz') if control_roo == 'xzy': pmc.xform(locdbl_offset, roo='yzx') if control_roo == 'yxz': pmc.xform(locdbl_offset, roo='zxy') if control_roo == 'zyx': pmc.xform(locdbl_offset, roo='xyz') md_trns = pmc.createNode('multiplyDivide', n='mdTRNS_locDBL_' + control) md_rot = pmc.createNode('multiplyDivide', n='mdROT_locDBL_' + control) md_scl = pmc.createNode('multiplyDivide', n='mdSCL_locDBL_' + control) pmc.setAttr(md_trns + '.input1', [-1,-1,-1]) pmc.setAttr(md_rot.input1, [-1,-1,-1]) pmc.setAttr(md_scl.input1, [ 1, 1, 1]) pmc.setAttr(md_scl.operation, 2) pmc.connectAttr(control + '.translate', md_trns + '.input2') pmc.connectAttr(control + '.rotate', md_rot + '.input2') pmc.connectAttr(control + '.scale', md_scl + '.input2') pmc.connectAttr(md_trns + '.output', locdbl_offset + '.translate') pmc.connectAttr(md_rot + '.output', locdbl_offset + '.rotate') pmc.connectAttr(md_scl + '.output', locdbl_offset + '.scale') pmc.setAttr(locdbl_parent + 'Shape.visibility', 0) pmc.setAttr(locdbl_offset + 'Shape.visibility', 0) pmc.undoInfo(closeChunk=True)
def connectChains(self,*args): """ Set elbows to only rotate in one axis, the upAxis. Create blend color nodes and connect ik/fk/bind joint chains. """ #Shoulder blendColors creation self.shldr_node1 = pm.PyNode((pm.createNode( 'blendColors' )).rename('%s_shldrRotate' % self.prefix)) #shldr_node1 attributes to connect self.ikChain[0].rotate >> self.shldr_node1.color1 self.fkChain[0].rotate >> self.shldr_node1.color2 self.shldr_node1.output >> self.jointChain[0].rotate #elbow1 blendColors creation self.elbow1_node1 = pm.PyNode((pm.createNode( 'blendColors' )).rename('%s_elbow1Rotate' % self.prefix)) self.elbow1_node2 = pm.PyNode((pm.createNode( 'blendColors' )).rename('%s_elbow1Translate' % self.prefix)) #elbow1_node1 attributes to connect self.ikChain[1].rotate >> self.elbow1_node1.color1 self.fkChain[1].rotate >> self.elbow1_node1.color2 self.elbow1_node1.output >> self.jointChain[1].rotate #elbow1_node2 attributes to connect self.ikChain[1].translate >> self.elbow1_node2.color1 self.fkChain[1].translate >> self.elbow1_node2.color2 self.elbow1_node2.output >> self.jointChain[1].translate #wrist blendColors creation self.wrist_node1 = pm.PyNode((pm.createNode( 'blendColors' )).rename('%s_elbow1Rotate' % self.prefix)) self.wrist_node2 = pm.PyNode((pm.createNode( 'blendColors' )).rename('%s_elbow1Translate' % self.prefix)) #wrist_node1 attributes to connect self.ikChain[2].rotate >> self.wrist_node1.color1 self.fkChain[2].rotate >> self.wrist_node1.color2 self.wrist_node1.output >> self.jointChain[2].rotate #wrist_node2 attributes to connect self.ikChain[2].translate >> self.wrist_node2.color1 self.fkChain[2].translate >> self.wrist_node2.color2 self.wrist_node2.output >> self.jointChain[2].translate #Lock elbow axis if self.up == 1: pm.setAttr('%s.rotateY'%self.fkChain[1],lock=True,k=False) pm.setAttr('%s.rotateZ'%self.fkChain[1],lock=True,k=False) pm.setAttr('%s.rotateY'%self.ikChain[1],lock=True,k=False) pm.setAttr('%s.rotateZ'%self.ikChain[1],lock=True,k=False) if self.up == 2: pm.setAttr('%s.rotateX'%self.fkChain[1],lock=True,k=False) pm.setAttr('%s.rotateZ'%self.fkChain[1],lock=True,k=False) pm.setAttr('%s.rotateX'%self.ikChain[1],lock=True,k=False) pm.setAttr('%s.rotateZ'%self.ikChain[1],lock=True,k=False) if self.up == 3: pm.setAttr('%s.rotateY'%self.fkChain[1],lock=True,k=False) pm.setAttr('%s.rotateX'%self.fkChain[1],lock=True,k=False) pm.setAttr('%s.rotateY'%self.ikChain[1],lock=True,k=False) pm.setAttr('%s.rotateX'%self.ikChain[1],lock=True,k=False)
def RigBendyLimb(**kwargs): jnts = kwargs.setdefault('jnts') volume = kwargs.setdefault('volume', False) limbName = kwargs.setdefault('limbName', 'arm') side = kwargs.setdefault('side', 'L') numOfSegs = kwargs.setdefault('numOfSegs', 5) FKIKMode = kwargs.setdefault('FKIKMode', 'FKIK') bendyCtrl = kwargs.setdefault('bendyCtrl') isMirroredJoint = kwargs.setdefault('isMirroredJoint', False) if not (jnts and bendyCtrl): objects = pm.ls(sl=True) if not len(objects) == 4: pm.error( 'ehm_tools...rigBendyLimb: select 3 joint and a control curve') uparmJnt = objects[0] elbowJnt = objects[1] handJnt = objects[2] bendyCtrl = objects[3] else: uparmJnt = jnts[0] elbowJnt = jnts[1] handJnt = jnts[2] # if limb is not straight, make it so. necessary for for skinning bendy curves. if not FKIKMode == "IK": tempElbowOri = elbowJnt.jointOrient.get() elbowJnt.jointOrient.set(0, 0, 0) else: # find position for putting the ik so that arm gets straight tempHandIKLoc = pm.spaceLocator() pm.parent(tempHandIKLoc, uparmJnt) tempHandIKLoc.rotate.set(0, 0, 0) armLen = elbowJnt.translate.translateX.get( ) + handJnt.translate.translateX.get() tempHandIKLoc.translate.set(armLen, 0, 0) tempHandIKPos = pm.xform(tempHandIKLoc, q=True, ws=True, translation=True) pm.parent(IKarmDistLocs[1], w=True) # straighten the arm for skinning IKarmDistLocs[1].translate.set(tempHandIKPos) # create bendy joint uparmSegStuff = Segmentor(jnt=uparmJnt, numOfSegs=numOfSegs, volume=volume, thicknessPlace='end', isMirroredJoint=isMirroredJoint) elbowSegStuff = Segmentor(jnt=elbowJnt, numOfSegs=numOfSegs, volume=volume, thicknessPlace='start', isMirroredJoint=isMirroredJoint) # avoid shear on elbow seg joints pm.scaleConstraint(uparmJnt, elbowSegStuff[1][2].getParent()) # create the uparm orientaion loc, point and aim constraint it so that it aims to hand joint uparmOriLoc = pm.spaceLocator() pm.pointConstraint(uparmJnt, uparmOriLoc) pm.aimConstraint(handJnt, uparmOriLoc) # create the elbow orientation loc, connect it to uparm ori loc and elbow joint elbowOriLoc = pm.spaceLocator() pm.pointConstraint(elbowJnt, elbowOriLoc) pm.orientConstraint(uparmOriLoc, elbowOriLoc) # move second and forth CVs of the bendy curves very close to where joints are. uparm_seg_crv = uparmSegStuff[1][2] elbow_seg_crv = elbowSegStuff[1][2] closeToUparm = FindPosBetween(percent=1, base=uparmJnt, tip=elbowJnt) closeToElbow = FindPosBetween(percent=99, base=uparmJnt, tip=elbowJnt) closeToElbowAfter = FindPosBetween(percent=1, base=elbowJnt, tip=handJnt) closeToHand = FindPosBetween(percent=99, base=elbowJnt, tip=handJnt) pm.xform(uparm_seg_crv.cv[1], ws=True, t=closeToUparm) pm.xform(uparm_seg_crv.cv[3], ws=True, t=closeToElbow) pm.xform(elbow_seg_crv.cv[1], ws=True, t=closeToElbowAfter) pm.xform(elbow_seg_crv.cv[3], ws=True, t=closeToHand) # create joints, sking to bendy curves and parent the middle one under elbow ori loc. bendyJnts_dict = {'one': uparmJnt, 'two': elbowJnt, 'three': handJnt} for i in bendyJnts_dict.keys(): pm.select(clear=True) tmp = pm.joint(name='%s_%s_bendy_%s_jnt' % (side, limbName, i)) tmp.setParent(bendyJnts_dict[i]) tmp.translate.set(0, 0, 0) bendyJnts_dict[i] = tmp bendyJnts_dict['two'].setParent(elbowOriLoc) # skin the seg_crvs and set the weights uparm_seg_crv_skinCluster = (pm.skinCluster(uparm_seg_crv, bendyJnts_dict['one'], bendyJnts_dict['two'], toSelectedBones=True)) elbow_seg_crv_skinCluster = (pm.skinCluster(elbow_seg_crv, bendyJnts_dict['two'], bendyJnts_dict['three'], toSelectedBones=True)) pm.skinPercent(uparm_seg_crv_skinCluster, (uparm_seg_crv + ".cv[2:4]"), transformValue=(bendyJnts_dict['two'], 1)) pm.skinPercent(elbow_seg_crv_skinCluster, (elbow_seg_crv + ".cv[0:2]"), transformValue=(bendyJnts_dict['two'], 1)) pm.skinPercent(uparm_seg_crv_skinCluster, (uparm_seg_crv + ".cv[0:1]"), transformValue=(bendyJnts_dict['two'], 0)) pm.skinPercent(elbow_seg_crv_skinCluster, (elbow_seg_crv + ".cv[3:4]"), transformValue=(bendyJnts_dict['two'], 0)) # setting the twist parameters for the segmenty joints # add bendy attribute to finger ctrl and connect it if not pm.attributeQuery('bendy', n=bendyCtrl, exists=True): try: pm.addAttr(bendyCtrl, ln="bendy", at='double', min=0, dv=0) pm.setAttr(bendyCtrl.bendy, e=True, keyable=True) except: pm.error( 'ehm_tools...rigBendyLimb: could not add bendy attr to %s' % bendyCtrl) # slow down the bendy attribute by 10 times bendySlower_mdn = pm.createNode('multiplyDivide', name='%s_%s_bendySlower_mdn' % (side, limbName)) bendyCtrl.bendy >> bendySlower_mdn.input1X bendySlower_mdn.input2X.set(0.1) bendySlower_mdn.outputX >> elbowOriLoc.scaleX # set the limb back to it's old position. if not FKIKMode == "IK": elbowJnt.jointOrient.set(tempElbowOri) else: pm.parent(IKarmDistLocs[1], handIKCtrl) IKarmDistLocs[1].translate.set(0, 0, 0) segStuffGrp = pm.group(uparmSegStuff[2], elbowSegStuff[2], name='%s_%s_bendyStuff_grp' % (side, limbName)) pm.xform(os=True, piv=(0, 0, 0)) # return return (uparmSegStuff, elbowSegStuff, segStuffGrp)
def bs_createModelBase(topGroup, assetName, assetGrade, assetType, episode=None, makeGroups=True): """ @ create asset model @ make modeling base hierarchy and add attributes on top group for query purpose. Args: topGroup (str): Hierarchy Top Group Name. assetName (str): Asset Name. assetGrade (str): Character Grade (Primary, Secondary, Tertiary). assetType (str): Asset Type Character, Prop, Set, Vehicle. episode (str): episode number like (ep000,ep001,ep002) format. makeGroups (bool): make groups if value is True Returns: topGrp. """ # raise popup window for current scene will be discarded if maya is not in batch mode. if not pm.about(batch=True): confirmation = pm.windows.confirmDialog( title='Confirm', message="Don't Save Current Scene\nAnd Load New Scene?", button=['Yes', 'No'], defaultButton='Yes') if confirmation == 'Yes': pm.newFile(f=True) else: print 'process cancelled', return False # create group if make hierarchy is True. astTypShortCode = { 'Character': 'ch', 'Prop': 'pr', 'Set': 'bg', 'Vehicle': 'vh', 'SetElement': 'se' } if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': uid = 'bsw_' + astTypShortCode[ assetType] + '_' + assetName + '_mod_' + episode else: uid = 'bsw_' + astTypShortCode[assetType] + '_' + assetName + '_mod' pm.select(cl=True) if makeGroups: # make groups. topGrp = pm.createNode('transform', n=topGroup, ss=True) modelGrp = pm.createNode('transform', n=assetName + '_grp', ss=True) if assetType == 'Character': bodyGrp = pm.createNode('transform', n='body_grp', ss=True) eyeGrp = pm.createNode('transform', n='eye_grp', ss=True) eyeBrowGrp = pm.createNode('transform', n='eyeBrow_grp', ss=True) innerMouthGrp = pm.createNode('transform', n='innerMouth_grp', ss=True) hairGrp = pm.createNode('transform', n='hair_grp', ss=True) clothGrp = pm.createNode('transform', n='cloth_grp', ss=True) propsGrp = pm.createNode('transform', n='props_grp', ss=True) shoeGrp = pm.createNode('transform', n='shoe_grp', ss=True) # make parent. pm.parent(bodyGrp, clothGrp, propsGrp, shoeGrp, modelGrp) pm.parent(eyeGrp, eyeBrowGrp, innerMouthGrp, hairGrp, bodyGrp) elif assetType == 'Set': setElementGrp = pm.createNode('transform', n='setElements_grp') pm.parent(modelGrp, setElementGrp, topGrp) pm.parent(modelGrp, topGrp) else: topGrp = topGroup # add attributes for query asset details purpose. pm.addAttr(topGrp, ln='assetBase', dt='string', k=True) pm.addAttr(topGrp, ln='assetType', dt='string', k=True) pm.addAttr(topGrp, ln='assetName', dt='string', k=True) pm.addAttr(topGrp, ln='assetGrade', dt='string', k=True) if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': pm.addAttr(topGrp, ln='assetEpisode', dt='string', k=True) pm.addAttr(topGrp, ln='assetUID', dt='string', k=True) # add asset details in top group attributes. pm.setAttr(topGrp + '.assetBase', 'Asset') pm.setAttr(topGrp + '.assetBase', l=True) pm.setAttr(topGrp + '.assetType', assetType) pm.setAttr(topGrp + '.assetType', l=True) pm.setAttr(topGrp + '.assetName', assetName) pm.setAttr(topGrp + '.assetName', l=True) pm.setAttr(topGrp + '.assetGrade', assetGrade) pm.setAttr(topGrp + '.assetGrade', l=True) if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': pm.setAttr(topGrp + '.assetEpisode', episode) pm.setAttr(topGrp + '.assetEpisode', l=True) pm.setAttr(topGrp + '.assetUID', uid) pm.setAttr(topGrp + '.assetUID', l=True) pm.select(topGrp, r=True) if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': bs_pathGenerator.bs_createAssetDirectories(assetType, assetName, episode=episode) else: bs_pathGenerator.bs_createAssetDirectories(assetType, assetName) bs_qui.bs_displayMessage('success', 'Asset Created Successfully....') return topGrp
def addJoint(self, obj, name, newActiveJnt=None, UniScale=False, segComp=0, gearMulMatrix=True): """Add joint as child of the active joint or under driver object. Args: obj (dagNode): The input driver object for the joint. name (str): The joint name. newActiveJnt (bool or dagNode): If a joint is pass, this joint will be the active joint and parent of the newly created joint. UniScale (bool): Connects the joint scale with the Z axis for a unifor scalin, if set Falsewill connect with each axis separated. segComp (bool): Set True or False the segment compensation in the joint.. gearMulMatrix (bool): Use the custom gear_multiply matrix node, if False will use Maya's default mulMatrix node. Returns: dagNode: The newly created joint. """ customName = self.getCustomJointName(len(self.jointList)) if self.options["joint_rig"]: if newActiveJnt: self.active_jnt = newActiveJnt jnt = primitive.addJoint(self.active_jnt, customName or self.getName(str(name) + "_jnt"), transform.getTransform(obj)) # Disconnect inversScale for better preformance if isinstance(self.active_jnt, pm.nodetypes.Joint): try: pm.disconnectAttr(self.active_jnt.scale, jnt.inverseScale) except RuntimeError: # This handle the situation where we have in between joints # transformation due a negative scaling pm.ungroup(jnt.getParent()) # All new jnts are the active by default self.active_jnt = jnt if gearMulMatrix: mulmat_node = applyop.gear_mulmatrix_op( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode( mulmat_node + ".output") m = mulmat_node.attr('output').get() else: mulmat_node = node.createMultMatrixNode( obj + ".worldMatrix", jnt + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode( mulmat_node + ".matrixSum") m = mulmat_node.attr('matrixSum').get() pm.connectAttr(dm_node + ".outputTranslate", jnt + ".t") pm.connectAttr(dm_node + ".outputRotate", jnt + ".r") # TODO: fix squash stretch solver to scale the joint uniform # the next line cheat the uniform scaling only fo X or Y axis # oriented joints if self.options["force_uniScale"]: UniScale = True # invert negative scaling in Joints. We only inver Z axis, so is # the only axis that we are checking if dm_node.attr("outputScaleZ").get() < 0: mul_nod_invert = node.createMulNode( dm_node.attr("outputScaleZ"), -1) out_val = mul_nod_invert.attr("outputX") else: out_val = dm_node.attr("outputScaleZ") # connect scaling if UniScale: pm.connectAttr(out_val, jnt + ".sx") pm.connectAttr(out_val, jnt + ".sy") pm.connectAttr(out_val, jnt + ".sz") else: pm.connectAttr(dm_node.attr("outputScaleX"), jnt + ".sx") pm.connectAttr(dm_node.attr("outputScaleY"), jnt + ".sy") pm.connectAttr(out_val, jnt + ".sz") pm.connectAttr(dm_node + ".outputShear", jnt + ".shear") # Segment scale compensate Off to avoid issues with the global # scale jnt.setAttr("segmentScaleCompensate", segComp) jnt.setAttr("jointOrient", 0, 0, 0) # setting the joint orient compensation in order to have clean # rotation channels jnt.attr("jointOrientX").set(jnt.attr("rx").get()) jnt.attr("jointOrientY").set(jnt.attr("ry").get()) jnt.attr("jointOrientZ").set(jnt.attr("rz").get()) im = m.inverse() if gearMulMatrix: mul_nod = applyop.gear_mulmatrix_op( mulmat_node.attr('output'), im, jnt, 'r') dm_node2 = mul_nod.output.listConnections()[0] else: mul_nod = node.createMultMatrixNode( mulmat_node.attr('matrixSum'), im, jnt, 'r') dm_node2 = mul_nod.matrixSum.listConnections()[0] # if jnt.attr("sz").get() < 0: if dm_node.attr("outputScaleZ").get() < 0: # if negative scaling we have to negate some axis for rotation neg_rot_node = pm.createNode("multiplyDivide") pm.setAttr(neg_rot_node + ".operation", 1) pm.connectAttr(dm_node2.outputRotate, neg_rot_node + ".input1", f=True) for v, axis in zip([-1, -1, 1], "XYZ"): pm.setAttr(neg_rot_node + ".input2" + axis, v) pm.connectAttr(neg_rot_node + ".output", jnt + ".r", f=True) # set not keyable attribute.setNotKeyableAttributes(jnt) else: jnt = primitive.addJoint(obj, customName or self.getName(str(name) + "_jnt"), transform.getTransform(obj)) pm.connectAttr(self.rig.jntVis_att, jnt.attr("visibility")) attribute.lockAttribute(jnt) self.addToGroup(jnt, "deformers") # This is a workaround due the evaluation problem with compound attr # TODO: This workaround, should be removed onces the evaluation issue # is fixed # github issue: Shifter: Joint connection: Maya evaluation Bug #210 dm = jnt.r.listConnections(p=True, type="decomposeMatrix") if dm: at = dm[0] dm_node = at.node() pm.disconnectAttr(at, jnt.r) pm.connectAttr(dm_node.outputRotateX, jnt.rx) pm.connectAttr(dm_node.outputRotateY, jnt.ry) pm.connectAttr(dm_node.outputRotateZ, jnt.rz) dm = jnt.t.listConnections(p=True, type="decomposeMatrix") if dm: at = dm[0] dm_node = at.node() pm.disconnectAttr(at, jnt.t) pm.connectAttr(dm_node.outputTranslateX, jnt.tx) pm.connectAttr(dm_node.outputTranslateY, jnt.ty) pm.connectAttr(dm_node.outputTranslateZ, jnt.tz) # dm = jnt.s.listConnections(p=True, type="decomposeMatrix") # if dm: # at = dm[0] # dm_node = at.node() # pm.disconnectAttr(at, jnt.s) # pm.connectAttr(dm_node.outputScaleX, jnt.sx) # pm.connectAttr(dm_node.outputScaleY, jnt.sy) # pm.connectAttr(dm_node.outputScaleZ, jnt.sz) return jnt
def MakeSplineStretchy(**kwargs): thicknessPlace = kwargs.setdefault('thicknessPlace', 'mid') stretchSwitch = kwargs.setdefault('stretchSwitch', True) volume = kwargs.setdefault('volume', True) ikCrv = kwargs.setdefault('ikCrv') if ikCrv == None: ikCrv = pm.ls(sl=True)[-1] else: ikCrv = pm.ls(ikCrv)[-1] if not ikCrv.getShape().type() == 'nurbsCurve': pm.error('ehm_tools...MakeSplineStretchy: Select an IK Spline Curve!') # the value used for keyging ss ssv = 0 if volume == True: ssv = 1 #=============================================================================== # create curveInfo node curveShape = ikCrv.getShape() crvLenNode = pm.createNode("curveInfo", n=(ikCrv.name() + "_Info")) pm.addAttr(ikCrv, keyable=True, ln="scalePower", at="double") ikH = pm.listConnections(curveShape, type="ikHandle") jntsToSS = pm.ikHandle(ikH[0], q=True, jointList=True) #================================================================================ # key the curve if thicknessPlace == "mid": pm.setKeyframe((ikCrv + ".scalePower"), t=1, v=0) pm.setKeyframe((ikCrv + ".scalePower"), t=len(jntsToSS) / 2, v=ssv) pm.setKeyframe((ikCrv + ".scalePower"), t=len(jntsToSS), v=0) elif thicknessPlace == "start": pm.setKeyframe((ikCrv + ".scalePower"), t=1, v=ssv) pm.setKeyframe((ikCrv + ".scalePower"), t=len(jntsToSS), v=0) elif thicknessPlace == "end": pm.setKeyframe((ikCrv + ".scalePower"), t=1, v=0) pm.setKeyframe((ikCrv + ".scalePower"), t=len(jntsToSS), v=ssv) else: print "ThinknessPlace not defined. Select one of these : 'start' , 'mid' , 'end' " curveShape.worldSpace[0] >> crvLenNode.inputCurve pm.addAttr(crvLenNode, ln="normalizedScale", at="double") normScl = pm.createNode("multiplyDivide", n=(ikCrv + "_normalizedScale")) pm.setAttr((normScl + ".operation"), 2) arcLen = pm.getAttr(crvLenNode + ".arcLength") pm.setAttr((normScl + ".input2X"), arcLen) pm.connectAttr((crvLenNode + ".arcLength"), (normScl + ".input1X"), f=True) pm.connectAttr((normScl + ".outputX"), (crvLenNode + ".normalizedScale"), f=True) stretchedScale = pm.createNode("multiplyDivide", n=(ikCrv + "_scale_mdn")) pm.connectAttr((normScl + ".outputX"), (stretchedScale + ".input1X"), f=True) pm.setAttr((stretchedScale + ".operation"), 2) lenJnts = len(jntsToSS) for k in range(lenJnts): pm.addAttr(jntsToSS[k], keyable=True, ln="pow", at="double") cacheN = pm.createNode("frameCache", n=(jntsToSS[k] + "_FCnode")) pm.connectAttr((cacheN + ".varying"), (jntsToSS[k] + ".pow")) pm.connectAttr((ikCrv + ".scalePower"), (cacheN + ".stream")) pm.setAttr((cacheN + ".varyTime"), (k + 1)) #=================================================================================== # create scale, sqrt and power nodes for keeping the volume using nodes instead of expression normScaleSqrt = pm.createNode("multiplyDivide", n="normScaleSqrt") pm.connectAttr((stretchedScale + ".outputX"), (normScaleSqrt + ".input1X")) pm.setAttr((normScaleSqrt + ".operation"), 3) pm.setAttr((normScaleSqrt + ".input2X"), 0.5) sqrtMult = pm.createNode("multiplyDivide", n="sqrtMult") pm.setAttr((sqrtMult + ".input1X"), 1) pm.setAttr((sqrtMult + ".operation"), 2) pm.connectAttr((normScaleSqrt + ".outputX"), (sqrtMult + ".input2X")) for k in range(lenJnts): scaleMult = pm.createNode("multiplyDivide", n=(jntsToSS[k] + "_scale_mdn")) pm.setAttr((scaleMult + ".operation"), 3) sqrtMult.outputX >> scaleMult.input1X jntsToSS[k].pow >> scaleMult.input2X stretchedScale.outputX >> jntsToSS[k].scaleX scaleMult.outputX >> jntsToSS[k].scaleY scaleMult.outputX >> jntsToSS[k].scaleZ #=================================================================================== # making the spine scalable by connecting the scale of the mian_ctrl to it's network if stretchSwitch == True: pm.addAttr(ikCrv, ln="stretchSwitch", at="double", keyable=True, min=0, max=1, dv=1) back_stretchSwitch_bln = pm.createNode("blendColors", n="back_stretchSwitch_bln") back_stretchSwitch_bln.color1R.set(1) normScl.outputX >> back_stretchSwitch_bln.color2R ikCrv.stretchSwitch >> back_stretchSwitch_bln.blender pm.connectAttr((back_stretchSwitch_bln + ".outputR"), (stretchedScale + ".input2X"), f=True)
def doRig(self): if pm.objExists(self.name + 'Constrained_grp'): pm.delete(self.name + 'Constrained_grp') if pm.objExists(self.name + 'tweakSys_grp'): pm.delete(self.name + 'tweakSys_grp') cnstrGrp = pm.group(n=self.name + 'Constrained_grp', em=True) allSliderGrp = pm.group(n=self.name + 'Sliders_grp', em=True) tweakCtrlGrp = pm.group(n=self.name + 'tweakCtrls_grp', em=True) tweakJntGrp = pm.group(n=self.name + 'tweakSys_grp', em=True) pm.parent(tweakCtrlGrp, allSliderGrp, cnstrGrp) tweakJntGrp.visibility.set(False) basePos = pm.xform(self.guideMoveall, t=True, q=True, ws=True) masterSlderGrp = pm.group(em=True, name=self.name + 'global_grp') masterSliderCtrl = pm.circle(nr=(0, 0, 1), r=0.2, n=self.name + 'global_ctrl')[0] pm.parent(masterSliderCtrl, masterSlderGrp) pm.parent(masterSlderGrp, allSliderGrp) p1 = pm.xform(self.tweak4, q=True, ws=True, t=True)[0] p2 = pm.xform(self.tweak3, q=True, ws=True, t=True)[0] pm.xform(masterSlderGrp, t=(p1 + (p1 - p2), basePos[1] + 1, basePos[2] + 1), ws=True) displaySetup = self.tweakCtrlSetup.copy() tweakGuides = [self.tweak1, self.tweak2, self.tweak3, self.tweak4] slidersNames = ['In', 'MidIn', 'MidOut', 'Out'] sliderList = [] sideMove = True for i in range(4): guide = tweakGuides[i] guideXpos = pm.xform(guide, q=True, ws=True, t=True)[0] slider = createSlider(self.name + slidersNames[i], size=0.1, sideMove=sideMove) sliderList.append(slider) pm.xform(slider.getParent(), t=(guideXpos, basePos[1] + 1, basePos[2] + 1), ws=True) pm.parent(slider.getParent(), allSliderGrp) addNode = pm.createNode('addDoubleLinear') clampConn = pm.listConnections(slider.translateY, p=True, d=True) for conn in clampConn: addNode.output >> conn masterSliderCtrl.translateY >> addNode.input1 slider.translateY >> addNode.input2 pm.parent(slider.getParent(), masterSliderCtrl) cntrlName = displaySetup['nameTempl'] + str(i) jntName = self.jntSetup['nameTempl'] + str(i) jnt = jointTools.makeJoint(name=jntName, obj=guide, jntSulfix='_jxt', hasZero=True, connectToLast=False) ctrl = controlTools.cntrlCrv(name=cntrlName, obj=jnt, connType='connection', offsets=1, **displaySetup) pm.parent(jnt.getParent(), tweakJntGrp) pm.parent(ctrl.getParent(2), tweakCtrlGrp) sideMove = False self.guideMoveall.visibility.set(0)
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. """ # mouth center rotation pm.connectAttr(self.jaw_ctl + ".rotateZ", self.mouthCenter + ".rotateZ") # Node Creation ######## # Mut Div nodes md_node_1 = pm.createNode("multiplyDivide") md_node_2 = pm.createNode("multiplyDivide") md_node_3 = pm.createNode("multiplyDivide") md_node_4 = pm.createNode("multiplyDivide") md_node_5 = pm.createNode("multiplyDivide") md_node_6 = pm.createNode("multiplyDivide") md_node_7 = pm.createNode("multiplyDivide") md_node_8 = pm.createNode("multiplyDivide") # Clamp o_node clamp_node = pm.createNode("clamp") # Condition nodes cond_node_1 = pm.createNode("condition") cond_node_2 = pm.createNode("condition") cond_node_3 = pm.createNode("condition") # Blend nodes blend_node_1 = pm.createNode("blendColors") blend_node_2 = pm.createNode("blendColors") # Node Conexions ######## # md_node_1 pm.connectAttr(self.jaw_ctl + ".translateY", md_node_1 + ".input1X") pm.connectAttr(self.vertRotation_att, md_node_1 + ".input2X") # md_node_2 pm.connectAttr(self.jaw_ctl + ".translateX", md_node_2 + ".input1X") pm.connectAttr(self.sideRotation_att, md_node_2 + ".input2X") # md_node_3 pm.connectAttr(self.jaw_ctl + ".translateY", md_node_3 + ".input1X") pm.connectAttr(self.lipsAlignSpeed_att, md_node_3 + ".input2X") # md_node_4 pm.connectAttr(self.jaw_ctl + ".translateY", md_node_4 + ".input1X") pm.connectAttr(self.verticalTranslation_att, md_node_4 + ".input2X") # md_node_5 pm.connectAttr(self.jaw_ctl + ".translateZ", md_node_5 + ".input1X") pm.connectAttr(self.frontalTranslation_att, md_node_5 + ".input2X") # md_node_6 pm.connectAttr(md_node_1 + ".outputX", md_node_6 + ".input1X") pm.setAttr(md_node_6 + ".input2X", -1.0) # md_node_7 pm.connectAttr(md_node_5 + ".outputX", md_node_7 + ".input1X") pm.connectAttr(clamp_node + ".outputR", md_node_7 + ".input2X") # md_node_8 pm.connectAttr(cond_node_2 + ".outColorR", md_node_8 + ".input1X") pm.connectAttr(clamp_node + ".outputR", md_node_8 + ".input2X") # clamp_node pm.connectAttr(md_node_3 + ".outputX", clamp_node + ".inputR") pm.setAttr(clamp_node + ".maxR", 1.0) # cond_node_1 pm.connectAttr(md_node_6 + ".outputX", cond_node_1 + ".colorIfTrueR") pm.connectAttr(md_node_6 + ".outputX", cond_node_1 + ".firstTerm") pm.setAttr(cond_node_1 + ".operation", 4) pm.setAttr(cond_node_1 + ".colorIfFalseR", 0) # cond_node_2 pm.connectAttr(md_node_2 + ".outputX", cond_node_2 + ".colorIfFalseR") pm.connectAttr(md_node_6 + ".outputX", cond_node_2 + ".firstTerm") pm.setAttr(cond_node_2 + ".operation", 2) # cond_node_3 pm.connectAttr(md_node_4 + ".outputX", cond_node_3 + ".colorIfTrueR") pm.connectAttr(md_node_4 + ".outputX", cond_node_3 + ".firstTerm") pm.setAttr(cond_node_3 + ".operation", 4) pm.setAttr(cond_node_3 + ".colorIfFalseR", 0) # blend_node_1 pm.connectAttr(self.followLips_att, blend_node_1 + ".blender") pm.connectAttr(md_node_6 + ".outputX", blend_node_1 + ".color1R") pm.connectAttr(md_node_2 + ".outputX", blend_node_1 + ".color1G") pm.connectAttr(cond_node_1 + ".outColorR", blend_node_1 + ".color2R") pm.connectAttr(md_node_8 + ".outputX", blend_node_1 + ".color2G") # blend_node_2 pm.connectAttr(self.followLips_att, blend_node_2 + ".blender") pm.connectAttr(cond_node_3 + ".outColorR", blend_node_2 + ".color1R") pm.connectAttr(md_node_5 + ".outputX", blend_node_2 + ".color1G") pm.connectAttr(md_node_7 + ".outputX", blend_node_2 + ".color2G") # inputs to transforms pm.connectAttr(md_node_6 + ".outputX", self.jawLow_rot + ".rotateX") pm.connectAttr(md_node_2 + ".outputX", self.jawLow_rot + ".rotateY") pm.connectAttr(blend_node_1 + ".outputR", self.jawUp_rot + ".rotateX") pm.connectAttr(blend_node_1 + ".outputG", self.jawUp_rot + ".rotateY") pm.connectAttr(cond_node_3 + ".outColorR", self.jawLow_pos + ".translateY") pm.connectAttr(md_node_5 + ".outputX", self.jawLow_pos + ".translateZ") pm.connectAttr(blend_node_2 + ".outputR", self.jawUp_pos + ".translateY") pm.connectAttr(blend_node_2 + ".outputG", self.jawUp_pos + ".translateZ")
def basicStretchyIk(ikHandle, stretchLimits=None, globalScaleAttr=None): """ stretchLimits - tuple with the min and max values for scaling the joints. if set to None, no limits will be set """ if isinstance(ikHandle, basestring): ikHandle = pmc.nodetypes.IkHandle(ikHandle) # Turn off snapping to avoid cycle error ikHandle.snapEnable.set(False) joints = ikHandle.getJointList() joints.extend(pmc.listConnections(ikHandle.getEndEffector().translateX)) # generate locators # move onto appropriate positioning startLoc = pmc.spaceLocator( n='loc_{0}_stretchyStart'.format(ikHandle.shortName())) endLoc = pmc.spaceLocator( n='loc_{0}_stretchyEnd'.format(ikHandle.shortName())) pmc.pointConstraint(joints[0], startLoc, maintainOffset=False) pmc.pointConstraint(ikHandle, endLoc, maintainOffset=False) # create distance node and connect # Using createNode() prevents distNode from showing up in Hypershade's utility tab # May or may not be helpful to you, based on how tidy you want to keep the scene distNode = pmc.createNode('distanceBetween', n='dst_{0}_length'.format(ikHandle.shortName())) # Using locator's shape nodes to connect the worldPosition attribute startLoc.getShape().worldPosition[0].connect(distNode.point1) endLoc.getShape().worldPosition[0].connect(distNode.point2) # Get total distance using python's sum() function # Returns sum of all values in a list # List created inline using list comprehension distance = sum([abs(jnt.translateX.get()) for jnt in joints[1:]]) # create divide node to divide current length normalizeNode = pmc.createNode('multiplyDivide', n='div_{0}_normalizer'.format( ikHandle.shortName())) distNode.distance.connect(normalizeNode.input1X) normalizeNode.operation.set(2) normalizeNode.input2X.set(distance) outputAttr = normalizeNode.outputX if stretchLimits: clampNode = makeStretchyClamp(normalizeNode=normalizeNode, minStretch=stretchLimits[0], maxStretch=stretchLimits[1], name=ikHandle.shortName()) outputAttr = clampNode.outputR # If rig has global scale, create additional nodes to preserve length if globalScaleAttr: globalScaleNode = makeStretchyGlobalScale(globalScaleAttr, distance, name=ikHandle.shortName()) globalScaleNode.outputX.connect(normalizeNode.input2X) # multiply node to scale each joint's translateX # connect multiply nodes to joints for jnt in joints[1:]: scaleNode = pmc.createNode('multiplyDivide', n='mul_{0}_stretch'.format(jnt.shortName())) outputAttr.connect(scaleNode.input1X) scaleNode.input2X.set(jnt.translateX.get()) scaleNode.outputX.connect(jnt.translateX) return [startLoc, endLoc]
def setup_swivel_ctrl(self, base_ctrl, ref, pos, ik_handle, constraint=True, mirror_setup=True, **kwargs): """ Create the swivel ctrl for the ik system. Redefined to add the possibility to create a mirror swivel setup to prevent flipping problem with pole vector when using ikSpringSolver :param base_ctrl: The ctrl used to setup the swivel, create one if needed :param ref: Reference object to position the swivel :param pos: The computed position of the swivel :param ik_handle: The handle to pole vector contraint :param constraint: Do we contraint the ik handle to the swivel ctrl :param mirror_setup: Is the swivel need a mirror setup (Hack to bypass ikSpringSolver flipping problem :param kwargs: Additionnal parameters :return: The created ctrl swivel """ # Do not contraint the ik handle now since we could maybe need the flipping setup ctrl_swivel = super(LegIkQuad, self).setup_swivel_ctrl(base_ctrl, ref, pos, ik_handle, constraint=False, **kwargs) nomenclature_rig = self.get_nomenclature_rig() flip_swivel_ref = None if mirror_setup: # HACK - In case the ikpringSolver is used, a flip can happen if the foot pos is behind the thigh pos # Since we already have a plane, only compare the world Z pos to know if the foot is behind the thigh thigh_pos = self.chain_jnt[0].getTranslation(space='world') foot_pos = self.chain_jnt[self.iCtrlIndex].getTranslation( space='world') # TODO - The check is not stable at all. The best we could do is to do real test on the bones # if foot_pos.z < thigh_pos.z: if foot_pos.z < thigh_pos.z and nomenclature_rig.side != nomenclature_rig.SIDE_R: # Flip will occur log.warning("Using the mirror swivel setup for {0}".format( self.name)) # The goal is to create a swivel ref that will be at the good position for the poleVectorContraint # to not flip and drive it by the pole vector ctrl that is in the real position we really wanted flip_swivel_ref = pymel.spaceLocator() flip_swivel_ref.rename( nomenclature_rig.resolve('swivelFlipRefBack')) flip_pos = pymel.dt.Vector(pos.x, pos.y, -pos.z) flip_swivel_ref.setTranslation(flip_pos, space='world') # Setup a ref parent that will always look at the foot ref_parent_name = nomenclature_rig.resolve( 'swivelParentFlipRef') ref_parent = pymel.createNode('transform', name=ref_parent_name, parent=self.grp_rig) ref_parent.setMatrix(self.chain_jnt[0].getMatrix(ws=True), ws=True) pymel.pointConstraint(self.parent, ref_parent, mo=True) pymel.aimConstraint(self.ctrl_ik, ref_parent, mo=True) ref_parent.setParent(self.grp_rig) # Parent the ref flipping swivel on it's parent flip_swivel_ref.setParent(ref_parent) # Create a ref that will be at the same position than the swivel ctrl # and that will control the flipping swivel ref_swivel_ctrl = pymel.spaceLocator() ref_swivel_ctrl.rename( nomenclature_rig.resolve('swivelCtrlRef')) ref_swivel_ctrl.setMatrix(ctrl_swivel.getMatrix(ws=True), ws=True) pymel.pointConstraint(ctrl_swivel, ref_swivel_ctrl) ref_swivel_ctrl.setParent(ref_parent) # Now, mirror position from the ref swivel ctrl to the flipping swivel ctrl inverse_MD = pymel.createNode('multiplyDivide') inverse_MD.input2.set(-1.0, -1.0, -1.0) ref_swivel_ctrl.translate.connect(inverse_MD.input1) inverse_MD.output.connect(flip_swivel_ref.translate) if constraint: # Pole vector contraint the swivel to the ik handle if flip_swivel_ref: # Use the flipping ref if needed pymel.poleVectorConstraint(flip_swivel_ref, ik_handle) else: pymel.poleVectorConstraint(ctrl_swivel, ik_handle) return ctrl_swivel
def cycleTweak(name, edgePair, mirrorAxis, baseMesh, rotMesh, transMesh, setupParent, ctlParent, jntOrg=None, grp=None, iconType="square", size=.025, color=13, ro=datatypes.Vector(1.5708, 0, 1.5708 / 2)): """The command to create a cycle tweak. A cycle tweak is a tweak that cycles to the parent position but doesn't create a cycle of dependency. This type of tweaks are very useful to create facial tweakers. Args: name (string): Name for the cycle tweak edgePair (list): List of edge pair to attach the cycle tweak mirrorAxis (bool): If true, will mirror the x axis behaviour. baseMesh (Mesh): The base mesh for the cycle tweak. rotMesh (Mesh): The mesh that will support the rotation transformations for the cycle tweak transMesh (Mesh): The mesh that will support the translation and scale transformations for the cycle tweak setupParent (dagNode): The parent for the setup objects ctlParent (dagNode): The parent for the control objects jntOrg (None or dagNode, optional): The parent for the joints grp (None or set, optional): The set to add the controls iconType (str, optional): The controls shape size (float, optional): The control size color (int, optional): The control color ro (TYPE, optional): The control shape rotation offset Returns: multi: the tweak control and the list of related joints. """ # rotation sctructure rRivet = rivet.rivet() rBase = rRivet.create(baseMesh, edgePair[0], edgePair[1], setupParent, name + "_rRivet_loc") pos = rBase.getTranslation(space="world") # translation structure tRivetParent = pm.createNode("transform", n=name + "_tRivetBase", p=ctlParent) tRivetParent.setMatrix(datatypes.Matrix(), worldSpace=True) tRivet = rivet.rivet() tBase = tRivet.create(transMesh, edgePair[0], edgePair[1], tRivetParent, name + "_tRivet_loc") # create the control tweakBase = pm.createNode("transform", n=name + "_tweakBase", p=ctlParent) tweakBase.setMatrix(datatypes.Matrix(), worldSpace=True) tweakNpo = pm.createNode("transform", n=name + "_tweakNpo", p=tweakBase) tweakBase.setTranslation(pos, space="world") tweakCtl = icon.create(tweakNpo, name + "_ctl", tweakNpo.getMatrix(worldSpace=True), color, iconType, w=size, d=size, ro=ro) inverseTranslateParent(tweakCtl) pm.pointConstraint(tBase, tweakBase) # rot rotBase = pm.createNode("transform", n=name + "_rotBase", p=setupParent) rotBase.setMatrix(datatypes.Matrix(), worldSpace=True) rotNPO = pm.createNode("transform", n=name + "_rot_npo", p=rotBase) rotJointDriver = pm.createNode("transform", n=name + "_rotJointDriver", p=rotNPO) rotBase.setTranslation(pos, space="world") node.createMulNode( [rotNPO.attr("tx"), rotNPO.attr("ty"), rotNPO.attr("tz")], [-1, -1, -1], [ rotJointDriver.attr("tx"), rotJointDriver.attr("ty"), rotJointDriver.attr("tz") ]) pm.pointConstraint(rBase, rotNPO) pm.connectAttr(tweakCtl.r, rotNPO.r) pm.connectAttr(tweakCtl.s, rotNPO.s) # transform posNPO = pm.createNode("transform", n=name + "_pos_npo", p=setupParent) posJointDriver = pm.createNode("transform", n=name + "_posJointDriver", p=posNPO) posNPO.setTranslation(pos, space="world") pm.connectAttr(tweakCtl.t, posJointDriver.t) # mirror behaviour if mirrorAxis: tweakBase.attr("ry").set(tweakBase.attr("ry").get() + 180) rotBase.attr("ry").set(rotBase.attr("ry").get() + 180) posNPO.attr("ry").set(posNPO.attr("ry").get() + 180) tweakBase.attr("sz").set(-1) rotBase.attr("sz").set(-1) posNPO.attr("sz").set(-1) # create joints rJoint = rigbits.addJnt(rotJointDriver, jntOrg, True, grp) tJoint = rigbits.addJnt(posJointDriver, jntOrg, True, grp) # add to rotation skin # TODO: add checker to see if joint is in the skincluster. rSK = skin.getSkinCluster(rotMesh) pm.skinCluster(rSK, e=True, ai=rJoint, lw=True, wt=0) # add to transform skin # TODO: add checker to see if joint is in the skincluster. tSK = skin.getSkinCluster(transMesh) pm.skinCluster(tSK, e=True, ai=tJoint, lw=True, wt=0) return tweakCtl, [rJoint, tJoint]
def createNode(self, type, **kwargs): node = pmc.createNode(type, **kwargs) name = '%s_%s' % (self.name(), type) node.rename(name) return node
def ghostSliderForMouth(ghostControls, intTra, surface, sliderParent): """Modify the ghost control behaviour to slide on top of a surface Args: ghostControls (dagNode): The ghost control surface (Surface): The NURBS surface sliderParent (dagNode): The parent for the slider. """ if not isinstance(ghostControls, list): ghostControls = [ghostControls] def conn(ctl, driver, ghost): for attr in ["translate", "scale", "rotate"]: try: pm.connectAttr("{}.{}".format(ctl, attr), "{}.{}".format(driver, attr)) pm.disconnectAttr("{}.{}".format(ctl, attr), "{}.{}".format(ghost, attr)) except RuntimeError: pass def connCenter(ctl, driver, ghost): # mul_node1 = pm.createNode("multMatrix") # mul_node2 = pm.createNode("multMatrix") down, _, up = ymt_util.findPathAtoB(ctl, driver) mult = pm.createNode("multMatrix") for i, d in enumerate(down): d.attr("matrix") >> mult.attr("matrixIn[{}]".format(i)) for j, u in enumerate(up[:-1]): u.attr("inverseMatrix") >> mult.attr( "matrixIn[{}]".format(i + j + 1)) decomp = pm.createNode("decomposeMatrix") dm_node = node.createDecomposeMatrixNode(mult.attr("matrixSum")) for attr in ["translate", "scale", "rotate"]: pm.connectAttr("{}.output{}".format(dm_node, attr.capitalize()), "{}.{}".format(driver, attr)) pm.disconnectAttr("{}.{}".format(ctl, attr), "{}.{}".format(ghost, attr)) surfaceShape = surface.getShape() sliders = [] for i, ctlGhost in enumerate(ghostControls): ctl = pm.listConnections(ctlGhost, t="transform")[-1] t = ctl.getMatrix(worldSpace=True) gDriver = primitive.addTransform(surface.getParent(), "{}_slideDriver".format(ctl.name()), t) if 0 == i: connCenter(ctl, gDriver, ctlGhost) else: conn(ctl, gDriver, ctlGhost) oParent = ctlGhost.getParent() npoName = "_".join(ctlGhost.name().split("_")[:-1]) + "_npo" oTra = pm.PyNode( pm.createNode("transform", n=npoName, p=oParent, ss=True)) oTra.setTransformation(ctlGhost.getMatrix()) pm.parent(ctlGhost, oTra) slider = primitive.addTransform(sliderParent, ctl.name() + "_slideDriven", t) sliders.append(slider) # connexion if 0 == i: dm_node = node.createDecomposeMatrixNode(gDriver.attr("matrix")) else: mul_node = pm.createNode("multMatrix") i = 0 parent = ctl while parent != sliderParent: parent.attr("matrix") >> mul_node.attr( "matrixIn[{}]".format(i)) parent = parent.getParent() i += 1 if 10 < i: logger.error("maximum recursion") break dm_node = node.createDecomposeMatrixNode( mul_node.attr("matrixSum")) cps_node = pm.createNode("closestPointOnSurface") dm_node.attr("outputTranslate") >> cps_node.attr("inPosition") surfaceShape.attr("local") >> cps_node.attr("inputSurface") cps_node.attr("position") >> slider.attr("translate") pm.normalConstraint(surfaceShape, slider, aimVector=[0, 0, 1], upVector=[0, 1, 0], worldUpType="objectrotation", worldUpVector=[0, 1, 0], worldUpObject=gDriver) pm.parent(ctlGhost.getParent(), slider) ymt_util.setKeyableAttributesDontLockVisibility(slider, []) for slider in sliders[1:]: _visi_off_lock(slider)
def postConnect(self): fk_ref_cond = pm.createNode("condition") pm.connectAttr(self.fkref_att, "{}.firstTerm".format(fk_ref_cond)) pm.setAttr("{}.secondTerm".format(fk_ref_cond), 0) pm.setAttr("{}.operation".format(fk_ref_cond), 0) pm.setAttr("{}.colorIfTrueR".format(fk_ref_cond), 0) pm.setAttr("{}.colorIfTrueG".format(fk_ref_cond), 0) pm.setAttr("{}.colorIfTrueB".format(fk_ref_cond), 0) pm.setAttr("{}.colorIfFalseR".format(fk_ref_cond), 0) pm.setAttr("{}.colorIfFalseG".format(fk_ref_cond), 0) pm.setAttr("{}.colorIfFalseB".format(fk_ref_cond), 0) pm.connectAttr("{}.outColorR".format(fk_ref_cond), "{}.rotateX".format(self.fk0_cns)) pm.connectAttr("{}.outColorG".format(fk_ref_cond), "{}.rotateY".format(self.fk0_cns)) pm.connectAttr("{}.outColorB".format(fk_ref_cond), "{}.rotateZ".format(self.fk0_cns)) if self.settings["fkrefarray"]: ref_names = self.settings["fkrefarray"].split(",") for i, ref_name in enumerate(ref_names): _head_ref_cond = pm.createNode("condition") pm.connectAttr("{}.outColorR".format(_head_ref_cond), "{}.colorIfFalseR".format(fk_ref_cond)) pm.connectAttr("{}.outColorG".format(_head_ref_cond), "{}.colorIfFalseG".format(fk_ref_cond)) pm.connectAttr("{}.outColorB".format(_head_ref_cond), "{}.colorIfFalseB".format(fk_ref_cond)) fk_ref_cond = _head_ref_cond pm.connectAttr(self.fkref_att, "{}.firstTerm".format(_head_ref_cond)) pm.setAttr("{}.secondTerm".format(_head_ref_cond), i + 1) pm.setAttr("{}.operation".format(_head_ref_cond), 0) src = self.rig.findRelative(ref_name) down, _, up = findPathAtoB(src, self.root) mult = pm.createNode("multMatrix") for i, d in enumerate(down): pm.connectAttr("{}.matrix".format(d), "{}.matrixIn[{}]".format(mult, i)) for j, u in enumerate(up): pm.connectAttr("{}.inverseMatrix".format(u), "{}.matrixIn[{}]".format(mult, i + j + 1)) decomp = pm.createNode("decomposeMatrix") pm.connectAttr("{}.matrixSum".format(mult), "{}.inputMatrix".format(decomp)) pm.connectAttr("{}.outputRotateX".format(decomp), "{}.colorIfTrueR".format(fk_ref_cond)) pm.connectAttr("{}.outputRotateY".format(decomp), "{}.colorIfTrueG".format(fk_ref_cond)) pm.connectAttr("{}.outputRotateZ".format(decomp), "{}.colorIfTrueB".format(fk_ref_cond))
def addBlendedJoint(oSel=None, compScale=True, blend=.5, name=None, select=True, *args): """Create and gimmick blended joint Create a joint that rotate 50% of the selected joint. This operation is done using a pairBlend node. Args: oSel (None or joint, optional): If None will use the selected joints. compScale (bool, optional): Set the compScale option of the blended joint. Default is True. blend (float, optional): blend rotation value name (None, optional): Name for the blended o_node *args: Maya's dummy Returns: list: blended joints list """ if not oSel: oSel = pm.selected() elif not isinstance(oSel, list): oSel = [oSel] jnt_list = [] for x in oSel: if isinstance(x, pm.nodetypes.Joint): parent = x.getParent() if name: bname = 'blend_' + name else: bname = 'blend_' + x.name() jnt = pm.createNode('joint', n=bname, p=x) jnt_list.append(jnt) jnt.attr('radius').set(1.5) pm.parent(jnt, parent) o_node = pm.createNode("pairBlend") o_node.attr("rotInterpolation").set(1) pm.setAttr(o_node + ".weight", blend) pm.connectAttr(x + ".translate", o_node + ".inTranslate1") pm.connectAttr(x + ".translate", o_node + ".inTranslate2") pm.connectAttr(x + ".rotate", o_node + ".inRotate1") pm.connectAttr(o_node + ".outRotateX", jnt + ".rotateX") pm.connectAttr(o_node + ".outRotateY", jnt + ".rotateY") pm.connectAttr(o_node + ".outRotateZ", jnt + ".rotateZ") pm.connectAttr(o_node + ".outTranslateX", jnt + ".translateX") pm.connectAttr(o_node + ".outTranslateY", jnt + ".translateY") pm.connectAttr(o_node + ".outTranslateZ", jnt + ".translateZ") pm.connectAttr(x + ".scale", jnt + ".scale") jnt.attr("overrideEnabled").set(1) jnt.attr("overrideColor").set(17) jnt.attr("segmentScaleCompensate").set(compScale) try: defSet = pm.PyNode("rig_deformers_grp") except TypeError: pm.sets(n="rig_deformers_grp") defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=jnt) else: pm.displayWarning("Blended Joint can't be added to: %s. Because " "is not ot type Joint" % x.name()) if jnt_list and select: pm.select(jnt_list) return jnt_list
test = pm.selected() #particle geo sphere creation import pymel.core as pm curve_selection = pm.selected() data_position_list = [] curve_root_list = [] yeti_outerRadius = [] for curve in curve_selection: cv_root = pm.PyNode(curve.name() + '.cv[0]') curve_root_list.append(cv_root) for root in curve_root_list: data_position = root.getPosition(space='world') data_position_list.append(data_position) clean_particle_group = pm.createNode( 'transform', name='Yeti_OutterRadius_grp', ) for number, position in enumerate(data_position_list): particle = pm.particle(p=[0, 0, 0], name=curve_selection[number].name() + '_' + str(number) + '_particle') particle[0].translate.set(position) particle[1].particleRenderType.set(4) pm.parent(particle[0], clean_particle_group)
# create zero groups ctrlsZerosAndOfss = ZeroGrp( ctrls ) ctrlsZeros = ctrlsZerosAndOfss[0] ctrlsOfss = ctrlsZerosAndOfss[1] jntsZerosAndOfss = ZeroGrp( jnts ) jntsZeros = jntsZerosAndOfss[0] jntsOfss = jntsZerosAndOfss[1] # connect transforms of ctrls to joints for i in range( len( ctrlsZeros ) ): ctrls[i].translate >> jntsOfss[i].translate ctrls[i].rotate >> jntsOfss[i].rotate ctrls[i].scale >> jntsOfss[i].scale # reverse the scale and connect it to next zeroGrp for i in range( len(ctrlsZeros)-1 ): scaleRev = pm.createNode( 'multiplyDivide', name='%s_scaleRev'%ctrlsZeros[i].name() ) scaleRev.input1.set(1,1,1) scaleRev.operation.set(2) ctrls[i].scale >> scaleRev.input2 scaleRev.output >> ctrlsZeros[i+1].scale for i in range( len(jntsZeros)-1 ): scaleRev = pm.createNode( 'multiplyDivide', name='%s_scaleRev'%jntsZeros[i].name() ) scaleRev.input1.set(1,1,1) scaleRev.operation.set(2) jntsOfss[i].scale >> scaleRev.input2 scaleRev.output >> jntsZeros[i+1].scale
def bdCreateReverseFootRoll(ankleLoc, heelLoc, ballLoc, toeLoc): blendColorHeelAuto = pm.createNode('blendColors', name=heelLoc.name().replace( 'loc', 'auto_BC')) blendColorBallAuto = pm.createNode('blendColors', name=ballLoc.name().replace( 'loc', 'auto_BC')) blendColorToeAuto = pm.createNode('blendColors', name=toeLoc.name().replace( 'loc', 'auto_BC')) ankleLoc.attr('Enabled').connect(blendColorHeelAuto.blender) ankleLoc.attr('Enabled').connect(blendColorBallAuto.blender) ankleLoc.attr('Enabled').connect(blendColorToeAuto.blender) ankleLoc.attr('HeelRoll').connect(blendColorHeelAuto.color2R) ankleLoc.attr('BallRoll').connect(blendColorBallAuto.color2R) ankleLoc.attr('TipRoll').connect(blendColorToeAuto.color2R) #setup auto part clampHeel = pm.createNode('clamp', n=heelLoc.name().replace('loc', 'roll_CL')) clampHeel.minR.set(-90) setRangeToe = pm.createNode('setRange', n=toeLoc.name().replace('loc', 'linestep_SR')) setRangeToe.minX.set(0) setRangeToe.maxX.set(1) setRangeBall1 = pm.createNode('setRange', n=ballLoc.name().replace( 'loc', 'linestep_SR')) setRangeBall1.minX.set(0) setRangeBall1.maxX.set(1) setRangeBall1.oldMinX.set(0) mdToeRoll = pm.createNode('multiplyDivide', n=toeLoc.name().replace('loc', 'roll_MD')) mdBallRoll = pm.createNode('multiplyDivide', n=ballLoc.name().replace('loc', 'roll_MD')) mdBallRange2 = pm.createNode('multiplyDivide', n=ballLoc.name().replace( 'loc', 'roll_range_MD')) pmaBallRange = pm.createNode('plusMinusAverage', n=ballLoc.name().replace('loc', 'range_PMA')) pmaBallRange.input1D[0].set(1) pmaBallRange.operation.set(2) #connect the heel for negative rolls ankleLoc.attr('Roll').connect(clampHeel.inputR) clampHeel.outputR.connect(blendColorHeelAuto.color1R) blendColorHeelAuto.outputR.connect(heelLoc.rotateX) #connect the toe ankleLoc.attr('Roll').connect(setRangeToe.valueX) ankleLoc.attr('BallStraight').connect(setRangeToe.oldMaxX) ankleLoc.attr('ToeStart').connect(setRangeToe.oldMinX) ankleLoc.attr('Roll').connect(mdToeRoll.input2X) setRangeToe.outValueX.connect(mdToeRoll.input1X) mdToeRoll.outputX.connect(blendColorToeAuto.color1R) blendColorToeAuto.outputR.connect(toeLoc.rotateX) #connect the ball ankleLoc.attr('Roll').connect(setRangeBall1.valueX) ankleLoc.attr('ToeStart').connect(setRangeBall1.oldMaxX) setRangeToe.outValueX.connect(pmaBallRange.input1D[1]) setRangeBall1.outValueX.connect(mdBallRange2.input1X) pmaBallRange.output1D.connect(mdBallRange2.input2X) ankleLoc.attr('Roll').connect(mdBallRoll.input2X) mdBallRange2.outputX.connect(mdBallRoll.input1X) mdBallRoll.outputX.connect(blendColorBallAuto.color1R) blendColorBallAuto.outputR.connect(ballLoc.rotateX)
def bdRigLegBones(side): ikAnimCon = pm.ls(side.upper() + '_Foot_CON', type='transform')[0] legBonesNames = ['Thigh', 'Shin', 'Foot', 'Toe'] legBones = [] for bone in legBonesNames: legBone = pm.ls(side + bone)[0] legBones.append(legBone) print legBone.name() toeEnd = pm.ls(side + 'Toe_end')[0] legBones.append(toeEnd) #START setup foot roll footIk = pm.ikHandle(sol='ikRPsolver', sticky='sticky', startJoint=legBones[0], endEffector=legBones[2], name=side + '_foot_ikHandle')[0] footIk.visibility.set(0) ballIk = pm.ikHandle(sol='ikSCsolver', sticky='sticky', startJoint=legBones[2], endEffector=legBones[3], name=side + '_ball_ikHandle')[0] ballIk.visibility.set(0) toeIk = pm.ikHandle(sol='ikSCsolver', sticky='sticky', startJoint=legBones[3], endEffector=legBones[4], name=side + '_toe_ikHandle')[0] toeIk.visibility.set(0) #create the groups that will controll the foot animations ( roll, bend, etc etc) footHelpers = pm.ls(side + '*_helper', type='transform') ankleLoc = bdCreateOffsetLoc(legBones[2], side + '_ankle_loc') footLoc = bdCreateOffsetLoc(legBones[2], side + '_foot_loc') ballLoc = bdCreateOffsetLoc(legBones[3], side + '_ball_loc') ballTwistLoc = bdCreateOffsetLoc(legBones[3], side + '_ball_twist_loc') toeLoc = bdCreateOffsetLoc(legBones[4], side + '_toe_loc') toeBendLoc = bdCreateOffsetLoc(legBones[3], side + '_toe_bend_loc') innerLoc = outerLoc = heelLoc = '' for helper in footHelpers: if 'inner' in helper.name(): innerLoc = bdCreateOffsetLoc(helper, side + '_inner_bank_loc') elif 'outer' in helper.name(): outerLoc = bdCreateOffsetLoc(helper, side + '_outer_bank_loc') elif 'heel' in helper.name(): heelLoc = bdCreateOffsetLoc(helper, side + '_heel_loc') #pm.delete(footHelpers) pm.parent(footIk, footLoc) pm.parent(ballIk, ballLoc) pm.parent(toeIk, toeBendLoc) pm.parent(toeBendLoc, toeLoc) pm.parent(footLoc, ballLoc) pm.parent(ballLoc, toeLoc) pm.parent(toeLoc, ballTwistLoc) pm.parent(ballTwistLoc, innerLoc) pm.parent(innerLoc, outerLoc) pm.parent(outerLoc, heelLoc) pm.parent(heelLoc, ankleLoc) #add atributes on the footGrp - will be conected later to an anim controler autoRollAttrList = ['Roll', 'ToeStart', 'BallStraight'] footAttrList = [ 'HeelTwist', 'BallTwist', 'TipTwist', 'Bank', 'ToeBend', 'KneeTwist' ] normalRollAttrList = ['HeelRoll', 'BallRoll', 'TipRoll'] pm.addAttr(ikAnimCon, ln='__AutoFootRoll__', nn='__AutoFootRoll__', at='bool') ikAnimCon.attr('__AutoFootRoll__').setKeyable(True) ikAnimCon.attr('__AutoFootRoll__').setLocked(True) pm.addAttr(ikAnimCon, ln='Enabled', nn='Enabled', at='long') ikAnimCon.attr('Enabled').setKeyable(True) ikAnimCon.attr('Enabled').setMin(0) ikAnimCon.attr('Enabled').setMax(1) ikAnimCon.attr('Enabled').set(1) pm.addAttr(ikAnimCon, ln='______', nn='______', at='bool') ikAnimCon.attr('______').setKeyable(True) ikAnimCon.attr('______').setLocked(True) for attr in autoRollAttrList: pm.addAttr(ikAnimCon, ln=attr, nn=attr, at='float') ikAnimCon.attr(attr).setKeyable(True) pm.addAttr(ikAnimCon, ln='__FootRoll__', nn='__FootRoll__', at='bool') ikAnimCon.attr('__FootRoll__').setKeyable(True) ikAnimCon.attr('__FootRoll__').setLocked(True) for attr in normalRollAttrList: pm.addAttr(ikAnimCon, ln=attr, nn=attr, at='float') ikAnimCon.attr(attr).setKeyable(True) pm.addAttr(ikAnimCon, ln='__FootAttr__', nn='__FootAttr__', at='bool') ikAnimCon.attr('__FootAttr__').setKeyable(True) ikAnimCon.attr('__FootAttr__').setLocked(True) for attr in footAttrList: pm.addAttr(ikAnimCon, ln=attr, nn=attr, at='float') ikAnimCon.attr(attr).setKeyable(True) ikAnimCon.attr('ToeStart').set(40) ikAnimCon.attr('BallStraight').set(80) bdCreateReverseFootRoll(ikAnimCon, heelLoc, ballLoc, toeLoc) #connect the attributes ikAnimCon.attr('HeelTwist').connect(heelLoc.rotateY) ikAnimCon.attr('BallTwist').connect(ballTwistLoc.rotateY) ikAnimCon.attr('TipTwist').connect(toeLoc.rotateY) ikAnimCon.attr('ToeBend').connect(toeBendLoc.rotateX) bdConnectBank(ikAnimCon, innerLoc, outerLoc) #START no flip knee knee mirror = 1 if side == 'r': mirror = -1 offset = 90 poleVectorLoc = pm.spaceLocator(name=side + '_knee_loc_PV') poleVectorLocGrp = pm.group(poleVectorLoc, n=poleVectorLoc + '_GRP') thighPos = legBones[0].getTranslation(space='world') poleVectorLocGrp.setTranslation( [thighPos[0] + mirror * 5, thighPos[1], thighPos[2]]) pm.poleVectorConstraint(poleVectorLoc, footIk) adlNode = pm.createNode('addDoubleLinear', name=side + '_adl_twist') adlNode.input2.set(mirror * offset) ikAnimCon.attr('KneeTwist').connect(adlNode.input1) adlNode.output.connect(footIk.twist) startTwist = mirror * offset limit = 0.001 increment = mirror * 0.01 while True: pm.select(cl=True) thighRot = pm.xform(legBones[0], q=True, ro=True, os=True) print thighRot[0] if ((thighRot[2] > limit)): startTwist = startTwist - increment adlNode.input2.set(startTwist) else: break #END knee pm.parent(ankleLoc, ikAnimCon)
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. """ # 1 bone chain Upv ref ============================================== self.ikHandleUpvRef = primitive.addIkHandle( self.root, self.getName("ikHandleArmChainUpvRef"), self.armChainUpvRef, "ikSCsolver") pm.pointConstraint(self.ik_ctl, self.ikHandleUpvRef) pm.parentConstraint(self.armChainUpvRef[0], self.upv_cns, mo=True) # Visibilities ------------------------------------- # 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")) if self.settings["ikTR"]: for shp in self.ikRot_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) for shp in self.roll_ctl.getShapes(): pm.connectAttr(self.blend_att, shp.attr("visibility")) # Controls ROT order ----------------------------------- attribute.setRotOrder(self.fk0_ctl, "XZY") attribute.setRotOrder(self.fk1_ctl, "XYZ") attribute.setRotOrder(self.fk2_ctl, "YZX") attribute.setRotOrder(self.ik_ctl, "XYZ") # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] o_node = applyop.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) # NOTE: Ideally we should not change hierarchy or move object after # object generation method. But is much easier this way since every # part is in the final and correct position # after the ctrn_loc is in the correct position with the ikfk2bone op # point constrain tip reference pm.pointConstraint(self.ik_ctl, self.tip_ref, mo=False) # interpolate transform mid point locator int_matrix = applyop.gear_intmatrix_op( self.armChainUpvRef[0].attr("worldMatrix"), self.tip_ref.attr("worldMatrix"), .5) applyop.gear_mulmatrix_op( int_matrix.attr("output"), self.interpolate_lvl.attr("parentInverseMatrix[0]"), self.interpolate_lvl) # match roll ctl npo to ctrn_loc current transform (so correct orient) transform.matchWorldTransform(self.ctrn_loc, self.roll_ctl_npo) # match roll ctl npo to interpolate transform current position pos = self.interpolate_lvl.getTranslation(space="world") self.roll_ctl_npo.setTranslation(pos, space="world") # parent constraint roll control npo to interpolate trans pm.parentConstraint(self.interpolate_lvl, self.roll_ctl_npo, mo=True) if self.settings["ikTR"]: # connect the control inputs outEff_dm = o_node.listConnections(c=True)[-1][1] inAttr = self.ikRot_npo.attr("translate") outEff_dm.attr("outputTranslate") >> inAttr outEff_dm.attr("outputScale") >> self.ikRot_npo.attr("scale") dm_node = node.createDecomposeMatrixNode(o_node.attr("outB")) dm_node.attr("outputRotate") >> self.ikRot_npo.attr("rotate") # rotation mulM_node = applyop.gear_mulmatrix_op( self.ikRot_ctl.attr("worldMatrix"), self.eff_loc.attr("parentInverseMatrix")) intM_node = applyop.gear_intmatrix_op(o_node.attr("outEff"), mulM_node.attr("output"), o_node.attr("blend")) dm_node = node.createDecomposeMatrixNode(intM_node.attr("output")) dm_node.attr("outputRotate") >> self.eff_loc.attr("rotate") transform.matchWorldTransform(self.fk2_ctl, self.ikRot_cns) # scale: this fix the scalin popping issue intM_node = applyop.gear_intmatrix_op( self.fk2_ctl.attr("worldMatrix"), self.ik_ctl_ref.attr("worldMatrix"), o_node.attr("blend")) mulM_node = applyop.gear_mulmatrix_op( intM_node.attr("output"), self.eff_loc.attr("parentInverseMatrix")) dm_node = node.createDecomposeMatrixNode(mulM_node.attr("output")) dm_node.attr("outputScale") >> self.eff_loc.attr("scale") pm.connectAttr(self.blend_att, o_node + ".blend") if self.negate: mulVal = -1 rollMulVal = 1 else: mulVal = 1 rollMulVal = -1 roll_m_node = node.createMulNode(self.roll_att, mulVal) roll_m_node2 = node.createMulNode(self.roll_ctl.attr("rx"), rollMulVal) node.createPlusMinusAverage1D( [roll_m_node.outputX, roll_m_node2.outputX], operation=1, output=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 --------------------------------- pm.pointConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) pm.connectAttr(self.mid_ctl.scaleX, self.tws1_loc.scaleX) pm.orientConstraint(self.mid_ctl_twst_ref, self.tws1_npo, maintainOffset=False) 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")) o_node = applyop.gear_mulmatrix_op( self.eff_loc.attr("worldMatrix"), self.tws2_rot.attr("parentInverseMatrix")) dm_node = pm.createNode("decomposeMatrix") pm.connectAttr(o_node + ".output", dm_node + ".inputMatrix") attribute.setRotOrder(self.tws2_rot, "XYZ") pm.connectAttr(dm_node + ".outputRotate", self.tws2_rot + ".rotate") self.tws0_rot.setAttr("sx", .001) self.tws2_rot.setAttr("sx", .001) add_node = node.createAddNode(self.roundness_att, .001) pm.connectAttr(add_node + ".output", self.tws1_rot.attr("sx")) pm.connectAttr(self.armpit_roll_att, self.tws0_rot + ".rotateX") # Roll Shoulder applyop.splineIK(self.getName("rollRef"), self.rollRef, parent=self.root, cParent=self.bone0) # 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.attr("sx")) 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" if self.settings["extraTweak"]: for tweak_ctl in self.tweak_ctl: for shp in tweak_ctl.getShapes(): pm.connectAttr(self.tweakVis_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 self.settings["supportJoints"]: if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .49 elif i < (self.settings["div0"] + 3): perc = .50 elif i < (self.settings["div0"] + 4): perc = .51 else: perc = .5 + \ (i - self.settings["div0"] - 3.0) * .5 / \ (self.settings["div1"] + 1.0) else: if i < (self.settings["div0"] + 1): perc = i * .5 / (self.settings["div0"] + 1.0) elif i < (self.settings["div0"] + 2): perc = .501 else: perc = .5 + \ (i - self.settings["div0"] - 1.0) * .5 / \ (self.settings["div1"] + 1.0) perc = max(.001, min(.990, perc)) # Roll if self.negate: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1.0 - perc, 40) else: o_node = applyop.gear_rollsplinekine_op( div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, 40) pm.connectAttr(self.resample_att, o_node + ".resample") pm.connectAttr(self.absolute_att, o_node + ".absolute") # 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") # match IK/FK ref pm.parentConstraint(self.bone0, self.match_fk0_off, mo=True) pm.parentConstraint(self.bone1, self.match_fk1_off, mo=True) if self.settings["ikTR"]: transform.matchWorldTransform(self.ikRot_ctl, self.match_ikRot) transform.matchWorldTransform(self.fk_ctl[2], self.match_fk2) return
def createPoseReader(target, rotation=None, name=None, outerRadius=90.0, innerRadius=0.0): target = pm.ls(target)[0] rotation = rotation or (0.0, 0.0, 0.0) if not name: suf = '_'.join( map(lambda p: p[0] + str(int(p[1])).replace('-', 'n'), zip(('x', 'y', 'z'), rotation))) name = 'poseReader_' + target.nodeName() + '_' + suf # Create reader as curve reader = pm.curve(name=name, **arrow) reader.overrideEnabled.set(1) reader.overrideColor.set(3) # Position reader on target mult = pm.createNode('multMatrix', name=name + '_OFFSET') mult.matrixIn[0].set(target.xformMatrix.get()) # Parent reader if target has parent parent = target.getParent() if parent: pm.connectAttr(parent.worldMatrix, mult.matrixIn[1]) pm.connectAttr(mult.matrixSum, reader.offsetParentMatrix) # Create vectorProduct and angleBetween nodes ab = pm.createNode('angleBetween', name=name + '_ANGLE') vps = [ pm.createNode('vectorProduct', name=name + '_VEC{}'.format(i)) for i in range(2) ] # Connect vps for src, vp in zip((reader, target), vps): vp.operation.set(3) vp.input1.set(1, 0, 0) pm.connectAttr(src.worldMatrix, vp.matrix) ab_in = 'vector1' if vp == vps[0] else 'vector2' pm.connectAttr(vp.output, ab.attr(ab_in)) # Create remapValue rv = pm.createNode('remapValue', name=name + '_VALUE') for i in range(2): rv.value[i].value_FloatValue.set(1 - i) # Create reader attributes pm.addAttr(reader, ln='outerRadius', at='float', maxValue=180.0, defaultValue=90.0, k=True) pm.addAttr(reader, ln='innerRadius', at='float', maxValue=180.0, k=True) pm.addAttr(reader, ln='poseWeight', at='float', k=True) # Connect angle & reader attributes pm.connectAttr(ab.angle, rv.inputValue) pm.connectAttr(reader.outerRadius, rv.inputMax) pm.connectAttr(reader.innerRadius, rv.inputMin) pm.connectAttr(rv.outValue, reader.poseWeight) # Rotate & set reader radius reader.outerRadius.set(pm.dt.Vector(rotation).length()) pm.rotate(reader, rotation, r=True) pm.select(reader)
def connectBndToPivot(bnd, pivot, drivePrimary=False): ''' basically the same at face.connectBndToPriCtl but can don't drive primary controls ''' # bnd's "local" matrix within pivot bnd_wMat = bnd.getMatrix(ws=True) pivot_wMat = pivot.getMatrix(ws=True) bnd_lMat = bnd_wMat * pivot_wMat.inverse() lMatNd = pm.createNode('fourByFourMatrix', n=bnd.replace('_bnd', '_lMat_in_' + pivot.nodeName())) # populate "local" matrix for i in range(4): for j in range(4): lMatNd.attr('in%d%d' % (i, j)).set(bnd_lMat[i][j]) # bnd's "local-inverse" matrix lInvMatNd = pm.createNode('inverseMatrix', n=bnd.replace('_bnd', '_lInvMat_in_' + pivot.nodeName())) lMatNd.output >> lInvMatNd.inputMatrix # for bnd to pivot around pivot, # the matrix is lMat * pivotMat * lInvMat mmNd = pm.createNode('multMatrix', n=bnd.replace('_bnd', '_calc_mm')) lMatNd.output >> mmNd.i[0] pivot.matrix >> mmNd.i[1] lInvMatNd.outputMatrix >> mmNd.i[2] # decompose matrix before passing into bw dmNd = pm.createNode('decomposeMatrix', n=bnd.replace('_bnd', '_calc_dm')) mmNd.o >> dmNd.inputMatrix # get bw nodes to connect to channels = ['tx', 'ty', 'tz', 'rx', 'ry', 'rz', 'sx', 'sy', 'sz'] bwNodes = {} for eachChannel in channels: bwNodes[eachChannel] = bnd.attr(eachChannel + '_bwMsg').get() # get index to connect to existingInputs = bwNodes['tx'].i.inputs() nextIndex = len(existingInputs) # actual connections dmNd.otx >> bwNodes['tx'].i[nextIndex] dmNd.oty >> bwNodes['ty'].i[nextIndex] dmNd.otz >> bwNodes['tz'].i[nextIndex] dmNd.orx >> bwNodes['rx'].i[nextIndex] dmNd.ory >> bwNodes['ry'].i[nextIndex] dmNd.orz >> bwNodes['rz'].i[nextIndex] dmNd.osx >> bwNodes['sx'].i[nextIndex] dmNd.osy >> bwNodes['sy'].i[nextIndex] dmNd.osz >> bwNodes['sz'].i[nextIndex] # channel box separator bnd.addAttr(pivot.nodeName() + '_weights', at='double', k=True, dv=0) bnd.setAttr(pivot.nodeName() + '_weights', lock=True) # connect weight to be blended to 0 for eachChannel in ['tx', 'ty', 'tz', 'rx', 'ry', 'rz']: bnd.addAttr(pivot.nodeName() + '_weight_' + eachChannel, at='double', k=True, min=-1, max=2, dv=1) bnd.attr(pivot.nodeName() + '_weight_' + eachChannel) >> bwNodes[eachChannel].weight[nextIndex] # scales need a minus 1, to be normalized to 0 for blending for eachChannel in ['sx', 'sy', 'sz']: adl = pm.createNode('addDoubleLinear', n=bnd.replace('_bnd', '_%s_adl' % eachChannel)) adl.input2.set(-1) dmNd.attr('o%s' % eachChannel) >> adl.input1 adl.output >> bwNodes[eachChannel].i[nextIndex] bnd.addAttr(pivot.nodeName() + '_weight_' + eachChannel, at='double', k=True, min=-1, max=2, dv=1) bnd.attr(pivot.nodeName() + '_weight_' + eachChannel) >> bwNodes[eachChannel].weight[nextIndex] if drivePrimary: # if this bnd already has it's own attached priCtl # we need to drive that too if bnd.hasAttr('attached_pri_ctl'): attachedCtl = bnd.attr('attached_pri_ctl').get() if attachedCtl != pivot: print 'Bnd: ' + bnd print 'Current Pri Ctl: ' + pivot print 'Attached Pri Ctl: ' + attachedCtl attachedCtg = attachedCtl.getParent() # add zero grp to take in connections zeroGrp = pm.PyNode( cgmrigging.groupMeObject(attachedCtg.nodeName(), True, True)) for eachChannel in channels: mdl = pm.createNode( 'multDoubleLinear', n=bnd.replace('_bnd', '_%s_%s_mdl' % (eachChannel, pivot))) if eachChannel in ['sx', 'sy', 'sz']: adl = pm.createNode( 'addDoubleLinear', n=bnd.replace('_bnd', '_%s_%s_adl' % (eachChannel, pivot))) dmNd.attr('o' + eachChannel) >> adl.input1 adl.input2.set(-1) adl.output >> mdl.input1 else: dmNd.attr('o' + eachChannel) >> mdl.input1 bnd.attr(pivot.nodeName() + '_weight_' + eachChannel) >> mdl.input2 if eachChannel in ['sx', 'sy', 'sz']: adl = pm.createNode( 'addDoubleLinear', n=bnd.replace('_bnd', '_%s_%s_adl' % (eachChannel, pivot))) mdl.output >> adl.input1 adl.input2.set(1) adl.output >> zeroGrp.attr(eachChannel) else: mdl.output >> zeroGrp.attr(eachChannel)
def createRivetTweak(mesh, edgePair, name, parent=None, parentJnt=None, ctlParent=None, color=[0, 0, 0], size=.04, defSet=None, ctlSet=None, side=None, gearMulMatrix=True): """Create a tweak joint attached to the mesh using a rivet Args: mesh (mesh): The object to add the tweak edgePair (pari list): The edge pairt to create the rivet name (str): The name for the tweak parent (None or dagNode, optional): The parent for the tweak parentJnt (None or dagNode, optional): The parent for the joints ctlParent (None or dagNode, optional): The parent for the tweak control color (list, optional): The color for the control size (float, optional): Size of the control defSet (None or set, optional): Deformer set to add the joints ctlSet (None or set, optional): the set to add the controls side (None, str): String to set the side. Valid values are L, R or C. If the side is not set or the value is not valid, the side will be set automatically based on the world position gearMulMatrix (bool, optional): If False will use Maya default multiply matrix node Returns: PyNode: The tweak control """ blendShape = blendShapes.getBlendShape(mesh) inputMesh = blendShape.listConnections(sh=True, t="shape", d=False)[0] oRivet = rivet.rivet() base = oRivet.create(inputMesh, edgePair[0], edgePair[1], parent) # get side if not side or side not in ["L", "R", "C"]: if base.getTranslation(space='world')[0] < -0.01: side = "R" elif base.getTranslation(space='world')[0] > 0.01: side = "L" else: side = "C" nameSide = name + "_tweak_" + side pm.rename(base, nameSide) if not ctlParent: ctlParent = base ctl_parent_tag = None else: ctl_parent_tag = ctlParent # Joints NPO npo = pm.PyNode( pm.createNode("transform", n=nameSide + "_npo", p=ctlParent, ss=True)) pm.pointConstraint(base, npo, mo=False) # create joints if not parentJnt: parentJnt = npo matrix_cnx = False else: # need extra connection to ensure is moving with th npo, even is # not child of npo matrix_cnx = True jointBase = primitive.addJoint(parentJnt, nameSide + "_jnt_lvl") joint = primitive.addJoint(jointBase, nameSide + "_jnt") # reset axis and invert behaviour for axis in "XYZ": pm.setAttr(jointBase + ".jointOrient" + axis, 0) pm.setAttr(npo + ".translate" + axis, 0) # pm.setAttr(jointBase + ".translate" + axis, 0) pp = npo.getParent() pm.parent(npo, w=True) for axis in "xyz": npo.attr("r" + axis).set(0) if side == "R": npo.attr("ry").set(180) npo.attr("sz").set(-1) pm.parent(npo, pp) dm_node = None if matrix_cnx: mulmat_node = applyop.gear_mulmatrix_op( npo + ".worldMatrix", jointBase + ".parentInverseMatrix") dm_node = node.createDecomposeMatrixNode(mulmat_node + ".output") m = mulmat_node.attr('output').get() pm.connectAttr(dm_node + ".outputTranslate", jointBase + ".t") pm.connectAttr(dm_node + ".outputRotate", jointBase + ".r") # invert negative scaling in Joints. We only inver Z axis, so is # the only axis that we are checking print dm_node.attr("outputScaleZ").get() if dm_node.attr("outputScaleZ").get() < 0: mul_nod_invert = node.createMulNode(dm_node.attr("outputScaleZ"), -1) out_val = mul_nod_invert.attr("outputX") else: out_val = dm_node.attr("outputScaleZ") pm.connectAttr(dm_node.attr("outputScaleX"), jointBase + ".sx") pm.connectAttr(dm_node.attr("outputScaleY"), jointBase + ".sy") pm.connectAttr(out_val, jointBase + ".sz") pm.connectAttr(dm_node + ".outputShear", jointBase + ".shear") # Segment scale compensate Off to avoid issues with the global # scale jointBase.setAttr("segmentScaleCompensate", 0) joint.setAttr("segmentScaleCompensate", 0) jointBase.setAttr("jointOrient", 0, 0, 0) # setting the joint orient compensation in order to have clean # rotation channels jointBase.attr("jointOrientX").set(jointBase.attr("rx").get()) jointBase.attr("jointOrientY").set(jointBase.attr("ry").get()) jointBase.attr("jointOrientZ").set(jointBase.attr("rz").get()) im = m.inverse() if gearMulMatrix: mul_nod = applyop.gear_mulmatrix_op(mulmat_node.attr('output'), im, jointBase, 'r') dm_node2 = mul_nod.output.listConnections()[0] else: mul_nod = node.createMultMatrixNode(mulmat_node.attr('matrixSum'), im, jointBase, 'r') dm_node2 = mul_nod.matrixSum.listConnections()[0] if dm_node.attr("outputScaleZ").get() < 0: negateTransformConnection(dm_node2.outputRotate, jointBase.rotate) else: resetJntLocalSRT(jointBase) # hidding joint base by changing the draw mode pm.setAttr(jointBase + ".drawStyle", 2) if not defSet: try: defSet = pm.PyNode("rig_deformers_grp") except TypeError: pm.sets(n="rig_deformers_grp", empty=True) defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=joint) controlType = "sphere" o_icon = icon.create(npo, nameSide + "_ctl", datatypes.Matrix(), color, controlType, w=size) transform.resetTransform(o_icon) if dm_node and dm_node.attr("outputScaleZ").get() < 0: pm.connectAttr(o_icon.scale, joint.scale) negateTransformConnection(o_icon.rotate, joint.rotate) negateTransformConnection(o_icon.translate, joint.translate, [1, 1, -1]) else: for t in [".translate", ".scale", ".rotate"]: pm.connectAttr(o_icon + t, joint + t) # create the attributes to handlde mirror and symetrical pose attribute.addAttribute(o_icon, "invTx", "bool", 0, keyable=False, niceName="Invert Mirror TX") attribute.addAttribute(o_icon, "invTy", "bool", 0, keyable=False, niceName="Invert Mirror TY") attribute.addAttribute(o_icon, "invTz", "bool", 0, keyable=False, niceName="Invert Mirror TZ") attribute.addAttribute(o_icon, "invRx", "bool", 0, keyable=False, niceName="Invert Mirror RX") attribute.addAttribute(o_icon, "invRy", "bool", 0, keyable=False, niceName="Invert Mirror RY") attribute.addAttribute(o_icon, "invRz", "bool", 0, keyable=False, niceName="Invert Mirror RZ") attribute.addAttribute(o_icon, "invSx", "bool", 0, keyable=False, niceName="Invert Mirror SX") attribute.addAttribute(o_icon, "invSy", "bool", 0, keyable=False, niceName="Invert Mirror SY") attribute.addAttribute(o_icon, "invSz", "bool", 0, keyable=False, niceName="Invert Mirror SZ") # magic of doritos connection pre_bind_matrix_connect(mesh, joint, jointBase) # add control tag node.add_controller_tag(o_icon, ctl_parent_tag) if not ctlSet: try: ctlSet = pm.PyNode("rig_controllers_grp") except TypeError: pm.sets(n="rig_controllers_grp", empty=True) ctlSet = pm.PyNode("rig_controllers_grp") pm.sets(ctlSet, add=o_icon) return o_icon
def build(self, ctrl_ik_orientation=None, constraint=True, constraint_handle=True, setup_softik=True, *args, **kwargs): """ Build the ik system when needed :param ctrl_ik_orientation: The ik ctrl orientation override :param constraint: Bool to tell if we constraint the chain_jnt to the system :param constraint_handle: Bool to tell if we constraint the ik handle to the ik ctrl :param setup_softik: Bool to tell if we setup the soft ik on this system :param args: More args passed to the superclass :param kwargs: More kwargs passed to the superclass :return: """ nomenclature_anm = self.get_nomenclature_anm() nomenclature_rig = self.get_nomenclature_rig() index_elbow = 1 #The elbow will always be on the second bone index_hand = self.iCtrlIndex jnt_elbow = self.chain_jnt[index_elbow] jnt_hand = self.chain_jnt[index_hand] #Compute swivel pos before any operation is done on the bones swivel_pos = self.calc_swivel_pos() # Create a group for the ik system # This group will be parentConstrained to the module parent. ikChainGrp_name = nomenclature_rig.resolve('ikChain') self._ikChainGrp = pymel.createNode('transform', name=ikChainGrp_name, parent=self.grp_rig) self._ikChainGrp.setMatrix(self.chain.start.getMatrix(worldSpace=True), worldSpace=True) super(IK, self).build(*args, **kwargs) self._ikChainGrp.setParent(self.grp_rig) # Duplicate input chain (we don't want to move the hierarchy) #self._chain_ik = pymel.duplicate(list(self.chain_jnt), renameChildren=True, parentOnly=True) self._chain_ik = self.chain.duplicate() i = 1 for oIk in self._chain_ik: oIk.rename(nomenclature_rig.resolve('{0:02}'.format(i))) i += 1 self._chain_ik[0].setParent( self.parent) # Trick the IK system (temporary solution) obj_e = self._chain_ik[index_hand] # Compute chain length self.chain_length = libPymel.PyNodeChain(self.chain[:self.iCtrlIndex + 1]).length() #self.chain_length = self.chain.length() # Create ikChain self._chain_ik[0].setParent(self._ikChainGrp) # Create ikEffector ik_solver_name = nomenclature_rig.resolve('ikHandle') ik_effector_name = nomenclature_rig.resolve('ikEffector') self._ik_handle, _ik_effector = self.create_ik_handle() self._ik_handle.rename(ik_solver_name) self._ik_handle.setParent(self._ikChainGrp) _ik_effector.rename(ik_effector_name) # Create CtrlIK if not isinstance(self.ctrl_ik, self._CLASS_CTRL_IK): self.ctrl_ik = self._CLASS_CTRL_IK() ctrl_ik_refs = [jnt_hand] + jnt_hand.getChildren(allDescendents=True) self.ctrl_ik.build( refs=ctrl_ik_refs, geometries=self.rig.get_meshes()) # refs is used by CtrlIkCtrl self.ctrl_ik.setParent(self.grp_anm) ctrl_ik_name = nomenclature_anm.resolve('ik') self.ctrl_ik.rename(ctrl_ik_name) self.ctrl_ik.offset.setTranslation(obj_e.getTranslation(space='world'), space='world') # Set ctrl_ik_orientation if ctrl_ik_orientation is None: ctrl_ik_orientation = obj_e.getRotation(space='world') self.ctrl_ik.offset.setRotation(ctrl_ik_orientation, space='world') self.ctrl_ik.create_spaceswitch(self, self.parent, default_name='World') # Create the ik_handle_target that will control the ik_handle # This is allow us to override what control the main ik_handle # Mainly used for the Leg setup self._ik_handle_target = pymel.createNode( 'transform', name=nomenclature_rig.resolve('ikHandleTarget')) self._ik_handle_target.setParent(self.grp_rig) pymel.pointConstraint(self.ctrl_ik, self._ik_handle_target) # # Create softIk node and connect user accessible attributes to it. # if setup_softik: self.setup_softik([self._ik_handle], self._chain_ik) # Connect global scale pymel.connectAttr(self.grp_rig.globalScale, self._ikChainGrp.sx) pymel.connectAttr(self.grp_rig.globalScale, self._ikChainGrp.sy) pymel.connectAttr(self.grp_rig.globalScale, self._ikChainGrp.sz) #Setup swivel self.ctrl_swivel = self.setup_swivel_ctrl(self.ctrl_swivel, jnt_elbow, swivel_pos, self._ik_handle) self.swivelDistance = self.chain_length # Used in ik/fk switch #pymel.poleVectorConstraint(flip_swivel_ref, self._ik_handle) # Connect rig -> anm if constraint_handle: pymel.pointConstraint(self.ctrl_ik, self._ik_handle, maintainOffset=True) pymel.orientConstraint(self.ctrl_ik, obj_e, maintainOffset=True) if constraint: for source, target in zip(self._chain_ik, self.chain): pymel.parentConstraint(source, target)
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 save(filename, objs=None, forceOverwrite=False, forceKeys=False, start=None, end=None): ''' Given a list of objects, save all the anim curves for t/r/s/v and user defined to the given filename. :param bool forceOverwrite: Allow prompting if the dest file already exists :param bool forceKeys: Put keys on the objects .. todo:: * Check if an attribute ISN'T keyed in the source and mark the static value somehow. Specifically, if parent/world stuff isn't present, copying animations goes poorly. * At some point animation layers need to be addressed properly. ''' global TAGGING_ATTR # USING CMDS VERSION FOR SPEED #listAttr = cmds.listAttr #listConnections = cmds.listConnections #addAttr = cmds.addAttr #setAttr = cmds.setAttr #duplicate = cmds.duplicate # --- sel = selected() objs = objs if objs else selected() info = createNode('network') info.addAttr('start', at='long') info.addAttr('end', at='long') info.addAttr('staticValues', dt='string') if start is None: start = playbackOptions(q=True, min=True) if end is None: end = playbackOptions(q=True, max=True) if start >= end: end = start + 1 info.start.set(start) info.end.set(end) defaultAttrs = [t + a for t in 'trs' for a in 'xyz'] + ['visibility'] dups = [] staticValues = {} for obj in objs: zooHack = ['ikBlend'] if obj.hasAttr('ikBlend') else [ ] # Since use uses builtin ik trans, this doesn't get picked up. if obj.hasAttr('tx'): attrs = chain(listAttr(obj.name(), ud=True, k=True), defaultAttrs, zooHack) else: attrs = chain(listAttr(obj.name(), ud=True, k=True), zooHack) for attr in attrs: _processAttr(obj.name() + '.' + attr, dups, forceKeys, staticValues, start, end) if not dups: warning("Nothing was animated") return info.staticValues.set(core.text.asciiCompress(json.dumps(staticValues))) select(dups, info) exportSelected(filename, force=forceOverwrite) select(sel) delete(dups)
def addOperators(self): # 1 bone chain Upv ref ===================================================================================== self.ikHandleUpvRef = pri.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 = 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")) # IK Solver ----------------------------------------- out = [self.bone0, self.bone1, self.ctrn_loc, self.eff_loc] node = aop.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, node+".blend") if self.negate: mulVal = -1 else: mulVal = 1 nod.createMulNode(self.roll_att, mulVal, node+".roll") # 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 --------------------------------- self.ikhArmRef, self.tmpCrv = aop.splineIK(self.getName("legRollRef"), self.rollRef, parent=self.root, cParent=self.bone0 ) pm.pointConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) pm.scaleConstraint(self.mid_ctl, self.tws1_loc, maintainOffset=False) aop.oriCns(self.mid_ctl, self.tws1_rot, maintainOffset=False) pm.pointConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) pm.scaleConstraint(self.eff_loc, self.tws2_loc, maintainOffset=False) aop.oriCns(self.bone1, self.tws2_loc, maintainOffset=False) aop.oriCns(self.tws_ref, self.tws2_rot) self.tws0_loc.setAttr("sx", .001) self.tws2_loc.setAttr("sx", .001) add_node = nod.createAddNode(self.roundness_att, .001) pm.connectAttr(add_node+".output", self.tws1_rot.attr("sx")) # 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_ctl.attr("sx")) #comp scaling issue 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" # 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): subdiv = False if i == len(self.div_cns)-1 or i == 0: subdiv = 45 else: subdiv = 10 if i < (self.settings["div0"]+1): perc = i*.5 / (self.settings["div0"]+1.0) elif i < (self.settings["div0"] + 2): perc = .49 subdiv = 45 elif i < (self.settings["div0"] + 3 ): perc = .50 subdiv = 45 elif i < (self.settings["div0"] + 4 ): perc = .51 subdiv = 45 else: perc = .5 + (i-self.settings["div0"]-3.0)*.5 / (self.settings["div1"]+1.0) perc = max(.001, min(.999, perc)) # Roll if self.negate: node = aop.gear_rollsplinekine_op(div_cns, [self.tws2_rot, self.tws1_rot, self.tws0_rot], 1-perc, subdiv) else: node = aop.gear_rollsplinekine_op(div_cns, [self.tws0_rot, self.tws1_rot, self.tws2_rot], perc, subdiv) pm.connectAttr(self.resample_att, node+".resample") pm.connectAttr(self.absolute_att, node+".absolute") # 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") # 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) return
def bs_createTextureBase(assetName, assetGrade, assetType, episode=None): """ @ create Texture Base group in reference model file in rig. Args: assetName (str): Model Name. assetGrade (str): Character Grade (Primary, Secondary, Tertiary). assetType (str): Asset Type Character, Prop, Set, Vehicle episode (str): asset Name dodo is like (dod). Returns: top Texture group. """ # raise popup window for current scene will be discarded if maya is not in batch mode. if not pm.about(batch=True): confirmation = pm.windows.confirmDialog( title='Confirm', message="Don't Save Current Scene\nAnd Load New Scene?", button=['Yes', 'No'], defaultButton='Yes') if confirmation == 'Yes': pm.newFile(f=True) else: print 'process cancelled', return False # get environments. serverPath = bs_pathGenerator.bs_getEnv()['projectDir'] # get model directory. if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': modelFile = bs_pathGenerator.bs_getOnlyFinalFileOfDept(assetType, 'Model', assetName, episode=episode) else: modelFile = bs_pathGenerator.bs_getOnlyFinalFileOfDept( assetType, 'Model', assetName) # create path using environment variable. modelFile = modelFile.replace(serverPath, '$BSW_PROJECT_DIR') bs_reference.bs_createReference(modelFile, prefixStyle='withoutNamespace', prefixName='') # create Texture Group. topGrp = pm.createNode('transform', n='Texture_Group', ss=True) # add asset uid. astTypShortCode = { 'Character': 'ch', 'Prop': 'pr', 'Set': 'bg', 'Vehicle': 'vh', 'SetElement': 'se' } if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': uid = 'bsw_' + astTypShortCode[ assetType] + '_' + assetName + '_tex_' + episode else: uid = 'bsw_' + astTypShortCode[assetType] + '_' + assetName + '_tex' # add attributes. pm.addAttr(topGrp, ln='assetBase', dt='string', k=True) pm.addAttr(topGrp, ln='assetType', dt='string', k=True) pm.addAttr(topGrp, ln='assetName', dt='string', k=True) pm.addAttr(topGrp, ln='assetGrade', dt='string', k=True) if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': pm.addAttr(topGrp, ln='assetEpisode', dt='string', k=True) pm.addAttr(topGrp, ln='assetUID', dt='string', k=True) # set Values. pm.setAttr(topGrp + '.assetBase', 'Asset') pm.setAttr(topGrp + '.assetBase', l=True) pm.setAttr(topGrp + '.assetType', assetType) pm.setAttr(topGrp + '.assetType', l=True) pm.setAttr(topGrp + '.assetName', assetName) pm.setAttr(topGrp + '.assetName', l=True) pm.setAttr(topGrp + '.assetGrade', assetGrade) pm.setAttr(topGrp + '.assetGrade', l=True) if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': pm.setAttr(topGrp + '.assetEpisode', episode) pm.setAttr(topGrp + '.assetEpisode', l=True) pm.setAttr(topGrp + '.assetUID', uid) pm.setAttr(topGrp + '.assetUID', l=True) # parent referenced model top group in texture group. pm.parent('geo', topGrp) if bs_pathGenerator.bs_getEnv()['projectType'] == 'series': bs_pathGenerator.bs_createAssetDirectories(assetType, assetName, episode=episode) else: bs_pathGenerator.bs_createAssetDirectories(assetType, assetName) bs_qui.bs_displayMessage( 'success', 'asset Created success and created sourceimages directory') return topGrp
def addJnt(obj=False, parent=False, noReplace=False, grp=None, jntName=None, *args): """Create one joint for each selected object. Args: obj (bool or dagNode, optional): The object to drive the new joint. If False will use the current selection. parent (bool or dagNode, optional): The parent for the joint. If False will try to parent to jnt_org. If jnt_org doesn't exist will parent the joint under the obj noReplace (bool, optional): If True will add the extension "_jnt" to the new joint name grp (pyNode or None, optional): The set to add the new joint. If none will use "rig_deformers_grp" *args: Maya's dummy Returns: pyNode: The New created joint. """ if not obj: oSel = pm.selected() else: oSel = [obj] for obj in oSel: if not parent: try: oParent = pm.PyNode("jnt_org") except TypeError: oParent = obj else: oParent = parent if not jntName: if noReplace: jntName = "_".join(obj.name().split("_")) + "_jnt" else: jntName = "_".join(obj.name().split("_")[:-1]) + "_jnt" jnt = pm.createNode("joint", n=jntName) if grp: grp.add(jnt) else: try: defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=jnt) except TypeError: pm.sets(n="rig_deformers_grp") defSet = pm.PyNode("rig_deformers_grp") pm.sets(defSet, add=jnt) oParent.addChild(jnt) jnt.setAttr("jointOrient", 0, 0, 0) try: applyop.gear_matrix_cns(obj, jnt) except RuntimeError: for axis in ["tx", "ty", "tz", "rx", "ry", "rz"]: jnt.attr(axis).set(0.0) return jnt
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. """ # Visibilities ------------------------------------- if self.isFkIk: # fk fkvis_node = node.createReverseNode(self.blend_att) for fk_ctl in self.fk_ctl: for shp in fk_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")) # FK Chain ----------------------------------------- if self.isFk: for off, ref in zip(self.fk_off[1:], self.fk_ref): applyop.gear_mulmatrix_op(ref.worldMatrix, off.parentInverseMatrix, off, "rt") # IK Chain ----------------------------------------- if self.isIk: self.ikh = primitive.addIkHandle(self.root, self.getName("ikh"), self.chain) self.ikh.attr("visibility").set(False) # Constraint and up vector pm.pointConstraint(self.ik_ctl, self.ikh, maintainOffset=False) pm.poleVectorConstraint(self.upv_ctl, self.ikh) # TwistTest o_list = [round(elem, 4) for elem in transform.getTranslation(self.chain[1])] \ != [round(elem, 4) for elem in self.guide.apos[1]] if o_list: add_nodeTwist = node.createAddNode(180.0, self.roll_att) pm.connectAttr(add_nodeTwist + ".output", self.ikh.attr("twist")) else: pm.connectAttr(self.roll_att, self.ikh.attr("twist")) # Chain of deformers ------------------------------- for i, loc in enumerate(self.loc): if self.settings["mode"] == 0: # fk only pm.parentConstraint(self.fk_ctl[i], loc, maintainOffset=False) pm.connectAttr(self.fk_ctl[i] + ".scale", loc + ".scale") elif self.settings["mode"] == 1: # ik only pm.parentConstraint(self.chain[i], loc, maintainOffset=False) elif self.settings["mode"] == 2: # fk/ik rev_node = node.createReverseNode(self.blend_att) # orientation cns = pm.parentConstraint(self.fk_ctl[i], self.chain[i], loc, maintainOffset=False) cns.interpType.set(0) weight_att = pm.parentConstraint(cns, query=True, weightAliasList=True) pm.connectAttr(rev_node + ".outputX", weight_att[0]) pm.connectAttr(self.blend_att, weight_att[1]) # scaling blend_node = pm.createNode("blendColors") pm.connectAttr(self.chain[i].attr("scale"), blend_node + ".color1") pm.connectAttr(self.fk_ctl[i].attr("scale"), blend_node + ".color2") pm.connectAttr(self.blend_att, blend_node + ".blender") pm.connectAttr(blend_node + ".output", loc + ".scale")
def ghostSlider(ghostControls, surface, sliderParent): """Modify the ghost control behaviour to slide on top of a surface Args: ghostControls (dagNode): The ghost control surface (Surface): The NURBS surface sliderParent (dagNode): The parent for the slider. """ if not isinstance(ghostControls, list): ghostControls = [ghostControls] # Seleccionamos los controles Ghost que queremos mover sobre el surface surfaceShape = surface.getShape() for ctlGhost in ghostControls: ctl = pm.listConnections(ctlGhost, t="transform")[-1] t = ctl.getMatrix(worldSpace=True) gDriver = primitive.addTransform(ctlGhost.getParent(), ctl.name() + "_slideDriver", t) try: pm.connectAttr(ctl + ".translate", gDriver + ".translate") pm.disconnectAttr(ctl + ".translate", ctlGhost + ".translate") except RuntimeError: pass try: pm.connectAttr(ctl + ".scale", gDriver + ".scale") pm.disconnectAttr(ctl + ".scale", ctlGhost + ".scale") except RuntimeError: pass try: pm.connectAttr(ctl + ".rotate", gDriver + ".rotate") pm.disconnectAttr(ctl + ".rotate", ctlGhost + ".rotate") except RuntimeError: pass oParent = ctlGhost.getParent() npoName = "_".join(ctlGhost.name().split("_")[:-1]) + "_npo" oTra = pm.PyNode( pm.createNode("transform", n=npoName, p=oParent, ss=True)) oTra.setTransformation(ctlGhost.getMatrix()) pm.parent(ctlGhost, oTra) slider = primitive.addTransform(sliderParent, ctl.name() + "_slideDriven", t) # connexion dm_node = node.createDecomposeMatrixNode( gDriver.attr("worldMatrix[0]")) cps_node = pm.createNode("closestPointOnSurface") dm_node.attr("outputTranslate") >> cps_node.attr("inPosition") surfaceShape.attr("worldSpace[0]") >> cps_node.attr("inputSurface") cps_node.attr("position") >> slider.attr("translate") pm.normalConstraint(surfaceShape, slider, aimVector=[0, 0, 1], upVector=[0, 1, 0], worldUpType="objectrotation", worldUpVector=[0, 1, 0], worldUpObject=gDriver) pm.parent(ctlGhost.getParent(), slider)