def getSkinWeights(meshDagPath, skinNode): """ get skin weight per vertex for each joint :param meshDagPath: MDagPath, MDagPath of mesh shape node :param skinNode:MObject, MObject of skinCluster node :return: dict, mesh skin weight for each joint Per vertex. dict={0:{joint1:0.1, ..., jointX: 0.0}, ..., x:{joint1:0.03, ..., jointX:0.2}} """ meshNode = meshDagPath.node() skinFn = oma2.MFnSkinCluster(skinNode) meshVertIterFn = om2.MItMeshVertex(meshNode) indices = range(meshVertIterFn.count()) data = {} for i in indices: singleIDComponent = om2.MFnSingleIndexedComponent() vertexComponent = singleIDComponent.create(om2.MFn.kMeshVertComponent) singleIDComponent.addElement(indices[i]) rawWeightDataPerVertex = skinFn.getWeights(meshDagPath, vertexComponent) influecesObjs = skinFn.influenceObjects() data[i] = {} for j in xrange(influecesObjs.__len__()): data[i][ influecesObjs[j].fullPathName()] = rawWeightDataPerVertex[0][j] return data
def redoIt(self): # get the skin cluster MObject by going up the history fnSkinCluster = omAnim.MFnSkinCluster(self.skinClusterMObject) oldVertexWeight, numInfluences = fnSkinCluster.getWeights( self.dagPath, self.component) neighborVertexWeights, numInfluences = fnSkinCluster.getWeights( self.dagPath, self.neighborComponents) influenceIndices = om.MIntArray() newWeights = om.MDoubleArray() for i in xrange(numInfluences): # set the vertex weight to the average of its neighbor parts influenceIndices.append(i) newWeights.append(0.0) for j in xrange(i, len(neighborVertexWeights), numInfluences): # add to a rolling average. This will be normalized by default. # NOTE bmorgan: This formula comes from tf_smoothSkinWeight newWeights[i] += ( ((neighborVertexWeights[j] / self.numVertexNeighbors) * self.strength) + ((oldVertexWeight[i] / self.numVertexNeighbors) * (1 - self.strength))) fnSkinCluster.setWeights(self.dagPath, self.component, influenceIndices, newWeights) self.undoQueue.append((self.skinClusterMObject, oldVertexWeight, self.dagPath, influenceIndices, self.component))
def set_weights(skin, data, prune=False): """Set an skin cluster with weight data. Args: skin: Skin cluster node or mobject data: Weight data specifically in the format `get_weights` returns prune: Remove unused influences from the skin cluster Returns: None """ influences = get_skin_influences(skin) influences_remapped = {v: k for k, v in influences.items()} mfn_skin = oma2.MFnSkinCluster(skin) for vert, weights in data: weight_list_index_attr = '{skincluster}.weightList[{vertId}]'.format( skincluster=mfn_skin.name(), vertId=vert) for influence, weight_value in weights: influence_logical_index = influences_remapped[influence] weights_attr = '.weights[{influenceId}]'.format( influenceId=influence_logical_index) cmds.setAttr(weight_list_index_attr + weights_attr, weight_value) if prune: skin_name = om2.MFnDependencyNode(skin).name() skin_geo = om2.MFnDependencyNode( oma2.MFnGeometryFilter(skin).getOutputGeometry()[0]).name() cmds.skinPercent(skin_name, skin_geo, nrm=False, prw=0)
def export_xml_weights(file_name, skins): """Save out skin weights to an XML file. Args: file_name: Name for output file skins: Skin clusters to gather skin weights from Returns: str: File path to output weights file """ weights_dir = get_weights_directory() if not os.path.exists(weights_dir): os.makedirs(weights_dir) output_file_name = '{}.xml'.format(file_name) skin_names = [oma2.MFnSkinCluster(v).name() for k, v in skins.items()] output_path = cmds.deformerWeights(output_file_name, p=weights_dir, ex=True, vc=True, deformer=skin_names) return output_path
def get_skin_influences(skin): """Get a skin clusters influence list. Args: skin: Skin cluster name or mobject Returns: dict: A map where keys are the logical index and values are the names of the influences """ influences = dict() sel = om2.MSelectionList() sel.add(skin) skin_mobject = sel.getDependNode(0) mfn_skin = oma2.MFnSkinCluster(skin_mobject) mfn_influences = mfn_skin.influenceObjects() for num in range(len(mfn_influences)): influence_idx = om2.MFnDependencyNode( mfn_influences[num].node()).uuid().asString() logical_index = mfn_skin.indexForInfluenceObject(mfn_influences[num]) influences[int(logical_index)] = influence_idx return influences
def redoIt(self): fnSkinCluster = omAnim.MFnSkinCluster(self.skinClusterMObject) # get the weights for our single vertex plus its neighbors oldVertexWeight, numInfluences = fnSkinCluster.getWeights(self.shapeDag, self.component) neighborVertexWeights, numInfluences = fnSkinCluster.getWeights(self.shapeDag, self.neighborComponents) neighborVertexWeightLength = self.numVertexNeighbors * numInfluences influenceIndices = om.MIntArray() newWeights = om.MDoubleArray() # set the vertex weight to the average of its neighbor parts for i in xrange(numInfluences): # taking advantage of this loop to create our influence indices array influenceIndices.append(i) # weights start at 0 so that we can add weight values to it newWeights.append(0.0) for j in xrange(i, neighborVertexWeightLength, numInfluences): # add to a rolling average. This will be normalized by default. # NOTE bmorgan: This formula comes from tf_smoothSkinWeight newWeights[i] += (((neighborVertexWeights[j] / self.numVertexNeighbors) * self.strength) + ((oldVertexWeight[i] / self.numVertexNeighbors) * (1 - self.strength))) # set the skin cluster weight for just that single component fnSkinCluster.setWeights(self.shapeDag, self.component, influenceIndices, newWeights) # add the previous weight value to our undo queue self.undoQueue.append((self.skinClusterMObject, oldVertexWeight, self.shapeDag, influenceIndices, self.component))
def setWeigths(skinNode, geo, inf, weigth): #获得一个组件列表 cmp_list = [universal.intoComponents(i) for i in universal.translateToName(geo)] #检查组件列表的数量 if len(cmp_list)<1: raise EOFError('geo没有任何对象') #建立一个组件选择列表 sel_list = om.MSelectionList() [sel_list.add(i) for i in cmp_list] if int(sel_list.length())>1: raise EOFError('%s 不在一个mesh或者其他对象上'%geo) return 1 path,comp = sel_list.getComponent(0) sel_list.add(skinNode) skinNode = sel_list.getDependNode(1) fn_skin = oma.MFnSkinCluster(skinNode) m_inf = om.MIntArray(inf) m_weigth = om.MDoubleArray(weigth) #撤销的权重 unWeights = fn_skin.getWeights(path,comp,m_inf) doIt = functools.partial(fn_skin.setWeights,path,comp,m_inf,m_weigth) undoIt = functools.partial(fn_skin.setWeights,path,comp,m_inf,unWeights) return cmcore.addCommand(doIt, undoIt)
def getSkinInfluences(self, scList): """ :param scList: :return: """ if scList: outputDict = dict() for sc in scList: mFnSkin = om2anim.MFnSkinCluster(sc) infObj = mFnSkin.influenceObjects() scName = mFnSkin.name() scNameNoNS = scName.split(':')[-1] jntList = list() for jnt in infObj: jntName = om2.MDagPath(jnt).fullPathName().split(':')[-1] if not jntName in jntList: jntList.append(jntName) else: continue outputDict.update({scNameNoNS: jntList}) return outputDict
def vtxLoad_api(self): selList = om.MGlobal.getActiveSelectionList() if selList.isEmpty(): om.MGlobal.displayError('Select Nothing') return MDagPath = selList.getDagPath(0) # 存储所选物体的路径 MObject = selList.getDependNode(0) # 存储所选物体的组件的列表 _selType = MDagPath.apiType() _selShapeType = MDagPath.extendToShape().apiType() if _selType != 110: om.MGlobal.displayError('Please Select Object') return if _selShapeType != 296: self.vtxLoad_Oapi() return skCluster = mel.eval('findRelatedSkinCluster("%s")' % MDagPath.partialPathName()) if not skCluster: return selList.add(skCluster) skinObj = selList.getDependNode(1) skinNode = omAni.MFnSkinCluster(skinObj) infs = skinNode.influenceObjects() infNameList = [infs[i].partialPathName() for i in range(len(infs))] # 骨骼列表 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.MItMeshVertex(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 set_skin_cluster_weights(mesh, skin_cluster, weights): """Set all weights on skin cluster via MFnSkinCluster. Weights should be in same form as returned by get_skin_cluster_weights. TODO options for selective influences. TODO options for selective components. """ sl = OpenMaya.MSelectionList() # get mesh dag path sl.add(mesh) mesh_dag = sl.getDagPath(0) # get skin sl.add(skin_cluster) m_skin = sl.getDependNode(1) # restructure weights to match form expected by MFnSkinCluster n_weights = numpy.array(weights) flat_weights = n_weights.transpose().flatten().tolist() weights = OpenMaya.MDoubleArray(flat_weights) if True: # construct component object for all verts # TODO perform on specific components?!? mesh_fn = OpenMaya.MFnMesh(mesh_dag) point_count = mesh_fn.numVertices component = OpenMaya.MFnSingleIndexedComponent() component.create(OpenMaya.MFn.kMeshVertComponent) component.addElements([i for i in range(point_count)]) components = component.object() else: # or simply pass in an empty MObject to set all weights # note sometimes this doesn't work?! components = OpenMaya.MObject() # set weights m_skin = OpenMayaAnim.MFnSkinCluster(m_skin) influences = [ m_skin.indexForInfluenceObject(i) for i in m_skin.influenceObjects() ] # influences must be passed in as a MIntArray # python list will throw an unhelpful error # Error: TypeError: file ...py line 116: an integer is required # influences = OpenMaya.MIntArray(influences) m_skin.setWeights(mesh_dag, components, influences, weights) return True
def __init__(self, cluster): """ :param cluster: The skinCluster MObject :type cluster: om2.MObject """ self.cluster = cluster self.mfn = om2Anim.MFnSkinCluster(cluster) self.shapeNode, self.component = geometryComponentsFromSet( self.mfn.deformerSet)
def getMFnSkinCluster(name): sel = OpenMaya.MSelectionList() try: sel.add(str(name)) except RuntimeError as e: return e m_object = sel.getDependNode(0) return OpenMayaAnim.MFnSkinCluster(m_object)
def undoIt(self): if self.undoQueue: fnSkinCluster = omAnim.MFnSkinCluster(self.undoQueue[-1][0]) oldWeight = self.undoQueue[-1][1] shapeDag = self.undoQueue[-1][2] influenceIndices = self.undoQueue[-1][3] component = self.undoQueue[-1][4] # when undoing, we're also only setting the weight on that single vertex fnSkinCluster.setWeights(shapeDag, component, influenceIndices, oldWeight) # after we've set weights, remove that data from the undo queue self.undoQueue.pop(-1)
def undoIt(self): if self.undoQueue: fnSkinCluster = omAnim.MFnSkinCluster(self.undoQueue[-1][0]) oldWeights = self.undoQueue[-1][1] meshDagPath = self.undoQueue[-1][2] influenceIndices = self.undoQueue[-1][3] component = self.undoQueue[-1][4] # when undoing, we have to set weights on every component fnSkinCluster.setWeights(meshDagPath, component, influenceIndices, oldWeights) self.undoQueue.pop(-1)
def getSkinFn(self): sel = om.MGlobal.getActiveSelectionList() meshDag = sel.getDagPath(0) meshDag.extendToShape() selList = om.MSelectionList() selList.add(meshDag) shapeObj = selList.getDependNode(0) dagIter = om.MItDependencyGraph(shapeObj, om.MItDependencyGraph.kDownstream, om.MItDependencyGraph.kPlugLevel) while not dagIter.isDone(): currentItem = dagIter.currentNode() if currentItem.hasFn(om.MFn.kSkinClusterFilter): self.skinFn = oma.MFnSkinCluster(currentItem) dagIter.next()
def om_get_skin_cluster(self, dagPath=None): if not dagPath: return None skinCluster = cmds.ls(cmds.listHistory(dagPath.fullPathName()), type='skinCluster') if not skinCluster: return None, None clusterName =skinCluster[0] sellist = om2.MGlobal.getSelectionListByName(clusterName) skinNode = sellist.getDependNode(0) skinFn = oma2.MFnSkinCluster( skinNode ) #print('get skin cluster :', clusterName, skinFn) return skinFn, clusterName
def get_skin_data(mesh): """ :param mesh: Pymel Transform Node :return: influences, skin_weights """ skin_cluster = mesh.listHistory(type='skinCluster')[0] sel_list = OpenMaya.MSelectionList() sel_list.add(str(skin_cluster)) cluster_node = sel_list.getDependNode(0) skin_fn = OpenMayaAnim.MFnSkinCluster(cluster_node) inf_dags = skin_fn.influenceObjects() """checking the update"""
def get_skin_cluster(self, mesh_fn): ''' get a list of all the skin clusters in the file, iterate and see if the shapes connected match our selection ''' self.in_plug = mesh_fn.findPlug('inMesh', False) connections = self.in_plug.connectedTo(True, False) for c in connections: obj = c.node() try: skin_cluster_fn = oma.MFnSkinCluster(obj) return skin_cluster_fn except: sys.stderr.write("No skin cluster found! ") return None
def vtxSave_api(self): selList = om.MGlobal.getActiveSelectionList() if selList.isEmpty(): om.MGlobal.displayError('Select Nothing') return MDagPath = selList.getDagPath(0) # 存储所选物体的路径 MObject = selList.getDependNode(0) # 存储所选物体的组件的列表 slMIt = om.MItSelectionList(selList) MItDagPath, MItcomponent = slMIt.getComponent() _selType = MDagPath.apiType() _selShapeType = MDagPath.extendToShape().apiType() if not _selType in set([110, 296, 267, 294, 279, ]): return elif _selShapeType == 296: suf = 'vtx' elif _selShapeType == 267 or _selShapeType == 294 or _selShapeType == 279: self.vtxSave_Oapi() return skCluster = mel.eval('findRelatedSkinCluster("%s")' % MDagPath.partialPathName()) if not skCluster: return selList.add(skCluster) skinObj = selList.getDependNode(1) skinNode = omAni.MFnSkinCluster(skinObj) infs = skinNode.influenceObjects() infNameList = [infs[i].partialPathName() for i in range(len(infs))] # 骨骼列表 filePath = cmds.fileDialog2(ff='WeightFile (*.vtxWeight *.sdd)', ds=2) if not filePath: return fileLine = [] Lineapp = fileLine.append if not MItcomponent.isNull(): # component组件不为空(点),线和面会强制转为点 vertIter = om.MItMeshVertex(MItDagPath, MItcomponent) else: vertIter = om.MItMeshVertex(MObject) while not vertIter.isDone(): weights = skinNode.getWeights(MDagPath, vertIter.currentItem())[0] 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 simplify_weights(path, target=None, fast=True, deformer=None, start=None, end=None, steps=1): """ Simplify weighting on the mesh so that each vertice may only have a single influence. :param path: The path to the mesh to simplify the weights on :param target: The target mesh to compare weights against. Defaults to the current mesh. :param fast: Use the fast mode (less accurate) or not (iterates frame range but better results) :param deformer: The skin cluster to simplify weights for :param start: The start frame to use for the non-fast path. :param end: The end frame to use for the non-fast path. :param steps: The intervals between frames to use for the non fast path """ sel = om.MSelectionList() sel.add(get_mesh(path)) dag = sel.getDagPath(sel.length() - 1) mesh = om.MFnMesh(dag) if target: sel.add(get_mesh(target)) target = sel.getDagPath(sel.length() - 1) target_mesh = om.MFnMesh(target) else: target = dag target_mesh = mesh if not deformer: deformer = get_skincluster(mesh.fullPathName()) sel.add(deformer) skin_node = sel.getDependNode(sel.length() - 1) skin_cluster = oma.MFnSkinCluster(skin_node) if fast: __simplify_weights_fast(mesh, skin_cluster) else: __simplify_weights(mesh, target_mesh, skin_cluster, start=start, end=end, steps=steps)
def __init__(self,skinNode, geo): #获得一个组件列表 cmp_list = [universal.intoComponents(i) for i in universal.translateToName(geo)] #检查组件列表的数量 if len(cmp_list)<1: raise EOFError('geo没有任何对象') #建立一个组件选择列表 sel_list = om.MSelectionList() [sel_list.add(i) for i in cmp_list] if int(sel_list.length())>1: raise EOFError('%s 不在一个mesh或者其他对象上'%geo) return 1 self.path,self.comp = sel_list.getComponent(0) sel_list.add(skinNode) skinNode = sel_list.getDependNode(1) self.fn_skin = oma.MFnSkinCluster(skinNode)
def get_weights(skin, prune=False, use_influence_names=False): """Given a skin cluster node, gather all the weight data in sequential vertex order. Args: skin: Skin cluster name or mobject prune: Remove skin weight data that is zero use_influence_names: Use node names instead of node UUIDs Returns: list: Skin weights nested by vertex order, then influence order """ data = list() mfn_skin = oma2.MFnSkinCluster(skin) influences = get_skin_influences(skin) if use_influence_names: influences = { k: cmds.ls(v, long=True)[0] for k, v in influences.items() } weight_list_attr = mfn_skin.findPlug('weightList', False) vertices = weight_list_attr.getExistingArrayAttributeIndices() weight_list_attr.evaluateNumElements() for vert in vertices: weights = list() weight_list_index_attr = weight_list_attr.elementByLogicalIndex(vert) weights_attr = weight_list_index_attr.child(0) influence_ids = weights_attr.getExistingArrayAttributeIndices() infPlug = om2.MPlug(weights_attr) for index in influence_ids: infPlug.selectAncestorLogicalIndex(index, weights_attr.attribute()) influence = influences[index] value = infPlug.asDouble() if prune and value <= 0.0: continue weights.append([influence, value]) data.append([vert, weights]) return data
def bindToSkin(meshPaths, skinIndex, skinWeight, skinJnts, numMaxInfluences): asl = om.MSelectionList() asl.clear() jntNames = [sj.name for sj in skinJnts] for sj in skinJnts: m = om.MMatrix(sj.bindPose.tolist()) m = om.MTransformationMatrix(m) om.MFnTransform(sj.path).setTransformation(m) asl.add(sj.path) offset = 0 for meshPath in meshPaths: mesh = om.MFnMesh(meshPath) meshName = om.MFnDagNode(mesh.parent(0)).name() skinNode = findSkinCluster(meshPath) if skinNode: cmds.skinCluster(meshName, edit=True, unbind=True) sl = om.MSelectionList(asl) sl.add(meshPath) om.MGlobal.setActiveSelectionList(sl) meshName = om.MFnDagNode(mesh.parent(0)).name() skinName = cmds.skinCluster(maximumInfluences=numMaxInfluences, name=meshName + 'Cluster', toSelectedBones=True)[0] skinObj = om.MGlobal.getSelectionListByName(skinName).getDependNode(0) skin = oma.MFnSkinCluster(skinObj) vertexIndices = om.MIntArray(mesh.numVertices, 0) for i in xrange(mesh.numVertices): vertexIndices[i] = i singleIndexedComp = om.MFnSingleIndexedComponent() vertexComp = singleIndexedComp.create(om.MFn.kMeshVertComponent) singleIndexedComp.addElements(vertexIndices) infDags = skin.influenceObjects() numInfDags = len(infDags) infIndices = om.MIntArray(numInfDags, 0) for i in xrange(numInfDags): infIndices[i] = i weights = om.MDoubleArray(mesh.numVertices * numInfDags, 0) for v in xrange(mesh.numVertices): for j, w in zip(skinIndex[offset + v], skinWeight[offset + v]): if j >= 0: weights[v * numInfDags + j] = w skin.setWeights(meshPath, vertexComp, infIndices, weights) offset += mesh.numVertices skin.findPlug('deformUserNormals', True).setBool(False)
def get_skin_cluster_weights(mesh, skin_cluster): sl = OpenMaya.MSelectionList() # get mesh dag path sl.add(mesh) mesh_dag = sl.getDagPath(0) # get skin sl.add(skin_cluster) mfn_skin = sl.getDependNode(1) # we just pass in an empty MObject to return all weights components = OpenMaya.MObject() # get weights mfn_skin = OpenMayaAnim.MFnSkinCluster(mfn_skin) weights, influence_count = mfn_skin.getWeights(mesh_dag, components) return weights
def getSkinFn(): sel = om.MGlobal.getActiveSelectionList() meshDag = sel.getDagPath(0) meshDag.extendToShape() selList = om.MSelectionList() selList.add(meshDag) shapeObj = selList.getDependNode(0) dagIter = om.MItDependencyGraph(shapeObj, om.MItDependencyGraph.kDownstream, om.MItDependencyGraph.kPlugLevel) skinFn = None while not dagIter.isDone(): currentItem = dagIter.currentNode() if currentItem.hasFn(om.MFn.kSkinClusterFilter): skinFn = oma.MFnSkinCluster(currentItem) dagIter.next() vertIter = om.MItMeshVertex(shapeObj) influences = skinFn.influenceObjects() print len(influences) while not vertIter.isDone(): weights = skinFn.getWeights(meshDag, vertIter.currentItem()) vertIter.next()
def import_json_weights(file_path, skin, mesh_key, **kwargs): """Apply skin weights from a json file to specified geometry. Args: file_path: Full file path to the JSON skin weights file skin: Skin clusters to apply weight data to mesh_key: Mesh name to evaluate and apply data to **kwargs: Currently unavailable Returns: None """ with open(file_path, 'r') as fp: weight_data = json.load(fp) mesh_vert_count = cmds.polyEvaluate(mesh_key, v=True) file_vert_count = len(weight_data[mesh_key]) if mesh_vert_count != file_vert_count: LOG.warning( 'Weight file has a different point count than the current geometry: {0}--{1}:{2}' .format(mesh_key, mesh_vert_count, file_vert_count)) return skin_influences = set([ x.fullPathName() for x in oma2.MFnSkinCluster(skin).influenceObjects() ]) file_influences = set([y[0] for x in weight_data[mesh_key] for y in x[1]]) if skin_influences != file_influences: missing_in_file = skin_influences.difference(file_influences) missing_in_skin = file_influences.difference(skin_influences) if missing_in_skin: LOG.warning( 'Skin is missing influences: {}'.format(*missing_in_skin)) elif missing_in_file: LOG.warning('Weight file is missing influences: {}'.format( *missing_in_file)) set_weights(skin, weight_data[mesh_key])
def flood_skin_cluster_influence_weights(mesh, skin_cluster, influence, weight): """ TODO/wip """ sl = OpenMaya.MSelectionList() sl.add(mesh) sl.add(skin_cluster) mesh_dag = sl.getDagPath(0) m_skin = sl.getDependNode(1) mfn_skin = OpenMayaAnim.MFnSkinCluster(m_skin) component = OpenMaya.MFnSingleIndexedComponent().create( OpenMaya.MFn.kMeshVertexComponent) # TODO find this influence_index = 0 mfn_skin.setWeights(mesh_dag, component, influence_index, weight) return True
def get_skin_cluster_weights(mesh, skin_cluster): """Get skin cluster weights via MFnSkinCluster. TODO check that mesh is deformed by skin cluster. TODO options for selective influences. Weights are returned as a list of lists, one per influence, containing weights for all points. """ sl = OpenMaya.MSelectionList() # get objects sl.add(mesh) mesh_dag = sl.getDagPath(0) sl.add(skin_cluster) m_skin = sl.getDependNode(1) # we just pass in an empty MObject to return all weights components = OpenMaya.MObject() # get weights m_skin = OpenMayaAnim.MFnSkinCluster(m_skin) weights, influence_count = m_skin.getWeights(mesh_dag, components) # slice weights per influence # mesh_fn = OpenMaya.MFnMesh(mesh_dag) # point_count = mesh_fn.numFaceVertices weights = list(weights) sliced_weights = [ weights[i::influence_count] for i in range(influence_count) ] return sliced_weights
jointWeights.append(weight) weightList.append(jointWeights) mFnTransform.setTranslation(world, om.MSpace.kWorld) if jntParent: cmds.parent(jointList[index], jntParent[0]) if jntChild: cmds.parent(jntChild[0], jointList[index]) #Set join weight to geometry geoSkinCluster = cmds.skinCluster(jointList, geometry)[0] skinMSelection = om.MSelectionList() skinMSelection.add(geoSkinCluster) skinMObject = skinMSelection.getDependNode(0) mfnSkinCluster = oma.MFnSkinCluster(skinMObject) #Vertex components vertexIndexList = range(len(geoPosition)) mfnIndexComp = om.MFnSingleIndexedComponent() vertexComp = mfnIndexComp.create(om.MFn.kMeshVertComponent) mfnIndexComp.addElements(vertexIndexList) #influences influenceObjects = mfnSkinCluster.influenceObjects() influenceList = om.MIntArray() for eachInfluenceObject in influenceObjects: currentIndex = mfnSkinCluster.indexForInfluenceObject(eachInfluenceObject) influenceList.append(currentIndex) #weights
def sang(chue_tem_file, satsuan_ok=1, chai_kraduk=True, chai_bs=True, chai_watsadu=True, lok_tex=False, thangmot=False): t0 = time.time() # 開始 print('"%s"へのエクスポート開始' % chue_tem_file) chue_path_file = os.path.dirname(chue_tem_file) shoki = os.path.join(os.path.dirname(__file__), 'asset', 'model00.pmx') pmx_model = mmdio.pmx.load(shoki) # 初期のpmxモデル # もっと速くするために予めappendメソッドを準備しておく model_vtx_ap = pmx_model.vertices.append # 頂点 model_face_ap = pmx_model.faces.append # 面 model_bon_ap = pmx_model.bones.append # 骨 model_mat_ap = pmx_model.materials.append # 材質 model_morph_ap = pmx_model.morphs.append # モーフ model_dis1_ap = pmx_model.display[1].data.append # 表示ょの表示枠 model_dis2_ap = pmx_model.display[2].data.append # 可動域の表示枠 if (thangmot): lis_chue_nod_poly = mc.filterExpand(mc.ls(transforms=1), selectionMask=12) if (lis_chue_nod_poly == None): # ポリゴンが全然ない場合 print('このシーンの中にポリゴンはありません') return else: lis_chue_nod_poly = mc.filterExpand(mc.ls(transforms=1, selection=1), selectionMask=12) if (lis_chue_nod_poly == None): # 選択されているポリゴンが一つもない場合 print('ポリゴンは選択せれていません') return print('エクスポートするポリゴン:%s' % lis_chue_nod_poly) lis_chue_nod_shp = [] # 全てのシェープのノードを収めるリスト lis_chue_nod_skin = [] # ポリゴンに使う全てのスキンのノードを収めるリスト lis_chue_tex = [] # テクスチャの名前を収めるリスト lis_matrix_mun = [0] for chue_nod_poly in lis_chue_nod_poly: # このポリゴンのシェープのノード chue_nod_shp = mc.listRelatives(chue_nod_poly, shapes=True, fullPath=True)[0] lis_chue_nod_shp.append(chue_nod_shp) # 骨もエクスポートすると選択した場合 if (chai_kraduk): for chue_nod_skin in mc.ls(typ='skinCluster'): # このポリゴンに使うスキンのノード # このスキンのノードに接続されているシェープのノードは、このホリゴンのシェープのノードに接続していれば、このスキンを使う if (pm.PyNode(chue_nod_shp).name() in mc.skinCluster(chue_nod_skin, query=True, geometry=True)): lis_chue_nod_skin.append(chue_nod_skin) break # このポリゴンと接続されているスキンがない場合 else: lis_chue_nod_skin.append(0) if (chai_kraduk): # ここで骨を作成しておく dic_chue_nod_kho = {'全ての親': 0} # 一番外のジョイント i_kho = 1 # ジョイントの順番をカウントする for k in mc.ls(typ='joint', long=True): # このジョイントがすでに作成された場合、スキップする if (k in dic_chue_nod_kho): continue # 使用するスキンのノードと接続されているかどうか for chue_nod_skin in lis_chue_nod_skin: if (chue_nod_skin and k in [ pm.PyNode(x).fullPath() for x in mc.skinCluster( chue_nod_skin, query=True, influence=True) ]): break # 接続されていない場合、このジョイントはスキップ else: continue # 親ジョイントを探す parent = mc.listRelatives(k, parent=True, fullPath=True) if (parent): # 親ジョイントがある場合 pp = [''] for p in parent[0].split('|')[1:]: pp.append(p) pj = '|'.join(pp) if (mc.nodeType(pj) == 'joint'): parent = pj break else: parent = k else: parent = k # 親がない場合、このジョイントそのもの # その親がすでに作られた場合、スキップする if (parent in dic_chue_nod_kho): continue # まだないければ、このジョイントを子ジョイントと共に新しく追加する lis_child = mc.listRelatives(parent, allDescendents=True, fullPath=True) lis_cp = [parent] # 親と全ての子のジョイントを収めるリスト if (lis_child): lis_cp += list(reversed(lis_child)) # 親と子のジョイントの名前を全部収める for j, chue_nod_kho in enumerate(lis_cp): dic_chue_nod_kho[chue_nod_kho] = i_kho + j for chue_nod_kho in lis_cp: # ボーンを作って初期値を与える bone = mmdio.pmx.Bone() bone.name = chue_nod_kho.split('|')[ -1] # ジョイントのノードの名前をボーンの名前に使う bone.isRotatable = True # 全てのボーンは回転可能 bone.isMovable = False # 親のないボーンだけ移動可能 bone.visible = True # 全てのボーン表示 bone.isControllable = True # 全てのボーンは操作できる bone.isIK = False # IKは使わない bone.hasAdditionalRotate = False # 回転付与 bone.hasAdditionalLocation = False # 移動付与 bone.transAfterPhis = False # 物理後 nod_kho = pm.PyNode(chue_nod_kho) # このジョイントのノード p = mc.xform(chue_nod_kho, query=True, t=True, ws=True) # このジョイントの位置 bone.location = [ p[0] * satsuan_ok, p[1] * satsuan_ok, -1 * p[2] * satsuan_ok ] try: chue_parent = nod_kho.getParent().fullPath() bone.parent = dic_chue_nod_kho[chue_parent] except: bone.parent = 0 bone.isMovable = True child = nod_kho.getChildren() if (len(child) == 1): bone.displayConnection = dic_chue_nod_kho[ child[0].fullPath()] else: bone.displayConnection = -1 jo = mc.getAttr(chue_nod_kho + '.jointOrient')[0] mm = lis_matrix_mun[bone.parent] if (jo == (0, 0, 0)): lis_matrix_mun.append(mm) else: mm *= 1 if (mm): mm *= om.MEulerRotation(math.radians(jo[0]), math.radians(jo[1]), math.radians( jo[2])).asMatrix() else: mm = om.MEulerRotation(math.radians(jo[0]), math.radians(jo[1]), math.radians(jo[2])).asMatrix() lis_matrix_mun.append(mm) if (mm): x_axis = [ mm.getElement(0, 0), mm.getElement(0, 1), -mm.getElement(0, 2) ] z_axis = [ mm.getElement(2, 0), mm.getElement(2, 1), -mm.getElement(2, 2) ] bone.localCoordinate = mmdio.pmx.Coordinate(x_axis, z_axis) model_bon_ap(bone) # 子を持っているジョイントだけを表示枠に入れる if (child): model_dis2_ap((0, i_kho)) i_kho += 1 lis_xyz = [] # 頂点の位置を収めるリスト lis_u = [] # 頂点のuvを収めるリスト lis_v = [] lis_norm = [] # 頂点の法線を収めるリスト lis_lis_lis_lek_chut_mai = [] dic_tup_chut = {} # 頂点の新しい番号と繋ぐ辞書 lai_lek_chut = 0 lai_lek_xyz = 0 lai_lek_uv = 0 lai_lek_norm = 0 i_poly = 0 # ポリゴンの順番 for chue_nod_poly in lis_chue_nod_poly: if (chai_kraduk): chue_nod_skin = lis_chue_nod_skin[i_poly] chue_nod_shp = lis_chue_nod_shp[i_poly] if (chue_nod_skin): dic_kho = {} # ジョイントの番号とジョイントの名前の辞書 for ii, chue_nod_kho in enumerate( mc.skinCluster(chue_nod_skin, query=True, influence=True)): dic_kho[ii] = dic_chue_nod_kho[pm.PyNode( chue_nod_kho).fullPath()] # ジョイントとポリゴンの接続される重みを取得する selelis = om.MSelectionList() selelis.add(chue_nod_skin) obj_skin = selelis.getDependNode(0) fn_skin = oma.MFnSkinCluster(obj_skin) selelis = om.MSelectionList() selelis.add(chue_nod_shp) dagpath_mesh = selelis.getDagPath(0) path_influ = fn_skin.influenceObjects() n_influ = len(path_influ) arr_index_influ = om.MIntArray(range(n_influ)) fn_compo = om.MFnSingleIndexedComponent() compo = fn_compo.create(om.MFn.kMeshVertComponent) # 重みのリストができた。長さはジョイント数×頂点数 lis_namnak = fn_skin.getWeights(dagpath_mesh, compo, arr_index_influ) if (chai_bs): w_doem = [] # 元の重みの値を収めるリスト # このポリゴンに接続しているブレンドシェープのノードだけ取る lis_chue_nod_bs = [] for chue_nod_bs in mc.ls(typ='blendShape'): # これがこのブレンドシェープに接続しているポリゴンであるかどうかチェック if (pm.PyNode(chue_nod_shp).name() not in mc.blendShape(chue_nod_bs, query=True, geometry=True)): continue # 違ったらスキップ try: ww = mc.getAttr(chue_nod_bs + '.w[*]') # 元の重みを収めておく except: ww = [] # 空っぽのブレンドシェープのノードの場合、エラーが出る continue if (type(ww) == float): ww = [ww] # 一つしかない場合は返り値がリストにはならないので、全部リストにしておく w_doem.append(ww) mc.setAttr(chue_nod_bs + '.w[*]', *[0] * len(ww)) # まずは全部の重みを0にしておく lis_chue_nod_bs.append(chue_nod_bs) # このポリゴンの頂点の位置 selelis = om.MSelectionList() selelis.add(chue_nod_shp) fnmesh = om.MFnMesh(selelis.getDagPath(0)) lis_xyz_nai_poly = fnmesh.getPoints(space=om.MSpace.kWorld) lis_xyz.extend(lis_xyz_nai_poly) lis_n_chut_nai_na, lis_lek_xyz = fnmesh.getVertices() # 頂点の法線 lis_norm_nai_poly = fnmesh.getNormals(space=om.MSpace.kWorld) lis_norm.extend(lis_norm_nai_poly) lis_lek_norm = fnmesh.getNormalIds()[1] # 頂点のuv lis_u_nai_poly, lis_v_nai_poly = fnmesh.getUVs() lis_u.extend(lis_u_nai_poly) lis_v.extend(lis_v_nai_poly) lis_lek_uv = fnmesh.getAssignedUVs()[1] # その面に構成する三角形の数と頂点 lis_n_samliam_nai_na, lis_lek_xyz_nai_na = fnmesh.getTriangles() lai_lek_samliam_nai_na = 0 lis_chue_bs = [] if (chai_bs): lis_xyz_bs = [] # 移動した後の頂点の位置を収めるリスト lis_luean_bs = [] lis_luean_bs_ap = [] for i_bs, chue_nod_bs in enumerate(lis_chue_nod_bs): n_bs_nai_nod = len(w_doem[i_bs]) # そのノードにある全てのブレンドシェープ # 一つずつブレンドシェープを処理する for i, bs in enumerate( mc.listAttr(chue_nod_bs + '.w', multi=True)): # 他は全部0にしておいて、そのブレンドシェープ一つだけ1にする ww = [0] * n_bs_nai_nod ww[i] = 1 mc.setAttr(chue_nod_bs + '.w[*]', *ww) # 移動した後の頂点の位置 xyz_bs = fnmesh.getPoints(space=om.MSpace.kWorld) lis_xyz_bs.append(xyz_bs) lis_chue_bs.append(bs) luean_bs = [] lis_luean_bs.append(luean_bs) lis_luean_bs_ap.append(luean_bs.append) # 重みを元に戻す for i_bs, chue_nod_bs in enumerate(lis_chue_nod_bs): mc.setAttr(chue_nod_bs + '.w[*]', *w_doem[i_bs]) n_bs = len(lis_chue_bs) lis_lis_lek_chut_mai_nai_poly = [] i_chut = 0 for n_samliam_nai_na, n_chut_nai_na in zip(lis_n_samliam_nai_na, lis_n_chut_nai_na): # その面の三角形の数と、その面の頂点の数 dic_lai_lek = {} for j in range(n_chut_nai_na): lek_xyz = lis_lek_xyz[i_chut] lek_norm = lis_lek_norm[i_chut] lek_uv = lis_lek_uv[i_chut] tup_chut = (lek_xyz + lai_lek_xyz, lek_norm + lai_lek_norm, lek_uv + lai_lek_uv) if (tup_chut in dic_tup_chut): lek_chut_mai = dic_tup_chut[tup_chut] else: lek_chut_mai = lai_lek_chut dic_tup_chut[tup_chut] = lek_chut_mai # スキンと接続している場合、重みの値を取る bowe = mmdio.pmx.BoneWeight() if (chai_kraduk and chue_nod_skin): n_kho = len(dic_kho) # ジョイントの数 w = [] # [ノード名, 重み]リストを収めるリスト # 重みのリストから重みの値を取る。長さはn_kho for i_namnak, namnak in enumerate( lis_namnak[lek_xyz * n_kho:(lek_xyz + 1) * n_kho]): # 重みが小さすぎないジョイントの[ノード名, 重み]だけ取る if (namnak > 0.001): w.append([dic_kho[i_namnak], namnak]) if (len(w) > 3): # 4つ以上ある場合 if (len(w) > 4): # 4つだけ取る w.sort(key=f_riang_namnak, reverse=1) w = w[:4] w_ruam = w[0][1] + w[1][1] + w[2][1] + w[3][ 1] # この4の重みの足し算 ww0 = w[0][1] / w_ruam ww1 = w[1][1] / w_ruam ww2 = w[2][1] / w_ruam ww3 = w[3][1] / w_ruam bowe.bones = [w[0][0], w[1][0], w[2][0], w[3][0]] bowe.weights = [ww0, ww1, ww2, ww3] bowe.type = mmdio.pmx.BoneWeight.BDEF4 elif (len(w) == 3): w_ruam = w[0][1] + w[1][1] + w[2][1] ww0 = w[0][1] / w_ruam ww1 = w[1][1] / w_ruam ww2 = w[2][1] / w_ruam bowe.bones = [w[0][0], w[1][0], w[2][0], -1] bowe.weights = [ww0, ww1, ww2, 0.] bowe.type = mmdio.pmx.BoneWeight.BDEF4 elif (len(w) == 2): ww0 = w[0][1] / (w[0][1] + w[1][1]) bowe.bones = [w[0][0], w[1][0]] bowe.weights = [ww0] bowe.type = mmdio.pmx.BoneWeight.BDEF2 elif (len(w) == 1): bowe.bones = [w[0][0]] bowe.type = mmdio.pmx.BoneWeight.BDEF1 else: bowe.bones = [0] bowe.type = mmdio.pmx.BoneWeight.BDEF1 # スキンに接続していない場合は全部一番外のジョイントのノードに繋ぐ else: bowe.bones = [0] bowe.type = mmdio.pmx.BoneWeight.BDEF1 # 取得した頂点データからモデルの頂点のリストに追加 vtx = mmdio.pmx.Vertex() p = lis_xyz[lek_xyz + lai_lek_xyz] vtx.co = [ p[0] * satsuan_ok, p[1] * satsuan_ok, -p[2] * satsuan_ok ] nm = lis_norm[lek_norm + lai_lek_norm] vtx.normal = [nm[0], nm[1], -nm[2]] vtx.uv = [ lis_u[lek_uv + lai_lek_uv], 1. - lis_v[lek_uv + lai_lek_uv] ] vtx.weight = bowe vtx.edge_factor = 1. model_vtx_ap(vtx) # モデルの頂点のリストに追加 for i_bs in range(n_bs): p1 = lis_xyz_bs[i_bs][lek_xyz] po = [(p1[0] - p[0]) * satsuan_ok, (p1[1] - p[1]) * satsuan_ok, (p[2] - p1[2]) * satsuan_ok] # 位置の変更が起きる頂点だけ取る if (po[0]**2 + po[1]**2 + po[2]**2 > 0): vmoffset = mmdio.pmx.VertexMorphOffset() vmoffset.index = lai_lek_chut vmoffset.offset = po lis_luean_bs_ap[i_bs](vmoffset) lai_lek_chut += 1 dic_lai_lek[lek_xyz + lai_lek_xyz] = lek_chut_mai i_chut += 1 lis_lek_chut_mai_nai_samliam = [] for j in range(lai_lek_samliam_nai_na * 3, (lai_lek_samliam_nai_na + n_samliam_nai_na) * 3, 3): for jj in range(3): lek_xyz = lis_lek_xyz_nai_na[j + 2 - jj] lek_chut_mai = dic_lai_lek[lek_xyz + lai_lek_xyz] lis_lek_chut_mai_nai_samliam.append(lek_chut_mai) lai_lek_samliam_nai_na += n_samliam_nai_na lis_lis_lek_chut_mai_nai_poly.append(lis_lek_chut_mai_nai_samliam) # 準備しておいたブレンドシェープのデータからモーフを作成する if (chai_bs): for i_morph, (chue_bs, luean_bs) in enumerate(zip(lis_chue_bs, lis_luean_bs)): morph = mmdio.pmx.VertexMorph(name=chue_bs, name_e=chue_bs, category=4) morph.offsets = luean_bs model_morph_ap(morph) model_dis1_ap((1, i_morph)) lai_lek_xyz += len(lis_xyz_nai_poly) lai_lek_norm += len(lis_norm_nai_poly) lai_lek_uv += len(lis_u_nai_poly) lis_lis_lis_lek_chut_mai.append(lis_lis_lek_chut_mai_nai_poly) i_poly += 1 # 材質を使う場合 if (chai_watsadu): i_tex = 0 # テクスチャの番号 i_mat = 0 # 材質の番号 for chue_mat in mc.ls(materials=True): # sgと繋がっている材質だけ取る liscon = mc.listConnections(chue_mat + '.outColor') if (not liscon): continue # sgと繋がっていない材質はスキップ sg = liscon[0] lis_lek_na_nai_mat = mc.sets(sg, query=True) # この材質を使っている面のリスト if (not lis_lek_na_nai_mat): if (len(liscon) > 1): sg = liscon[1] lis_lek_na_nai_mat = mc.sets(sg, query=True) # 全然使われていない場合、この材質をスキップ if (not lis_lek_na_nai_mat): continue n_chut_nai_mat = 0 # この面の中の頂点の数 for na_nai_mat in lis_lek_na_nai_mat: if ('[' in na_nai_mat): # ただこのポリゴンの面の一部だけ材質が使われる場合 # ポリゴンの名前と、最初の面と最後の面の番号 chue_nod_poly, lek_na_roem, lek_na_chop = re.findall( r'(\w+).f\[(\d+):?(\d+)?]', na_nai_mat)[0] lek_na_roem = int(lek_na_roem) # 最初の面の番号 if (lek_na_chop == ''): # ただ一面しかない場合 lek_na_chop = lek_na_roem else: lek_na_chop = int(lek_na_chop) # 最後の面の番号 else: # このポリゴン全体がこの材質を使う場合 chue_nod_poly = mc.listRelatives(na_nai_mat, parent=True)[0] lek_na_roem = 0 lek_na_chop = mc.polyEvaluate(chue_nod_poly, face=True) - 1 # 選択されたポリゴンのリストの中にある場合、そのポリゴンの番号を取る if (chue_nod_poly in lis_chue_nod_poly): lek_nod_poly = lis_chue_nod_poly.index(chue_nod_poly) # このリストにない場合、無視する else: continue for lek_na in range(lek_na_roem, lek_na_chop + 1): # 頂点の番号をモデルの面のリストに追加する lis_lek_chut_nai_na = lis_lis_lis_lek_chut_mai[ lek_nod_poly][lek_na] for ii in range(0, len(lis_lek_chut_nai_na), 3): model_face_ap(lis_lek_chut_nai_na[ii:ii + 3]) n_chut_nai_mat += 3 # 選択されているポリゴンの中で使われていない材質は無視する if (n_chut_nai_mat == 0): continue if (mc.objExists(chue_mat + '.namae')): namae = mc.getAttr(chue_mat + '.namae') else: namae = '材質%d' % (i_mat + 1) # 材質を作成して、まずは初期値を与える mat = mmdio.pmx.Material() mat.name = namae mat.name_e = chue_mat mat.diffuse = [1, 1, 1, 1] mat.specular = [0, 0, 0, 0.5] mat.ambient = [0.5, 0.5, 0.5] mat.edge_color = [0, 0, 0, 1] mat.edge_size = 1 mat.texture = -1 mat.sphere_texture = -1 mat.sphere_texture_mode = 0 mat.is_shared_toon_texture = False mat.toon_texture = -1 mat.comment = '' mat.vertex_count = n_chut_nai_mat mat.is_double_sided = True # 普通に使えない材質の場合、エラーが出る try: nodetype = mc.nodeType(chue_mat) # 材質のシェーディングタイプ # テクスチャが使われるかどうかを調べる if (nodetype in ['standardSurface', 'aiStandardSurface']): chue_nod_tex = mc.listConnections(chue_mat + '.baseColor') else: # blinn、lambert、phongなど chue_nod_tex = mc.listConnections(chue_mat + '.color') # ファイルのテクスチャが使われている材質の場合 if (chue_nod_tex): if (mc.nodeType(chue_nod_tex[0]) == 'file'): chue_tem_file_tex = mc.getAttr( chue_nod_tex[0] + '.ftn') # このテクスチャのファイルの名前 # 既存のファイルの場合、これを使う if (chue_tem_file_tex in lis_chue_tex): mat.texture = lis_chue_tex.index(chue_tem_file_tex) # まだない場合、追加する else: lis_chue_tex.append(chue_tem_file_tex) texture = mmdio.pmx.Texture() texture.path = os.path.join(chue_tem_file_tex) # テクスチャのファイルをコピーすると選択しておいた場合 if (lok_tex): chue_tex = os.path.basename(chue_tem_file_tex) chue_tem_path_tex_mai = os.path.join( chue_path_file, chue_tex) shutil.copyfile(chue_tem_file_tex, chue_tem_path_tex_mai) texture.path = os.path.join( chue_tem_path_tex_mai) pmx_model.textures.append(texture) mat.texture = i_tex i_tex += 1 # テクスチャの番号を数え続ける else: print('注意:テクスチャ%sはファイルではないため無視されます' % chue_nod_tex[0]) dc = [1., 1., 1.] # テクスチャが使われていない材質の場合、拡散色の値を使う else: if (nodetype in ['standardSurface', 'aiStandardSurface']): dc = mc.getAttr(chue_mat + '.baseColor')[0] else: dc = mc.getAttr(chue_mat + '.color')[0] dc = [min(max(s, 0.), 1.) for s in dc] mat.diffuse[:3] = dc if (nodetype not in ['standardSurface', 'aiStandardSurface']): tran = sum( mc.getAttr(chue_mat + '.transparency')[0]) / 3 # 透明度は3色の平均値を使う mat.diffuse[3] = min(max(1 - tran, 0), 1.) mat.ambient = [ min(max(s, 0.), 1.) * d for s, d in zip( mc.getAttr(chue_mat + '.ambientColor')[0], dc) ] # blinnだけスペキュラを使う if (nodetype == 'blinn'): sr = min( max(mc.getAttr(chue_mat + '.specularRollOff'), 0.1), 1.) mat.specular[3] = round( math.pow(2, math.log(max(sr, 0.1), 0.75) - 1)) mat.specular[:3] = [ min(max(s, 0.), 1.) for s in mc.getAttr(chue_mat + '.specularColor')[0] ] # standardSurfaceの場合 else: opa = sum(mc.getAttr(chue_mat + '.opacity')[0]) / 3 # 不透明度は3色の平均値を使う mat.diffuse[3] = min(max(opa, 0.), 1.) mat.specular[:3] = [ min(max(s, 0.), 1.) for s in mc.getAttr(chue_mat + '.specularColor')[0] ] sr = max(mc.getAttr(chue_mat + '.specularRoughness'), 0.1) mat.specular[3] = round( math.pow(2, math.log(max(sr, 0.1), 0.75) - 1)) mat.ambient = [0, 0, 0] # standardSurfaceの場合にアンビアントがないので except: print('材質%sに問題が見つかったようです' % chue_mat) model_mat_ap(mat) # モデルの材質のリストに収める i_mat += 1 # 材質を使わないと選択した場合、全部同じ材質にする else: n_chut_nai_mat = 0 for lis_lis_lek_chut_nai_poly in lis_lis_lis_lek_chut_mai: for lis_lek_chut_nai_na in lis_lis_lek_chut_nai_poly: n_chut_nai_na = len(lis_lek_chut_nai_na) n_chut_nai_mat += n_chut_nai_na for i in range(0, n_chut_nai_na, 3): model_face_ap(lis_lek_chut_nai_na[i:i + 3]) mat = mmdio.pmx.Material() mat.name = '材質1' mat.name_e = '' mat.diffuse = [0.5, 0.5, 0.5, 1] mat.specular = [0.5, 0.5, 0.5, 0.5] mat.ambient = [0.25, 0.25, 0.25] mat.edge_color = [0, 0, 0, 1] mat.edge_size = 1 mat.texture = -1 mat.sphere_texture = -1 mat.sphere_texture_mode = 0 mat.is_shared_toon_texture = False mat.toon_texture = -1 mat.comment = '' mat.vertex_count = n_chut_nai_mat mat.is_double_sided = True model_mat_ap(mat) chue_model = os.path.basename(chue_tem_file).split('.')[0] pmx_model.name = chue_model pmx_model.name_e = chue_model if (not pmx_model.display[2].data): pmx_model.display.pop() mmdio.pmx.save(chue_tem_file, pmx_model) mc.select(lis_chue_nod_poly) print('"%s"へエクスポート完了。\n%.2f秒かかりました' % (chue_tem_file, time.time() - t0))