def _exportBones(self, mesh, dagPath): options = self.options.copy() if options['bones']: # export skeleton skinIndices skinWeights and animation for skin in self.skins: skinMeshes = mc.skinCluster(skin, q=1, g=1) if mesh in skinMeshes: selectionList = MSelectionList() selectionList.add(skin) node = MObject() selectionList.getDependNode(0, node) skinClusterNode = omAnim.MFnSkinCluster(node) infs = MDagPathArray() numInfs = skinClusterNode.influenceObjects(infs) skinPath = MDagPath() index = 0 skinClusterNode.indexForOutputConnection(index) skinClusterNode.getPathAtIndex(index, skinPath) geom = MItGeometry(dagPath) vertecies = geom.count() inflNames = [] for counter in range(0, numInfs, 1): infName = infs[counter].partialPathName() inflNames.append(infName) firstJoint = inflNames[0] while mc.listRelatives(firstJoint, p=True): parent = mc.listRelatives(firstJoint, p=True) firstJoint = parent[0] if len(self.bones) == 0: self.saveJoints(firstJoint, -1) elif firstJoint != self.bones[0].name: self.saveJoints(firstJoint, -1) jointIndices = [] for n in range(0, len(inflNames), 1): for i in range(0, len(self.bones), 1): if self.bones[i].name == inflNames[n]: jointIndices.append(i) wts = MDoubleArray() infCount = MScriptUtil() ccc = infCount.asUintPtr() component = MObject() while not geom.isDone(): component = geom.component() skinClusterNode.getWeights(skinPath, component, wts, ccc) vertInfluences = [] vertWeightInfo = [] if len(jointIndices): for i in range(0, (len(wts) / len(jointIndices)), 1): vertInfluences = [] for n in range(0, len(jointIndices), 1): jointIndex = jointIndices[n] vertInfluences.append( VertInfluence(wts[n], jointIndex)) vertInfluences = sorted( vertInfluences, key=lambda vertInfluence: vertInfluence. weight) vertInfluences.reverse() vertWeightTotal = 0 for n in range(0, MAX_INFLUENCES, 1): weight = _round8(vertInfluences[n].weight) #if this is the last influence the next influence will take the remainder. if n == MAX_INFLUENCES - 1 or vertInfluences[ n + 1].weight == 0: weight = vertInfluences[ n].weight = 1 - vertWeightTotal vertWeightTotal += weight self.skinIndices.append( vertInfluences[n].jointIndex) self.skinWeights.append(float(weight)) #DEBUG print 'component = ' + str(component) + ' index = ' + str(vertInfluences[n].jointIndex) + ' weight = ' + str(weight) geom.next()
def setSkinCluster(self, skinClusterName): self.skinCluster = skinClusterName self.fn = oma.MFnSkinCluster(Utils.getMObjectForNode(skinClusterName)) return self
def exportSkinWeight(exportPath, meshes, namespace=False): ''' Args: exportPath: The file path where a json file is saved. meshes: A list of mesh nodes. namespace: True to export with namespace. False to export without namespace. Returns: True if export succeeds. False if export fails. Skin file data formatting: # { # "mesh_name": { # "weights": { # "vert id": { # "influence id": weight, # "influence id": weight # } # }, # "infs": [inf1, inf2, inf3, inf4, ...], # "skinCluster": skinCluster_name # } # } ''' data = {} if not meshes: LOG.error('Meshes input {0} is not valid.'.format(meshes)) return False for mesh in meshes: skinCluster = getSkinCluster(mesh) skinNorm = cmds.getAttr('%s.normalizeWeights' % skinCluster) deformNorm = cmds.getAttr('%s.deformUserNormals' % skinCluster) # get the MFnSkinCluster for clusterName selList = om.MSelectionList() selList.add(skinCluster) clusterNode = om.MObject() selList.getDependNode(0, clusterNode) skinFn = oma.MFnSkinCluster(clusterNode) # get the MDagPath for all influence infDags = om.MDagPathArray() skinFn.influenceObjects(infDags) infIds = {} infs = [] unique = True for i in xrange(infDags.length()): infPath = infDags[i].partialPathName() if '|' in infPath: LOG.warning( 'Influence of {}: "{}" is not have a unique name.'.format( mesh, infDags[i].fullPathName())) unique = False infId = int(skinFn.indexForInfluenceObject(infDags[i])) infIds[infId] = i infs.append(infPath) if not unique: LOG.warning( '{} skincluster export is skipped. Please make sure all influence names are unique' .format(mesh)) continue # get the MPlug for the weightList and weights attributes wlPlug = skinFn.findPlug('weightList') wPlug = skinFn.findPlug('weights') wlAttr = wlPlug.attribute() wAttr = wPlug.attribute() wInfIds = om.MIntArray() # progressBar visualization total = wlPlug.numElements() progressBar = QtWidgets.QProgressBar() progressBar.setStyleSheet(STYLESHEET) progressBar.setMinimumSize(QtCore.QSize(450, 25)) progressBar.setMinimum(1) progressBar.setMaximum(total) progressBar.setWindowTitle('Exporting skincluster: {}'.format(mesh)) progressBar.show() completed = 0 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) completed += 1 progressBar.setValue(completed) 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 if namespace: meshName = mesh else: meshName = mesh.split(':')[-1] data[meshName] = { 'weights': weights, 'infs': infs, 'skinCluster': skinCluster, 'nw': skinNorm, 'deformUserNormals': deformNorm } with open(exportPath, 'w') as outfile: try: json.dump(data, outfile, sort_keys=True, indent=4) LOG.info('Exported skin weights for mesh {} to {}'.format( ' '.join(meshes), exportPath)) return True except: LOG.error( 'Unable to export skinWeight data to {0}.'.format(exportPath)) return False
# input object to dag path mesh_selection_list = om.MSelectionList() mesh_selection_list.add(mesh_object) mesh_dag_path = om.MDagPath() mesh_selection_list.getDagPath(0, mesh_dag_path) joint_selection_list = om.MSelectionList() joint_selection_list.add(joint_object) joint_dag_path = om.MDagPath() joint_selection_list.getDagPath(0, joint_dag_path) skin_selection_list = om.MSelectionList() skin_mobject = om.MObject() om.MGlobal.getSelectionListByName(skin_object, skin_selection_list) skin_selection_list.getDependNode(0, skin_mobject) skin_mfn = oma.MFnSkinCluster(skin_mobject) # get joint influcenced points and weight values components = om.MSelectionList() weights = om.MDoubleArray() skin_mfn.getPointsAffectedByInfluence(joint_dag_path, components, weights) # create cluster components_list = list() components.getSelectionStrings(components_list) cluster_node = cmds.cluster(components_list) cluster_selection_list = om.MSelectionList() om.MGlobal.getSelectionListByName(cluster_node[0], cluster_selection_list) cluster_mobject = om.MObject() cluster_selection_list.getDependNode(0, cluster_mobject)
def ExportMesh(filepath, meshShapedagPath): meshFn = OpenMaya.MFnMesh(meshShapedagPath) meshIntersector = OpenMaya.MMeshIntersector() meshIntersector.create(meshShapedagPath.node()) faceIdList = [] baryCoordList = [] points = OpenMaya.MPointArray() meshFn.getPoints(points, OpenMaya.MSpace.kWorld) normals = OpenMaya.MFloatVectorArray() meshFn.getVertexNormals(False, normals, OpenMaya.MSpace.kWorld) triangleCounts = OpenMaya.MIntArray() triangleVertexIndices = OpenMaya.MIntArray( ) # the size of this array is three times of the number of total triangles meshFn.getTriangles(triangleCounts, triangleVertexIndices) #------------------------- # Get skin cluster object #------------------------- skinClusterName = '' mesh_shape_name = meshFn.name() skinClusters = cmds.listHistory(mesh_shape_name) skinClusters = cmds.ls(skinClusters, type="skinCluster") if skinClusters: skinClusterName = skinClusters[0] else: cmds.warning('No skin cluster found on ' + mesh_shape_name) return #print skinClusterName # get the MFnSkinCluster using skinClusterName selList = OpenMaya.MSelectionList() selList.add(skinClusterName) skinClusterNode = OpenMaya.MObject() selList.getDependNode(0, skinClusterNode) skinFn = OpenMayaAnim.MFnSkinCluster(skinClusterNode) dagPaths = MDagPathArray() skinFn.influenceObjects(dagPaths) # influence object is a joint influenceObjectsNames = [] # get joint names for i in range(dagPaths.length()): influenceName = dagPaths[i].partialPathName() influenceObjectsNames.append( influenceName) # Need to remove namespace? skinMeshes = cmds.skinCluster(skinClusterName, query=1, geometry=1) geoIter = OpenMaya.MItGeometry(meshShapedagPath) infCount = OpenMaya.MScriptUtil() infCountPtr = infCount.asUintPtr() numVertices = geoIter.count() weightArray = [ 0 ] * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT * numVertices # joint weight array for all vertices. Each vertex will have TRESSFX_MAX_INFLUENTIAL_BONE_COUNT weights. # It is initialized with zero for empty weight in case there are less weights than TRESSFX_MAX_INFLUENTIAL_BONE_COUNT . jointIndexArray = [ -1 ] * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT * numVertices # joint index array for all vertices. It is initialized with -1 for an empty element in case # there are less weights than TRESSFX_MAX_INFLUENTIAL_BONE_COUNT . # collect bone weights for all vertices in the mesh index = 0 progressBar = ProgressBar('Collect data', numVertices) while geoIter.isDone() == False: weights = OpenMaya.MDoubleArray() skinFn.getWeights(meshShapedagPath, geoIter.currentItem(), weights, infCountPtr) weightJointIndexPairs = [] for i in range(len(weights)): pair = WeightJointIndexPair() pair.weight = weights[i] pair.joint_index = i weightJointIndexPairs.append(pair) weightJointIndexPairs.sort() a = 0 for j in range( min(len(weightJointIndexPairs), TRESSFX_MAX_INFLUENTIAL_BONE_COUNT)): weightArray[index * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT + a] = weightJointIndexPairs[j].weight jointIndexArray[index * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT + a] = weightJointIndexPairs[j].joint_index a += 1 index += 1 progressBar.Increment() geoIter.next() progressBar.Kill() #---------------------------------------------------------- # We collected all necessary data. Now save them in file. #---------------------------------------------------------- totalProgress = points.length() + triangleVertexIndices.length() / 3 + len( influenceObjectsNames) progressBar = ProgressBar('Export collision mesh', totalProgress) f = open(filepath, "w") f.write("# TressFX collision mesh exported by TressFX Exporter in Maya\n") # Write all bone (joint) names f.write("numOfBones %g\n" % (len(influenceObjectsNames))) f.write("# bone index, bone name\n") for i in range(len(influenceObjectsNames)): f.write("%d %s\n" % (i, influenceObjectsNames[i])) progressBar.Increment() # write vertex positions and skinning data f.write("numOfVertices %g\n" % (points.length())) f.write( "# vertex index, vertex position x, y, z, normal x, y, z, joint index 0, joint index 1, joint index 2, joint index 3, weight 0, weight 1, weight 2, weight 3\n" ) for vertexIndex in xrange(points.length()): point = points[vertexIndex] normal = normals[vertexIndex] weightJointIndexPairs = GetSortedWeightsFromOneVertex( TRESSFX_MAX_INFLUENTIAL_BONE_COUNT, vertexIndex, jointIndexArray, weightArray) f.write( "%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g\n" % (vertexIndex, point.x, point.y, point.z, normal.x, normal.y, normal.z, weightJointIndexPairs[0].joint_index, weightJointIndexPairs[1].joint_index, weightJointIndexPairs[2].joint_index, weightJointIndexPairs[3].joint_index, weightJointIndexPairs[0].weight, weightJointIndexPairs[1].weight, weightJointIndexPairs[2].weight, weightJointIndexPairs[3].weight)) progressBar.Increment() # write triangle face indices f.write("numOfTriangles %g\n" % (triangleVertexIndices.length() / 3)) f.write( "# triangle index, vertex index 0, vertex index 1, vertex index 2\n") for i in range(triangleVertexIndices.length() / 3): f.write("%g %d %d %d\n" % (i, triangleVertexIndices[i * 3 + 0], triangleVertexIndices[i * 3 + 1], triangleVertexIndices[i * 3 + 2])) progressBar.Increment() f.close() progressBar.Kill() return
def vtxSave_Oapi(self): selList = Om.MSelectionList() Om.MGlobal.getActiveSelectionList(selList) #_prselList = [] # selList.getSelectionStrings(_prselList) #获取 MSelectionList 内容 # print _prselList if selList.isEmpty(): Om.MGlobal.displayError('Select Nothing') return MDagPath = Om.MDagPath() # 存储所选物体的路径 MObject = Om.MObject() # 存储所选物体的组件的列表 selList.getDagPath(0, MDagPath) selList.getDependNode(0, MObject) # MDagPath.fullPathName() #获取 MDagPath 内容 slMIt = Om.MItSelectionList(selList) MItDagPath = Om.MDagPath() MItcomponent = Om.MObject() slMIt.getDagPath(MItDagPath, MItcomponent) _selType = MDagPath.apiType() MDagPath.extendToShape() # 获取当前物体的shape节点 _selShapeType = MDagPath.apiType() if not _selType in set([110, 296, 267, 294, 279, ]): return elif _selShapeType == 296: suf = 'vtx' elif _selShapeType == 267 or _selShapeType == 294: suf = 'cv' elif _selShapeType == 279: suf = 'pt' skCluster = mel.eval('findRelatedSkinCluster("%s")' % MDagPath.partialPathName()) if not skCluster: return #connectNode = cmds.listHistory(MDagPath.partialPathName(), il=1, pdo=1) # if not connectNode: # Om.MGlobal.displayError('Select No Skin') # return # for skCluster in connectNode: # if cmds.nodeType(skCluster) == 'skinCluster': # break # if skCluster == connectNode[-1]: # return Om.MGlobal.getSelectionListByName(skCluster, selList) skinObj = Om.MObject() selList.getDependNode(1, skinObj) skinNode = OmAni.MFnSkinCluster(skinObj) infs = Om.MDagPathArray() numInfs = skinNode.influenceObjects(infs) infNameList = [] # 骨骼列表 for i in range(numInfs): infName = infs[i].partialPathName() infNameList.append(infName) # fn = Om.MFnDependencyNode(MDagPath.node()) #获取MDagPath的内容? # print fn.name() #获取 MFnDependencyNode 内容 filePath = cmds.fileDialog2(ff='WeightFile (*.vtxWeight *.sdd)', ds=2) # vtxWeight (*.vtxWeight);;sdd (*.sdd) if not filePath: return fileLine = [] Lineapp = fileLine.append if not MItcomponent.isNull(): # component组件不为空(点), 线和面会强制转为点 vertIter = Om.MItGeometry(MItDagPath, MItcomponent) else: vertIter = Om.MItGeometry(MObject) while not vertIter.isDone(): infCount = Om.MScriptUtil() infCountPtr = infCount.asUintPtr() Om.MScriptUtil.setUint(infCountPtr, 0) weights = Om.MDoubleArray() skinNode.getWeights(MDagPath, vertIter.currentItem(), weights, infCountPtr) tvList = self.zeroWeightData_Save(weights, infNameList) wtStr = '%s[%s]--%s\r\n' % (suf, vertIter.index(), tvList) Lineapp(wtStr) vertIter.next() with open(filePath[0], 'w') as vwfile: for i in fileLine: vwfile.write(i) DisplayYes().showMessage('Process Finish!')
def sang_kraduk(mmddata, chue_nod_poly, khanat, ao_ik): print(u'骨を作成中') list_chue_nod_kho = [] # ลิสต์เก็บชื่อของโหนดข้อ for i, b in enumerate(mmddata.bones): # แก้ชื่อข้อต่อให้เป็นโรมาจิ chue_kho = romaji(chuedidi(b.name, u'kho%d' % i)) p = b.position # ตำแหน่งของข้อต่อ mc.select(d=1) # สร้างข้อต่อตามตำแหน่งที่กำหนด chue_nod_kho = mc.joint(p=[p.x * khanat, p.y * khanat, -p.z * khanat], rad=khanat / 2, n=chue_kho + '_' + chue_nod_poly) # เก็บชื่อเดิมไว้เผื่อใช้ mc.addAttr(chue_nod_kho, ln='namae', nn=u'名前', dt='string') mc.setAttr(chue_nod_kho + '.namae', chuedidi(b.name, chue_nod_kho), typ='string') # ซ่อนข้อต่อที่ไม่จำเป็นต้องเห็น if (b.getIkFlag() or not b.getVisibleFlag()): mc.setAttr(chue_nod_kho + '.drawStyle', 2) else: mc.setAttr(chue_nod_kho + '.drawStyle', 0) # ตั้งค่าการจัดวางแกนหมุนของข้อ if (b.getLocalCoordinateFlag() or b.getFixedAxisFlag()): if (b.getFixedAxisFlag()): kaen_x = b.fixed_axis kaen_z = cross([0.0, 1.0, 0.0], kaen_x) else: kaen_x = b.local_x_vector kaen_z = b.local_z_vector kaen_y = cross(kaen_z, kaen_x) array_mun = [ kaen_x[0], kaen_x[1], -kaen_x[2], 0., kaen_y[0], kaen_y[1], -kaen_y[2], 0., kaen_z[0], kaen_z[1], -kaen_z[2], 0., 0., 0., 0., 1. ] matrix_mun = om.MMatrix() # สร้างเมทริกซ์หมุน om.MScriptUtil.createMatrixFromList(array_mun, matrix_mun) trans = om.MTransformationMatrix(matrix_mun) mum_euler = trans.eulerRotation().asVector() mc.setAttr(chue_nod_kho + '.jointOrientX', math.degrees(mum_euler.x)) mc.setAttr(chue_nod_kho + '.jointOrientY', math.degrees(mum_euler.y)) mc.setAttr(chue_nod_kho + '.jointOrientZ', math.degrees(mum_euler.z)) list_chue_nod_kho.append(chue_nod_kho) list_mi_ik = [] # ลิสต์ของข้อต่อที่มี IK list_chue_nod_nok = [] # ลิสต์ของข้อต่อที่อยู่นอกสุด for i, b in enumerate(mmddata.bones): chue_nod_kho = list_chue_nod_kho[i] if (b.parent_index >= 0): # ผูกติดข้อต่อแต่ละข้อเข้าด้วยกัน chue_nod_parent = list_chue_nod_kho[b.parent_index] mc.connectJoint(chue_nod_kho, chue_nod_parent, pm=1) else: list_chue_nod_nok.append(chue_nod_kho) # แก้ปัญหากรณีที่มุมหมุนของกระดูกมีค่าแปลกๆ (เกิดขึ้นได้อย่างไรยังไม่รู้แน่ชัด) if (round(mc.getAttr(chue_nod_kho + '.rx')) == -360.): mc.setAttr(chue_nod_kho + '.rx', 0) if (round(mc.getAttr(chue_nod_kho + '.ry')) == -360.): mc.setAttr(chue_nod_kho + '.ry', 0) if (round(mc.getAttr(chue_nod_kho + '.rz')) == -360.): mc.setAttr(chue_nod_kho + '.rz', 0) if (round(mc.getAttr(chue_nod_kho + '.rx')) % 360 == 180. and round(mc.getAttr(chue_nod_kho + '.ry')) % 360 == 180. and round(mc.getAttr(chue_nod_kho + '.rz')) % 360 == 180.): mc.setAttr(chue_nod_kho + '.rx', 0) mc.setAttr(chue_nod_kho + '.ry', 0) mc.setAttr(chue_nod_kho + '.rz', 0) if (b.getExternalRotationFlag()): # ตั้งมุมการหมุนให้ข้อที่เปลี่ยนมุมตามการหมุนของข้ออื่น chue_nod_effect = list_chue_nod_kho[ b.effect_index] # โหนดข้อที่ส่งผลให้ x = mc.getAttr(chue_nod_effect + '.jointOrientX') y = mc.getAttr(chue_nod_effect + '.jointOrientY') z = mc.getAttr(chue_nod_effect + '.jointOrientZ') mc.setAttr(chue_nod_kho + '.jointOrientX', x) mc.setAttr(chue_nod_kho + '.jointOrientY', y) mc.setAttr(chue_nod_kho + '.jointOrientZ', z) # ตั้งเอ็กซ์เพรชชันให้ข้อที่เปลี่ยนมุมตามการหมุนของข้ออื่น ef = b.effect_factor s = '%s.rotateX = %s.rotateX * %s;\n' % (chue_nod_kho, chue_nod_effect, ef) s += '%s.rotateY = %s.rotateY * %s;\n' % (chue_nod_kho, chue_nod_effect, ef) s += '%s.rotateZ = %s.rotateZ * %s;\n' % (chue_nod_kho, chue_nod_effect, ef) mc.expression(s=s, n='expression_%s_%s' % (chue_nod_kho, chue_nod_effect)) if (b.getExternalTranslationFlag()): # ตั้งเอ็กซ์เพรชชันให้ข้อที่เลื่อนตำแหน่งตามตำแหน่งของข้ออื่น chue_nod_effect = list_chue_nod_kho[ b.effect_index] # โหนดข้อที่ส่งผลให้ ef = b.effect_factor s = '%s.translateX = %s.translateX * %s;\n' % (chue_nod_kho, chue_nod_effect, ef) s += '%s.translateY = %s.translateY * %s;\n' % ( chue_nod_kho, chue_nod_effect, ef) s += '%s.translateZ = %s.translateZ * %s;\n' % ( chue_nod_kho, chue_nod_effect, ef) mc.expression(s=s, n='expression_%s_%s' % (chue_nod_kho, chue_nod_effect)) if (b.ik): list_mi_ik.append(i) # เก็บโหนดที่มี IK # สร้าง IK ถ้าเลือกไว้ว่าให้สร้าง if (ao_ik): list_chue_nod_ik = [] # ลิสต์เก็บชื่อโหนด IK for i in list_mi_ik: b = mmddata.bones[i] index_kho = [b.ik.target_index] + [l.bone_index for l in b.ik.link] for j in range(0, len(b.ik.link)): kho1 = list_chue_nod_kho[index_kho[j]] kho2 = list_chue_nod_kho[index_kho[j + 1]] mc.select(kho1, kho2) chue_nod_ik = mc.ikHandle(n=list_chue_nod_kho[i] + '_IK', sol='ikRPsolver')[0] list_chue_nod_ik.append(chue_nod_ik) nod_skin = pm.skinCluster(list_chue_nod_kho, chue_nod_poly, mi=4, tsb=1) nod_poly = pm.PyNode(chue_nod_poly) path_mesh = om.MDagPath() sl = om.MSelectionList() sl.add(nod_poly.fullPath()) sl.getDagPath(0, path_mesh) obj_skin = om.MObject() sl = om.MSelectionList() sl.add(nod_skin.name()) sl.getDependNode(0, obj_skin) fn_skin = oma.MFnSkinCluster(obj_skin) sl = om.MSelectionList() list_influ = [] for i, chue_nod_kho in enumerate(list_chue_nod_kho): dagpath = om.MDagPath() sl.add(pm.PyNode(chue_nod_kho).fullPath()) sl.getDagPath(i, dagpath) idx = fn_skin.indexForInfluenceObject(dagpath) list_influ.append(idx) n_kho = len(mmddata.bones) list_namnak = [] for v in mmddata.vertices: namnak = [0.] * n_kho d = v.deform if (isinstance(d, pymeshio.pmx.Bdef1)): # ส่วนที่ได้รับอิทธิพลจากแค่จุดเดียว namnak[d.index0] = 1. elif (isinstance(d, (pymeshio.pmx.Bdef2, pymeshio.pmx.Sdef))): # ส่วนที่ได้รับอิทธิพลจาก 2 จุด namnak[d.index0] += d.weight0 namnak[d.index1] += 1. - d.weight0 elif (isinstance(d, pymeshio.pmx.Bdef4)): # ส่วนที่ได้รับอิทธิพลจาก 4 จุด namnak[d.index0] += d.weight0 namnak[d.index1] += d.weight1 namnak[d.index2] += d.weight2 namnak[d.index3] += 1. - d.weight0 - d.weight1 - d.weight2 list_namnak.extend(namnak) n_chut = len(mmddata.vertices) # จำนวนจุดยอด util = om.MScriptUtil() util.createFromList(list_namnak, n_kho * n_chut) array_namnak = om.MDoubleArray(util.asDoublePtr(), n_kho * n_chut) util = om.MScriptUtil() util.createFromList(list_influ, n_kho) array_influ = om.MIntArray(util.asIntPtr(), n_kho) fn_compo = om.MFnSingleIndexedComponent() compo = fn_compo.create(om.MFn.kMeshVertComponent) util = om.MScriptUtil() util.createFromList(range(n_chut), n_chut) index_chut = om.MIntArray(util.asIntPtr(), n_chut) fn_compo.addElements(index_chut) # ตั้งค่าน้ำหนักของอิทธิพลที่แต่ละข้อมีต่อแต่ละจุดบนโพลิกอน fn_skin.setWeights(path_mesh, compo, array_influ, array_namnak, 1) for chue_nod_kho in list_chue_nod_kho: if (chue_nod_kho not in list_chue_nod_nok): mc.rename(chue_nod_kho, chue_nod_kho.replace('_' + chue_nod_poly, '')) return list_chue_nod_nok
def bSkinObject(objectName, fileJoints, weights): if not cmds.objExists(objectName): print objectName, " doesn't exist - skipping. " return it = OpenMaya.MItDependencyNodes(OpenMaya.MFn.kJoint) # quick check if all the joints are in scene # allInfluencesInScene = True sceneJointTokens = [] for jointIndex in range(len(fileJoints)): jointHere = False it = OpenMaya.MItDependencyNodes(OpenMaya.MFn.kJoint) while not it.isDone(): sceneJointTokens = str( OpenMaya.MFnDagNode(it.item()).fullPathName()).split('|') if str(fileJoints[jointIndex]) == str( sceneJointTokens[len(sceneJointTokens) - 1]): jointHere = True it.next() if not jointHere: allInfluencesInScene = False print 'missing influence: ', fileJoints[jointIndex] if not allInfluencesInScene: print objectName, " can't be skinned because of missing influences." return # create some arrays # allJointsHere = False totalJointsCount = len(fileJoints) fileJointsMapArray = range(len(fileJoints)) objectEmptyJoints = [] # let's check if there's already a skinCluster, let's try to use that - if it contains all the needed joints # skinCluster = bFindSkinCluster(objectName) if type(skinCluster) != type(True): fnSkinCluster = OpenMayaAnim.MFnSkinCluster(skinCluster) influentsArray = OpenMaya.MDagPathArray() infCount = fnSkinCluster.influenceObjects(influentsArray) influenceStringArray = [] for i in range(infCount): influenceStringArray.append( OpenMaya.MFnDagNode(influentsArray[i]).name()) allJointsHere = True for joint in fileJoints: if joint not in influenceStringArray: print 'missing a joint (', joint, ', ..)' allJointsHere = False break if not allJointsHere: maya.mel.eval("DetachSkin " + objectName) else: objectFoundJointsInFile = [False] * len(influenceStringArray) for i in range(len(fileJoints)): for k in range(len(influenceStringArray)): if fileJoints[i] == influenceStringArray[k]: fileJointsMapArray[i] = k objectFoundJointsInFile[k] = True for i in range(len(influenceStringArray)): if not objectFoundJointsInFile[i]: objectEmptyJoints.append(i) totalJointsCount = len(fileJointsMapArray) + len(objectEmptyJoints) #print 'jointMapArray: ', fileJointsMapArray if not allJointsHere: cmd = "select " for i in range(len(fileJoints)): cmd += " " + fileJoints[i] cmd += " " + objectName maya.mel.eval(cmd) maya.mel.eval("skinCluster -tsb -mi 10") maya.mel.eval("select `listRelatives -p " + objectName + "`") maya.mel.eval("refresh") #maya.mel.eval("undoInfo -st 1") skinCluster = bFindSkinCluster(objectName) fnSkinCluster = OpenMayaAnim.MFnSkinCluster(skinCluster) influentsArray = OpenMaya.MDagPathArray() fnSkinCluster.influenceObjects(influentsArray) bSkinPath = OpenMaya.MDagPath() fnSkinCluster.getPathAtIndex(fnSkinCluster.indexForOutputConnection(0), bSkinPath) weightStrings = [] vertexIter = OpenMaya.MItGeometry(bSkinPath) weightDoubles = OpenMaya.MDoubleArray() singleIndexed = True vtxComponents = OpenMaya.MObject() fnVtxComp = OpenMaya.MFnSingleIndexedComponent() fnVtxCompDouble = OpenMaya.MFnDoubleIndexedComponent() if bSkinPath.node().apiType() == OpenMaya.MFn.kMesh: vtxComponents = fnVtxComp.create(OpenMaya.MFn.kMeshVertComponent) elif bSkinPath.node().apiType() == OpenMaya.MFn.kNurbsSurface: singleIndexed = False vtxComponents = fnVtxCompDouble.create( OpenMaya.MFn.kSurfaceCVComponent) elif bSkinPath.node().apiType() == OpenMaya.MFn.kNurbsCurve: vtxComponents = fnVtxComp.create(OpenMaya.MFn.kCurveCVComponent) # nurbs curves.. # counterValue = 0 if not singleIndexed: currentU = 0 currentV = 0 cvsU = OpenMaya.MFnNurbsSurface(bSkinPath.node()).numCVsInU() cvsV = OpenMaya.MFnNurbsSurface(bSkinPath.node()).numCVsInV() formU = OpenMaya.MFnNurbsSurface(bSkinPath.node()).formInU() formV = OpenMaya.MFnNurbsSurface(bSkinPath.node()).formInV() if formU == 3: cvsU -= 3 if formV == 3: cvsV -= 3 # go through all vertices and append to the weightDoubles array # vertexIter = OpenMaya.MItGeometry(bSkinPath) while not vertexIter.isDone(): weightStrings = [] if singleIndexed: fnVtxComp.addElement(counterValue) else: fnVtxCompDouble.addElement(currentU, currentV) currentV += 1 if currentV >= cvsV: currentV = 0 currentU += 1 weightStrings = weights[counterValue].split(' ') for i in range(len(weightStrings)): weightDoubles.append(float(weightStrings[i])) for i in range(len(objectEmptyJoints)): weightDoubles.append(0) counterValue += 1 vertexIter.next() # createing the influence Array # mayafileJointsMapArray = OpenMaya.MIntArray() for i in range(len(fileJointsMapArray)): mayafileJointsMapArray.append(fileJointsMapArray[i]) for i in range(len(objectEmptyJoints)): mayafileJointsMapArray.append(objectEmptyJoints[i]) # set the weights # fnSkinCluster.setWeights(bSkinPath, vtxComponents, mayafileJointsMapArray, weightDoubles, 0)
def export_skeletons(self): dag_it = om.MItDependencyNodes(om.MFn.kSkinClusterFilter) while not dag_it.isDone(): obj = dag_it.thisNode() joints = om.MDagPathArray() skin_fn = omanim.MFnSkinCluster(obj) num_joints = skin_fn.influenceObjects(joints) # Loop through joints and look in block cache whether # a skeleton for this joint has been exported. If not, # we will ignore this binding altogether. skel = None #print('found skin cluster for %s!' % skel) for i in range(num_joints): #print('affected joint: %s' % joints[i].fullPathName()) skel = self.block_cache.get(self.get_skeleton_root(joints[i].fullPathName())) if skel is not None: break # Skeleton was found if skel is not None: #print('found skeleton in cache!') #print('num joints: %d' % num_joints) # Loop through meshes that are influenced by this # skeleton, and add weight stream to their mesh data num_geoms = skin_fn.numOutputConnections() #print('num geoms: %d' % num_geoms) for i in range(num_geoms): skin_path = om.MDagPath() skin_fn.getPathAtIndex(i, skin_path) vert_it = om.MItMeshVertex(skin_path) #print('skin obj: %s' % skin_path.fullPathName()) # Check whether a mesh data for this geometry has # been added to the block cache. If not, bindings # for this mesh can be ignored. md = self.block_cache.get(self.get_name(skin_path.fullPathName())) if md is not None: #print('found mesh in cache!') weight_data = [] index_data = [] self.has_skelanim = True while not vert_it.isDone(): comp = vert_it.currentItem() weights = om.MDoubleArray() weight_objs = [] #script_util = om.MScriptUtil() for ii in range(num_joints): skin_fn.getWeights(skin_path, comp, ii, weights) joint_name = joints[ii].fullPathName() joint_idx = self.joint_indices[joint_name.split('|')[-1]] weight_objs.append( (joint_idx, weights[0]) ) def comp_weight_objs(wo0, wo1): if wo0[1] > wo1[1]: return -1 else: return 1 weight_objs.sort(comp_weight_objs) # Normalize top weights weight_objs = weight_objs[0:self.joints_per_vert] sum_obj = reduce(lambda w0,w1: (0, w0[1]+w1[1]), weight_objs) if sum_obj[1] > 0.0: weight_objs = map(lambda w: (w[0], w[1] / sum_obj[1]), weight_objs) # Add more empty weight objects if too few if len(weight_objs) != self.joints_per_vert: weight_objs.extend([(0,0)] * (self.joints_per_vert - len(weight_objs))) for w_obj in weight_objs: index_data.append(w_obj[0]) weight_data.append(w_obj[1]) vert_it.next() weight_stream = [] index_stream = [] # This list contains the old-index of each vertex in the AWD vertex stream vert_indices = self.mesh_vert_indices[skin_path.fullPathName()] for idx in vert_indices: start_idx = idx*self.joints_per_vert end_idx = start_idx + self.joints_per_vert w_tuple = weight_data[start_idx:end_idx] i_tuple = index_data[start_idx:end_idx] weight_stream.extend(w_tuple) index_stream.extend(i_tuple) if len(md) == 1: print('Setting streams!') sub = md[0] sub.add_stream(pyawd.geom.STR_JOINT_WEIGHTS, weight_stream) sub.add_stream(pyawd.geom.STR_JOINT_INDICES, index_stream) else: print('skinning not implemented for meshes with <> 1 sub-mesh') dag_it.next()
def bSaveVertexSkinValues(inputFile, ignoreSoftSelection): timeBefore = time.time() print 'saving Vertex skinWeights.. ' if not ignoreSoftSelection: verts, softWeights = getSoftSelection() else: verts = cmds.ls(selection=True, flatten=True) vertIds = vertexToIdList(verts) selection = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(selection) iterate = OpenMaya.MItSelectionList(selection) dagPath = OpenMaya.MDagPath() component = OpenMaya.MObject() iterate.getDagPath(dagPath, component) skinCluster = bFindSkinCluster( OpenMaya.MFnDagNode(dagPath).partialPathName()) fnSkinCluster = OpenMayaAnim.MFnSkinCluster(skinCluster) if not skinCluster.hasFn(OpenMaya.MFn.kSkinClusterFilter): print 'no skinCluster found on selected vertices' return output = open(inputFile, 'w') output.write(str(OpenMaya.MItGeometry(bSkinPath).count()) + '\n') fnVtxComp = OpenMaya.MFnSingleIndexedComponent() vtxComponents = OpenMaya.MObject() vtxComponents = fnVtxComp.create(OpenMaya.MFn.kMeshVertComponent) WeightArray = OpenMaya.MFloatArray() meshIter = OpenMaya.MItMeshVertex(dagPath, component) #while not meshIter.isDone(): for vertId in vertIds: fnVtxComp.addElement(vertId) #meshIter.next() vertexCount = meshIter.count() scriptUtil = OpenMaya.MScriptUtil() infCountPtr = scriptUtil.asUintPtr() fnSkinCluster.getWeights(bSkinPath, vtxComponents, WeightArray, infCountPtr) infCount = OpenMaya.MScriptUtil.getUint(infCountPtr) weightCheckArray = [] for i in range(infCount): weightCheckArray.append(False) for i in range(vertexCount): for k in range(infCount): if not weightCheckArray[k] and WeightArray[((i * infCount) + k)]: weightCheckArray[k] = True #joints.. influentsArray = OpenMaya.MDagPathArray() fnSkinCluster.influenceObjects(influentsArray) for i in range(infCount): if (weightCheckArray[i]): output.write(OpenMaya.MFnDagNode(influentsArray[i]).name() + '\n') output.write('============\n') counter = 0 weightArrayString = [] for i in range(len(vertIds)): vertId = vertIds[i] softWeight = '' if not ignoreSoftSelection: softWeight = '%f:' % softWeights[i] #weightArrayString = '%d:%s' % (vertId, softWeight) """ for k in range(infCount): if weightCheckArray[k] == True: weightArrayString += str(WeightArray[(counter * infCount) + k]) + ' ' """ weightsString = ' '.join([ '0' if x == 0 else str(x) for n, x in enumerate(WeightArray[i * infCount:(i + 1) * infCount]) if weightCheckArray[n] ]) weightArrayString = "%d:%s%s" % (vertId, softWeight, weightsString) output.write(weightArrayString + '\n') counter += 1 meshIter.next() output.close() print 'done, it took', (time.time() - timeBefore), ' seconds'
def bSaveSkinValues(inputFile): timeBefore = time.time() output = open(inputFile, 'w') selection = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(selection) iterate = OpenMaya.MItSelectionList(selection) while not iterate.isDone(): node = OpenMaya.MDagPath() component = OpenMaya.MObject() iterate.getDagPath(node, component) if not node.hasFn(OpenMaya.MFn.kTransform): print OpenMaya.MFnDagNode(node).name( ) + ' is not a Transform node (need to select transform node of polyMesh)' else: objectName = OpenMaya.MFnDagNode(node).name() newTransform = OpenMaya.MFnTransform(node) for childIndex in range(newTransform.childCount()): childObject = newTransform.child(childIndex) if childObject.hasFn(OpenMaya.MFn.kMesh) or childObject.hasFn( OpenMaya.MFn.kNurbsSurface) or childObject.hasFn( OpenMaya.MFn.kCurve): skinCluster = bFindSkinCluster( OpenMaya.MFnDagNode(childObject).partialPathName()) if skinCluster is not False: bSkinPath = OpenMaya.MDagPath() fnSkinCluster = OpenMayaAnim.MFnSkinCluster( skinCluster) fnSkinCluster.getPathAtIndex(0, bSkinPath) influenceArray = OpenMaya.MDagPathArray() fnSkinCluster.influenceObjects(influenceArray) influentsCount = influenceArray.length() output.write(objectName + '\n') for k in range(influentsCount): jointTokens = str( influenceArray[k].fullPathName()).split('|') jointTokens = jointTokens[len(jointTokens) - 1].split(':') output.write(jointTokens[len(jointTokens) - 1] + '\n') output.write('============\n') fnVtxComp = OpenMaya.MFnSingleIndexedComponent() vtxComponents = OpenMaya.MObject() vtxComponents = fnVtxComp.create( OpenMaya.MFn.kMeshVertComponent) vertexCount = OpenMaya.MFnMesh(bSkinPath).numVertices() for i in range(vertexCount): fnVtxComp.addElement(i) WeightArray = OpenMaya.MFloatArray() scriptUtil = OpenMaya.MScriptUtil() infCountPtr = scriptUtil.asUintPtr() fnSkinCluster.getWeights(bSkinPath, vtxComponents, WeightArray, infCountPtr) infCount = OpenMaya.MScriptUtil.getUint(infCountPtr) for i in range(vertexCount): #saveString = ' '.join(map(str,WeightArray[i*infCount : (i+1)*infCount])) saveString = ' '.join([ '0' if x == 0 else str(x) for n, x in enumerate(WeightArray[i * infCount:(i + 1) * infCount]) ]) output.write(saveString + '\n') output.write('\n') iterate.next() output.close() print 'done saving weights, it took ', (time.time() - timeBefore), ' seconds.'
import maya.OpenMaya as OpenMaya import maya.OpenMayaAnim as OpenMayaAnim import maya.cmds as cmds import maya.mel as mel # poly mesh and skinCluster name shapeName = 'pSphere1' clusterName = 'skinCluster1' # get the MFnSkinCluster for clusterName selList = OpenMaya.MSelectionList() selList.add(clusterName) clusterNode = OpenMaya.MObject() selList.getDependNode(0, clusterNode) skinFn = OpenMayaAnim.MFnSkinCluster(clusterNode) # get the MDagPath for all influence infDags = OpenMaya.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)
def redoIt(self): if len(self.points) < 3: return if self.aWeights.length(): self.fnSkin.setWeights(self.dgPath, self.components, self.aInfluences, self.aWeights, False, self.aUndoWeights) return for i in range(len(self.points)): self.sel.add(self.points[i]) self.sel.getDagPath(0, self.dgPath, self.components) skin = mc.ls(mc.listHistory(self.dgPath.partialPathName()), type='skinCluster') if not skin: return else: self.skin = skin[0] self.sel.clear() self.sel.add(self.skin) oSkin = OpenMaya.MObject() self.sel.getDependNode(0, oSkin) self.fnSkin = OpenMayaAnim.MFnSkinCluster(oSkin) fComponents = OpenMaya.MFnSingleIndexedComponent(self.components) mc.setAttr(self.skin + '.envelope', 0.0) fnMesh = OpenMaya.MFnMesh(self.dgPath) fUV = self.sUtil.asFloat2Ptr() if self.UVSpace: dist = lambda a, b: math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2) else: dist = lambda a, b: math.sqrt((a[0] - b[0])**2 + (a[1] - b[1])**2 + (a[2] - b[2])**2) maxDistance = 0 for i in range(len(self.points)): for j in range(i + 1, len(self.points)): if self.UVSpace: for k in range(2): pntPos = mc.pointPosition( self.points[(j * k) + (i * abs(1 - k))]) vPnt = OpenMaya.MFloatVector(pntPos[0], pntPos[1], pntPos[2]) pPnt = OpenMaya.MPoint(vPnt) fnMesh.getUVAtPoint(pPnt, fUV) if k: lPntB = [self.sUtil.getFloat2ArrayItem(fUV, 0, 0)] lPntB.append( self.sUtil.getFloat2ArrayItem(fUV, 0, 1)) else: lPntA = [self.sUtil.getFloat2ArrayItem(fUV, 0, 0)] lPntA.append( self.sUtil.getFloat2ArrayItem(fUV, 0, 1)) else: lPntA = OpenMaya.MPoint() fnMesh.getPoint(fComponents.element(i), lPntA) lPntB = OpenMaya.MPoint() fnMesh.getPoint(fComponents.element(j), lPntB) d = dist(lPntA, lPntB) if d > maxDistance: maxDistance = d maxPoint = self.points[j] minPoint = self.points[i] minDist = list(lPntA) self.sel.clear() self.sel.add(minPoint) self.sel.add(maxPoint) baseComponents = OpenMaya.MObject() self.sel.getDagPath(0, self.dgPath, baseComponents) ptrInfCount = self.sUtil.asUintPtr() aBaseWeights = OpenMaya.MDoubleArray() self.fnSkin.getWeights(self.dgPath, baseComponents, aBaseWeights, ptrInfCount) iInfCount = self.sUtil.getUint(ptrInfCount) self.fnSkin.getWeights(self.dgPath, self.components, self.aWeights, ptrInfCount) self.aUndoWeights.copy(self.aWeights) dgInfluences = OpenMaya.MDagPathArray() self.fnSkin.influenceObjects(dgInfluences) for i in range(iInfCount): self.aInfluences.append(i) for i in range(0, self.aWeights.length(), iInfCount): index = fComponents.element(i / iInfCount) pPnt = OpenMaya.MPoint() fnMesh.getPoint(index, pPnt) if self.UVSpace: fnMesh.getUVAtPoint(pPnt, fUV) lPnt = [self.sUtil.getFloat2ArrayItem(fUV, 0, 0)] lPnt.append(self.sUtil.getFloat2ArrayItem(fUV, 0, 1)) dMin = dist(minDist, lPnt) / maxDistance else: dMin = dist(minDist, pPnt) / maxDistance if self.quadraticBlend: blend = lambda x, y: (x * (1.0 - dMin)**2) / ( maxDistance**2) + (y * (dMin)**2) / (maxDistance**2) else: blend = lambda x, y: (x * (1.0 - dMin)) + (y * dMin) for j in range(iInfCount): self.aWeights.set( blend(aBaseWeights[j], aBaseWeights[iInfCount + j]), i + j) sumTotal = sum(self.aWeights[i:i + iInfCount]) self.aWeights[i:i + iInfCount] = [ x / sumTotal for x in self.aWeights[i:i + iInfCount] ] mc.setAttr(self.skin + '.envelope', 1.0) self.fnSkin.setWeights(self.dgPath, self.components, self.aInfluences, self.aWeights, False, self.aUndoWeights)
def saveWeights(mesh): filePath = cmds.file(q=1, l=1)[0].rsplit('/', 1)[0] fileName = filePath + '/%s_faceWeights.json' % mesh.name() skin = getSkin(mesh) if not skin: return 'no skin cluster found on %s' % node.name() # get the MFnskin for skin selList = OpenMaya.MSelectionList() selList.add(skin) skinNode = OpenMaya.MObject() selList.getDependNode(0, skinNode) skinFn = OpenMayaAnim.MFnSkinCluster(skinNode) # get the MDagPath for all influence infDags = OpenMaya.MDagPathArray() skinFn.influenceObjects(infDags) joints = [ str(infDags[i].fullPathName().split('|')[-1]) for i in range(infDags.length()) ] print joints # get the MPlug for the weightList and weights attributes wlPlug = skinFn.findPlug('weightList') wPlug = skinFn.findPlug('weights') wlAttr = wlPlug.attribute() wAttr = wPlug.attribute() wInfIds = OpenMaya.MIntArray() 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 = OpenMaya.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[str(infDags[infId].fullPathName().split('|') [-1])] = infPlug.asDouble() except KeyError: # assumes a removed influence pass weights[vId] = vWeights weights['joints'] = joints with open(fileName, "w") as jsonFile: json.dump(weights, jsonFile, indent=2) return '%s saved succesfully' % fileName
def doIt(self, args): # get the skinCluster for the component # selected skinned geo selection = om.MSelectionList() om.MGlobal.getActiveSelectionList(selection) # get dag path for selection component = om.MObject() try: selection.getDagPath(0, self.dagPath, component) self.dagPath.extendToShape() except: return # get skincluster from shape itSkin = om.MItDependencyGraph(self.dagPath.node(), om.MFn.kSkinClusterFilter, om.MItDependencyGraph.kUpstream, om.MItDependencyGraph.kBreadthFirst, om.MItDependencyGraph.kPlugLevel) skcMObj = None while not itSkin.isDone(): # current MObject in the iteration skcMObj = itSkin.currentItem() # here's our skinCluster node self.fnSkin = oma.MFnSkinCluster(skcMObj) # cast current MObj to MFnDependencyNode to get attribute value mFnDependSkinCluster = om.MFnDependencyNode(skcMObj) # get if maintain max influences is checked maintainMaxInfMPlug = mFnDependSkinCluster.findPlug( 'maintainMaxInfluences') self.maintainMaxInfluences = maintainMaxInfMPlug.asBool() # get number of max influences to maintain maxInfMPlug = mFnDependSkinCluster.findPlug('maxInfluences') self.maxInfluences = maxInfMPlug.asInt() # done, break out break # check for skinCluster if not self.fnSkin: om.MGlobal.displayError( 'Cannot find skinCluster node connected to component.') return # check if max influenc if self.maintainMaxInfluences == True and self.maxInfluences < 1: om.MGlobal.displayWarning( 'Maintain max influences is ON and Max influences is set to 0. No weight will be set.' ) return # # find tweak node # itMesh = om.MItDependencyGraph(skcMObj, # om.MFn.kMesh, # om.MItDependencyGraph.kUpstream, # om.MItDependencyGraph.kBreadthFirst, # om.MItDependencyGraph.kPlugLevel) # # iterate thru tweak connections looking for mesh # while not itMesh.isDone(): # meshMObj = itMesh.currentItem() # # check if current item is an intermediate object # if om.MFnDagNode(meshMObj).isIntermediateObject() == True: # self.fnOrigMesh = om.MFnMesh(meshMObj) # break # itMesh.next() # # check for origMesh # if not self.fnOrigMesh: # om.MGlobal.displayError('Cannot find orig mesh of the deformation chain.') # return # parse flags argData = om.MArgDatabase(self.syntax(), args) # -index if argData.isFlagSet(kIndexFlag): self.index = argData.flagArgumentInt(kIndexFlag, 0) # -value if argData.isFlagSet(kValueFlag): self.pressure = argData.flagArgumentDouble(kValueFlag, 0) # do the actual work self.redoIt()
def bLoadVertexSkinValues(inputFile): line = '' joints = [] weights = [] splittedStrings = [] splittedWeights = [] weightDoubles = OpenMaya.MDoubleArray() selectionList = OpenMaya.MSelectionList() vertexCount = 0 OpenMaya.MGlobal.getActiveSelectionList(selectionList) node = OpenMaya.MDagPath() component = OpenMaya.MObject() selectionList.getDagPath( 0, node, component) if not node.hasFn(OpenMaya.MFn.kTransform): print 'select a skinned object' NewTransform = OpenMaya.MFnTransform(node) if not NewTransform.childCount() or not NewTransform.child(0).hasFn(OpenMaya.MFn.kMesh): print 'select a skinned object..' mesh = NewTransform.child(0) objectName = OpenMaya.MFnDagNode(mesh).name() skinCluster = bFindSkinCluster(objectName) if not skinCluster.hasFn(OpenMaya.MFn.kSkinClusterFilter): print 'select a skinned object' fnSkinCluster = OpenMayaAnim.MFnSkinCluster(skinCluster) input = open(inputFile, 'r') joints = [] weightLines = [] filePosition = 0 while True: line = input.readline().strip() if not line: break if filePosition == 0: vertexCount = int(line) filePosition = 1 elif filePosition == 1: if not line.startswith("========"): joints.append(line) else: filePosition = 2 elif filePosition == 2: weightLines.append(line) if OpenMaya.MItGeometry(node).count() != vertexCount: print "vertex counts don't match, result might be bad" # joints.. influenceArray = OpenMaya.MDagPathArray() influenceStringArray = [] influenceMapArray = OpenMaya.MIntArray() jointsMapArray = OpenMaya.MIntArray() infCount = fnSkinCluster.influenceObjects(influenceArray) for i in range(infCount): influenceStringArray.append(OpenMaya.MFnDagNode(influenceArray[i]).name()) influenceMapArray.append(-1) for k in range(len(joints)): if influenceStringArray[i] == joints[k]: influenceMapArray[i] = k for i in range(len(joints)): jointsMapArray.append(-1) allInfluencesInScene = True influenceInScene = False for i in range(len(joints)): influenceInScene = False for k in range(len(influenceStringArray)): if influenceStringArray[k] == joints[i]: influenceInScene = True jointsMapArray[i] = k if not influenceInScene: allInfluencesInScene = False print joints[i], ' is missing in the skinCluster' if not allInfluencesInScene: print 'There are influences missing' return extraInfluencesCount = 0 for i in range(len(influenceStringArray)): jointInInfluences = False for k in range(len(joints)): if joints[k] == influenceStringArray[i]: jointInInfluences = True if not jointInInfluences: jointsMapArray.append(i) extraInfluencesCount += 1 # load points fnVtxComp = OpenMaya.MFnSingleIndexedComponent() vtxComponents = OpenMaya.MObject() vtxComponents = fnVtxComp.create(OpenMaya.MFn.kMeshVertComponent ) for i in range(len(weightLines)): splittedStrings = weightLines[i].split(':') if len(splittedStrings) > 1: fnVtxComp.addElement(int(splittedStrings[0])) splittedWeights = splittedStrings[1].split(' ') for k in range(len(splittedWeights)): weightDoubles.append(float(splittedWeights[k])) weightDoubles += [0] * extraInfluencesCount # SET WEIGHTS fnSkinCluster.setWeights(bSkinPath, vtxComponents, jointsMapArray, weightDoubles, 0) # select the vertices pointSelectionList = OpenMaya.MSelectionList() pointSelectionList.add(OpenMaya.MDagPath(node), vtxComponents) OpenMaya.MGlobal.setActiveSelectionList(pointSelectionList)
def _fix(self, skinCluster): """ :param str skinCluster: """ obj = api.toMObject(skinCluster) skinFn = OpenMayaAnim.MFnSkinCluster(obj) # normalize normalize = "{0}.normalizeWeights".format(skinCluster) normalize = cmds.getAttr(normalize) # max influence data maxInfluences = "{0}.maxInfluences".format(skinCluster) maxInfluences = cmds.getAttr(maxInfluences) # get influences infIds, infPaths = skin.getInfluencesApi(skinFn) infIdsLocked = { i: cmds.getAttr("{0}.liw".format(infPaths[i])) for _, i in infIds.iteritems() } # get weights weights = skin.getWeightsApi(skinFn, infIds) for vId, vWeights in weights.iteritems(): # variable nWeights = vWeights.copy() # sort weights ordered = sorted(vWeights.items(), key=lambda x: -x[1]) keepIndices = [ index for i, (index, weight) in enumerate(ordered) if i <= maxInfluences - 1 ] removeIndices = [ index for i, (index, weight) in enumerate(ordered) if i > maxInfluences - 1 ] # remove weights for i in removeIndices: nWeights[i] = 0 # normalize weights if normalize == 1: # get normalizable weights normalizeIndices = [ i for i in keepIndices if not infIdsLocked.get(i) ] # if no weights can be normalized, normalize all if not normalizeIndices: normalizeIndices = keepIndices # get normalizing multiplier total = sum([vWeights.get(i) for i in normalizeIndices]) multiplier = 1 / total # normalize indices for i in normalizeIndices: nWeights[i] = vWeights.get(i) * multiplier # set weights for infId, infValue in nWeights.items(): infAttr = "{0}.weightList[{1}].weights[{2}]".format( skinCluster, vId, infId) cmds.setAttr(infAttr, infValue)
def bSaveVertexSkinValues(inputFile): print 'saving Vertex skinWeights.. ' selection = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(selection) iterate = OpenMaya.MItSelectionList(selection) while not iterate.isDone(): dagPath = OpenMaya.MDagPath() component = OpenMaya.MObject() iterate.getDagPath(dagPath, component) skinCluster = bFindSkinCluster(OpenMaya.MFnDagNode(dagPath).partialPathName()) fnSkinCluster = OpenMayaAnim.MFnSkinCluster(skinCluster) iterate.next() if skinCluster.hasFn(OpenMaya.MFn.kSkinClusterFilter): output = open(inputFile, 'w') output.write(str(OpenMaya.MItGeometry(bSkinPath).count()) + '\n') fnVtxComp = OpenMaya.MFnSingleIndexedComponent() vtxComponents = OpenMaya.MObject() vtxComponents = fnVtxComp.create(OpenMaya.MFn.kMeshVertComponent) WeightArray = OpenMaya.MFloatArray() meshIter = OpenMaya.MItMeshVertex(dagPath, component) while not meshIter.isDone(): fnVtxComp.addElement(meshIter.index()) meshIter.next() vertexCount = meshIter.count() scriptUtil = OpenMaya.MScriptUtil() infCountPtr = scriptUtil.asUintPtr() fnSkinCluster.getWeights(bSkinPath, vtxComponents, WeightArray, infCountPtr) infCount = OpenMaya.MScriptUtil.getUint(infCountPtr) weightCheckArray = [] for i in range(infCount): weightCheckArray.append(False) for i in range(vertexCount): for k in range(infCount): if not weightCheckArray[k] and WeightArray[((i * infCount) + k)]: weightCheckArray[k] = True #joints.. InfluentsArray = OpenMaya.MDagPathArray() fnSkinCluster.influenceObjects(InfluentsArray) for i in range(infCount): if weightCheckArray[i]: output.write(OpenMaya.MFnDagNode(InfluentsArray[i]).name() + '\n') output.write('============\n') counter = 0 weightArrayString = [] meshIter = OpenMaya.MItMeshVertex(dagPath, component) while not meshIter.isDone(): weightArrayString = str(meshIter.index()) + ':' for k in range(infCount): if weightCheckArray[k] == True: weightArrayString += str(WeightArray[(counter * infCount) + k]) + ' ' output.write(weightArrayString + '\n') counter += 1 meshIter.next() output.close() iterate.next()
def vtxLoad_Oapi(self): selList = Om.MSelectionList() Om.MGlobal.getActiveSelectionList(selList) if selList.isEmpty(): Om.MGlobal.displayError('Select Nothing') return elif selList.length() != 1: Om.MGlobal.displayError("Nothing selected") MDagPath = Om.MDagPath() # 存储所选物体的路径 MObject = Om.MObject() # 存储所选物体的组件的列表 selList.getDagPath(0, MDagPath) selList.getDependNode(0, MObject) # MDagPath.fullPathName() #获取 MDagPath 内容 _selType = MDagPath.apiType() if _selType != 110: Om.MGlobal.displayError('Please Select Object') return skCluster = mel.eval('findRelatedSkinCluster("%s")' % MDagPath.partialPathName()) if not skCluster: return Om.MGlobal.getSelectionListByName(skCluster, selList) skinObj = Om.MObject() selList.getDependNode(1, skinObj) skinNode = OmAni.MFnSkinCluster(skinObj) infs = Om.MDagPathArray() numInfs = skinNode.influenceObjects(infs) infNameList = [] # 骨骼列表 for i in range(numInfs): infName = infs[i].partialPathName() infNameList.append(infName) # fn = Om.MFnDependencyNode(MDagPath.node()) #获取MDagPath的内容? # print fn.name() #获取 MFnDependencyNode 内容 filePath = cmds.fileDialog2(ff='WeightFile (*.vtxWeight *.sdd)', ds=2, fm=1) if not filePath: return allLine = self.readWeightData_Load(filePath[0]) if allLine == 'toMel': Om.MGlobal.displayWarning('Some Error. Please ReSelect') self.vtxLoad_Mel() return jntLock = [] for j in infNameList: jntLock.append(cmds.getAttr(j + '.liw')) cmds.setAttr(j + '.liw', 0) vertIter = Om.MItGeometry(MObject) _Num = 0 while not vertIter.isDone(): if vertIter.index() != int(allLine[_Num][0]): vertIter.next() continue jntindex = Om.MIntArray() weights = Om.MDoubleArray() jntindexapp = jntindex.append weightsapp = weights.append for i in range(len(allLine[_Num][1])): jntindexapp(infNameList.index(allLine[_Num][1][i])) weightsapp(allLine[_Num][2][i]) skinNode.setWeights(MDagPath, vertIter.currentItem(), jntindex, weights, False) # False规格化开关默认为True _Num += 1 vertIter.next() for j, l in zip(infNameList, jntLock): cmds.setAttr(j + '.liw', l) DisplayYes().showMessage('Process Finish!')
def bSaveSkinValues(inputFile): output = open(inputFile, 'w') selection = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(selection) iterate = OpenMaya.MItSelectionList(selection) while not iterate.isDone(): node = OpenMaya.MDagPath() component = OpenMaya.MObject() iterate.getDagPath (node, component) if not node.hasFn(OpenMaya.MFn.kTransform): print OpenMaya.MFnDagNode(node).name() + ' is not a Transform node (need to select transform node of polyMesh)' else: objectName = OpenMaya.MFnDagNode(node).name() newTransform = OpenMaya.MFnTransform(node) for childIndex in range(newTransform.childCount()): childObject = newTransform.child(childIndex) if childObject.hasFn(OpenMaya.MFn.kMesh) or childObject.hasFn(OpenMaya.MFn.kNurbsSurface) or childObject.hasFn(OpenMaya.MFn.kCurve): skinCluster = bFindSkinCluster(OpenMaya.MFnDagNode(childObject).partialPathName()) if skinCluster is not False: bSkinPath = OpenMaya.MDagPath() fnSkinCluster = OpenMayaAnim.MFnSkinCluster(skinCluster) fnSkinCluster.getPathAtIndex(0,bSkinPath) influenceArray = OpenMaya.MDagPathArray() fnSkinCluster.influenceObjects(influenceArray) influentsCount = influenceArray.length() #output.write(bSkinPath.partialPathName() + '\n') output.write(objectName + '\n') for k in range(influentsCount): jointTokens = str(influenceArray[k].fullPathName()).split('|') jointTokens = jointTokens[len(jointTokens)-1].split(':') output.write(jointTokens[len(jointTokens)-1] + '\n') output.write('============\n') vertexIter = OpenMaya.MItGeometry(bSkinPath) saveString = '' counterValue = 0 while not vertexIter.isDone(): counterValue = counterValue + 1 vertex = vertexIter.component() scriptUtil = OpenMaya.MScriptUtil() infCountPtr = scriptUtil.asUintPtr() vtxComponents = OpenMaya.MObject() weightArray = OpenMaya.MDoubleArray() fnSkinCluster.getWeights(bSkinPath, vertex, weightArray, infCountPtr) saveString = '' for j in range(OpenMaya.MScriptUtil.getUint(infCountPtr)): saveString += str(weightArray[j]) saveString += ' ' output.write(saveString + '\n') vertexIter.next() output.write('\n') iterate.next() output.close() print "done saving weights"
def writeWeights(self, fileName, exclusive): # get the current selection skinClusterNode = cmds.ls(selection=True, flatten=True) if len(skinClusterNode) != 0: skinClusterNode = skinClusterNode[0] else: OpenMaya.MGlobal.displayError( "Select a skinCluster node to export.") return -1 # check if it's a skinCluster if cmds.nodeType(skinClusterNode) != "skinCluster": OpenMaya.MGlobal.displayError( "Selected node is not a skinCluster.") return -1 # get the MFnSkinCluster sel = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(sel) skinClusterObject = OpenMaya.MObject() sel.getDependNode(0, skinClusterObject) skinClusterFn = OpenMayaAnim.MFnSkinCluster(skinClusterObject) # get the influence objects infls = cmds.skinCluster(skinClusterNode, query=True, influence=True) if len(infls) == 0: OpenMaya.MGlobal.displayError( "No influence objects found for skinCluster {}.".format( skinClusterNode)) return -1 # get the connected shape node shape = cmds.skinCluster(skinClusterNode, query=True, geometry=True)[0] if len(shape) == 0: OpenMaya.MGlobal.displayError("No connected shape nodes found.") return -1 # get the dag path of the shape node cmds.select(shape, replace=True) sel = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(sel) shapeDag = OpenMaya.MDagPath() sel.getDagPath(0, shapeDag) # create the geometry iterator geoIter = OpenMaya.MItGeometry(shapeDag) # create a pointer object for the influence count of the MFnSkinCluster infCount = OpenMaya.MScriptUtil() infCountPtr = infCount.asUintPtr() OpenMaya.MScriptUtil.setUint(infCountPtr, 0) value = OpenMaya.MDoubleArray() # # default export to a single skin weights file # if not exclusive: try: with open(fileName, "w") as fileObj: lines = [] nodes = [] # write all influences and the shape node to the file for i in range(0, len(infls), 1): nodes.append(infls[i]) nodes.append(shape) lines.append(" ".join(nodes)) lines.append(skinClusterNode) # write the attributes of the skinCluster node to the file normalize = cmds.getAttr(skinClusterNode + ".normalizeWeights") maxInfluences = cmds.getAttr(skinClusterNode + ".maxInfluences") dropoff = cmds.getAttr(skinClusterNode + ".dropoff")[0][0] lines.append("-nw {} -mi {} -dr {}".format( normalize, maxInfluences, dropoff)) # get the skinCluster weights while not geoIter.isDone(): skinClusterFn.getWeights(shapeDag, geoIter.currentItem(), value, infCountPtr) for j in range(0, len(infls)): if value[j] > 0: lineArray = [ geoIter.index(), infls[j], j, value[j] ] lines.append(str(lineArray)) geoIter.next() lines.append("") fileObj.write("\n".join(lines)) except: OpenMaya.MGlobal.displayError( "A file error has occurred for file: {}".format(fileName)) return -1 # # custom export to individual files # else: cmds.skinCluster(skinClusterNode, edit=True, forceNormalizeWeights=True) dataPath = "{}/{}".format(fileName, skinClusterNode) if not os.path.exists(dataPath): try: os.makedirs(dataPath) except: OpenMaya.MGlobal.displayError( "Unable to create export directory: {}".format( dataPath)) return -1 for j in range(0, len(infls)): fileName = "{}/{}.bsw".format(dataPath, infls[j]) try: with open(fileName, "w") as fileObj: lines = [] while not geoIter.isDone(): skinClusterFn.getWeights(shapeDag, geoIter.currentItem(), value, infCountPtr) line = "{} {}".format(str(geoIter.index()), str(value[j])) lines.append(line) geoIter.next() lines.append("") fileObj.write("\n".join(lines)) except: OpenMaya.MGlobal.displayError( "A file error has occurred for file: {}".format( fileName)) return -1 geoIter.reset() return 1
def bSkinObject(objectName, joints, weights): if not cmds.objExists(objectName): print objectName, " doesn't exist - skipping. " return allInfluencesInScene = True jointsCheck = [] for i in range(len(joints)): jointsCheck = joints[i] sceneJointTokens = [] fileJointTokens = [] it = OpenMaya.MItDependencyNodes ( OpenMaya.MFn.kJoint) # quick check: for jointIndex in range(len(joints)): jointHere = False it = OpenMaya.MItDependencyNodes ( OpenMaya.MFn.kJoint) while not it.isDone(): sceneJointTokens = str(OpenMaya.MFnDagNode(it.item()).fullPathName()).split('|') if str(joints[jointIndex]) == str(sceneJointTokens[len(sceneJointTokens) - 1]): jointHere = True it.next() if not jointHere: allInfluencesInScene = False print 'missing influence: ', joints[jointIndex] if not allInfluencesInScene: print objectName, " can't be skinned because of missing influences." return #maya.mel.eval("undoInfo -st 0") if type(bFindSkinCluster(objectName)) != type(True): maya.mel.eval("DetachSkin " + objectName) cmd = "select " for i in range(len(joints)): cmd += " " + joints[i] cmd += " " + objectName maya.mel.eval(cmd) maya.mel.eval("skinCluster -tsb -mi 10") maya.mel.eval("select `listRelatives -p " + objectName + "`") maya.mel.eval("refresh") #maya.mel.eval("undoInfo -st 1") skinCluster = bFindSkinCluster(objectName) fnSkinCluster = OpenMayaAnim.MFnSkinCluster(skinCluster) InfluentsArray = OpenMaya.MDagPathArray() fnSkinCluster.influenceObjects(InfluentsArray) bSkinPath = OpenMaya.MDagPath() fnSkinCluster.getPathAtIndex(fnSkinCluster.indexForOutputConnection(0),bSkinPath) weightStrings = [] vertexIter = OpenMaya.MItGeometry (bSkinPath) weightDoubles = OpenMaya.MDoubleArray() singleIndexed = True vtxComponents = OpenMaya.MObject() fnVtxComp = OpenMaya.MFnSingleIndexedComponent() fnVtxCompDouble = OpenMaya.MFnDoubleIndexedComponent() if bSkinPath.node().apiType() == OpenMaya.MFn.kMesh: vtxComponents = fnVtxComp.create( OpenMaya.MFn.kMeshVertComponent ) elif bSkinPath.node().apiType() == OpenMaya.MFn.kNurbsSurface: singleIndexed = False vtxComponents = fnVtxCompDouble.create( OpenMaya.MFn.kSurfaceCVComponent ) elif bSkinPath.node().apiType() == OpenMaya.MFn.kNurbsCurve: vtxComponents = fnVtxComp.create( OpenMaya.MFn.kCurveCVComponent ) #mapping joint-indices influenceIndices = OpenMaya.MIntArray() checkInfluences = [] for k in range(InfluentsArray.length()): checkInfluences.append(0) for i in range(len(joints)): influenceIndices.append(-1) for i in range(len(joints)): fileJointTokens = joints[i].split('|') for k in range(InfluentsArray.length()): sceneJointTokens = str(OpenMaya.MFnDagNode(InfluentsArray[k]).fullPathName()).split('|') if fileJointTokens[len(fileJointTokens) - 1] == sceneJointTokens[len(sceneJointTokens) - 1]: # changed from joints influenceIndices[i] = k checkInfluences[k] = 1 counterValue = 0 if not singleIndexed: currentU = 0 currentV = 0 cvsU = OpenMaya.MFnNurbsSurface(bSkinPath.node()).numCVsInU() cvsV = OpenMaya.MFnNurbsSurface(bSkinPath.node()).numCVsInV() formU = OpenMaya.MFnNurbsSurface(bSkinPath.node()).formInU() formV = OpenMaya.MFnNurbsSurface(bSkinPath.node()).formInV() if formU == 3: cvsU -= 3 if formV == 3: cvsV -= 3 vertexIter = OpenMaya.MItGeometry(bSkinPath) while not vertexIter.isDone(): weightStrings = [] if singleIndexed: fnVtxComp.addElement(counterValue) else: fnVtxCompDouble.addElement(currentU, currentV) currentV += 1 if currentV >= cvsV: currentV = 0 currentU += 1 weightStrings = weights[counterValue].split(' ') for i in range(len(weightStrings)): weightDoubles.append(float(weightStrings[i])) counterValue += 1 vertexIter.next() #SET WEIGHTS print "setting weights for ", objectName fnSkinCluster.setWeights(bSkinPath, vtxComponents, influenceIndices,weightDoubles, 0) #Maya.mel.eval("skinPercent -normalize true " + fnSkinCluster.name() + " " + objectName) influenceIndices.clear() weightDoubles.clear()
def asMFnSkinCluster(self): assert (self.asMObject().hasFn(OpenMaya.MFn.kSkinClusterFilter)), "Object has no functions 'kSkinCluster'" scFn = OpenMayaAnim.MFnSkinCluster() scFn.setObject(self.asMObject()) return scFn
def readFile(filepath): files = path_wrangler(filepath) files.get_files() md = open(files.data['uexp'], 'rb') ua = open(files.data['uasset'], 'rb') meshName = files.data['meshName'] submesh_name = files.data['submesh_name'] arm = False weightData = {} Weight_array = [] vertexArray = [] NA = [] normal_array = [] faces = [] U0 = om2.MFloatArray() V0 = om2.MFloatArray() U1 = om2.MFloatArray() V1 = om2.MFloatArray() U2 = om2.MFloatArray() V2 = om2.MFloatArray() U3 = om2.MFloatArray() V3 = om2.MFloatArray() U4 = om2.MFloatArray() V4 = om2.MFloatArray() U5 = om2.MFloatArray() V5 = om2.MFloatArray() t1 = time.time() names = readUasset(ua) pattern0 = re.compile(b'\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00........') for x in xrange(20000): s1 = struct.unpack("18s", md.read(18))[0] if pattern0.match(s1): c0 = struct.unpack("<L", md.read(4))[0] c1 = struct.unpack("<L", md.read(4))[0] c2 = struct.unpack("<L", md.read(4))[0] c3 = struct.unpack("<L", md.read(4))[0] c4 = struct.unpack("<L", md.read(4))[0] if (c0 and c1 and c2 and c3 and c4 > 1000000000): break else: md.seek(-20, 1) md.seek(-17, 1) materialCount = struct.unpack("<L", md.read(4))[0] materials = {} for m in xrange(materialCount): materials[m] = {} materials[m]['val0'] = struct.unpack("<l", md.read(4))[0] stringIndex = struct.unpack("<L", md.read(4))[0] unk0 = struct.unpack("<L", md.read(4))[0] unk1 = struct.unpack("<L", md.read(4))[0] unk2 = struct.unpack("<L", md.read(4))[0] unk3 = struct.unpack("<f", md.read(4))[0] unk4 = struct.unpack("<f", md.read(4))[0] unk5 = struct.unpack("<L", md.read(4))[0] unk6 = struct.unpack("<L", md.read(4))[0] materials[m]['name'] = names[stringIndex] boneCount = struct.unpack("<L", md.read(4))[0] joint_data = {} bt = np.empty([1, boneCount], dtype='U32') for i in xrange(boneCount): string_index = struct.unpack("<L", md.read(4))[0] jName = names[string_index] unk = struct.unpack("<L", md.read(4))[0] parent = struct.unpack("<l", md.read(4))[0] joint_data[i] = {"name": jName, "parent": parent} bt[0, i] = jName boneCount2 = struct.unpack("<L", md.read(4))[0] bone_list = [] boneArray = [] for k in xrange(boneCount2): m1 = struct.unpack("<10f", md.read(40)) boneName = joint_data[k]["name"] BNparent = joint_data[k]["parent"] boneArray.append(boneName) BNps = om.MVector(-m1[5], -m1[6], m1[4]) BNrt = om.MQuaternion(m1[1], m1[2], -m1[0], -m1[3]) BNsc = om.MVector(-m1[8], -m1[9], -m1[7]) if BNparent == -1: cmds.select(clear=True) else: pm.select(bone_list[BNparent]) newBone = pm.joint(p=(0, 0, 0), name=boneName, radius=0.1) newBone.setTranslation(BNps) newBone.setOrientation(BNrt) newBone.setScale(BNsc) bone_list.append(newBone) arm = True boneCount3 = struct.unpack("<L", md.read(4))[0] md.seek(boneCount3 * 12, 1) vertexGroups = {} unk0 = struct.unpack("<L", md.read(4))[0] unk1 = struct.unpack("B", md.read(1))[0] unk2 = struct.unpack("B", md.read(1))[0] groupCount = struct.unpack("<L", md.read(4))[0] for m in xrange(groupCount): z1 = struct.unpack("<H", md.read(2))[0] ID = struct.unpack("<H", md.read(2))[0] md.seek(24, 1) vertexGroups[ID] = {'range': 0, 'bones': []} # pragma region bone palette start = struct.unpack("<L", md.read(4))[0] count = struct.unpack("<L", md.read(4))[0] bt = np.empty([1, count], dtype='U32') for bn in xrange(count): bid = struct.unpack("<H", md.read(2))[0] vertexGroups[ID]['bones'].append(bid) bt[0, bn] = joint_data[bid]["name"] # pragma endregion bone palette size = struct.unpack("<L", md.read(4))[0] stop = start + size vertexGroups[ID]['range'] = range(start, stop) vertexGroups[ID]["start"] = start vertexGroups[ID]["stop"] = stop vertexGroups[ID]["size"] = size vertexGroups[ID]["names"] = bt md.seek(34, 1) FFx4 = readHexString(md, 4) flag = struct.unpack("<L", md.read(4))[0] if flag: # extra data for this group count = struct.unpack("<L", md.read(4))[0] md.seek(count * 16, 1) else: null = struct.unpack("<L", md.read(4))[0] unk = struct.unpack("B", md.read(1))[0] checkHere = md.tell() stride = struct.unpack("<L", md.read(4))[0] fCount = struct.unpack("<L", md.read(4))[0] faceByteCount = fCount * stride fi = np.fromfile(md, dtype='B', count=faceByteCount) if stride == 4: fi_0 = fi.view(dtype='<L').reshape(fCount // 3, 3) elif stride == 2: fi_0 = fi.view(dtype='<H').reshape(fCount // 3, 3) fi_1 = fi_0.ravel() faces = tuple(fi_1) pCounts = [3] * (len(faces) // 3) gh = pCounts[0] unkCount = struct.unpack("<L", md.read(4))[0] md.seek(unkCount * 2, 1) unk = struct.unpack("<L", md.read(4))[0] vertexCount = struct.unpack("<L", md.read(4))[0] boneCount = struct.unpack("<L", md.read(4))[0] md.seek(boneCount * 2, 1) null0 = struct.unpack("<L", md.read(4))[0] null1 = struct.unpack("<L", md.read(4))[0] uv_count = struct.unpack("<L", md.read(4))[0] unk0 = struct.unpack("<H", md.read(2))[0] uv_count2 = struct.unpack("<L", md.read(4))[0] null2 = struct.unpack("<L", md.read(4))[0] unk1 = struct.unpack("<f", md.read(4))[0] unk2 = struct.unpack("<f", md.read(4))[0] unk3 = struct.unpack("<f", md.read(4))[0] null3 = struct.unpack("<L", md.read(4))[0] null4 = struct.unpack("<L", md.read(4))[0] null5 = struct.unpack("<L", md.read(4))[0] vStride = struct.unpack("<L", md.read(4))[0] vCount = struct.unpack("<L", md.read(4))[0] byteCount = vCount * vStride vi = np.fromfile(md, dtype='B', count=byteCount).reshape((vCount, vStride)) pos = vi[:, 8:20].ravel().view(dtype='<f').reshape((vCount, 3)) pos[:, [0, 2]] = pos[:, [2, 0]] pos[:, [0, 1]] = pos[:, [1, 0]] pos[:, [2]] *= -1 positions = pos.tolist() VA = om2.MFloatPointArray(positions) if uv_count > 0: uvData_ = vi[:, 20:24].ravel().view(dtype='<f2').reshape((vCount, 2)) uvData_[:, 1:2] *= -1 uvData_[:, 1:2] += 1 uvData = tuple(map(tuple, uvData_)) u = zip(*uvData)[0] v = zip(*uvData)[1] U0.copy(u) V0.copy(v) if uv_count > 1: uvData_ = vi[:, 24:28].ravel().view(dtype='<f2').reshape((vCount, 2)) uvData_[:, 1:2] *= -1 uvData_[:, 1:2] += 1 uvData = tuple(map(tuple, uvData_)) u = zip(*uvData)[0] v = zip(*uvData)[1] U1.copy(u) V1.copy(v) if uv_count > 2: uvData_ = vi[:, 28:32].ravel().view(dtype='<f2').reshape((vCount, 2)) uvData_[:, 1:2] *= -1 uvData_[:, 1:2] += 1 uvData = tuple(map(tuple, uvData_)) u = zip(*uvData)[0] v = zip(*uvData)[1] U2.copy(u) V2.copy(v) if uv_count > 3: uvData_ = vi[:, 32:36].ravel().view(dtype='<f2').reshape((vCount, 2)) uvData_[:, 1:2] *= -1 uvData_[:, 1:2] += 1 uvData = tuple(map(tuple, uvData_)) u = zip(*uvData)[0] v = zip(*uvData)[1] U3.copy(u) V3.copy(v) if uv_count > 4: uvData_ = vi[:, 36:40].ravel().view(dtype='<f2').reshape((vCount, 2)) uvData_[:, 1:2] *= -1 uvData_[:, 1:2] += 1 uvData = tuple(map(tuple, uvData_)) u = zip(*uvData)[0] v = zip(*uvData)[1] U4.copy(u) V4.copy(v) mesh = om2.MFnMesh() ShapeMesh = cmds.group(em=True) parentOwner = get_mobject(ShapeMesh) meshMObj = mesh.create(VA, pCounts, faces, uValues=U0, vValues=V0, parent=parentOwner) cmds.sets(ShapeMesh, e=True, forceElement='initialShadingGroup') cmds.polyUVSet(rename=True, newUVSet='map_0', uvSet=mesh.currentUVSetName(-1)) mesh.setUVs(U0, V0, 'map_0') mesh.assignUVs(pCounts, faces, 'map_0') cmds.rename(meshName) s1 = cmds.ls(sl=1) s2 = s1[0] shapeName = s2.encode('ascii', 'ignore') if uv_count > 1: mesh.createUVSet('map_1') mesh.setUVs(U1, V1, 'map_1') mesh.assignUVs(pCounts, faces, 'map_1') if uv_count > 2: mesh.createUVSet('map_2') mesh.setUVs(U2, V2, 'map_2') mesh.assignUVs(pCounts, faces, 'map_2') if uv_count > 3: mesh.createUVSet('map_3') mesh.setUVs(U3, V3, 'map_3') mesh.assignUVs(pCounts, faces, 'map_3') if uv_count > 4: mesh.createUVSet('map_4') mesh.setUVs(U4, V4, 'map_4') mesh.assignUVs(pCounts, faces, 'map_4') unkS = struct.unpack("<H", md.read(2))[0] extraBoneWeights = struct.unpack("<L", md.read(4))[0] wCount = struct.unpack("<L", md.read(4))[0] stride = struct.unpack("<L", md.read(4))[0] wCount2 = struct.unpack("<L", md.read(4))[0] subStride = int(stride / 2) clusterName = shapeName + '_' + 'skinCluster' pm.skinCluster(boneArray[:], shapeName, sm=1, mi=8, omi=1, n=clusterName) skin = mm.eval('findRelatedSkinCluster "' + s2 + '"') sel = om.MSelectionList() sel.add(shapeName) meshMObject = om.MObject() sel.getDependNode(0, meshMObject) sel2 = om.MSelectionList() sel2.add(skin) skinMObject = om.MObject() sel2.getDependNode(0, skinMObject) FnSkin = oma.MFnSkinCluster(skinMObject) dag_path, skinMObject = get_skin_dag_path_and_mobject(FnSkin) weights = om.MDoubleArray() influence_paths = om.MDagPathArray() influence_count = FnSkin.influenceObjects(influence_paths) components_per_influence = weights.length() / influence_count # influences unused_influences = list() influences = [ influence_paths[inf_count].partialPathName() for inf_count in xrange(influence_paths.length()) ] wSize = vCount * influence_count weights = om.MDoubleArray(wSize, 0.0) w_byteCount = wCount * stride wi = np.fromfile(md, dtype='B', count=w_byteCount).reshape( (wCount, stride)) wi_b = wi[:, :subStride].ravel().view().reshape((wCount, subStride)) wi_w = wi[:, subStride:stride].ravel().view().reshape( (wCount, subStride)).astype(np.float64) wi_w /= 255.0 def do_stuff(n): fg = influences.index(L[n]) idx = fg + (j * influence_count) weights[idx] = W[n] for h in xrange(len(vertexGroups)): crnt_grp = vertexGroups[h] g_names = crnt_grp["names"] g_range = crnt_grp["range"] for j in g_range: Wt = np.trim_zeros(wi_w[j], 'b') W = tuple(Wt) a = Wt.shape[0] ids = wi_b[j, :a] L = tuple(g_names[0, ids]) map(do_stuff, range(len(L))) influence_array = om.MIntArray(influence_count) m_util.createIntArrayFromList(range(influence_count), influence_array) FnSkin.setWeights(dag_path, skinMObject, influence_array, weights, False) createMaterials(files, vertexGroups, materials, shapeName) pm.select(shapeName) cmds.viewFit() elapsed = time.time() - t1 return elapsed md.close() ua.close()
def SaveTFXBoneBinaryFile(filepath, selected_mesh_shape_name, meshShapedagPath, rootPositions): #--------------------------------------------------------------------------- # Build a face/triangle index list to convert face index into triangle index #--------------------------------------------------------------------------- faceIter = OpenMaya.MItMeshPolygon(meshShapedagPath) triangleCount = 0 faceTriaIndexList = [] index = 0 util = OpenMaya.MScriptUtil() util.createFromInt(0) while not faceIter.isDone(): faceTriaIndexList.append(triangleCount) if faceIter.hasValidTriangulation(): numTrianglesPtr = util.asIntPtr() faceIter.numTriangles(numTrianglesPtr) numTriangles = util.getInt(numTrianglesPtr) triangleCount += numTriangles faceIter.next() #print "TressFX: Triangle count:%d\n" % triangleCount #---------------------- # Find the closest face #---------------------- meshFn = OpenMaya.MFnMesh(meshShapedagPath) meshIntersector = OpenMaya.MMeshIntersector() meshIntersector.create(meshShapedagPath.node()) triangleCounts = OpenMaya.MIntArray() triangleVertexIndices = OpenMaya.MIntArray( ) # the size of this array is three times of the number of total triangles meshFn.getTriangles(triangleCounts, triangleVertexIndices) vertexTriangleList = [] triangleIdForStrandsList = [] baryCoordList = [] uvCoordList = [] pointOnMeshList = [] progressBar = ProgressBar('Collecting bone data', len(rootPositions)) for i in range(len(rootPositions)): rootPoint = rootPositions[i] # Find the closest point info meshPt = OpenMaya.MPointOnMesh() meshIntersector.getClosestPoint(rootPoint, meshPt) pt = meshPt.getPoint() pointOnMesh = OpenMaya.MPoint() pointOnMesh.x = pt.x pointOnMesh.y = pt.y pointOnMesh.z = pt.z pointOnMeshList.append(pointOnMesh) # Find face index faceId = meshPt.faceIndex() # Find triangle index triangleId = faceTriaIndexList[faceId] + meshPt.triangleIndex() dummy = OpenMaya.MScriptUtil() dummyIntPtr = dummy.asIntPtr() triangleId_local = meshPt.triangleIndex( ) # This values is either 0 or 1. It is not a global triangle index. triangleId is the global triangle index. pointArray = OpenMaya.MPointArray() vertIdList = OpenMaya.MIntArray() faceIter.setIndex(faceId, dummyIntPtr) faceIter.getTriangle(triangleId_local, pointArray, vertIdList, OpenMaya.MSpace.kWorld) vertexTriangleList.append( (vertIdList[0], vertIdList[1], vertIdList[2])) triangleIdForStrandsList.append(triangleId) # Find three vertex indices for the triangle. Following two lines should give us three correct vertex indices for the triangle. I haven't really verified though. #vertexIndex = [triangleVertexIndices[triangleId*3], triangleVertexIndices[triangleId*3+1], triangleVertexIndices[triangleId*3+2]] vertexIndex = [vertIdList[0], vertIdList[1], vertIdList[2]] # Find barycentric coordinates uvw = OpenMaya.MPoint() # Somehow, below code gives me negative barycentric coordinates sometimes. # uPtr = OpenMaya.MScriptUtil().asFloatPtr() # vPtr = OpenMaya.MScriptUtil().asFloatPtr() # meshPt.getBarycentricCoords(uPtr,vPtr) # uvw.x = OpenMaya.MScriptUtil(uPtr).asFloat() # uvw.y = OpenMaya.MScriptUtil(vPtr).asFloat() # uvw.z = 1.0 - uvw.x - uvw.y # Instead getting barycentric coords from getBarycentricCoords, we compute it by the following function. uvw_a = ComputeBarycentricCoordinates(pointArray[0], pointArray[1], pointArray[2], pointOnMesh) uvw.x = uvw_a[0] uvw.y = uvw_a[1] uvw.z = uvw_a[2] # barycentric coordinates should be non-zero uvw.x = max(uvw.x, 0) uvw.y = max(uvw.y, 0) uvw.z = max(uvw.z, 0) # normalize barycentric coordinates so that their sum is equal to 1 sum = uvw.x + uvw.y + uvw.z uvw.x /= sum uvw.y /= sum uvw.z /= sum baryCoordList.append(uvw) # Find UV coordinates - We don't really use UV coords for tfxbone file. # util = OpenMaya.MScriptUtil() # util.createFromList([0.0, 0.0], 2) # uv_ptr = util.asFloat2Ptr() # meshFn.getUVAtPoint(rootPoint, uv_ptr) # u = OpenMaya.MScriptUtil.getFloat2ArrayItem(uv_ptr, 0, 0) # v = OpenMaya.MScriptUtil.getFloat2ArrayItem(uv_ptr, 0, 1) # uv_coord = OpenMaya.MPoint() # uv_coord.x = u # uv_coord.y = v # uv_coord.z = 0 # uvCoordList.append(uv_coord) # update progress gui progressBar.Increment() progressBar.Kill() #------------------------- # Get skin cluster object #------------------------- skinClusterName = '' skinClusters = cmds.listHistory(selected_mesh_shape_name) skinClusters = cmds.ls(skinClusters, type="skinCluster") if skinClusters: skinClusterName = skinClusters[0] else: cmds.warning('No skin cluster found on ' + selected_mesh_shape_name) return #print skinClusterName #--------------------------------------------------------------------------------------------------- # TODO: Try the following method. # skins = filter(lambda skin: mesh.getShape() in skin.getOutputGeometry(), ls(type='skinCluster')) # if len(skins) > 0 : # skin = skins[0] # skinJoints = skin.influenceObjects(); # root = skinJoints[0] # while root.getParent() : # root = root.getParent() # skin.getWeights(mesh.verts[index]) # select(root, hierarchy=True, replace=True) # joints = ls(selection=True, transforms=True, type='joint') #--------------------------------------------------------------------------------------------------- # get the MFnSkinCluster using skinClusterName selList = OpenMaya.MSelectionList() selList.add(skinClusterName) skinClusterNode = OpenMaya.MObject() selList.getDependNode(0, skinClusterNode) skinFn = OpenMayaAnim.MFnSkinCluster(skinClusterNode) dagPaths = MDagPathArray() skinFn.influenceObjects(dagPaths) # influence object is a joint influenceObjectsNames = [] # get joint names for i in range(dagPaths.length()): influenceName = dagPaths[i].partialPathName() influenceObjectsNames.append( influenceName) # Need to remove namespace? skinMeshes = cmds.skinCluster(skinClusterName, query=1, geometry=1) geoIter = OpenMaya.MItGeometry(meshShapedagPath) infCount = OpenMaya.MScriptUtil() infCountPtr = infCount.asUintPtr() numVertices = geoIter.count() weightArray = [ 0 ] * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT * numVertices # joint weight array for all vertices. Each vertex will have TRESSFX_MAX_INFLUENTIAL_BONE_COUNT weights. # It is initialized with zero for empty weight in case there are less weights than TRESSFX_MAX_INFLUENTIAL_BONE_COUNT . jointIndexArray = [ -1 ] * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT * numVertices # joint index array for all vertices. It is initialized with -1 for an empty element in case # there are less weights than TRESSFX_MAX_INFLUENTIAL_BONE_COUNT . # collect bone weights for all vertices in the mesh index = 0 while geoIter.isDone() == False: weights = OpenMaya.MDoubleArray() skinFn.getWeights(meshShapedagPath, geoIter.currentItem(), weights, infCountPtr) weightJointIndexPairs = [] for i in range(len(weights)): pair = WeightJointIndexPair() pair.weight = weights[i] pair.joint_index = i weightJointIndexPairs.append(pair) weightJointIndexPairs.sort() a = 0 for j in range( min(len(weightJointIndexPairs), TRESSFX_MAX_INFLUENTIAL_BONE_COUNT)): weightArray[index * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT + a] = weightJointIndexPairs[j].weight jointIndexArray[index * TRESSFX_MAX_INFLUENTIAL_BONE_COUNT + a] = weightJointIndexPairs[j].joint_index a += 1 index += 1 geoIter.next() #------------------------ # Save the tfxbone file. #------------------------ progressBar = ProgressBar( 'Saving a tfxbone file', len(influenceObjectsNames) + len(triangleIdForStrandsList)) f = open(filepath, "wb") # Number of Bones f.write(ctypes.c_int(len(influenceObjectsNames))) # Write all bone (joint) names for i in range(len(influenceObjectsNames)): # Bone Joint Index f.write(ctypes.c_int(i)) # Size of the string, add 1 to leave room for the nullterminate. f.write(ctypes.c_int(len(influenceObjectsNames[i]) + 1)) # Print the characters of the string 1 by 1. for j in range(len(influenceObjectsNames[i])): f.write(ctypes.c_byte(ord(influenceObjectsNames[i][j]))) # Add a zero to null terminate the string. f.write(ctypes.c_byte(0)) progressBar.Increment() # Number of Strands f.write(ctypes.c_int(len(triangleIdForStrandsList))) for i in range(len(triangleIdForStrandsList)): triangleId = triangleIdForStrandsList[i] # three vertex indices from one triangle - Following two lines should work equally but I haven't verified it yet. #vertexIndices = [triangleVertexIndices[triangleId*3], triangleVertexIndices[triangleId*3+1], triangleVertexIndices[triangleId*3+2]] vertexIndices = vertexTriangleList[i] baryCoord = baryCoordList[i] weightJointIndexPairs = GetSortedWeightsFromTriangleVertices( TRESSFX_MAX_INFLUENTIAL_BONE_COUNT, vertexIndices, jointIndexArray, weightArray, baryCoord) # Index, the rest should be self explanatory. f.write(ctypes.c_int(i)) f.write(ctypes.c_int(weightJointIndexPairs[0].joint_index)) f.write(ctypes.c_float(weightJointIndexPairs[0].weight)) f.write(ctypes.c_int(weightJointIndexPairs[1].joint_index)) f.write(ctypes.c_float(weightJointIndexPairs[1].weight)) f.write(ctypes.c_int(weightJointIndexPairs[2].joint_index)) f.write(ctypes.c_float(weightJointIndexPairs[2].weight)) f.write(ctypes.c_int(weightJointIndexPairs[3].joint_index)) f.write(ctypes.c_float(weightJointIndexPairs[3].weight)) progressBar.Increment() f.close() progressBar.Kill() return
def getSkinWeights(skin): # MAYA API influenceDict = {} # get the MFnSkinCluster for clusterName selList = OpenMaya.MSelectionList() selList.add(skin) clusterNode = OpenMaya.MObject() selList.getDependNode(0, clusterNode) skinFn = OpenMayaAnim.MFnSkinCluster(clusterNode) # get the MDagPath for all influence infDags = OpenMaya.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) influenceDict[infId] = infPath.split('|')[-1] # get the MPlug for the weightList and weights attributes wlPlug = skinFn.findPlug('weightList') wPlug = skinFn.findPlug('weights') wlAttr = wlPlug.attribute() wAttr = wPlug.attribute() wInfIds = OpenMaya.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 = OpenMaya.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() vWeights[influenceDict[infId]] = {infIds[infId]: infPlug.asDouble()} except KeyError: # assumes a removed influence pass weights[vId] = vWeights return weights
def pinocchioWeightsImport(mesh, skin, skelList, weightFile=None, undoable=False): #Ensure that all influences in the skelList are influences for the skin allInfluences = influenceObjects(skin) pinocInfluences = [joint for joint, parent in skelList] for joint in pinocInfluences: if not nodeIn(joint, allInfluences): cmds.skinCluster(skin, edit=1, addInfluence=joint) if weightFile is None: weightFile = browseForFile(m=0, actionName='Import') vertBoneWeights = readPinocchioWeights(weightFile) numVertices = len(vertBoneWeights) numBones = len(vertBoneWeights[0]) numJoints = len(skelList) numWeights = numVertices * numJoints if DEBUG: print "numVertices:", numVertices print "numBones:", numBones assert numBones == numJoints - 1, \ "numBones (%d) != numJoints (%d) - 1" % (numBones, numJoints) # Pinocchio sets weights per-bone... maya weights per joint. # Need to decide whether to assign the bone weight to the 'start' joint # of the bone, or the 'end' joint boneIndexToJointIndex = [0] * numBones vertJointWeights = [[0] * numJoints for i in xrange(numVertices)] assignBoneToEndJoint = False if assignBoneToEndJoint: for jointIndex in xrange(1, numJoints): boneIndexToJointIndex[jointIndex - 1] = jointIndex else: for jointIndex in xrange(1, numJoints): parentIndex = skelList[jointIndex][1] boneIndexToJointIndex[jointIndex - 1] = parentIndex for vertIndex, boneWeights in enumerate(vertBoneWeights): assert abs(sum(boneWeights) - 1) < 0.1, \ "Output for vert %d not normalized - total was: %.03f" % \ (vertIndex, sum(boneWeights)) for boneIndex, boneValue in enumerate(boneWeights): # multiple bones can correspond to a single joint - # make sure to add the various bones values together! jointIndex = boneIndexToJointIndex[boneIndex] vertJointWeights[vertIndex][jointIndex] += boneValue if DEBUG: print "vertJointWeights:" for i, jointWeights in enumerate(vertJointWeights): if i < 20: print jointWeights else: print "..." break if not undoable: # If we're using the non-undoable api method, there's a lot of setup # we have to do first; want to do this before zeroing weights, # in case there's an error apiWeights = api.MDoubleArray(numWeights, 0) for vertIndex, jointWeights in enumerate(vertJointWeights): for jointIndex, jointValue in enumerate(jointWeights): apiWeights.set(jointValue, vertIndex * numJoints + jointIndex) apiJointIndices = api.MIntArray(numJoints, 0) if DEBUG: for jointIndex, (joint, parentIndex) in enumerate(skelList): print jointIndex, (joint, parentIndex) influences = influenceObjects(skin) for apiIndex, joint in enumerate(influences): influenceIndex = getNodeIndex(joint, pinocInfluences) if influenceIndex is None: raise InfluenceNotFoundError("%r not found in influences for skin %r: %r" % (joint, skin, pinocInfluences)) apiJointIndices.set(apiIndex, influenceIndex) if DEBUG: print "apiJointIndices:", pyJointIndices = [] for i in xrange(apiJointIndices.length()): pyJointIndices.append(apiJointIndices[i]) print pyJointIndices apiComponents = api.MFnSingleIndexedComponent().create(api.MFn.kMeshVertComponent) apiVertices = api.MIntArray(numVertices, 0) for i in xrange(numVertices): apiVertices.set(i, i) api.MFnSingleIndexedComponent(apiComponents).addElements(apiVertices) mfnSkin = apiAnim.MFnSkinCluster(toMObject(skin)) meshDag = toMDagPath(mesh) # Save the weights, so that if there's an error later, we # can still restore the weights savedWeights = api.MDoubleArray(numWeights, 0) numInfluencesPtr = api.MScriptUtil() numInfluencesPtr.createFromInt(0) mfnSkin.getWeights(meshDag, apiComponents, savedWeights, numInfluencesPtr.asUintPtr()) # Zero all weights (so if there's influences not among those we're # importing, they will have zero influence) cmds.skinPercent(skin, mesh, pruneWeights=100, normalize=False) if not undoable: # Use the api methods to set skin weights - MUCH faster than using # mel skinPercent, but api doesn't have built-in undo support, so # flush the undo queue zeroedWeights = api.MDoubleArray() undoState = cmds.undoInfo(q=1, state=1) cmds.undoInfo(state=False) try: try: mfnSkin.setWeights(meshDag, apiComponents, apiJointIndices, apiWeights, False, zeroedWeights) print "successfully set weights!" except Exception: # There was a problem, restore the saved weights! influenceIndices = api.MIntArray(len(influences), 0) for i in xrange(len(influences)): influenceIndices.set(i,i) mfnSkin.setWeights(meshDag, apiComponents, influenceIndices, savedWeights, False, zeroedWeights) api.MGlobal.displayError("Encountered error setting new weights - original weights restored") raise finally: cmds.flushUndo() cmds.undoInfo(state=undoState) else: # Use mel skinPercent - much slower, but undoable cmds.progressWindow(title="Setting new weights...", isInterruptable=True, max=numVertices) try: lastUpdateTime = cmds.timerX() updateInterval = .5 for vertIndex, vertJoints in enumerate(vertJointWeights): jointValues = {} if cmds.progressWindow( query=True, isCancelled=True ) : break #print "weighting vert:", vertIndex for jointIndex, jointValue in enumerate(vertJoints): if jointValue > 0: jointValues[pinocInfluences[jointIndex]] = jointValue if cmds.timerX(startTime=lastUpdateTime) > updateInterval: cmds.progressWindow(edit=True, progress=vertIndex, status="Setting Vert: (%i of %i)" % (vertIndex, numVertices)) lastUpdateTime = cmds.timerX() cmds.skinPercent(skin, mesh + ".vtx[%d]" % vertIndex, normalize=False, transformValue=jointValues.items()) finally: cmds.progressWindow(endProgress=True)
def writeWeights(self, fileName, exclusive): # get the current selection skinClusterNode = cmds.ls(sl=True, fl=True) if len(skinClusterNode) != 0: skinClusterNode = skinClusterNode[0] else: OpenMaya.MGlobal.displayError( 'Select a skinCluster node to export.') return (-1) # check if it's a skinCluster if cmds.nodeType(skinClusterNode) != 'skinCluster': OpenMaya.MGlobal.displayError( 'Selected node is not a skinCluster.') return (-1) # get the MFnSkinCluster sel = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(sel) skinClusterObject = OpenMaya.MObject() sel.getDependNode(0, skinClusterObject) # documentation: MFNSkinCluster: https://help.autodesk.com/view/MAYAUL/2018/ENU/?guid=__cpp_ref_class_m_fn_skin_cluster_html skinClusterFn = OpenMayaAnim.MFnSkinCluster(skinClusterObject) # get the influence objects infls = cmds.skinCluster(skinClusterNode, q=True, inf=True) if len(infls) == 0: OpenMaya.MGlobal.displayError( 'No influence objects found for skinCluster %s.' % skinClusterNode) return (-1) # get the connected shape node shape = cmds.skinCluster(skinClusterNode, q=True, g=True)[0] if len(shape) == 0: OpenMaya.MGlobal.displayError('No connected shape nodes found.') return (-1) # get the dag path of the shape node cmds.select(shape, r=True) sel = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(sel) shapeDag = OpenMaya.MDagPath() sel.getDagPath(0, shapeDag) # create the geometry iterator geoIter = OpenMaya.MItGeometry(shapeDag) # create a pointer object for the influence count of the MFnSkinCluster infCount = OpenMaya.MScriptUtil() infCountPtr = infCount.asUintPtr() OpenMaya.MScriptUtil.setUint(infCountPtr, 0) value = OpenMaya.MDoubleArray() # # default export to a single skin weights file # if not exclusive: try: weightFile = open(fileName, 'wb') except: OpenMaya.MGlobal.displayError( 'A file error has occured for file \'' + fileName + '\'.') return (-1) # write all influences and the shape node to the file for i in range(0, len(infls), 1): weightFile.write(infls[i] + " ") weightFile.write(shape + '\n') weightFile.write(skinClusterNode + '\n') # write the attributes of the skinCluster node to the file result = cmds.getAttr(skinClusterNode + ".normalizeWeights") weightFile.write('-nw %s ' % result) result = cmds.getAttr(skinClusterNode + ".maxInfluences") weightFile.write('-mi %s ' % result) result = cmds.getAttr(skinClusterNode + ".dropoff")[0][0] weightFile.write('-dr %s\n' % result) # get the skinCluster weights while geoIter.isDone() == False: skinClusterFn.getWeights(shapeDag, geoIter.currentItem(), value, infCountPtr) for j in range(0, len(infls)): if value[j] > 0: lineArray = [geoIter.index(), infls[j], j, value[j]] weightFile.write(str(lineArray) + '\n') geoIter.next() weightFile.close() # # custom export to individual files # else: cmds.skinCluster(skinClusterNode, e=True, fnw=True) dataPath = '%s/%s' % (fileName, skinClusterNode) if not os.path.exists(dataPath): try: os.makedirs(dataPath) except: OpenMaya.MGlobal.displayError( 'Unable to create export directory \'' + dataPath + '\'.') return (-1) for j in range(0, len(infls)): fileName = '%s/%s.bsw' % (dataPath, infls[j]) try: weightFile = open(fileName, 'wb') except: OpenMaya.MGlobal.displayError( 'A file error has occured for file \'' + fileName + '\'.') return (-1) geoIter.reset() while geoIter.isDone() == False: skinClusterFn.getWeights(shapeDag, geoIter.currentItem(), value, infCountPtr) line = str(geoIter.index()) + ' ' + str(value[j]) + '\n' weightFile.write(line) geoIter.next() weightFile.close() return (1)
def bLoadVertexSkinValues(inputFile, ignoreJointLocks): timeBefore = time.time() line = '' fileJoints = [] weights = [] splittedStrings = [] splittedWeights = [] selectionList = OpenMaya.MSelectionList() vertexCount = 0 OpenMaya.MGlobal.getActiveSelectionList(selectionList) node = OpenMaya.MDagPath() component = OpenMaya.MObject() selectionList.getDagPath(0, node, component) if not node.hasFn(OpenMaya.MFn.kTransform): print 'select a skinned object' NewTransform = OpenMaya.MFnTransform(node) if not NewTransform.childCount() or not NewTransform.child(0).hasFn( OpenMaya.MFn.kMesh): print 'select a skinned object..' mesh = NewTransform.child(0) objectName = OpenMaya.MFnDagNode(mesh).name() skinCluster = bFindSkinCluster(objectName) if not skinCluster.hasFn(OpenMaya.MFn.kSkinClusterFilter): print 'select a skinned object' fnSkinCluster = OpenMayaAnim.MFnSkinCluster(skinCluster) input = open(inputFile, 'r') fileJoints = [] weightLines = [] filePosition = 0 # getting the weightLines # fileWeightFloats = [] fnVtxComp = OpenMaya.MFnSingleIndexedComponent() vtxComponents = OpenMaya.MObject() vtxComponents = fnVtxComp.create(OpenMaya.MFn.kMeshVertComponent) bindVertCount = 0 didCheckSoftSelection = False while True: line = input.readline().strip() if not line: break if filePosition == 0: vertexCount = int(line) if OpenMaya.MItGeometry(node).count() != vertexCount: print "vertex counts don't match!" return filePosition = 1 elif filePosition == 1: if not line.startswith("========"): fileJoints.append(line) else: filePosition = 2 elif filePosition == 2: splittedStrings = line.split(':') # do we have softselection? if not didCheckSoftSelection: if len(splittedStrings) == 3: weightsIndex = 2 doSoftSelection = True softWeights = [1.0] * bindVertCount else: weightsIndex = 1 doSoftSelection = False didCheckSoftSelection = True # vertId vertId = int(splittedStrings[0]) fnVtxComp.addElement(vertId) #softselection if doSoftSelection: softWeights.append(float(splittedStrings[1])) # weights splittedWeights = splittedStrings[weightsIndex].split(' ') fileWeightFloats.append(map(float, splittedWeights)) #for k in range(len(fileJoints)): # fileWeightFloats[bindVertCount].append(float(splittedWeights[k])) bindVertCount += 1 #print 'fileWeightFloats: ', fileWeightFloats # getting mayaJoints # influenceArray = OpenMaya.MDagPathArray() mayaJoints = [] infCount = fnSkinCluster.influenceObjects(influenceArray) for i in range(infCount): mayaJoints.append( OpenMaya.MFnDagNode(influenceArray[i]).name().split('|')[-1]) # getting old weights # oldWeightDoubles = OpenMaya.MDoubleArray() scriptUtil = OpenMaya.MScriptUtil() infCountPtr = scriptUtil.asUintPtr() fnSkinCluster.getWeights(bSkinPath, vtxComponents, oldWeightDoubles, infCountPtr) # making allJoints # allJoints = list(fileJoints) for mayaJoint in mayaJoints: if mayaJoint not in fileJoints: allJoints.append(mayaJoint) # mapping joints and making sure we have all joints in the skinCluster # allInfluencesInScene = True missingInfluencesList = [] for i in range(len(fileJoints)): influenceInScene = False for k in range(len(mayaJoints)): if mayaJoints[k] == fileJoints[i]: influenceInScene = True if not influenceInScene: allInfluencesInScene = False missingInfluencesList.append(fileJoints[i]) if not allInfluencesInScene: print 'There are influences missing:', missingInfluencesList return # getting allExistInMaya # allExistInMaya = [-1] * len(allJoints) for i in range(len(allJoints)): for k in range(len(mayaJoints)): if allJoints[i] == mayaJoints[k]: allExistInMaya[i] = k break #print 'allExistInMaya: ', allExistInMaya # getting joint locks # allLocks = [False] * len(allJoints) if not ignoreJointLocks: for i in range(len(allJoints)): allLocks[i] = cmds.getAttr('%s.liw' % allJoints[i]) weightDoubles = OpenMaya.MDoubleArray(0) # copy weights from fileWeightFloats and oldWeightDoubles into weightDoubles (include joint locks) and softWeights lists # print 'bindVertCount: ', bindVertCount for i in range(bindVertCount): for k in range(len(allJoints)): # fileJoints: # if k < len(fileJoints): if not allLocks[k]: weightDoubles.append( fileWeightFloats[i][k] ) #weightDoubles[k + len(allJoints) * i] = fileWeightFloats[i][k] else: if allExistInMaya[k]: weightDoubles.append( oldWeightDoubles[allExistInMaya[k] + len(mayaJoints) * i]) else: weightDoubles.append(0) # mayaJoints # else: if not allLocks[k]: weightDoubles.append(0) else: if allExistInMaya[k]: weightDoubles.append( oldWeightDoubles[allExistInMaya[k] + len(mayaJoints) * i]) else: weightDoubles.append(0) # normalize # for i in range(bindVertCount): sumA = 0 sumB = 0 for inf in range(len(allJoints)): if not allLocks[inf]: sumA += weightDoubles[inf + i * len(allJoints)] else: sumB += weightDoubles[inf + i * len(allJoints)] if sumA > 0.0001: sumADenom = 1 / sumA for inf in range(len(allJoints)): if not allLocks[inf]: weightDoubles[inf + i * len(allJoints)] *= sumADenom * (1 - sumB) # soft selection # if doSoftSelection: for i in range(bindVertCount): for inf in range(len(allExistInMaya)): index = inf + i * len(allExistInMaya) oldWeights = oldWeightDoubles[allExistInMaya[inf] + len(mayaJoints) * i] weightDoubles[index] = weightDoubles[index] * softWeights[ i] + oldWeights * (1.0 - softWeights[i]) #SET WEIGHTS # allJointsIndices = OpenMaya.MIntArray(len(allExistInMaya)) for i in range(len(allExistInMaya)): allJointsIndices[i] = allExistInMaya[i] #print 'mayaJoints: ', mayaJoints #print 'allJointsIndices: ', allJointsIndices #print 'allJoints: ', allJoints #print 'weightDoubles before: ', weightDoubles print 'setting weights...' fnSkinCluster.setWeights(bSkinPath, vtxComponents, allJointsIndices, weightDoubles, 0) # select the vertices # pointSelectionList = OpenMaya.MSelectionList() pointSelectionList.add(OpenMaya.MDagPath(node), vtxComponents) OpenMaya.MGlobal.setActiveSelectionList(pointSelectionList) print 'done, it took', (time.time() - timeBefore), ' seconds'
def deLinearSkinWeights(vertices, method): """ Loop over all of the provided vertices. Loop over all of the vertices and see if these vertices are deformed by a skin cluster. If this is the case, the weights will be de-linearized by the function provided. This function is found in the tweening module using :func:`getTweeningMethod`. :param list vertices: List of vertices :param str method: De-linearization method """ func = getTweeningMethod(method) if not func: raise ValueError("Tweening method is not supported.") data = {} objects = list(set([vtx.split(".")[0] for vtx in vertices])) with utils.UndoChunkContext(): for obj in objects: # get skin cluster sk = utils.getSkinCluster(obj) if not sk: continue # get indices indices = [ getIndexFromString(vtx) for vtx in vertices if vtx.startswith(obj) ] # get api objects meshObj = utils.asMObject(obj) meshDag = utils.asMDagPath(meshObj) meshDag.extendToShape() skObj = utils.asMObject(sk) skMfn = OpenMayaAnim.MFnSkinCluster(skObj) # get weights components = utils.asComponent(indices) weightsAll, num = utils.getSkinWeights( meshDag, skMfn, components ) # split weights weightChunks = splitByInfluences(weightsAll, num) for i, weights in enumerate(weightChunks): # calculate per vertex weights weights = utils.normalizeWeights(weights) weights = [func(w) for w in weights] weights = utils.normalizeWeights(weights) # set weights for j, w in enumerate(weights): cmds.setAttr( "{0}.weightList[{1}].weights[{2}]".format( sk, indices[i], j ), w )