def getControlShapeFiles(): dir = CONTROL_DIRECTORY if isinstance(dir, basestring): dir = Path(dir) if not isinstance(dir, Path) or not dir.exists(): dir = Path(__file__).up() shapes = [] if dir.exists(): shapes = [f for f in dir.files() if f.hasExtension('shape')] if not shapes: searchPaths = map(Path, sys.path) searchPaths += map(Path, os.environ.get('MAYA_SCRIPT_PATH', '').split(';')) searchPaths = removeDupes(searchPaths) for d in searchPaths: try: shapes += [f for f in d.files() if f.hasExtension('shape')] except WindowsError: continue return shapes
def packageScripts( scriptFilesToPackage, destPackageFilepath, dependencyTree ): ''' will package all given files and import dependencies into a single zip file ''' destPackageFilepath = Path( destPackageFilepath ).setExtension( 'zip' ) if destPackageFilepath.exists: destPackageFilepath.delete() filesToPackage = map( Path, scriptFilesToPackage ) for f in scriptFilesToPackage: filesToPackage += dependencyTree.findDependencies( f, None, False ) if not filesToPackage: return None #remove any duplicate files... filesToPackage = removeDupes( filesToPackage ) #this is a little hacky - but we don't want to re-distribute wingdbstub so lets check to see if its in the list of files for f in filesToPackage: if f.name() == 'wingdbstub': filesToPackage.remove( f ) break #now build the zip file import zipfile with zipfile.ZipFile( str( destPackageFilepath ), 'w' ) as thePackage: for f in filesToPackage: thePackage.write( str( f ), str( makeScriptPathRelative( f ) ) ) return destPackageFilepath
def autoSkinToVolumeMesh( mesh, skeletonMeshRoot ): ''' given a mesh and the root node for a hierarchy mesh volumes, this function will create a skeleton with the same hierarchy and skin the mesh to this skeleton using the mesh volumes to determine skin weights ''' #grab a list of meshes under the hierarchy - we need to grab this geo, parent it to a skeleton and transfer defacto weighting to the given mesh volumes = listRelatives( skeletonMeshRoot, ad=True, type='mesh', pa=True ) #now generate the skeleton transforms = removeDupes( listRelatives( volumes, p=True, type='transform', pa=True ) or [] ) jointRemap = {} for t in transforms: select( cl=True ) jName = '%s_joint' % t if objExists( jName ): jName += '#' j = joint( n=jName ) jointRemap[ t ] = j #now do parenting for t, j in jointRemap.iteritems(): tParent = listRelatives( t, p=True, pa=True ) if tParent: tParent = tParent[0] jParent = jointRemap.get( tParent, None ) else: jParent = None if jParent is not None: parent( j, jParent ) #now do positioning for t in api.sortByHierarchy( transforms ): j = jointRemap[ t ] pos = xform( t, q=True, ws=True, rp=True ) move( pos[0], pos[1], pos[2], j, ws=True, rpr=True ) #duplicate the geometry and parent the geo to the joints in the skeleton we just created - store the duplicates so we can delete them later dupes = [] for t, j in jointRemap.iteritems(): dupe = apiExtensions.asMObject( duplicate( t, returnRootsOnly=True, renameChildren=True )[0] ) children = listRelatives( dupe, type='transform', pa=True ) or [] if children: delete( children ) parent( dupe, j ) dupes.append( dupe ) f = saveWeights( map( str, dupes ) ) loadWeights( [mesh], f, usePosition=True, tolerance=0.5, averageVerts=True, jointNameRemapDict=jointRemap ) delete( dupes ) return jointRemap
def on_storeB( self, *a ): kw = {} if self.UI_file.getValue(): kw[ 'filepath' ] = Path( self.UI_file.getValue() ) joints = cmd.ls( type='joint', r=True ) jointMeshes = removeDupes( cmd.listRelatives( joints, ad=True, pa=True, type='mesh' ) ) skinWeights.saveWeights( jointMeshes, **kw )
def buildPackage(dependencyTree=None): if not _PYTHON_TOOLS_TO_PACKAGE.exists(): raise ValueError("Cannot find %s file!" % _PYTHON_TOOLS_TO_PACKAGE.name()) modulesToPackage = [] for toolName in _PYTHON_TOOLS_TO_PACKAGE.read(): if toolName: if toolName.startswith('#'): continue elif toolName.startswith('//'): continue modulesToPackage.append(toolName) cleanPackageDir() if dependencyTree is None: dependencyTree = generateDepTree() filesToPackage = [] for moduleName in modulesToPackage: moduleScriptPath = dependencyTree.moduleNameToScript(moduleName) filesToPackage += dependencyTree.findDependencies( moduleScriptPath, None, False) if not filesToPackage: return None #remove any duplicate files... filesToPackage = removeDupes(filesToPackage) #this is a little hacky - but we don't want to re-distribute wingdbstub so lets check to see if its in the list of files for f in filesToPackage: if f.name() == 'wingdbstub': filesToPackage.remove(f) break print >> Good, "Found dependencies - %d files" % len(filesToPackage) for f in filesToPackage: relativePath = makeScriptPathRelative(f) packagedPath = _PACKAGE_DIR / relativePath if len(relativePath) > 1: packagedPath.up().create() f.copy(packagedPath) print 'copying ----> %s' % f #now zip up the files into a package cmdStr = '7z a -r ..\\%s\\zooToolBoxPy.7z ..\\%s\\' % (_PACKAGE_DIR_NAME, _PACKAGE_DIR_NAME) os.system(cmdStr) #now write a simple mel script to load the toolbox UI cmdStr = """global proc zooToolBox() { return; }""" bootstrapMelScript = _PACKAGE_DIR / 'zooToolBox.mel' bootstrapMelScript.write(cmdStr)
def on_storeB(self, *a): kw = {} if self.UI_file.getValue(): kw['filepath'] = Path(self.UI_file.getValue()) joints = cmd.ls(type='joint', r=True) jointMeshes = removeDupes( cmd.listRelatives(joints, ad=True, pa=True, type='mesh')) skinWeights.saveWeights(jointMeshes, **kw)
def buildPackage( dependencyTree=None ): if not _PYTHON_TOOLS_TO_PACKAGE.exists: raise ValueError( "Cannot find %s file!" % _PYTHON_TOOLS_TO_PACKAGE.name() ) modulesToPackage = [] for toolName in _PYTHON_TOOLS_TO_PACKAGE.read(): if toolName: if toolName.startswith( '#' ): continue elif toolName.startswith( '//' ): continue modulesToPackage.append( toolName ) cleanPackageDir() if dependencyTree is None: dependencyTree = generateDepTree() filesToPackage = [] for moduleName in modulesToPackage: moduleScriptPath = dependencyTree.moduleNameToScript( moduleName ) filesToPackage += dependencyTree.findDependencies( moduleScriptPath, None, False ) if not filesToPackage: return None #remove any duplicate files... filesToPackage = removeDupes( filesToPackage ) #this is a little hacky - but we don't want to re-distribute wingdbstub so lets check to see if its in the list of files for f in filesToPackage: if f.name() == 'wingdbstub': filesToPackage.remove( f ) break print >> Good, "Found dependencies - %d files" % len( filesToPackage ) for f in filesToPackage: relativePath = makeScriptPathRelative( f ) packagedPath = _PACKAGE_DIR / relativePath if len( relativePath ) > 1: packagedPath.up().create() f.copy( packagedPath ) print 'copying ----> %s' % f #now zip up the files into a package cmdStr = '7z a -r ..\\%s\\zooToolBoxPy.7z ..\\%s\\' % (_PACKAGE_DIR_NAME, _PACKAGE_DIR_NAME) os.system( cmdStr ) #now write a simple mel script to load the toolbox UI cmdStr = """global proc zooToolBox() { return; }""" bootstrapMelScript = _PACKAGE_DIR / 'zooToolBox.mel' bootstrapMelScript.write( cmdStr )
def getAutoOffsetAmount( placeObject, joints=None, axis=AX_Z, threshold=0.65 ): ''' returns a value reflecting the distance from the placeObject to the edge of the bounding box containing the verts skinned to the joints in the joints list the axis controls what edge of the bounding box is used if joints is None, [placeObject] is used ''' if joints is None: joints = [ placeObject ] else: joints = removeDupes( [ placeObject ] + joints ) #make sure the placeObject is the first item in the joints list, otherwise the bounds won't be transformed to the correct space #get the bounds of the geo skinned to the hand and use it to determine default placement of the slider control bounds = rigUtils.getJointBounds( joints ) offsetAmount = abs( bounds[ axis.isNegative() ][ axis % 3 ] ) #print bounds[ 0 ].x, bounds[ 0 ].y, bounds[ 0 ].z, bounds[ 1 ].x, bounds[ 1 ].y, bounds[ 1 ].z return offsetAmount
def getControlShapeFiles(): dir = CONTROL_DIRECTORY if isinstance( dir, basestring ): dir = Path( dir ) if not isinstance( dir, Path ) or not dir.exists: dir = Path( __file__ ).up() shapes = [] if dir.exists: shapes = [ f for f in dir.files() if f.hasExtension( 'shape' ) ] if not shapes: searchPaths = map( Path, sys.path ) searchPaths += map( Path, os.environ.get( 'MAYA_SCRIPT_PATH', '' ).split( ';' ) ) searchPaths = removeDupes( searchPaths ) for d in searchPaths: try: shapes += [ f for f in d.files() if f.hasExtension( 'shape' ) ] except WindowsError: continue return shapes
def autoSkinToVolumeMesh(mesh, skeletonMeshRoot): ''' given a mesh and the root node for a hierarchy mesh volumes, this function will create a skeleton with the same hierarchy and skin the mesh to this skeleton using the mesh volumes to determine skin weights ''' #grab a list of meshes under the hierarchy - we need to grab this geo, parent it to a skeleton and transfer defacto weighting to the given mesh volumes = listRelatives(skeletonMeshRoot, ad=True, type='mesh', pa=True) #now generate the skeleton transforms = removeDupes( listRelatives(volumes, p=True, type='transform', pa=True) or []) jointRemap = {} for t in transforms: select(cl=True) jName = '%s_joint' % t if objExists(jName): jName += '#' j = joint(n=jName) jointRemap[t] = j #now do parenting for t, j in jointRemap.iteritems(): tParent = listRelatives(t, p=True, pa=True) if tParent: tParent = tParent[0] jParent = jointRemap.get(tParent, None) else: jParent = None if jParent is not None: parent(j, jParent) #now do positioning for t in api.sortByHierarchy(transforms): j = jointRemap[t] pos = xform(t, q=True, ws=True, rp=True) move(pos[0], pos[1], pos[2], j, ws=True, rpr=True) #duplicate the geometry and parent the geo to the joints in the skeleton we just created - store the duplicates so we can delete them later dupes = [] for t, j in jointRemap.iteritems(): dupe = apiExtensions.asMObject( duplicate(t, returnRootsOnly=True, renameChildren=True)[0]) children = listRelatives(dupe, type='transform', pa=True) or [] if children: delete(children) parent(dupe, j) dupes.append(dupe) f = saveWeights(map(str, dupes)) loadWeights([mesh], f, usePosition=True, tolerance=0.5, averageVerts=True, jointNameRemapDict=jointRemap) delete(dupes) return jointRemap
def saveWeights(geos, filepath=None): start = time.clock() miscData = api.writeExportDict(TOOL_NAME, TOOL_VERSION) #if filepath is None, then generate a default filepath based on the location of the file if filepath is None: filepath = getDefaultPath() else: filepath = Path(filepath) geoAndData = {} skinPercent = cmd.skinPercent xform = cmd.xform #define teh data we're gathering masterJointList = [] weightData = [] #data gathering time! rigidBindObjects = [] for geo in geos: skinClusters = cmd.ls(cmd.listHistory(geo), type='skinCluster') if len(skinClusters) > 1: api.melWarning("more than one skinCluster found on %s" % geo) continue #so the geo isn't skinned in the traditional way - check to see if it is parented to a joint. if so, #stuff it into the rigid bind list to be dealt with outside this loop, and continue if not skinClusters: dealtWith = False for p in iterParents(geo): if cmd.nodeType(p) == 'joint': rigidBindObjects.append((geo, p)) masterJointList.append(p) masterJointList = removeDupes(masterJointList) dealtWith = True break if not dealtWith: msg = "cannot find a skinCluster for %s" % geo api.melWarning(msg) continue skinCluster = skinClusters[0] masterJointList += cmd.skinCluster(skinCluster, q=True, inf=True) masterJointList = removeDupes(masterJointList) verts = cmd.ls(cmd.polyListComponentConversion(geo, toVertex=True), fl=True) for idx, vert in enumerate(verts): jointList = skinPercent(skinCluster, vert, ib=1e-4, q=True, transform=None) weightList = skinPercent(skinCluster, vert, ib=1e-4, q=True, value=True) if jointList is None: raise SkinWeightException( "I can't find any joints - sorry. do you have any post skin cluster history???" ) pos = xform(vert, q=True, ws=True, t=True) vertData = VertSkinWeight(pos) vertData.populate(geo, idx, [masterJointList.index(j) for j in jointList], weightList) weightData.append(vertData) #deal with rigid bind objects for geo, j in rigidBindObjects: verts = cmd.ls(cmd.polyListComponentConversion(geo, toVertex=True), fl=True) for idx, vert in enumerate(verts): jIdx = masterJointList.index(j) pos = xform(vert, q=True, ws=True, t=True) vertData = VertSkinWeight(pos) vertData.populate(geo, idx, [jIdx], [1]) weightData.append(vertData) #sort the weightData by ascending x values so we can search faster weightData.sort() #turn the masterJointList into a dict keyed by index joints = {} for n, j in enumerate(masterJointList): joints[n] = j #generate joint hierarchy data - so if joints are missing on load we can find the best match jointHierarchies = {} for n, j in joints.iteritems(): jointHierarchies[n] = getAllParents(j) toWrite = miscData, joints, jointHierarchies, weightData filepath = Path(filepath) filepath.pickle(toWrite, False) melPrint('Weights Successfully Saved to %s: time taken %.02f seconds' % (filepath, time.clock() - start)) return filepath
def changeRo(objs=None, ro=XYZ): if ro not in ROTATION_ORDER_STRS: raise TypeError("need to specify a valid rotation order - one of: %s" % ' '.join(ROTATION_ORDER_STRS)) if objs is None: objs = ls(sl=True, type='transform') roIdx = list(ROTATION_ORDER_STRS).index(ro) #filter out objects that don't have all 3 rotation axes settable and while we're at it store the rotation orders for each object #in a dict - since accessing a python dict is WAY faster than doing a getAttr for each frame in the loop below RO_DICT = {} objsWithAllChannelsSettable = [] for obj in objs: if not getAttr('%s.r' % obj, se=True): printWarningStr( "Not all rotation axes on the object %s are settable - skipping!" % obj) continue objRo = getAttr('%s.ro' % obj) #if the rotation order of this object is the same as what we're changing it to - skip the object entirely if objRo == roIdx: printWarningStr( "The object %s already has the rotation order %s - skipping!" % (obj, ro)) continue RO_DICT[obj] = objRo objsWithAllChannelsSettable.append(obj) #early out if we have no objects to work on objs = objsWithAllChannelsSettable if not objs: printWarningStr("No objects to act on - exiting") return #first we need to make sure that any frame with a rotation key needs to have a key on ALL rotation axes - so make this happen keyTimes = keyframe(objs, q=True, at='r', tc=True) if not keyTimes: printWarningStr("No keys found on the objects - nothing to do!") return #remove duplicate key times and sort them keyTimes = removeDupes(keyTimes) keyTimes.sort() #cache out the conversion method convertToMethod = MATRIX_ROTATION_ORDER_CONVERSIONS_TO[roIdx] #store the objects that each have keys at each key time in a dict so we don't have to query maya again. maya queries are slower than accessing python data structures timeObjs = {} for time in keyTimes: currentTime(time, e=True) timeObjs[time] = objsWithKeysAtThisTime = [] for obj in objs: keyOnCurrentTime = keyframe(obj, q=True, t=(time, ), kc=True) if keyOnCurrentTime: setKeyframe(obj, at='r') objsWithKeysAtThisTime.append(obj) #now that we're secured the rotation poses with keys on all axes, fix up each rotation value to use the desired rotation order for time, objsWithKeysAtThisTime in timeObjs.iteritems(): currentTime(time, e=True) for obj in objsWithKeysAtThisTime: currentRoIdx = RO_DICT[obj] rot = getAttr('%s.r' % obj)[0] rotMatrix = MATRIX_ROTATION_ORDER_CONVERSIONS_FROM[currentRoIdx]( degrees=True, *rot) newRot = convertToMethod(rotMatrix, True) setAttr('%s.r' % obj, *newRot) setKeyframe(obj, at='r') #now change the rotation order to what it should be for obj in objs: setAttr('%s.ro' % obj, roIdx)
from apiExtensions import asMObject, MObject from common import printErrorStr SPACE_WORLD = rigUtils.SPACE_WORLD SPACE_LOCAL = rigUtils.SPACE_LOCAL SPACE_OBJECT = rigUtils.SPACE_OBJECT Axis = rigUtils.Axis CONTROL_DIRECTORY = None if CONTROL_DIRECTORY is None: #try to determine the directory that contains the control macros dirsToSearch = [ Path( __file__ ).up() ] + sys.path + os.environ[ 'MAYA_SCRIPT_PATH' ].split( os.pathsep ) dirsToSearch = map( Path, dirsToSearch ) dirsToSearch = removeDupes( dirsToSearch ) for dirToSearch in dirsToSearch: if not dirToSearch.isDir(): continue foundControlDir = False for f in dirToSearch.files( recursive=True ): if f.hasExtension( 'shape' ): if f.name().startswith( 'control' ): CONTROL_DIRECTORY = f.up() foundControlDir = True break if foundControlDir: break
def resetAttrs( obj, skipVisibility=True ): ''' simply resets all keyable attributes on a given object to its default value great for running on a large selection such as all character controls... ''' #obj = apiExtensions.asMObject( obj ) attrs = listAttr( obj, k=True, s=True, m=True ) or [] if skipVisibility: if 'visibility' in attrs: attrs.remove( 'visibility' ) #if the transform is a joint, see if its part of a bindpose, and if so, restore to #the bindpose, not zero, as this is generally the preferred behaviour poses = listConnections( obj, s=False, type='dagPose' ) bindPoses = [] if poses: poses = removeDupes( poses ) for pose in poses: if getAttr( '%s.bindPose' % pose ): bindPoses.append( pose ) numBindPoses = len( bindPoses ) if numBindPoses == 1: dagPose( obj, r=True, bp=True ) #in this case we want to throw a list of bindposes to the user and let them pick which bindpose to go to elif numBindPoses > 1: dagPose( obj, r=True, name=bindPoses[ 0 ] ) #otherwise just reset attribute values else: if not attrs: return selAttrs = channelBox( 'mainChannelBox', q=True, sma=True ) or channelBox( 'mainChannelBox', q=True, sha=True ) for attr in attrs: #if there are selected attributes AND the current attribute isn't in the list of selected attributes, skip it... if selAttrs: attrShortName = attributeQuery( attr, n=obj, shortName=True ) if attrShortName not in selAttrs: continue default = 0 try: default = attributeQuery( attr, n=obj, listDefault=True )[ 0 ] except RuntimeError: pass attrpath = '%s.%s' % (obj, attr) if not getAttr( attrpath, settable=True ): continue #need to catch because maya will let the default value lie outside an attribute's #valid range (ie maya will let you creat an attrib with a default of 0, min 5, max 10) try: setAttr( attrpath, default ) except RuntimeError: pass
def resetAttrs(obj, skipVisibility=True): ''' simply resets all keyable attributes on a given object to its default value great for running on a large selection such as all character controls... ''' #obj = apiExtensions.asMObject( obj ) attrs = listAttr(obj, k=True, s=True, m=True) or [] if skipVisibility: if 'visibility' in attrs: attrs.remove('visibility') #if the transform is a joint, see if its part of a bindpose, and if so, restore to #the bindpose, not zero, as this is generally the preferred behaviour poses = listConnections(obj, s=False, type='dagPose') bindPoses = [] if poses: poses = removeDupes(poses) for pose in poses: if getAttr('%s.bindPose' % pose): bindPoses.append(pose) numBindPoses = len(bindPoses) if numBindPoses == 1: dagPose(obj, r=True, bp=True) #in this case we want to throw a list of bindposes to the user and let them pick which bindpose to go to elif numBindPoses > 1: dagPose(obj, r=True, name=bindPoses[0]) #otherwise just reset attribute values else: if not attrs: return selAttrs = channelBox('mainChannelBox', q=True, sma=True) or channelBox( 'mainChannelBox', q=True, sha=True) for attr in attrs: #if there are selected attributes AND the current attribute isn't in the list of selected attributes, skip it... if selAttrs: attrShortName = attributeQuery(attr, n=obj, shortName=True) if attrShortName not in selAttrs: continue default = 0 try: default = attributeQuery(attr, n=obj, listDefault=True)[0] except RuntimeError: pass attrpath = '%s.%s' % (obj, attr) if not getAttr(attrpath, settable=True): continue #need to catch because maya will let the default value lie outside an attribute's #valid range (ie maya will let you creat an attrib with a default of 0, min 5, max 10) try: setAttr(attrpath, default) except RuntimeError: pass
from common import printErrorStr SPACE_WORLD = rigUtils.SPACE_WORLD SPACE_LOCAL = rigUtils.SPACE_LOCAL SPACE_OBJECT = rigUtils.SPACE_OBJECT Axis = rigUtils.Axis CONTROL_DIRECTORY = None if CONTROL_DIRECTORY is None: #try to determine the directory that contains the control macros dirsToSearch = [ Path(__file__).up() ] + sys.path + os.environ['MAYA_SCRIPT_PATH'].split(os.pathsep) dirsToSearch = map(Path, dirsToSearch) dirsToSearch = removeDupes(dirsToSearch) for dirToSearch in dirsToSearch: if not dirToSearch.isDir(): continue foundControlDir = False for f in dirToSearch.files(recursive=True): if f.hasExtension('shape'): if f.name().startswith('control'): CONTROL_DIRECTORY = f.up() foundControlDir = True break if foundControlDir: break
def saveWeights( geos, filepath=None ): start = time.clock() miscData = api.writeExportDict(TOOL_NAME, TOOL_VERSION) #if filepath is None, then generate a default filepath based on the location of the file if filepath is None: filepath = getDefaultPath() else: filepath = Path(filepath) geoAndData = {} skinPercent = cmd.skinPercent xform = cmd.xform #define teh data we're gathering masterJointList = [] weightData = [] #data gathering time! rigidBindObjects = [] for geo in geos: skinClusters = cmd.ls( cmd.listHistory( geo ), type='skinCluster' ) if len( skinClusters ) > 1: api.melWarning("more than one skinCluster found on %s" % geo) continue #so the geo isn't skinned in the traditional way - check to see if it is parented to a joint. if so, #stuff it into the rigid bind list to be dealt with outside this loop, and continue if not skinClusters: dealtWith = False for p in iterParents( geo ): if cmd.nodeType( p ) == 'joint': rigidBindObjects.append( (geo, p) ) masterJointList.append( p ) masterJointList = removeDupes( masterJointList ) dealtWith = True break if not dealtWith: msg = "cannot find a skinCluster for %s" % geo api.melWarning(msg) continue skinCluster = skinClusters[ 0 ] masterJointList += cmd.skinCluster( skinCluster, q=True, inf=True ) masterJointList = removeDupes( masterJointList ) verts = cmd.ls(cmd.polyListComponentConversion(geo, toVertex=True), fl=True) for idx, vert in enumerate(verts): jointList = skinPercent(skinCluster, vert, ib=1e-4, q=True, transform=None) weightList = skinPercent(skinCluster, vert, ib=1e-4, q=True, value=True) if jointList is None: raise SkinWeightException("I can't find any joints - sorry. do you have any post skin cluster history???") pos = xform(vert, q=True, ws=True, t=True) vertData = VertSkinWeight( pos ) vertData.populate( geo, idx, [ masterJointList.index( j ) for j in jointList ], weightList ) weightData.append( vertData ) #deal with rigid bind objects for geo, j in rigidBindObjects: verts = cmd.ls( cmd.polyListComponentConversion(geo, toVertex=True), fl=True ) for idx, vert in enumerate( verts ): jIdx = masterJointList.index( j ) pos = xform( vert, q=True, ws=True, t=True ) vertData = VertSkinWeight( pos ) vertData.populate( geo, idx, [jIdx], [1] ) weightData.append( vertData ) #sort the weightData by ascending x values so we can search faster weightData.sort() #turn the masterJointList into a dict keyed by index joints = {} for n, j in enumerate( masterJointList ): joints[ n ] = j #generate joint hierarchy data - so if joints are missing on load we can find the best match jointHierarchies = {} for n, j in joints.iteritems(): jointHierarchies[ n ] = getAllParents( j ) toWrite = miscData, joints, jointHierarchies, weightData filepath = Path( filepath ) filepath.pickle( toWrite, False ) melPrint( 'Weights Successfully Saved to %s: time taken %.02f seconds' % (filepath, time.clock()-start) ) return filepath
def changeRo( objs=None, ro=XYZ ): if ro not in ROTATION_ORDER_STRS: raise TypeError( "need to specify a valid rotation order - one of: %s" % ' '.join( ROTATION_ORDER_STRS ) ) if objs is None: objs = ls( sl=True, type='transform' ) roIdx = list( ROTATION_ORDER_STRS ).index( ro ) #filter out objects that don't have all 3 rotation axes settable and while we're at it store the rotation orders for each object #in a dict - since accessing a python dict is WAY faster than doing a getAttr for each frame in the loop below RO_DICT = {} objsWithAllChannelsSettable = [] for obj in objs: if not getAttr( '%s.r' % obj, se=True ): printWarningStr( "Not all rotation axes on the object %s are settable - skipping!" % obj ) continue objRo = getAttr( '%s.ro' % obj ) #if the rotation order of this object is the same as what we're changing it to - skip the object entirely if objRo == roIdx: printWarningStr( "The object %s already has the rotation order %s - skipping!" % (obj, ro) ) continue RO_DICT[ obj ] = objRo objsWithAllChannelsSettable.append( obj ) #early out if we have no objects to work on objs = objsWithAllChannelsSettable if not objs: printWarningStr( "No objects to act on - exiting" ) return #first we need to make sure that any frame with a rotation key needs to have a key on ALL rotation axes - so make this happen keyTimes = keyframe( objs, q=True, at='r', tc=True ) if not keyTimes: printWarningStr( "No keys found on the objects - nothing to do!" ) return #remove duplicate key times and sort them keyTimes = removeDupes( keyTimes ) keyTimes.sort() #cache out the conversion method convertToMethod = MATRIX_ROTATION_ORDER_CONVERSIONS_TO[ roIdx ] #store the objects that each have keys at each key time in a dict so we don't have to query maya again. maya queries are slower than accessing python data structures timeObjs = {} for time in keyTimes: currentTime( time, e=True ) timeObjs[ time ] = objsWithKeysAtThisTime = [] for obj in objs: keyOnCurrentTime = keyframe( obj, q=True, t=(time,), kc=True ) if keyOnCurrentTime: setKeyframe( obj, at='r' ) objsWithKeysAtThisTime.append( obj ) #now that we're secured the rotation poses with keys on all axes, fix up each rotation value to use the desired rotation order for time, objsWithKeysAtThisTime in timeObjs.iteritems(): currentTime( time, e=True ) for obj in objsWithKeysAtThisTime: currentRoIdx = RO_DICT[ obj ] rot = getAttr( '%s.r' % obj )[0] rotMatrix = MATRIX_ROTATION_ORDER_CONVERSIONS_FROM[ currentRoIdx ]( degrees=True, *rot ) newRot = convertToMethod( rotMatrix, True ) setAttr( '%s.r' % obj, *newRot ) setKeyframe( obj, at='r' ) #now change the rotation order to what it should be for obj in objs: setAttr( '%s.ro' % obj, roIdx )