import logging
import time, os
#import simplejson as json
import maya.api.OpenMaya as om2
import maya.cmds as cmds
#from OM2core.plugs.utils import getPlugValue, findPlugOnNode
def findPlugOnNode(node, plugName):
"""
:param node: MObjectHandle
:return: MPlug
"""
if not node.isValid():
raise Exception("Node is no longer valid!")
mFn = om2.MFnDependencyNode(node.object())
for x in xrange(mFn.attributeCount()):
attr = om2.MFnAttribute(mFn.attribute(x))
if attr.name == plugName:
attr = mFn.attribute(plugName)
plug = om2.MPlug(node.object(), attr)
return plug
raise Exception("PlugName {} is not valid!".format(plugName))
def getPlugValue(plug):
"""
:param plug: MPlug. The node plug.
:return: The value of the passed in node plug or None
"""
pAttribute = plug.attribute()
apiType = pAttribute.apiType()
# Float Groups - rotate, translate, scale; Com2pounds
if apiType in [om2.MFn.kAttribute3Double, om2.MFn.kAttribute3Float, om2.MFn.kCompoundAttribute]:
result = []
if plug.isCompound:
for c in xrange(plug.numChildren()):
result.append(getPlugValue(plug.child(c)))
return result
# Distance
elif apiType in [om2.MFn.kDoubleLinearAttribute, om2.MFn.kFloatLinearAttribute]:
return plug.asMDistance().asCentimeters()
# Angle
elif apiType in [om2.MFn.kDoubleAngleAttribute, om2.MFn.kFloatAngleAttribute]:
return plug.asMAngle().asDegrees()
# TYPED
elif apiType == om2.MFn.kTypedAttribute:
pType = om2.MFnTypedAttribute(pAttribute).attrType()
# Matrix
if pType == om2.MFnData.kMatrix:
return om2.MFnMatrixData(plug.asMObject()).matrix()
# String
elif pType == om2.MFnData.kString:
return plug.asString()
# MATRIX
elif apiType == om2.MFn.kMatrixAttribute:
return om2.MFnMatrixData(plug.asMObject()).matrix()
# NUMBERS
elif apiType == om2.MFn.kNumericAttribute:
pType = om2.MFnNumericAttribute(pAttribute).numericType()
if pType == om2.MFnNumericData.kBoolean:
return plug.asBool()
elif pType in [om2.MFnNumericData.kShort, om2.MFnNumericData.kInt, om2.MFnNumericData.kLong,
om2.MFnNumericData.kByte]:
return plug.asInt()
elif pType in [om2.MFnNumericData.kFloat, om2.MFnNumericData.kDouble, om2.MFnNumericData.kAddr]:
return plug.asDouble()
# Enum
elif apiType == om2.MFn.kEnumAttribute:
return plug.asInt()
return None
def _iterForSkinCluster(node):
"""
:param node: MObject for the source connection
:return: MObject
"""
if node.apiType() == om2.MFn.kSkinClusterFilter:
return om2.MObjectHandle(node)
iterDg = om2.MItDependencyGraph(node,
om2.MItDependencyGraph.kDownstream,
om2.MItDependencyGraph.kPlugLevel)
while not iterDg.isDone():
currentItem = iterDg.currentNode() # use currentItem for 2017 and below
if currentItem.hasFn(om2.MFn.kSkinClusterFilter):
return om2.MObjectHandle(currentItem)
iterDg.next()
def _findSkinCluster(mesh=None):
"""
Returns a skinCluster attached to the kMesh or kNurbsCurve
@:param mesh: MObjectHandle. Not the shape! Use the transform.
:return: MObject
"""
if not mesh.isValid():
logger.warning("Destination is no longer valid!")
return
dagPath = om2.MDagPath()
geo = dagPath.getAPathTo(mesh.object())
## Does it have a valid number of shapes?
if geo.numberOfShapesDirectlyBelow() != 0:
## Fetch the shape of the geo now.
shapeMobj = geo.extendToShape().node()
mFn_shape = om2.MFnDependencyNode(shapeMobj)
apiType = shapeMobj.apiType()
if apiType == om2.MFn.kMesh:
## Look at the inMesh attr for the source
inMesh_attr = mFn_shape.attribute('inMesh')
elif apiType == om2.MFn.kNurbsCurve:
inMesh_attr = mFn_shape.attribute('create')
else:
logger.warning("This type of om2.MFn node is not supported! int: {}".format(apiType))
return
inMesh_plug = om2.MPlug(shapeMobj, inMesh_attr)
getSource = inMesh_plug.source().node()
## Now use the iterForSkinCluster() function to find the skinCluster in the connected network.
skinClusterNode_MObjH = _iterForSkinCluster(getSource)
if skinClusterNode_MObjH is not None:
return skinClusterNode_MObjH
else:
return None
return None
def _findInfluences(skinClusterMobjH=None):
"""
Returns all the valid influences from the .matrix attribute on the skinCluster node.
@:param mesh: MObjectHandle for the skinCluster. Using the handles here may be playing it a little too safe. But meh.
:return: MObject
"""
if not skinClusterMobjH.isValid():
logger.warning("Skincluster is no longer valid! Did it get deleted?")
return
skClsMFnDep = om2.MFnDependencyNode(skinClusterMobjH.object())
mtxAttr = skClsMFnDep.attribute("matrix")
matrixPlug = om2.MPlug(skinClusterMobjH.object(), mtxAttr)
## Get a list of all the valid connected indices in the matrix array now.
indices = matrixPlug.getExistingArrayAttributeIndices()
influences = []
for idx in indices:
name = om2.MFnDependencyNode(matrixPlug.elementByLogicalIndex(idx).source().node()).absoluteName()
influences.append(str(om2.MNamespace.stripNamespaceFromName(name)))
return influences
def fileExists(filePath):
if filePath is not None and os.path.isfile(filePath):
logger.info("File exists!")
return True
return False
def writetoJSON(filePath, data):
with open(filePath, 'w') as outfile:
outfile.write(json.dumps(data))
return True
def readFromJSON(filePath):
with open(filePath) as infile:
data = json.load(infile)
return data
return None
def _fetchSkinWeights(geoList=None, skipZeroWeights=True):
"""
If you send in a list of geo, we'll use that. Else we assume we're working off selected.
:param geoList: list() of string names for geometry to fetch data for
:param skipZeroWeights: if you want to avoid saving all 0.0 weight data
:return:
"""
geo = om2.MSelectionList()
if geoList is not None:
for eachGeo in geoList:
geo.add(eachGeo)
else: #Assume selected
for eachGeo in cmds.ls(sl=True):
geo.add(eachGeo)
weightData = {}
for x in range(geo.length()):
geoMObjH = om2.MObjectHandle(geo.getDependNode(x))
geoName = om2.MFnDependencyNode(geoMObjH.object()).name()
skinClusterMObjH = _findSkinCluster(geoMObjH)
if skinClusterMObjH is None:
logger.warning("Skipping {} has no skinCluster!".format(geoName))
continue
skName = str(om2.MFnDependencyNode(skinClusterMObjH.object()).name())
influences = _findInfluences(skinClusterMObjH)
## Add the data to the dict
weightData[geoName] = {}
weightData[geoName][skName] = {}
weightData[geoName][skName]['influences'] = influences
weightData[geoName][skName]['maxInf'] = cmds.skinCluster(skName, q=True, maximumInfluences=True)
weightData[geoName][skName]['weights'] = {}
## Fetch the weights now
weightPlug = findPlugOnNode(skinClusterMObjH, 'weightList')
weightCount = weightPlug.getExistingArrayAttributeIndices()
for x in range(len(weightCount)):
# .weightList[x]
p = weightPlug.elementByLogicalIndex(weightCount[x])
# .weights
c = p.child(0)
## Now fetch the list of idx numbers that should relate to the inf [23, 66, 99]
w = c.getExistingArrayAttributeIndices()
## For each idx we're going to build a tuple (idx, infName, weightVal)
weightList = list()
for i in range(len(w)):
childPlug = c.elementByLogicalIndex(w[i])
weightValue = getPlugValue(childPlug)
if skipZeroWeights and weightValue == 0.0:
continue
idx = w[i]
weightList.append((idx, weightValue))
weightData[geoName][skName]['weights'][str(x)] = weightList
print("weightData["+str(geoName)+"]["+str(skName)+"][weights]["+str(x)+"]"+"= "+str(weightList))
return weightData
weightData=_fetchSkinWeights(None,False)
#print("weightData= "+str(weightData))
_Weights=weightData[dupMesh][skincluster]["weights"][str(vert)]
print("_Weights= "+str(_Weights))
boneInt=0
bones = pm.listConnections(str(skincluster) + ".matrix")
boneslen=len(bones)
for b in range(0,boneslen):
bonename=bones[b]
if influence in str(bonename):
#print("found hit")
boneInt=b
print("boneInt= "+str(boneInt))
weight=0
for _Weight in _Weights:
#_Weight=(0, 0.8388942003250122)
boneNum=_Weight[0]
if(boneNum==boneInt):
weight=_Weight[1]
print("weight= "+str(weight))
class Acla:
def unite_selection(self):
#selected = [x for x in cmds.ls(sl=True) if cmds.listRelatives(x, type="mesh")]
selected=[]
for x in cmds.ls(sl=True):
xx= cmds.listRelatives(x, type="mesh")
if xx:
selected.append(xx)
if not selected:
print("not selected")
return
#invalid_meshes = [x for x in cmds.listRelatives(selected, type="mesh", f=True) if not cmds.listConnections(x)]
invalid_meshes = []
for x in cmds.listRelatives(selected, type="mesh", f=True):
xx= cmds.listConnections(x)
if not xx:
invalid_meshes.append(xx)
if invalid_meshes:
print("invalid", invalid_meshes)
return
res = cmds.polyUnite(*cmds.ls(sl=True), ch=0, op=True, muv=1)
print(res)
ClassIns=Acla()
ClassIns.unite_selection()