def importSkel( char ): ''' imports the charName_skel.ma file from the character's directory if one exists. If no file exists, asks whether you want to import the default skel. ''' skelFile = os.path.join(common.getCharDir( char ), '%s_skel.ma' % char) if not os.path.exists(skelFile): if showDialog( title='WARNING', message='Character %s skeleton file not found.\n Would you like to load default skeleton?' % char, button=['yes', 'no'] ) != 'yes': return 'User cancelled' skelFile = os.path.join(common.getCharDir( 'defaultChar' ), 'defaultChar_skel.ma') cmds.file(skelFile, i=1, dns=1)
def readJoints( char ): ''' reads joint data for the specified character. First, attemps to locate charName_joints.py in the character's local directory. If this fails, loads in the data from the default character ''' jointFile = os.path.join(common.getCharDir( char ), '%s_joints.py' % char) if not os.path.exists(jointFile): if showDialog( title='WARNING', message='Character %s joint data not found.\n Would you like to load default joint data?' % char, button=['yes', 'no'] ) != 'yes': return 'User cancelled' jointFile = os.path.join(common.getCharDir( 'defaultChar' ), 'defaultChar_joints.py') f = open(jointFile, 'r') jointDict = json.loads(f.readline()) f.close() return jointDict
def importGeo(char): ''' imports the charName_geo.ma file from the character's directory if one exists. If no file exists, asks whether you want to import the default geo. Returns a list of new nodes added to the scene (rnn flag) ''' geoFile = os.path.join(common.getCharDir( char ), '%s_geo.ma' % char) if not os.path.exists(geoFile): if showDialog( title='WARNING', message='Character %s geometry file not found.\n Would you like to load default geometry?' % char, button=['yes', 'no'] ) != 'yes': return 'User cancelled' geoFile = os.path.join(common.getCharDir( 'defaultChar' ), 'defaultChar_geo.ma') importList = cmds.file(geoFile, i=1, dns=1, rnn=1) meshNodes = [ m for m in importList if m.split('_')[-1] == 'mesh' ] return meshNodes
def exportSkel( char, jointList ): ''' exports the charName_skel.ma file from the supplied jointlist. If file exists, asks whether you want to overwrite. ''' skelFile = os.path.join(common.getCharDir( char ), '%s_skel.ma' % char) if os.path.exists(skelFile): if showDialog( title='WARNING', message='Character %s skeleton file Exists.\n Overwrite File?' % char, button=['yes', 'no'] ) != 'yes': return 'User cancelled' cmds.select(jointList) cmds.file(skelFile, es=1, f=1, type='mayaAscii')
def writeJoints( char, jointList ): ''' function to save joint data out to a json file joints are stored in a dictionary called jointDict with one key - 'joints' the value of jointDict['joints'] is another dictionary with a key corresponding to the name of each joint the value of each joint key is also a dictionary containing all the data for that joint ''' joints = {} xformAttrs = ['tx', 'ty', 'tz', 'rx', 'ry', 'rz', 'sx', 'sy', 'sz', 'jox', 'joy', 'joz'] # Populate data for j in jointList: jointData = {} for attr in xformAttrs: jointData.setdefault( attr, cmds.getAttr('%s.%s' % (j, attr))) joints.setdefault( j, jointData ) jointDict = {'joints':joints} charDir = common.getCharDir( char ) jointFile = os.path.join( charDir, '%s_joints.py' % char) # Check to see if file exists if os.path.isfile(jointFile): if showDialog( title='WARNING', message='Overwrite existing joint data?', button=['yes', 'no'] ) != 'yes': return 'User cancelled' # Make sure a destination folder exists destDir = os.path.dirname( jointFile ) if not os.path.exists( destDir ): if showDialog( title='WARNING', message='Character %s Does not exist.\n Would you like to create it now?' % char, button=['yes', 'no'] ) != 'yes': return 'User cancelled' else: os.makedirs( destDir ) # Write data to disk f = open(jointFile, 'w') f.write(json.dumps(jointDict)) f.close() showDialog( 'Success!', 'Joint data dumped to file:\n"%s_joints.py".' % jointFile )
def rebindSkinClusters(char="", meshes=[]): """ delete and recreate skinclusters on supplied or selected meshes with influences from skinWeightsFile """ # abort if no char is given if char == "": return cmds.warning("No character selected. Please supply a character name in function call.") # abort if there no mesh supplied or selected if meshes == []: meshes = cmds.ls(sl=1) print("No meshes supplied as param, attempting to use selected objects(%s)." % ", ".join(meshes)) if meshes == []: return cmds.warning("No mesh to found. Please select a mesh.") # confirm rebind if ( cmds.confirmDialog( title="Warning", message="Delete and rebind skinclusters for [ %s ]?" % ", ".join(meshes), button=["yes", "no"], ) != "yes" ): return "User cancelled" # get path to skin file charDir = common.getCharDir(char) skinWeightsFile = os.path.join(charDir, "%s_skin.py" % char) # use default skinWeightsFile if character specific file does not exist if not os.path.exists(skinWeightsFile): skinWeightsFile = os.path.join(common.getCharDir("defaultChar"), "defaultChar_skin.py") cmds.warning("Did not find skin weights file for selected character, using default character file.") # read skin weights from file f = open(skinWeightsFile, "r") allWeights = json.loads(f.readline()) f.close() # remove meshes for which there is no infs-key or weight dictionary for mesh in meshes: if mesh not in allWeights.keys(): cmds.warning("No weights dictionary found for %s" % mesh) meshes.remove(mesh) if "infs" not in allWeights[mesh].keys(): cmds.warning("No Influences key found for %s" % mesh) meshes.remove(mesh) skinclusters = [] for mesh in meshes: weights = allWeights[mesh] # unbind mesh if skincluster exists clusterName = mel.eval("findRelatedSkinCluster " + mesh) if clusterName != "": cmds.skinCluster(mesh, edit=True, unbind=True) # rebind skincluster = cmds.skinCluster( weights["infs"], mesh, name="skincluster_" + str(mesh), toSelectedBones=True, maximumInfluences=5, obeyMaxInfluences=False, skinMethod=0, )[0] skinclusters.append(skincluster) showDialog( "Succss!", 'Skinclusters rebound on [ %s ] from file:\n"%s_skin.py"' % (", ".join(meshes), skinWeightsFile) ) cmds.select(meshes) return skinclusters
def setSkinWeights(char="", meshes=[]): """ applies skinweights from file to supplied or selected geometries (which need to already have a skincluster) """ # abort if no char is given if char == "": return cmds.warning("No character selected. Please supply a character name in function call.") # abort if there no mesh supplied or selected if meshes == []: meshes = cmds.ls(sl=1) print("No meshes supplied as param, attempting to use selected objects(%s)." % ", ".join(meshes)) if meshes == []: return cmds.warning("No mesh to export weights from. Please select a mesh.") # get path to skin file charDir = common.getCharDir(char) skinWeightsFile = os.path.join(charDir, "%s_skin.py" % char) # use default skinWeightsFile if character specific file does not exist if not os.path.exists(skinWeightsFile): skinWeightsFile = os.path.join(common.getCharDir("defaultChar"), "defaultChar_skin.py") cmds.warning("Did not find skin weights file for selected character, using default character file.") # read skin weights from file f = open(skinWeightsFile, "r") allWeights = json.loads(f.readline()) f.close() # compare meshes to keys of allWeights dictionary print("File contains skinweights for: " + ",".join(allWeights.keys())) for mesh in meshes: if mesh not in allWeights.keys(): cmds.warning("No weights found for %s" % mesh) meshes.remove(mesh) for mesh in meshes: # find skinCluster clusterName = mel.eval("findRelatedSkinCluster " + mesh) if clusterName == "": cmds.warning("No skinclutser found on %s." % mesh) break weights = allWeights[mesh] # unlock influences infs = cmds.skinCluster(clusterName, q=True, weightedInfluence=True) for inf in infs: cmds.setAttr("%s.liw" % inf, False) # prune weights to get rid of weights not stored in skinWeightsFile # normalize needs to be turned off for the prune to work normState = cmds.getAttr("%s.normalizeWeights" % clusterName) shapeName = cmds.listRelatives(mesh, shapes=True)[0] cmds.setAttr("%s.normalizeWeights" % clusterName, False) cmds.skinPercent(clusterName, shapeName, normalize=False, pruneWeights=100.0) cmds.setAttr("%s.normalizeWeights" % clusterName, normState) # pop influences key if "infs" in weights: weights.pop("infs") # set weights in skinCluster.weightsList[].weights[] to infValue for vertId, weightData in weights.items(): weightListAttr = "%s.weightList[%s]" % (clusterName, vertId) for infId, infValue in weightData.items(): weightsAttr = ".weights[%s]" % infId cmds.setAttr(weightListAttr + weightsAttr, infValue) showDialog( "Succss!", 'Skin weights applied to [ %s ] from file:\n"%s_skin.py"' % (", ".join(meshes), skinWeightsFile) ) return
def getSkinWeights(char="", meshes=[]): """ saves skinweights of supplied or selected geometries to a file the data is store in nested dictionaries in this structure {geometry{vertexId{influenceId:weight}...}...} """ # abort if no char is given if char == "": return cmds.warning("No character selected. Please supply a character name in function call.") # abort if there no mesh supplied or selected if meshes == []: meshes = cmds.ls(sl=1) print("No meshes supplied as param, attempting to use selected objects(%s)." % meshes) if meshes == []: return cmds.warning("No mesh to export weights from. Please select a mesh.") # check if output file already exists charDir = common.getCharDir(char) skinWeightsFile = os.path.join(charDir, "%s_skin.py" % char) if os.path.isfile(skinWeightsFile): if ( cmds.confirmDialog(title="Warning", message="Overwrite existing skin weights data?", button=["yes", "no"]) != "yes" ): return "User cancelled" allWeights = {} for mesh in meshes: # find skinCluster clusterName = mel.eval("findRelatedSkinCluster " + mesh) # abort if there is no skinCluster if clusterName == "": cmds.warning("No skinCluster found, " + mesh + " is not bound to a skeleton?") meshes.remove(mesh) break # prune to get rid of 0 zero value indices normState = cmds.getAttr("%s.normalizeWeights" % clusterName) shapeName = cmds.listRelatives(mesh, shapes=True)[0] cmds.setAttr("%s.normalizeWeights" % clusterName, False) cmds.skinPercent(clusterName, shapeName, normalize=False, pruneWeights=0.001) cmds.setAttr("%s.normalizeWeights" % clusterName, normState) # get the MFnSkinCluster for clusterName selList = om.MSelectionList() selList.add(clusterName) clusterNode = om.MObject() selList.getDependNode(0, clusterNode) skinFn = oma.MFnSkinCluster(clusterNode) # get the MDagPath for all influence infDags = om.MDagPathArray() skinFn.influenceObjects(infDags) # create a dictionary whose key is the MPlug indice id and # whose value is the influence list id infIds = {} infs = [] for i in xrange(infDags.length()): infPath = infDags[i].fullPathName() infId = int(skinFn.indexForInfluenceObject(infDags[i])) infIds[infId] = i infs.append(infPath) # get weightList and weight plugs weightListPlug = skinFn.findPlug("weightList") weightsPlug = skinFn.findPlug("weights") weightListAttr = weightListPlug.attribute() weightsAttr = weightsPlug.attribute() weightsInfIds = om.MIntArray() # the weights are stored in dictionary, the key is the vertId, # the value is another dictionary whose key is the influence id and # value is the weight for that influence # first key 'infs' is the list of influences in bind order weights = {} weights["infs"] = infs for vertId in xrange(weightListPlug.numElements()): vertWeights = {} weightsPlug.selectAncestorLogicalIndex(vertId, weightListAttr) weightsPlug.getExistingArrayAttributeIndices(weightsInfIds) infPlug = om.MPlug(weightsPlug) for infId in weightsInfIds: infPlug.selectAncestorLogicalIndex(infId, weightsAttr) try: vertWeights[infIds[infId]] = infPlug.asDouble() except KeyError: pass weights[vertId] = vertWeights allWeights[mesh] = weights # save data to file f = open(skinWeightsFile, "w") f.write(json.dumps(allWeights)) f.close() showDialog("Succss!", 'Skin weights for [ %s ] saved to file:\n"%s_skin.py"' % (", ".join(meshes), skinWeightsFile)) return allWeights