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 )
Beispiel #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
Beispiel #3
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
Beispiel #4
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)