def getParentAndRootControl( theJoint ): ''' returns a 2 tuple containing the nearest control up the hierarchy, and the most likely control to use as the "root" control for the rig. either of these may be the world control, but both values are guaranteed to be an existing control object ''' parentControl, rootControl = None, None for p in api.iterParents( theJoint ): theControl = getItemRigControl( p ) if theControl is None: continue if parentControl is None: parentControl = theControl skelPart = SkeletonPart.InitFromItem( p ) if isinstance( skelPart, skeletonBuilder.Root ): rootControl = theControl if parentControl is None or rootControl is None: world = WorldPart.Create() if parentControl is None: parentControl = world.control if rootControl is None: rootControl = world.control return parentControl, rootControl
def getSpaceSwitchControls( theJoint ): ''' walks up the joint chain and returns a list of controls that drive parent joints ''' parentControls = [] for p in api.iterParents( theJoint ): theControl = getItemRigControl( p ) if theControl is not None: parentControls.append( theControl ) return parentControls
def getChain( startNode, endNode ): ''' returns a list of all the joints from the given start to the end inclusive ''' chainNodes = [ endNode ] for p in api.iterParents( endNode ): if not p: raise ValueError( "Chain terminated before reaching the end node!" ) chainNodes.append( p ) if apiExtensions.cmpNodes( p, startNode ): #cmpNodes is more reliable than just string comparing - cmpNodes casts to MObjects and compares object handles break chainNodes.reverse() return chainNodes
def chainLength( startNode, endNode ): ''' measures the length of the chain were it to be straightened out ''' length = 0 curNode = endNode for p in api.iterParents( endNode ): curPos = Vector( xform( curNode, q=True, ws=True, rp=True ) ) parPos = Vector( xform( p, q=True, ws=True, rp=True ) ) dif = curPos - parPos length += dif.get_magnitude() if apiExtensions.cmpNodes( p, startNode ): #cmpNodes is more reliable than just string comparing - cmpNodes casts to MObjects and compares object handles break curNode = p return length
def getChain(startNode, endNode): ''' returns a list of all the joints from the given start to the end inclusive ''' chainNodes = [endNode] for p in api.iterParents(endNode): if not p: raise ValueError("Chain terminated before reaching the end node!") chainNodes.append(p) if apiExtensions.cmpNodes( p, startNode ): #cmpNodes is more reliable than just string comparing - cmpNodes casts to MObjects and compares object handles break chainNodes.reverse() return chainNodes
def chainLength(startNode, endNode): ''' measures the length of the chain were it to be straightened out ''' length = 0 curNode = endNode for p in api.iterParents(endNode): curPos = Vector(xform(curNode, q=True, ws=True, rp=True)) parPos = Vector(xform(p, q=True, ws=True, rp=True)) dif = curPos - parPos length += dif.get_magnitude() if apiExtensions.cmpNodes( p, startNode ): #cmpNodes is more reliable than just string comparing - cmpNodes casts to MObjects and compares object handles break curNode = p return length
def on_xfer( self, *a ): mapping = api.resolveMapping( self.UI_mapping.getMapping() ) theSrcs = [] theTgts = [] #perform the hierarchy sort idx = 0 if self.sortBySrcs else 1 toSort = [ (len(list(api.iterParents( srcAndTgt[ idx ] ))), srcAndTgt) for srcAndTgt in mapping.iteritems() if cmd.objExists( srcAndTgt[ idx ] ) ] toSort.sort() for idx, (src, tgt) in toSort: theSrcs.append( src ) theTgts.append( tgt ) offset = '' isDupe = self.isTraceMode( self.RAD_dupe ) isCopy = self.isTraceMode( self.RAD_copy ) isTraced = self.isTraceMode( self.RAD_trace ) instance = cmd.checkBox( self.UI_check1, q=True, v=True ) traceKeys = cmd.checkBox( self.UI_keysOnly, q=True, v=True ) matchRo = cmd.checkBox( self.UI_check2, q=True, v=True ) startTime = cmd.textField( self.UI_start, q=True, tx=True ) endTime = cmd.textField( self.UI_end, q=True, tx=True ) world = cmd.checkBox( self.UI_check3, q=True, v=True ) #this is also "process trace cmds" nocreate = cmd.checkBox( self.UI_check4, q=True, v=True ) if startTime.isdigit(): startTime = int( startTime ) else: if startTime == '!': startTime = cmd.playbackOptions( q=True, min=True ) elif startTime == '.': startTime = cmd.currentTime( q=True ) elif startTime == '$': startTime = cmd.playbackOptions( q=True, animationStartTime=True ) if endTime.isdigit(): endTime = int( endTime ) else: if endTime == '!': endTime = cmd.playbackOptions( q=True, max=True ) elif endTime == '.': endTime = cmd.currentTime( q=True ) elif endTime == '$': endTime = cmd.playbackOptions( q=True, animationEndTime=True ) withinRange = cmd.checkBox( self.UI_withinRange, q=True, v=True ) if withinRange: traceKeys = 2 if isCopy: offset = "*" api.mel.zooXferAnimUtils() if self._clipPreset is not None: print self._clipPreset.asClip() #convert to mapping as expected by animLib... this is messy! animLibMapping = {} for src, tgts in mapping.iteritems(): animLibMapping[ src ] = tgts[ 0 ] self._clipPreset.asClip().apply( animLibMapping ) elif isDupe: api.melecho.zooXferBatch( "-mode 0 -instance %d -matchRo %d" % (instance, matchRo), theSrcs, theTgts ) elif isCopy: api.melecho.zooXferBatch( "-mode 1 -range %s %s -matchRo %d" % (startTime, endTime, matchRo), theSrcs, theTgts ) elif isTraced: api.melecho.zooXferBatch( "-mode 2 -keys %d -postCmds %d -matchRo %d -sortByHeirarchy 0 -range %s %s" % (traceKeys, world, matchRo, startTime, endTime), theSrcs, theTgts )
def commonApply(rig, rigNS, filename, nodes, mapping, postTraceSchemeFilepath=None, sortBySrcs=True): #apply the post trace scheme if applicable if postTraceSchemeFilepath is not None: loadPostTraceSchemeFilepath(postTraceSchemeFilepath) possibleSrcs = cmd.ls('%s*' % IMPORT_DATA_NS, typ='transform') possibleTgts = cmd.ls('%s*' % rigNS, typ='transform') #build the ctrl-bone mapping - and ensure proper namespaces are present... the mapping contains no namespaces srcs, tgts = [], [] idx = 0 if sortBySrcs else 1 toSort = [] for src, tgt in mapping.iteritems(): src = names.matchNames([src], possibleSrcs)[0] tgt = names.matchNames([tgt], possibleTgts)[0] srcOrTgt = src, tgt if cmd.objExists(srcOrTgt[idx]): numParents = len(list(api.iterParents(srcOrTgt[idx]))) toSort.append((numParents, src, tgt)) toSort.sort() for idx, src, tgt in toSort: srcs.append(src) tgts.append(tgt) print "rig namespace is:", rigNS print 'srcs are', srcs print 'tgts are', tgts #sort the items by hierarchy based on the src items - xferAnim does have the option of doing this, but it sorts using the tgt list, and its done in mel, so... I don't trust it srcsParentCount = [(len([p for p in api.iterParents(s)]), s, t) for s, t in zip(srcs, tgts) if cmd.objExists(s)] srcsParentCount.sort() srcs = [s[1] for s in srcsParentCount] tgts = [s[2] for s in srcsParentCount] #now turn any ik off - we'll restore it afterwards, but if ik is on, then fk controls don't get traced properly... coz maya is ghey! initIkBlendValues = {} for t in tgts: attrPath = "%s.ikBlend" % t if cmd.objExists(attrPath): initIkBlendValues[attrPath] = cmd.getAttr(attrPath) cmd.setAttr(attrPath, 0) #perform the trace api.melecho.zooXferTrace(srcs, tgts, True, True, False, True, False, -1000, 1000) #restore ik settings for attrPath, value in initIkBlendValues.iteritems(): cmd.setAttr(attrPath, value) #rename the file mayaFilepath = apps.getAssetRoot( rig, apps.MAYA) / 'maya/animation' / filename.name() mayaFilepath.up().create() cmd.file(rename=mayaFilepath) mayaFilepath = Path(cmd.file(q=True, sn=True)) #try to determine the info node to export exportNode = None for n in cmd.ls(typ='vstInfo'): if n.startswith(rigNS): exportNode = n break #setup the export manager data if we can... if exportNode is not None: xm = exportManagerCore.ExportManager() comp = xm.createExportComponent([exportNode]) comp.setAttr('name', mayaFilepath.name()) comp.setAttr('type', exportManagerCore.ExportComponent.kANIM) #save changes... cmd.file(save=True, f=True) return mayaFilepath
def commonApply( rig, rigNS, filename, nodes, mapping, postTraceSchemeFilepath=None, sortBySrcs=True ): #apply the post trace scheme if applicable if postTraceSchemeFilepath is not None: loadPostTraceSchemeFilepath( postTraceSchemeFilepath ) possibleSrcs = cmd.ls( '%s*' % IMPORT_DATA_NS, typ='transform' ) possibleTgts = cmd.ls( '%s*' % rigNS, typ='transform' ) #build the ctrl-bone mapping - and ensure proper namespaces are present... the mapping contains no namespaces srcs, tgts = [], [] idx = 0 if sortBySrcs else 1 toSort = [] for src, tgt in mapping.iteritems(): src = names.matchNames( [ src ], possibleSrcs )[ 0 ] tgt = names.matchNames( [ tgt ], possibleTgts )[ 0 ] srcOrTgt = src, tgt if cmd.objExists( srcOrTgt[ idx ] ): numParents = len( list( api.iterParents( srcOrTgt[ idx ] ) ) ) toSort.append( (numParents, src, tgt) ) toSort.sort() for idx, src, tgt in toSort: srcs.append( src ) tgts.append( tgt ) print "rig namespace is:", rigNS print 'srcs are', srcs print 'tgts are', tgts #sort the items by hierarchy based on the src items - xferAnim does have the option of doing this, but it sorts using the tgt list, and its done in mel, so... I don't trust it srcsParentCount = [ (len( [p for p in api.iterParents( s )] ), s, t) for s, t in zip( srcs, tgts ) if cmd.objExists( s ) ] srcsParentCount.sort() srcs = [ s[ 1 ] for s in srcsParentCount ] tgts = [ s[ 2 ] for s in srcsParentCount ] #now turn any ik off - we'll restore it afterwards, but if ik is on, then fk controls don't get traced properly... coz maya is ghey! initIkBlendValues = {} for t in tgts: attrPath = "%s.ikBlend" % t if cmd.objExists( attrPath ): initIkBlendValues[ attrPath ] = cmd.getAttr( attrPath ) cmd.setAttr( attrPath, 0 ) #perform the trace api.melecho.zooXferTrace( srcs, tgts, True, True, False, True, False, -1000, 1000 ) #restore ik settings for attrPath, value in initIkBlendValues.iteritems(): cmd.setAttr( attrPath, value ) #rename the file mayaFilepath = apps.getAssetRoot( rig, apps.MAYA ) / 'maya/animation' / filename.name() mayaFilepath.up().create() cmd.file( rename=mayaFilepath ) mayaFilepath = Path( cmd.file( q=True, sn=True ) ) #try to determine the info node to export exportNode = None for n in cmd.ls( typ='vstInfo' ): if n.startswith( rigNS ): exportNode = n break #setup the export manager data if we can... if exportNode is not None: xm = exportManagerCore.ExportManager() comp = xm.createExportComponent( [ exportNode ] ) comp.setAttr( 'name', mayaFilepath.name() ) comp.setAttr( 'type', exportManagerCore.ExportComponent.kANIM ) #save changes... cmd.file( save=True, f=True ) return mayaFilepath