def __init__(self, meshData, baseInfo=None): self._meshData = meshData fn = MFnMesh(meshData) # 頂点座標リストを生成。各要素は API 2.0 の MVector とする。 pntArr = MFloatPointArray() fn.getPoints(pntArr) nVrts = pntArr.length() if baseInfo and baseInfo[0] != nVrts: # ベースケージと頂点数が合わない場合は無効とする。 self._vertices = None return vertices = _NONE_LIST * nVrts for i in xrange(nVrts): p = pntArr[i] vertices[i] = api2_MVector(p.x, p.y, p.z) #_pprt(vertices) self._vertices = vertices # ベースケージの場合はトライアングル情報を構築する。 # トライアングルリストを生成。各要素は3頂点のインデクスリストとする。 if baseInfo: triangles = baseInfo[1] self._triRestEdges = baseInfo[2] self._triRestAreas = baseInfo[3] else: triCounts = MIntArray() triVrts = MIntArray() fn.getTriangles(triCounts, triVrts) nPlys = triCounts.length() #print(triCounts.length(), triVrts.length()) triangles = [] vi = 0 for i in xrange(nPlys): for j in range(triCounts[i]): triangles.append([triVrts[k] for k in range(vi, vi + 3)]) vi += 3 #_pprt(triangles) self._triangles = triangles # トライアングルのエッジベクトルを計算。 self._triEdges = [(vertices[tri[1]] - vertices[tri[0]], vertices[tri[2]] - vertices[tri[1]]) for tri in triangles] # トライアングルの法線ベクトルを計算。 self._triNrms = [(u ^ v).normalize() for u, v in self._triEdges] # ベースケージの場合はトライアングルの面積を計算。変形ケージでは不要。 if not baseInfo: self._triAreas = [(u ^ v).length() * .5 for u, v in self._triEdges]
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)