Decomposing SkinCluster Weights into Relationships


#1

I am working on some tools that will provide me with limited capability to transfer over, or automate replication of, UV unwrapping, DQ blend weights, and skinCluster’s joint weights for meshes that have changed since I exported these things. I have been reasonably successful in the first two, but I’m stuck on at the start with the last one.

I’ve found the following code from this site, which gathers a representation of all the basic relationships stored in the SkinCluster: VertexIds, InfluenceIds, and Weight values.


  def getWeightsFromSkin( skin ):
  	clusterName = skin.shortName()
  	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 x in xrange(infDags.length()):
  		infPath = infDags[x].fullPathName()
  		infId = int(skinFn.indexForInfluenceObject(infDags[x]))
  		infIds[infId] = x
  		infs.append(infPath)
  	
  	# get the MPlug for the weightList and weights attributes
  	skinFn = oma.MFnSkinCluster( clusterNode )
  	wlPlug = skinFn.findPlug('weightList')
  	wPlug = skinFn.findPlug('weights')
  	wlAttr = wlPlug.attribute()
  	wAttr = wPlug.attribute()
  	wInfIds = 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
  	weights = {}
  	for vId in xrange(wlPlug.numElements()):
  		vWeights = {}
  		# tell the weights attribute which vertex id it represents
  		wPlug.selectAncestorLogicalIndex(vId, wlAttr)
  		
  		# get the indice of all non-zero weights for this vert
  		wPlug.getExistingArrayAttributeIndices(wInfIds)
  	
  		# create a copy of the current wPlug
  		infPlug = om.MPlug(wPlug)
  		for infId in wInfIds:
  			# tell the infPlug it represents the current influence id
  			infPlug.selectAncestorLogicalIndex(infId, wAttr)
  			
  			# add this influence and its weight to this verts weights
  			try:
  				vWeights[infIds[infId]] = infPlug.asDouble()
  			except KeyError:
  				# assumes a removed influence
  				pass
  		weights[vId] = vWeights
  	
  	return weights
  

In my work on the DQ Blend weights, I came up with a way to use the vertexIDs I gathered to access the MeshVertex represented from the Mesh and with that get the position data I needed. I use store position rather than Ids because the import scripts are designed to work on models that have had minor (or in the case of the UV script, fairly significant) modifications that would have shuffled the ids about.

But, for the skin weights and data from this method, I don’t know how to identify the names of the joints influencing the vertices, based on these influenceIds. Any ideas how I can do that?


#2

Ignore that question, I’m an idiot. :stuck_out_tongue:

It seems I misunderstood the getInfluence() method of the SkinCluster nodeType. All I had to do is get those influences as a list and use the indexId from the output of the method attached to get the appropriate joint out of the list. Almost exactly the same thing as I had to do for the vetices with the mesh’s getVertices() method.

Everything else with the scripts is going swimmingly.

EDIT: On another note, has anyone ever explored logic for choosing good UV cut edge loops? As it stands, I simply look for the vertices nearest to those of the edge I saved and (if necessary) build a path between them with A*. This works great for models that haven’t changed or changed only a bit since I saved the original cuts. A real timesaver! But the more divergent a model becomes, the less effective at choosing to make good selections it becomes and the more manual work I have to do.

Has anyone ever tried to codify good UV edge cutting selection? Or at least thought about ways of improving selection through local topology anaylsis and comparison to a given ideal topology or shape? Any thoughts, suggestions or ideas would be most welcome and I would love to discuss these scripts and ideas further! :smiley: