示例#1
0
def setSkinWeights(skinCluster, vertJointWeightData):
    '''
	vertJointWeightData is a list of 2-tuples containing the vertex component name, and a list of 2-tuples
	containing the joint name and weight.  ie it looks like this:
	[ ('someMesh.vtx[0]', [('joint1', 0.25), 'joint2', 0.75)]),
	  ('someMesh.vtx[1]', [('joint1', 0.2), 'joint2', 0.7, 'joint3', 0.1)]),
	  ... ]
	'''

    #convert the vertex component names into vertex indices
    idxJointWeight = []
    for vert, jointsAndWeights in vertJointWeightData:
        idx = int(vert[vert.rindex('[') + 1:-1])
        idxJointWeight.append((idx, jointsAndWeights))

    #get an MObject for the skin cluster node
    skinCluster = apiExtensions.asMObject(skinCluster)
    skinFn = MFnSkinCluster(skinCluster)

    #construct a dict mapping joint names to joint indices
    jApiIndices = {}
    _tmp = MDagPathArray()
    skinFn.influenceObjects(_tmp)
    for n in range(_tmp.length()):
        jApiIndices[str(_tmp[n].node())] = skinFn.indexForInfluenceObject(
            _tmp[n])

    weightListP = skinFn.findPlug("weightList")
    weightListObj = weightListP.attribute()
    weightsP = skinFn.findPlug("weights")

    tmpIntArray = MIntArray()
    baseFmtStr = str(
        skinCluster
    ) + '.weightList[%d]'  #pre build this string: fewer string ops == faster-ness!

    for vertIdx, jointsAndWeights in idxJointWeight:

        #we need to use the api to query the physical indices used
        weightsP.selectAncestorLogicalIndex(vertIdx, weightListObj)
        weightsP.getExistingArrayAttributeIndices(tmpIntArray)

        weightFmtStr = baseFmtStr % vertIdx + '.weights[%d]'

        #clear out any existing skin data - and awesomely we cannot do this with the api - so we need to use a weird ass mel command
        for n in range(tmpIntArray.length()):
            removeMultiInstance(weightFmtStr % tmpIntArray[n])

        #at this point using the api or mel to set the data is a moot point...  we have the strings already so just use mel
        for joint, weight in jointsAndWeights:
            if weight:
                try:
                    infIdx = jApiIndices[joint]
                except KeyError:
                    try:
                        infIdx = jApiIndices[joint.split('|')[0]]
                    except KeyError:
                        continue

                setAttr(weightFmtStr % infIdx, weight)
示例#2
0
def jointVerts(joint, tolerance=1e-4, onlyVisibleMeshes=True):
    '''
	returns a dict containing data about the verts influences by the given joint - dict keys are mesh names the
	joint affects.  each dict value is a list of tuples containing (weight, idx) for the verts affected by the joint
	'''
    newObjs = []
    meshVerts = {}

    joint = apiExtensions.asMObject(joint)
    jointMDag = joint.dagPath()
    try:
        skins = list(set(listConnections(joint, s=0, type='skinCluster')))
    except TypeError:
        return meshVerts

    MObject = OpenMaya.MObject
    MDagPath = OpenMaya.MDagPath
    MDoubleArray = OpenMaya.MDoubleArray
    MSelectionList = OpenMaya.MSelectionList
    MIntArray = OpenMaya.MIntArray
    MFnSingleIndexedComponent = OpenMaya.MFnSingleIndexedComponent
    for skin in skins:
        skin = apiExtensions.asMObject(skin)
        mfnSkin = MFnSkinCluster(skin)

        mSel = MSelectionList()
        mWeights = MDoubleArray()
        mfnSkin.getPointsAffectedByInfluence(jointMDag, mSel, mWeights)

        for n in range(mSel.length()):
            mesh = MDagPath()
            component = MObject()
            mSel.getDagPath(n, mesh, component)

            #if we only want visible meshes - check to see that this mesh is visible
            if onlyVisibleMeshes:
                if not isNodeVisible(mesh):
                    continue

            c = MFnSingleIndexedComponent(component)
            idxs = MIntArray()
            c.getElements(idxs)

            meshVerts[mesh.partialPathName()] = [
                (w, idx) for idx, w in zip(idxs, mWeights) if w > tolerance
            ]

    return meshVerts