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 doIt(self, *args): # NOTE(fuzes): Here we only gather the data for the command and then call the reDoIt() method to do the rest of the job argDB = om2.MArgDatabase(self.syntax(), args[0]) if argDB.isFlagSet("-pn"): self._plugName = argDB.flagArgumentString("-pn", 0) if not self._plugName in _PER_VERTEX_ATTRIBUTE_NAMES: m_cmds.error("Invalid Plug Name") return else: m_cmds.error("plugName flag must be set") selList = argDB.getObjectList() mob = selList.getDependNode(0) self._nObjectMobHandle = om2.MObjectHandle(mob) if argDB.isFlagSet("-vw"): self._current_weights = om2.MDoubleArray() for i in xrange(argDB.numberOfFlagUses("-vw")): argList = argDB.getFlagArgumentList("-vw", i) self._current_weights.append(argList.asDouble(0)) else: m_cmds.error("vertexWeight flag must be set") self.redoIt()
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 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 makeCurvFromPoints(cvs_array, transform_fn=None): """ Generate a spline from an array of points. :param cvs_array: MPointArray to generate curve from. :param transform_fn: Optional argument for parenting curve under existing transform. :return: TransformFn, NurbsCurveFn """ knot_vector = om2.MDoubleArray() # calculate knot vector degree = 2 nspans = len(cvs_array) - degree nknots = nspans + 2 * degree - 1 for i in range(degree - 1): knot_vector.append(0.0) for j in range(nknots - (2 * degree) + 2): knot_vector.append(j) for k in range(degree - 1): knot_vector.append(j) # create curve if transform_fn is None: transform_fn = om2.MFnTransform() transform_fn.create() # transform_fn.setName('%s_input_curv' % name) curvFn = om2.MFnNurbsCurve() curvFn.create(cvs_array, knot_vector, degree, om2.MFnNurbsCurve.kOpen, False, True, transform_fn.object()) return transform_fn, curvFn
def add_keys(anim_curve, key_dict): # type: (unicode, dict) -> None """ Add keyframes to animation curve :param anim_curve: animation curve name :param key_dict: dictionary of keyframes in {frame_number (float): value (float)} format :return: None """ unit = om.MTime.uiUnit() nodeNattr = cmds.listConnections(anim_curve, d=True, s=False, p=True)[0] selList = om.MSelectionList() selList.add(nodeNattr) mplug = selList.getPlug(0) dArrTimes = om.MTimeArray() dArrVals = om.MDoubleArray() if 'rotate' in nodeNattr: for i in key_dict.keys(): dArrTimes.append(om.MTime(float(i), unit)) dArrVals.append(om.MAngle.uiToInternal(key_dict[i])) else: for i in key_dict.keys(): dArrTimes.append(om.MTime(float(i), unit)) dArrVals.append(key_dict[i]) crvFnc = oma.MFnAnimCurve(mplug) crvFnc.addKeys(dArrTimes, dArrVals, crvFnc.kTangentAuto, crvFnc.kTangentAuto)
def redoIt(self, *args): nMob = getNObjectMobFromMob(self._nObjectMobHandle.object()) if nMob.isNull(): m_cmds.error("Selection has no relationship with nObjects") return mfn_dep_nCloth = om2.MFnDependencyNode(nMob) plug = mfn_dep_nCloth.findPlug(self._plugName, False) dataHandle = plug.asMDataHandle() data = dataHandle.data() isDataNull = data.isNull() # NOTE(Fuzes): If the Data is Null we set it ourselves, else we work on the reference if isDataNull: newData = om2.MFnDoubleArrayData() mobData = newData.create(self._current_weights) dataHandle.setMObject(mobData) plug.setMDataHandle(dataHandle) self._needsUndo = True return else: doubleArrayData = om2.MFnDoubleArrayData(data) self._prev_weights = om2.MDoubleArray() for i, value in enumerate(self._current_weights): self._prev_weights.append(doubleArrayData[i]) doubleArrayData[i] = value self._needsUndo = True return
def setBlendWeights(self,weigth): #执行的权重 m_weigth = om.MDoubleArray(weigth) #撤销的权重 unWeights = self.fn_skin.getBlendWeights(self.path,self.comp) doIt = functools.partial(self.fn_skin.setBlendWeights,self.path,self.comp,m_weigth) undoIt = functools.partial(self.fn_skin.setBlendWeights,self.path,self.comp,unWeights) return cmcore.addCommand(doIt, undoIt)
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 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 setWeigths(self,inf,weigth): m_inf = om.MIntArray(inf) #执行的权重 m_weigth = om.MDoubleArray(weigth) #撤销的权重 unWeights = self.fn_skin.getWeights(self.path,self.comp,m_inf) doIt = functools.partial(self.fn_skin.setWeights,self.path,self.comp,m_inf,m_weigth) undoIt = functools.partial(self.fn_skin.setWeights,self.path,self.comp,m_inf,unWeights) return cmcore.addCommand(doIt, undoIt)
def __init__(self): super(AverageVertexWeightsCommand, self).__init__() self._index_arg = '' self._weight_arg = None self._skin_cluster_arg = '' self._skin_fn = None self._components = None self._influence_indices = None self._dag_path = OpenMaya.MDagPath() self._old_weights = OpenMaya.MDoubleArray()
def clearWeights(attribute): """Clear the deformer weights of the given attribute by assigning an empty array. This is much faster than iterating through all weights indices individually and removing them. :param attribute: The full path of the weights attribute which should get cleared. :type attribute: str """ sel = om2.MSelectionList() sel.add(attribute) plug = sel.getPlug(0) emptyArray = om2.MDoubleArray() dataFn = om2.MFnDoubleArrayData() obj = dataFn.create(emptyArray) plug.setMObject(obj)
def maya_api_addkeys(plugName, times, values): sel = OpenMaya.MSelectionList() sel.add(plugName) plug = sel.getPlug(0) animFn = OpenMayaAnim.MFnAnimCurve() animFn.create(plug, OpenMayaAnim.MFnAnimCurve.kAnimCurveTL) timeArray = OpenMaya.MTimeArray() valueArray = OpenMaya.MDoubleArray() for i in range(len(times)): timeArray.append(OpenMaya.MTime(times[i], OpenMaya.MTime.kSeconds)) valueArray.append(values[i]) animFn.addKeys(timeArray, valueArray)
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 applyShapeData(ctrlName, crvData, transOffset=(0, 0, 0), rotOffset=(0, 0, 0), scaleOffset=(1, 1, 1)): """ Applies the supplied curve data to the specified control. [Args]: ctrlName (string) - The name of the control to change crvData (string) - The point data to apply transOffset (int, int, int) - The translation offset to apply to the new crv data rotOffset (int, int, int) - The rotation offset to apply to the new crv data scaleOffset (int, int, int) - The scale offset to apply to the new crv data """ curveShapes = utils.getShapeNodes(ctrlName) ctrlMObj = api.getMObj(ctrlName) if curveShapes: for each in curveShapes: cmds.delete(each) for crvShape in crvData.keys(): nurbsCrv = om.MFnNurbsCurve() cvArray = om.MPointArray() for i, x in enumerate(crvData[crvShape]['CVs']): cvArray.append((x['x'], x['y'], x['z'])) cvArray[i] = (api.transformMPoint(cvArray[i], rot=rotOffset, trans=transOffset, scale=scaleOffset)) knotArray = om.MDoubleArray() for x in crvData[crvShape]['knots']: knotArray.append(x) degree = crvData[crvShape]['degree'] form = crvData[crvShape]['form'] nurbsCrv.create(cvArray, knotArray, degree, form, 0, 1, ctrlMObj) if 'color' in crvData[crvShape].keys(): utils.setColor(nurbsCrv.name(), color=crvData[crvShape]['color']) shapes = utils.getShapeNodes(ctrlName) for i, each in enumerate(shapes): cmds.rename(each, '{}Shape{}'.format(ctrlName, i + 1))
def doIt(self, *args): # NOTE(fuzes): Here we only gather the data for the command argDB = om2.MArgDatabase(self.syntax(), args[0]) if argDB.isFlagSet("-pn"): plugName = argDB.flagArgumentString("-pn", 0) if not plugName in _PER_VERTEX_ATTRIBUTE_NAMES: m_cmds.error("Invalid Plug Name") return else: m_cmds.error("plugName flag must be set") selList = argDB.getObjectList() mob = selList.getDependNode(0) nMob = getNObjectMobFromMob(mob) if nMob.isNull(): m_cmds.error("Selection has no relationship with nObjects") return mfn_dep_nCloth = om2.MFnDependencyNode(nMob) plug = mfn_dep_nCloth.findPlug(plugName, False) dataHandle = plug.asMDataHandle() data = dataHandle.data() isDataNull = data.isNull() result = om2.MDoubleArray() if isDataNull: self.clearResult() self.setResult(result) else: doubleArrayData = om2.MFnDoubleArrayData(data) result = doubleArrayData.array() self.clearResult() self.setResult(result)
def redoIt(self): self._dag_path, self._components = self._get_mesh() surrounding_weights = OpenMaya.MDoubleArray() surrounding_vertex_array = OpenMaya.MIntArray() influences_count = 0 influence = None vertex_iterator = OpenMaya.MItMeshVertex(self._dag_path, self._components) surrounding_vertex_array = vertex_iterator.getConnectedVertices() surrounding_components = OpenMaya.MFnSingleIndexedComponent().create( OpenMaya.MFn.kMeshVertComponent) OpenMaya.MFnSingleIndexedComponent(surrounding_components).addElements( surrounding_vertex_array) self._old_weights, influence = self._skin_fn.getWeights( self._dag_path, self._components) surrounding_weights, influence = self._skin_fn.getWeights( self._dag_path, surrounding_components) print(self._old_weights) print(surrounding_weights) print(influence)
def getShapeData(ctrlName, color=False): """ Gets the shape data of the control. [Args]: ctrlName (string) - The name of the control color (bool) - Toggles if the function will store the colour information [Returns]: crvData (string) - The point data of the control shape """ curveShapes = utils.getShapeNodes(ctrlName) crvData = {} for i, each in enumerate(curveShapes): crvData[i] = {} crvData[i]['CVs'] = [] crvData[i]['knots'] = [] nurbsCrv = api.getNurbsCurve(each) cvArray = om.MPointArray() knotArray = om.MDoubleArray() cvArray = nurbsCrv.cvPositions(om.MSpace.kObject) knotArray = nurbsCrv.knots() for cvNum in range(len(cvArray)): cv = { 'x': cvArray[cvNum].x, 'y': cvArray[cvNum].y, 'z': cvArray[cvNum].z } crvData[i]['CVs'].append(cv) crvData[i]['knots'].extend(knotArray) crvData[i]['degree'] = nurbsCrv.degree crvData[i]['form'] = nurbsCrv.form if color: crvData[i]['color'] = cmds.getAttr('{}.overrideColor'.format(each)) return crvData
def __simplify_weights(mesh, target, skin, start=None, end=None, steps=1): """ Sets each vertex to follow the single joint that produces the least difference in position over the given frame range :param mesh: :param target: :param skin: :param start: :param end: :param steps: :return: """ # Verify we have the right number of vertices numVerts = mesh.numVertices if target.numVertices != numVerts: raise RuntimeError("Target Mesh has a different vertex count") # Figure out the start and end range if start is None: start = mc.playbackOptions(minTime=True, query=True) if end is None: end = mc.playbackOptions(maxTime=True, query=True) start = int(math.floor(start)) end = int(math.ceil(end)) currentTime = mc.currentTime(query=True) same_mesh = mesh.fullPathName() == target.fullPathName() space = om.MSpace.kObject # Lets get the weights vertices = range(mesh.numVertices) influence_indexes, vertex_cmpt, weights = get_weights(mesh, skin, vertices) deltas = [0.0 for x in weights] stride = len(influence_indexes) # We'll calculate the pattern of the list before hand so we aren't calculating # it on every frame preweights = [] for i in range(stride): preweights.append([float(x == i) for x in range(stride)]) # Now go through the frame range for frame in range(start, end + 1, steps): logger.info('Processing frame %s', frame) mc.currentTime(frame) # If we have the same mesh, restore the default weights on each frame before we continue if same_mesh: skin.setWeights(mesh.dagPath(), vertex_cmpt, influence_indexes, weights) target_points = mesh.getPoints(space) # Set each vertex weight to full then measure the distance and add to the deltas for i in range(stride): skin.setWeights(mesh.dagPath(), vertex_cmpt, influence_indexes, om.MDoubleArray(preweights[i] * numVerts)) points = mesh.getPoints() for vtx, point in enumerate(points): # Then calculate the distance between the vertexes. tpoint = target_points[vtx] distance = math.sqrt(((point.x - tpoint.x)**2) + ((point.y - tpoint.y)**2) + ((point.z - tpoint.z)**2)) deltas[(vtx * stride) + i] += distance for vtx in vertices: vtx_deltas = deltas[vtx * stride:(vtx * stride) + stride] idx = min(enumerate(vtx_deltas), key=lambda x: x[1])[0] weights[vtx * stride:(vtx * stride) + stride] = preweights[idx] * numVerts skin.setWeights(mesh.dagPath(), vertex_cmpt, influence_indexes, weights) mc.currentTime(currentTime)
def doIt(self, args): # メッシュの取得 dagPath = om.MGlobal.getActiveSelectionList().getDagPath(0) meshFn = om.MFnMesh(dagPath) if meshFn is None: raise # 変換時間範囲の取得 startTime = oma.MAnimControl.animationStartTime() endTime = oma.MAnimControl.animationEndTime() numFrames = int((endTime - startTime).asUnits(om.MTime.uiUnit())) + 1 oma.MAnimControl.setCurrentTime(startTime) # 先頭フレームの形状(world座標系)をバインド姿勢として登録 points = meshFn.getPoints(om.MSpace.kWorld) numVertices = len(points) bindVertices = [] for p in points: bindVertices += [p.x, p.y, p.z] # 変換対象シェイプアニメーションの取得 time = om.MTime(startTime) animVertices = [] while time <= endTime: oma.MAnimControl.setCurrentTime(time) points = meshFn.getPoints(om.MSpace.kWorld) for p in points: animVertices += [p.x, p.y, p.z] time += 1 # ひとまず先頭フレームに移動 oma.MAnimControl.setCurrentTime(startTime) # SSDR本体 : 戻り値は平方根平均二乗誤差(RMSE) rmse = ssdr.build(self.numMinBones, self.numMaxInfluences, self.numMaxIterations, bindVertices, animVertices, numVertices, numFrames) # 推定されたボーン数 numBones = ssdr.getNumBones() om.MGlobal.displayInfo('RMSE = ' + str(rmse) + ', #Bones = ' + str(numBones)) # C++モジュール内部に格納されているスキンウェイトとボーンインデクスの情報を取得 # [頂点1のウェイト1, 頂点1のウェイト2, ..., 頂点2のウェイト1, ... , 頂点Nのウェイト1, ... , ] のような並び # ボーンインデクスも同じ並び skinningWeight = ssdr.getSkinningWeight() skinningIndex = ssdr.getSkinningIndex() # 複製されるメッシュの名前を適当に指定 newSkinName = 'SsdrMesh' # メッシュの複製 cmds.duplicate(meshFn.name(), returnRootsOnly=True, name=newSkinName) # 複製されたシェイプに紐付けるボーン群を生成 # # ボーンのリスト bones = [] for b in range(numBones): cmds.select(d=True) # ボーン名は適当な接頭辞+番号 bone = cmds.joint(name='SsdrBone{0}'.format(b + 1)) # ニュートラル状態(先頭フレーム)におけるボーンの姿勢をC++モジュールから取得 # 平行移動 t = ssdr.getBoneTranslation(b, 0) # 回転クォータニオン q = ssdr.getBoneRotation(b, 0) u = om.MQuaternion(q[0], q[1], q[2], q[3]) e = u.asEulerRotation() cmds.move(t[0], t[1], t[2], bone, relative=False) cmds.rotate(e.x, e.y, e.z, bone, relative=False) # リストに追加 bones.append(bone) # 複製メッシュとボーン群をグループ化 newGroup = cmds.group(newSkinName, bones, name='SsdrResult') # スキンクラスタの生成 ssdrRig = cmds.skinCluster(bones, newSkinName, maximumInfluences=self.numMaxInfluences, name='skinClusterSsdr')[0] # スキンクラスタとスキンメッシュの取得 skinNode = om.MGlobal.getSelectionListByName(ssdrRig).getDependNode(0) skinFn = oma.MFnSkinCluster(skinNode) meshPath = om.MGlobal.getSelectionListByName(newSkinName).getDagPath(0) # 全頂点を対象にスキニング情報を更新 indices = om.MIntArray(numVertices, 0) for i in xrange(len(indices)): indices[i] = i singleIndexedComp = om.MFnSingleIndexedComponent() vertexComp = singleIndexedComp.create(om.MFn.kMeshVertComponent) singleIndexedComp.addElements(indices) # インフルエンスオブジェクトの情報 infDags = skinFn.influenceObjects() numInfluences = len(infDags) infIndices = om.MIntArray(numInfluences, 0) for i in xrange(numInfluences): infIndices[i] = i # ウェイトの設定 weights = om.MDoubleArray(numVertices * numInfluences, 0) for v in xrange(numVertices): for i in xrange(self.numMaxInfluences): weights[v * numInfluences + skinningIndex[v * self.numMaxInfluences + i]] = skinningWeight[ v * self.numMaxInfluences + i] skinFn.setWeights(meshPath, vertexComp, infIndices, weights) # ボーンモーションを設定 startTime = cmds.playbackOptions(min=True, query=True) for f in range(numFrames): frame = startTime + f for b in range(numBones): t = ssdr.getBoneTranslation(b, f) q = ssdr.getBoneRotation(b, f) u = om.MQuaternion(q[0], q[1], q[2], q[3]) e = u.asEulerRotation() cmds.setKeyframe(bones[b], t=frame, at='tx', v=t[0]) cmds.setKeyframe(bones[b], t=frame, at='ty', v=t[1]) cmds.setKeyframe(bones[b], t=frame, at='tz', v=t[2]) cmds.setKeyframe(bones[b], t=frame, at='rx', v=math.degrees(e.x)) cmds.setKeyframe(bones[b], t=frame, at='ry', v=math.degrees(e.y)) cmds.setKeyframe(bones[b], t=frame, at='rz', v=math.degrees(e.z))
MFnAnimCurve = oma.MFnAnimCurve(connectedNode) newAnimCurve = 0 if newAnimCurve: MFnAnimCurve = oma.MFnAnimCurve() MFnAnimCurve.create(attributeMPlug, animCurveType) # set value MFnAnimCurve.setPreInfinityType(preInfinity) MFnAnimCurve.setPostInfinityType(postInfinity) MFnAnimCurve.setIsWeighted(weightedTangents) MTimeArray = om.MTimeArray() MDoubleValueList = om.MDoubleArray() for index in range(len(timeList)): MTimeArray.append(om.MTime(timeList[index]), om.MTime.uiUnit()) MDoubleValueList.append(valueList[index]) MFnAnimCurve.addKeys(MTimeArray, MDoubleValueList, 0, 0, 1) for index in range(len(timeList)): MFnAnimCurve.setInTangentType(index, inTangentTypeList[index]) MFnAnimCurve.setOutTangentType(index, outTangentTypeList[index]) inTangentAngle = om.MAngle(inTangentAngleList[index]) outTangentAngle = om.MAngle(outTangentAngleList[index]) MFnAnimCurve.setAngle(index, inTangentAngle, 1)
def set_nurbsCurve_data(node, curves_data, world_space=False): """Set the nurbsCurve shapes' data on `node`. Parameters ---------- node : maya.api.OpenMaya.MObject A DAG node in the scene curves_data : list List of nurbsCurve data world_space : bool If True, assign the nurbsCurve data in world space. Otherwise, assign the data local to the node. """ dagMod = OpenMaya.MDagModifier() number_of_curves = len(curves_data) curves = [ obj for obj in iter_shapes(node) if obj.hasFn(OpenMaya.MFn.kNurbsCurve) ] excess = len(curves) - number_of_curves if excess > 0: for i in range(excess): obj = curves.pop(-1) dagMod.deleteNode(obj) elif excess < 0: for i in range(-excess): obj = dagMod.createNode('nurbsCurve', node) curves.append(obj) dagMod.doIt() for data, curve in zip(curves_data, curves): curve_fn = OpenMaya.MFnNurbsCurve() curveData_fn = OpenMaya.MFnNurbsCurveData() curveData_obj = curveData_fn.create() if world_space: wm = get_world_matrix(curve) else: wm = OpenMaya.MMatrix(data['worldMatrix']) wim = wm.inverse() cvs = [OpenMaya.MPoint(p) * wim for p in data['cvs']] knots = OpenMaya.MDoubleArray(data['knots']) curve_fn.create(cvs, knots, data['degree'], data['form'], False, True, curveData_obj) create_plug = OpenMaya.MFnDagNode(curve).findPlug('create', True) if is_locked_or_connected(create_plug): raise ValueError() create_plug.setMObject(curveData_obj) return dagMod
selection = mc.ls(sl=True) mMatrixArray = ompy.MMatrixArray() for elem in selection: matrixNumTmp = mc.xform(elem, q=True, matrix=True, ws=True) mMatrix = ompy.MMatrix(matrixNumTmp) mMatrixArray.append(mMatrix) #GET POINT FROM MATRIX positions = ompy.MPointArray() for i in range(0, len(mMatrixArray)): mTrs = ompy.MTransformationMatrix(mMatrixArray[i]) mVector = mTrs.translation(ompy.MSpace.kWorld) mPoint = ompy.MPoint(mVector.x, mVector.y, mVector.z) positions.append(mPoint) #GET Knot nbrKnot = len(positions) + degree - 1 knotsValues = ompy.MDoubleArray() for i in range(0, 3): knotsValues.append(0.0) for i in range(1, nbrKnot - 5): knotsValues.append(i / (nbrKnot - 5.0)) for i in range(nbrKnot - 3, nbrKnot): knotsValues.append(1.0) for i in range(0, len(knotsValues)): print(knotsValues[i]) #FILL ATTR curve = ompy.MFnNurbsCurve() cvs = positions knots = knotsValues form = curve.kOpen
def sang(chue_tem_file, satsuan=1, yaek_poly=False, ao_bs=True, ao_kraduk=True, watsadu=1): t_roem = time.time() # 開始 print('モデルインポート開始') sakun = os.path.splitext(chue_tem_file)[1] # 拡張子 try: if (sakun == '.pmx'): pmx_model = mmdio.pmx.load(chue_tem_file) elif (sakun == '.pmd'): pmx_model = mmdio.pmd.load2pmx(chue_tem_file) elif (sakun == '.x'): pmx_model = mmdio.xxx.load2pmx(chue_tem_file) else: print('pmxとpmdとxファイルしか使用できません') raise except: print('モデルに何か問題があって、ファイルの読み込みは失敗です') raise chue_nod_model = romaji(pmx_model.name) # モデルの名前をロマジに変換してモデルのノードの名前にする if (not chue_nod_model or set(chue_nod_model) == {'_'}): chue_nod_model = os.path.basename(chue_tem_file).split('.')[1] lis_chue_nod_kho_nok = [] # 一番外のジョイントのノードの名前を収めるリスト chue_nod_skin = None chue_nod_bs = None # その名前のノードがすでに存在している場合'_'を追加する while (mc.objExists(chue_nod_model)): chue_nod_model += '_' print('ポリゴン作成') if (yaek_poly): # ポリゴンを分割する場合、今まだ何もしなくていい lis_chue_nod_poly_mat = [] else: # pmxモデルから頂点の位置とuv一つずつ入れていく lis_xyz = [] # 頂点の位置を収めるリスト lis_u = [] # 頂点のuvを収めるリスト lis_v = [] lis_norm = [] # 頂点の法線を収めるリスト for vtx in pmx_model.vertices: try: lis_xyz.append( om.MFloatPoint(vtx.co[0] * satsuan, vtx.co[1] * satsuan, -vtx.co[2] * satsuan)) except: # 大きすぎたりとエラーが出る場合もあるので、(0,0,0)にする lis_xyz.append(om.MFloatPoint(0, 0, 0)) lis_u.append(vtx.uv[0]) # 頂点のuvをリストに収める lis_v.append(1. - vtx.uv[1]) if (vtx.normal): # 頂点の法線のデータがあった場合 lis_norm.append( om.MFloatVector(vtx.normal[0], vtx.normal[1], -vtx.normal[2])) lis_index_chut = [] # この面に使う頂点を収めるリスト lis_n_chut_nai_na = [] # この面に使う頂点の数を収めるリスト lis_na_ni_chai_mai = [] # この面が使うかどうかという情報を収めるリスト for i_chut_nai_na in pmx_model.faces: i_chut_nai_na = list(dict.fromkeys(i_chut_nai_na)) # この面に使う頂点 n_chut_nai_na = len(i_chut_nai_na) # この面に使う頂点の数 if (n_chut_nai_na >= 3): # 重複しない頂点が3以上ある場合のみ、この面を使う lis_index_chut.extend(i_chut_nai_na) lis_n_chut_nai_na.append(n_chut_nai_na) lis_na_ni_chai_mai.append(True) # この面を使う else: lis_na_ni_chai_mai.append(False) # この面を使わない chue_nod_poly = sang_poly(chue_nod_model, lis_xyz, lis_index_chut, lis_n_chut_nai_na, lis_u, lis_v, lis_norm) if (not watsadu): # 材質を使わないと選択したら全部ただのlambertにする mc.select(chue_nod_poly) mc.hyperShade(assign='lambert1') set_index_tex = set([mat.texture for mat in pmx_model.materials]) lis_chue_nod_file = [] # テクスチャファイルの名前を収めるリスト # テクスチャを作成する for i, tex in enumerate(pmx_model.textures): path_tem_tex = tex.path chue_tex = os.path.basename(path_tem_tex) # テクスチャの名前 chue_tex = re.sub(r'\W', '_', chue_tex) chue_tex = romaji(chue_tex) # テクスチャの名前をロマジにする chue_nod_file = chue_tex + '_file_' + chue_nod_model # 使われているテクスチャだけshadingNodeのノードを作る if (i in set_index_tex): # 同じ名前が既存である場合、ノードの名前が自動的に変更される chue_nod_file = mc.shadingNode('file', asTexture=True, name=chue_nod_file) mc.setAttr(chue_nod_file + '.ftn', path_tem_tex, typ='string') # place2dのノードを作る chue_nod_placed2d = mc.shadingNode('place2dTexture', asUtility=True, name=chue_tex + '_placed2d_' + chue_nod_model) # place2dノードの値とファイルノードの値を接続する for cp in chueam_placed2d: mc.connectAttr('%s.%s' % (chue_nod_placed2d, cp[0]), '%s.%s' % (chue_nod_file, cp[1]), force=1) lis_chue_nod_file.append(chue_nod_file) # 材質を作成する nap_na_nai_mat = 0 # すでに材質を付けた面の数 for i_mat, mat in enumerate(pmx_model.materials): if (mat.vertex_count == 0): # 面一つもないならスキップ continue n_na_nai_mat = int(mat.vertex_count / 3) # この材質を付ける面の数 chue_mat = romaji(mat.name) chue_nod_mat = chue_mat + '_mat_' + chue_nod_model i_tex = mat.texture # この材質に付けるテクスチャの番号 dc = mat.diffuse[:3] # 拡散色 ambc = mat.ambient # 環境色 spec = mat.specular[:3] # 反射色 alpha = mat.diffuse[3] # 不透明度 opa = [alpha, alpha, alpha] trans = [1 - alpha, 1 - alpha, 1 - alpha] # 透明度 sf = mat.specular[3] # 反射強度 if (watsadu == 1): chue_nod_mat = mc.shadingNode('blinn', asShader=True, name=chue_nod_mat) mc.setAttr(chue_nod_mat + '.specularColor', *spec, typ='double3') mc.setAttr(chue_nod_mat + '.specularRollOff', min(0.75**(math.log(max(sf, 2**-10), 2) + 1), 1)) mc.setAttr(chue_nod_mat + '.eccentricity', sf * 0.01) elif (watsadu == 2): chue_nod_mat = mc.shadingNode('phong', asShader=1, n=chue_nod_mat) mc.setAttr(chue_nod_mat + '.specularColor', *spec, typ='double3') mc.setAttr(chue_nod_mat + '.cosinePower', max((10000. / max(sf, 15)**2 - 3.357) / 0.454, 2)) elif (watsadu == 3 or not watsadu): chue_nod_mat = mc.shadingNode('lambert', asShader=1, name=chue_nod_mat) if (watsadu in [1, 2, 3]): mc.setAttr(chue_nod_mat + '.color', *dc, typ='double3') mc.setAttr(chue_nod_mat + '.ambientColor', *ambc, typ='double3') mc.setAttr(chue_nod_mat + '.transparency', *trans, typ='double3') elif (watsadu == 4): # arnoldを使う場合 chue_nod_mat = mc.shadingNode('standardSurface', asShader=True, name=chue_nod_mat) mc.setAttr(chue_nod_mat + '.baseColor', *dc, typ='double3') mc.setAttr(chue_nod_mat + '.specularColor', *spec, typ='double3') mc.setAttr(chue_nod_mat + '.opacity', *opa, typ='double3') mc.setAttr(chue_nod_mat + '.specular', 0.75**(math.log(max(sf, 0.5), 2) + 1)) mc.setAttr(chue_nod_mat + '.specularRoughness', min(sf * 0.01, 1)) mc.setAttr(chue_nod_mat + '.base', 1) # 日本語の名前も一応収めておく mc.addAttr(chue_nod_mat, longName='namae', niceName='名前', dataType='string') mc.setAttr(chue_nod_mat + '.namae', mat.name, typ='string') if (i_tex >= 0): chue_nod_file = lis_chue_nod_file[i_tex] if (watsadu != 4): mc.connectAttr(chue_nod_file + '.outColor', chue_nod_mat + '.color') else: mc.connectAttr(chue_nod_file + '.outColor', chue_nod_mat + '.baseColor') tex = pmx_model.textures[i_tex] if (mc.getAttr(chue_nod_file + '.fileHasAlpha') and tex.path[-3:].lower() in ['png', 'tga', 'dds', 'bmp']): # テクスチャノードのアルファを材質ノードに接続する if (watsadu in [1, 2, 3]): mc.connectAttr(chue_nod_file + '.outTransparency', chue_nod_mat + '.transparency') elif (watsadu == 4): mc.connectAttr(chue_nod_file + '.outAlpha', chue_nod_mat + '.opacityR') mc.connectAttr(chue_nod_file + '.outAlpha', chue_nod_mat + '.opacityG') mc.connectAttr(chue_nod_file + '.outAlpha', chue_nod_mat + '.opacityB') chue_nod_sg = mc.sets(renderable=1, noSurfaceShader=1, empty=1, name=chue_nod_mat + 'SG') mc.connectAttr(chue_nod_mat + '.outColor', chue_nod_sg + '.surfaceShader', force=True) if (yaek_poly): lis_index_chut_mat = [] lis_n_chut_nai_na_nai_mat = [] dic_chut = {} k = 0 for i_chut_nai_na in pmx_model.faces[ nap_na_nai_mat:nap_na_nai_mat + n_na_nai_mat]: i_chut_nai_na = list(dict.fromkeys(i_chut_nai_na)) n_chut_nai_na = len(i_chut_nai_na) if (n_chut_nai_na >= 3): for j in range(n_chut_nai_na): if (i_chut_nai_na[j] not in dic_chut): dic_chut[i_chut_nai_na[j]] = k # 元の番号と新しい番号を繋ぐ辞書 k += 1 lis_index_chut_mat.append(dic_chut[i_chut_nai_na[j]]) lis_n_chut_nai_na_nai_mat.append(n_chut_nai_na) lis_xyz_mat = [] lis_u_mat = [] lis_v_mat = [] lis_norm_mat = [] for ic in dic_chut: k = dic_chut[ic] vtx = pmx_model.vertices[ic] try: lis_xyz_mat.append( om.MFloatPoint(vtx.co[0] * satsuan, vtx.co[1] * satsuan, -vtx.co[2] * satsuan)) except: lis_xyz_mat.append(om.MFloatPoint(0, 0, 0)) lis_u_mat.append(vtx.uv[0]) lis_v_mat.append(1. - vtx.uv[1]) lis_norm_mat.append( om.MFloatVector(vtx.normal[0], vtx.normal[1], -vtx.normal[2])) # この材質のポリゴンを作成する chue_nod_poly_mat = sang_poly(chue_nod_model + '_%d' % (i_mat + 1), lis_xyz_mat, lis_index_chut_mat, lis_n_chut_nai_na_nai_mat, lis_u_mat, lis_v_mat, lis_norm_mat) n_na_chai_mat = len(lis_n_chut_nai_na_nai_mat) # 実際に使う面の数 mc.sets(chue_nod_poly_mat + '.f[%s:%s]' % (0, n_na_chai_mat - 1), forceElement=chue_nod_sg) lis_chue_nod_poly_mat.append(chue_nod_poly_mat) else: nap_na_chai0 = sum(lis_na_ni_chai_mai[:nap_na_nai_mat]) nap_na_chai1 = sum(lis_na_ni_chai_mai[:nap_na_nai_mat + n_na_nai_mat]) # 指定の面に材質を貼る mc.sets(chue_nod_poly + '.f[%s:%s]' % (nap_na_chai0, nap_na_chai1 - 1), forceElement=chue_nod_sg) nap_na_nai_mat += n_na_nai_mat # 面の数を数え続ける if (yaek_poly): chue_nod_poly = mc.group(lis_chue_nod_poly_mat, name=chue_nod_model) if (ao_bs and not yaek_poly): print('ブレンドシェープ作成') # 各パネル(眉、目、口、他) lis_chue_nod_poly_bs = [[], [], [], []] # ブレンドシェープを作るためのポリゴンのノードのリストを収める lis_chue_bs_doem = [[], [], [], []] # 元の名前(日本の名前)を収めるリスト for i, mo in enumerate(pmx_model.morphs): # 頂点モーフをブレンドシェープに変換する。他のモーフは変換できないので無視する if (mo.type_index() == 1): # ブレンドシェープの名前はロマジに変換しなければならない chue_bs = romaji(mo.name) # ブレンドシェープを作るために、元のポリゴンをコピーする chue_nod_poly_bs = mc.duplicate(chue_nod_poly, name=chue_bs)[0] selelis = om.MSelectionList() selelis.add(chue_nod_poly_bs) dagpath = selelis.getDagPath(0) fn_mesh = om.MFnMesh(dagpath) arr_chut = fn_mesh.getPoints() # 頂点の位置が入っている配列 for off in mo.offsets: vi = off.index # 動く頂点の番号 d = off.offset # 元の位置から動く距離 p = arr_chut[vi] # 元の頂点のいち arr_chut[vi] = [ p[0] + d[0] * satsuan, p[1] + d[1] * satsuan, p[2] - d[2] * satsuan ] # 頂点が動いた後の位置を配列に入れる fn_mesh.setPoints(arr_chut) lis_chue_nod_poly_bs[mo.category - 1].append(chue_nod_poly_bs) lis_chue_bs_doem[mo.category - 1].append(mo.name) # 一つのリストにする。順番はパネルによる lis_chue_nod_poly_bs = list(itertools.chain(*lis_chue_nod_poly_bs)) mc.select(lis_chue_nod_poly_bs, chue_nod_poly) # ブレンドシェープのノードを作成する chue_nod_bs = mc.blendShape(name='bs_' + chue_nod_poly)[0] mc.delete(lis_chue_nod_poly_bs) # すでにブレンドシェープを作るために使ったポリゴンは用済みだから消す if (ao_kraduk and not yaek_poly): print('ジョイント作成') lis_chue_nod_kho = [] # ジョイントの名前を収めるリスト for b in pmx_model.bones: mc.select(deselect=1) chue_kho = romaji(b.name) loc = b.location # ジョイントの位置 # ジョイントの半径 if ('yubi' in chue_kho): # 指は小さめ r_kho = satsuan / 4 elif (chue_kho == 'sentaa'): # サンターは大きめ r_kho = satsuan else: # その他 r_kho = satsuan / 2 # ジョイントのノードを作成する chue_nod_kho = mc.joint(position=[ loc[0] * satsuan, loc[1] * satsuan, -loc[2] * satsuan ], radius=r_kho, name=chue_nod_poly + '_' + chue_kho) mc.addAttr(chue_nod_kho, longName='namae', niceName='名前', dataType='string') # 日本語の名前も一応ここに収めておく mc.setAttr(chue_nod_kho + '.namae', b.name, typ='string') if (b.isIK or not b.visible): # 表示しないジョイント mc.setAttr(chue_nod_kho + '.drawStyle', 2) else: mc.setAttr(chue_nod_kho + '.drawStyle', 0) # ローカル軸が指定されている場合 if (b.localCoordinate or b.axis): if (b.axis): # x軸だけが指定されている場合 kaen_x = b.axis kaen_z = cross([0.0, 1.0, 0.0], kaen_x) else: # x軸もz軸も指定されている場合 kaen_x = b.localCoordinate.x_axis kaen_z = b.localCoordinate.z_axis kaen_y = cross(kaen_z, kaen_x) # ジョイントの方向を表すオイラー角に変換するための行列 matrix_mun = om.MMatrix([ 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. ]) mum_euler = om.MTransformationMatrix(matrix_mun).rotation() # できたオイラー角の単位がラジアンなので角度に変換する ox = math.degrees(mum_euler.x) oy = math.degrees(mum_euler.y) oz = math.degrees(mum_euler.z) mc.setAttr(chue_nod_kho + '.jointOrient', ox, oy, oz) # ジョイントの方向 lis_chue_nod_kho.append(chue_nod_kho) for i, b in enumerate(pmx_model.bones): chue_nod_kho = lis_chue_nod_kho[i] if (b.parent >= 0): # ジョイントを結び合う chue_nod_parent = lis_chue_nod_kho[b.parent] mc.connectJoint(chue_nod_kho, chue_nod_parent, parentMode=1) else: lis_chue_nod_kho_nok.append(chue_nod_kho) # 回転角の不具合がある場合の解決 if (round(mc.getAttr(chue_nod_kho + '.rx')) % 360 == 0): mc.setAttr(chue_nod_kho + '.rx', 0) if (round(mc.getAttr(chue_nod_kho + '.ry')) % 360 == 0): mc.setAttr(chue_nod_kho + '.ry', 0) if (round(mc.getAttr(chue_nod_kho + '.rz')) % 360 == 0): 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 + '.r', 0, 0, 0) if (b.hasAdditionalRotate): # 回転付与のあるジョイントの場合 chue_nod_effect = lis_chue_nod_kho[ b.additionalTransform[0]] # 影響を与えるノード jo = mc.getAttr(chue_nod_effect + '.jointOrient')[0] # このジョイントの方向を取得 mc.setAttr(chue_nod_kho + '.jointOrient', *jo) # 同じジョイントの方向にする # 回転付与をエクスプレッションにする ef = b.additionalTransform[1] # 付与率 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(string=s, name='expression_%s_%s' % (chue_nod_kho, chue_nod_effect)) if (b.hasAdditionalLocation): # 移動付与をエクスプレッションにする chue_nod_effect = lis_chue_nod_kho[ b.additionalTransform[0]] # 影響を与えるノード ef = b.additionalTransform[1] # 付与率 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(string=s, name='expression_%s_%s' % (chue_nod_kho, chue_nod_effect)) selelis = om.MSelectionList() selelis.add(chue_nod_poly) dagpath_mesh = selelis.getDagPath(0) chue_nod_skin = 'skin_' + chue_nod_poly chue_nod_skin = mc.skinCluster(lis_chue_nod_kho, chue_nod_poly, maximumInfluences=4, toSelectedBones=True, name=chue_nod_skin)[0] # スキンのノードを作成する selelis = om.MSelectionList() selelis.add(chue_nod_skin) obj_skin = selelis.getDependNode(0) fn_skin = oma.MFnSkinCluster(obj_skin) n_kho = len(pmx_model.bones) lis_namnak = [] # 重みの値を収めるリスト for vtx in pmx_model.vertices: namnak = [0.] * n_kho # この頂点に対する各ジョイントの影響の重み if (vtx.weight.type == mmdio.pmx.BoneWeight.BDEF1): # 2つだけのジョイントの影響を受ける場合 namnak[vtx.weight.bones[0]] = 1. elif (vtx.weight.type == mmdio.pmx.BoneWeight.BDEF2): # 2つのジョイントの影響を受ける場合 namnak[vtx.weight.bones[0]] += vtx.weight.weights[0] namnak[vtx.weight.bones[1]] += 1. - vtx.weight.weights[0] elif (vtx.weight.type == mmdio.pmx.BoneWeight.SDEF): # SDEFの場合もBDEF2と同様に2つのジョイント扱い namnak[vtx.weight.bones[0]] += vtx.weight.weights.weight namnak[vtx.weight.bones[1]] += 1. - vtx.weight.weights.weight elif (vtx.weight.type == mmdio.pmx.BoneWeight.BDEF4): # 4つのジョイントの影響を受ける場合 namnak[vtx.weight.bones[0]] += vtx.weight.weights[0] namnak[vtx.weight.bones[1]] += vtx.weight.weights[1] namnak[vtx.weight.bones[2]] += vtx.weight.weights[2] namnak[vtx.weight.bones[3]] += 1. - vtx.weight.weights[ 0] - vtx.weight.weights[1] - vtx.weight.weights[2] lis_namnak.extend(namnak) n_chut = len(pmx_model.vertices) # 頂点の数 arr_index_chut = om.MIntArray(range(n_chut)) # 頂点の番号の配列 arr_namnak = om.MDoubleArray(lis_namnak) # 重みの値の配列 arr_index_influ = om.MIntArray(range(n_kho)) # ジョイントの番号の配列 fn_compo = om.MFnSingleIndexedComponent() compo = fn_compo.create(om.MFn.kMeshVertComponent) fn_compo.addElements(arr_index_chut) # ポリゴンに対するそれぞれのジョウントの影響の重みの値を設置する fn_skin.setWeights(dagpath_mesh, compo, arr_index_influ, arr_namnak, 1) for chue_nod_kho in lis_chue_nod_kho: if (chue_nod_kho not in lis_chue_nod_kho_nok): mc.rename(chue_nod_kho, chue_nod_kho.replace(chue_nod_poly + '_', '')) # 日本語の名前も一応収めておく mc.addAttr(chue_nod_poly, longName='namae', niceName='名前', dataType='string') mc.setAttr(chue_nod_poly + '.namae', pmx_model.name, typ='string') mc.select(chue_nod_poly) if (ao_kraduk): mc.select(lis_chue_nod_kho_nok) try: mc.setAttr('hardwareRenderingGlobals.transparencyAlgorithm', 3) mc.setAttr('defaultArnoldRenderOptions.autotx', 0) mc.setAttr('defaultArnoldRenderOptions.use_existing_tiled_textures', 0) except: 0 print('モデルインポート完了。%.2f秒かかりました' % (time.time() - t_roem)) return chue_nod_poly, lis_chue_nod_kho_nok, chue_nod_skin, chue_nod_bs
#检查组件列表的数量 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) cmcore.addCommand(doIt, undoIt) fl_array = fn_skin.getBlendWeights(path,comp) fn_skin.setBlendWeights(path,comp,fl_array) class SetWeights: ''' 操作蒙皮权重的类 setWeigths(self,inf,weigth)#设置蒙皮权重