def doSimpleSolver(self): """ Solve single joint in the x-y plane - first it calculates the angle between the handle and the end-effector. - then it determines which way to rotate the joint. """ handle_group = self.handleGroup() handle = handle_group.handle(0) handlePath = OpenMaya.MDagPath.getAPathTo(handle) fnHandle = OpenMayaAnim.MFnIkHandle(handlePath) # Get the position of the end_effector end_effector = OpenMaya.MDagPath() fnHandle.getEffector(end_effector) tran = OpenMaya.MFnTransform(end_effector) effector_position = tran.rotatePivot(OpenMaya.MSpace.kWorld) # Get the position of the handle handle_position = fnHandle.rotatePivot(OpenMaya.MSpace.kWorld) # Get the start joint position start_joint = OpenMaya.MDagPath() fnHandle.getStartJoint(start_joint) start_transform = OpenMaya.MFnTransform(start_joint) start_position = start_transform.rotatePivot(OpenMaya.MSpace.kWorld) # Calculate the rotation angle v1 = start_position - effector_position v2 = start_position - handle_position angle = v1.angle(v2) # -------- Figure out which way to rotate -------- # # define two vectors U and V as follows # U = EndEffector(E) - StartJoint(S) # N = Normal to U passing through EndEffector # # Clip handle_position to half-plane U to determine the region it # lies in. Use the region to determine the rotation direction. # # U # ^ Region Rotation # | B # (E)---N A C-C-W # A | B C-W # | B # | # (S) # rot = 0.0 # Rotation about Z-axis # U and N define a half-plane to clip the handle against U = effector_position - start_position U.normalize() # Get a normal to U zAxis = OpenMaya.MVector(0.0, 0.0, 1.0) N = U ^ zAxis # Cross product N.normalize() # P is the handle position vector P = handle_position - effector_position # Determine the rotation direction PdotN = P[0] * N[0] + P[1] * N[1] if PdotN < 0: rot = angle # counter-clockwise else: rot = -1.0 * angle # clockwise # get and set the Joint Angles jointAngles = OpenMaya.MDoubleArray() try: self._getJointAngles(jointAngles) except: # getting angles failed, do nothing pass else: jointAngles.set(jointAngles[0] + rot, 0) self._setJointAngles(jointAngles)
def set_blend_weights(self, dag_path, components): blend_weights = om.MDoubleArray(len(self.data['blendWeights'])) for i, w in enumerate(self.data['blendWeights']): blend_weights.set(w, i) self.fn.setBlendWeights(dag_path, components, blend_weights)
def addParticlePosToScatter(operation, toleranceForRemove): sel = mom.MSelectionList() mom.MGlobal.getActiveSelectionList(sel) scatterDag = mom.MDagPath() ##clear scatter data if (operation == 3) and (sel.length() == 1): sel.getDagPath(0, scatterDag) scatterDag.extendToShape() dgFn = mom.MFnDependencyNode(scatterDag.node()) sctModePlug = dgFn.findPlug('scatterMode') sctMd = sctModePlug.asShort() mom.MGlobal.displayInfo('JCFeather : Scatter operate on node ' + dgFn.name()) mom.MGlobal.displayInfo('JCFeather : Clear scatter user point array.') if sctMd == 1: clearJCScatterUserData(scatterDag) elif sctMd == 2: clearJCScatterInPosition(scatterDag) return if sel.length() != 2: mom.MGlobal.displayError( 'JCFeather : Select a particle and a jcScatter node.') particleDag = mom.MDagPath() particleComponent = mom.MObject() sel.getDagPath(0, particleDag, particleComponent) sel.getDagPath(1, scatterDag) scatterDag.extendToShape() dgFn = mom.MFnDependencyNode(scatterDag.node()) growMeshPlug = dgFn.findPlug('inGrowMesh') sctModePlug = dgFn.findPlug('scatterMode') sctMd = sctModePlug.asShort() plugArray = mom.MPlugArray() growMeshPlug.connectedTo(plugArray, 1, 0) if plugArray.length() == 0: return mom.MGlobal.displayInfo('JCFeather : Scatter operate on node ' + dgFn.name()) if sctMd == 1: ############################################## if the jcScatter is in UV scatter mode mom.MGlobal.displayInfo('JCFeather : Scatter UV mode.') uAryPlug = dgFn.findPlug('userUArray') vAryPlug = dgFn.findPlug('userVArray') uArray = mom.MDoubleArray() vArray = mom.MDoubleArray() if (getParticleClosestUVOnMesh(particleDag, particleComponent, plugArray[0].node(), uArray, vArray) == 0): return mom.MGlobal.displayInfo('JCFeather : Select particle data size ' + str(uArray.length())) if operation == 1: ###################################### replace uDDFn = mom.MFnDoubleArrayData() vDDFn = mom.MFnDoubleArrayData() uAryPlug.setMObject(uDDFn.create(uArray)) vAryPlug.setMObject(vDDFn.create(vArray)) mom.MGlobal.displayInfo( 'JCFeather : Replace scatter userUVArray data.') elif operation == 0: ###################################### add defaultVecArray = mom.MDoubleArray() try: uDDFn = mom.MFnDoubleArrayData(uAryPlug.asMObject()) except: uDDFn = mom.MFnDoubleArrayData() uAryPlug.setMObject(uDDFn.create(defaultVecArray)) try: vDDFn = mom.MFnDoubleArrayData(vAryPlug.asMObject()) except: vDDFn = mom.MFnDoubleArrayData() vAryPlug.setMObject(vDDFn.create(defaultVecArray)) oldUArray = uDDFn.array() oldVArray = vDDFn.array() oldLen = oldUArray.length() addNewUvToUV(oldUArray, oldVArray, uArray, vArray, toleranceForRemove) uAryPlug.setMObject(uDDFn.object()) vAryPlug.setMObject(vDDFn.object()) mom.MGlobal.displayInfo( 'JCFeather : Add scatter userUVArray data. ' + str(oldLen) + ' --> ' + str(oldUArray.length())) elif operation == 2: ###################################### remove try: uDDFn = mom.MFnDoubleArrayData(uAryPlug.asMObject()) except: mom.MGlobal.displayError( "JCFeather : No userUArray data to remove.") try: vDDFn = mom.MFnDoubleArrayData(vAryPlug.asMObject()) except: mom.MGlobal.displayError( "JCFeather : No userVArray data to remove.") oldUArray = uDDFn.array() oldVArray = vDDFn.array() newULen = uArray.length() oldULen = oldUArray.length() resultU = mom.MDoubleArray() resultV = mom.MDoubleArray() for j in range(0, oldUArray.length()): for i in range(0, newULen): if isDistanceSmaller(oldUArray[j], oldVArray[j], uArray[i], vArray[i], toleranceForRemove) == 1: oldUArray.remove(j) oldVArray.remove(j) uAryPlug.setMObject(uDDFn.object()) vAryPlug.setMObject(vDDFn.object()) mom.MGlobal.displayInfo( 'JCFeather : Remove scatter userUVArray data. ' + str(oldULen) + ' --> ' + str(oldUArray.length())) elif sctMd == 2: ##### if the jcScatter is in InPosition scatter mode mom.MGlobal.displayInfo('JCFeather : Scatter inPosition mode.') inPositionPlug = dgFn.findPlug('inPosition') clstPtAry = getPartticlePos(particleDag, particleComponent) print('JCFeather : Select particle data size ' + str(clstPtAry.length())) if operation == 1: ########################### replace uDDFn = mom.MFnVectorArrayData() inPositionPlug.setMObject(uDDFn.create(clstPtAry)) mom.MGlobal.displayInfo( 'JCFeather : Replace scatter inPosition data.') elif operation == 0: ############################ add try: uDDFn = mom.MFnVectorArrayData(inPositionPlug.asMObject()) except: uDDFn = mom.MFnVectorArrayData() defaultVecArray = mom.MVectorArray() inPositionPlug.setMObject(uDDFn.create(defaultVecArray)) myOldVecAry = uDDFn.array() oldLen = myOldVecAry.length() addNewParticleToVector(clstPtAry, myOldVecAry, toleranceForRemove) inPositionPlug.setMObject(uDDFn.object()) mom.MGlobal.displayInfo( 'JCFeather : Add scatter inPosition data. ' + str(oldLen) + ' --> ' + str(myOldVecAry.length())) elif operation == 2: ############################# remove try: uDDFn = mom.MFnVectorArrayData(inPositionPlug.asMObject()) except: mom.MGlobal.displayError( "JCFeather : No inPosition data to remove.") oldVArray = uDDFn.array() newULen = clstPtAry.length() oldULen = oldVArray.length() result = mom.MVectorArray() idAry = mom.MIntArray() for j in range(0, oldVArray.length()): for i in range(0, newULen): dist = mom.MPoint(oldVArray[j].x, oldVArray[j].y, oldVArray[j].z).distanceTo( mom.MPoint(clstPtAry[i].x, clstPtAry[i].y, clstPtAry[i].z)) if dist < toleranceForRemove: oldVArray.remove(j) inPositionPlug.setMObject(uDDFn.object()) mom.MGlobal.displayInfo( 'JCFeather : Remove scatter inPosition data. ' + str(oldULen) + ' --> ' + str(oldVArray.length()))
def findSurfaceIntersections(self): ''' Return the pierced points on a surface from a raySource and rayDir ''' try: self._str_funcName = 'findSurfaceIntersections' log.debug(">>> %s >> "%self._str_funcName + "="*75) if len(mc.ls(surface))>1: raise StandardError,"findSurfaceIntersections>>> More than one surface named: %s"%surface self.centerPoint = mc.xform(surface, q=1, ws=1, t=1) #checking the type self.objType = search.returnObjectType(surface) if self.objType == 'nurbsSurface': raySource = om.MPoint(raySource[0], raySource[1], raySource[2]) self.raySourceVector = om.MVector(raySource[0], raySource[1], raySource[2]) self.centerPointVector = om.MVector(self.centerPoint[0],self.centerPoint[1],self.centerPoint[2]) rayDir = om.MPoint(self.centerPointVector - self.raySourceVector) self.rayDirection = om.MVector(rayDir[0], rayDir[1], rayDir[2]) self.hitPoints = om.MPoint() self.selectionList = om.MSelectionList() self.selectionList.add(surface) self.surfacePath = om.MDagPath() self.selectionList.getDagPath(0, self.surfacePath) self.surfaceFn = om.MFnNurbsSurface(self.surfacePath) #maxDist self.maxDist = maxDistance #other variables self.u = om.MDoubleArray() self.v = om.MDoubleArray() self.spc = om.MSpace.kWorld self.toleranceSU = om.MScriptUtil() self.tolerance = self.toleranceSU.asDoublePtr() om.MScriptUtil.setDouble(self.tolerance, .1) #Get the closest intersection. self.gotHit = self.surfaceFn.intersect(raySource,self.rayDirection,self.u,self.v,self.hitPoints,self.toleranceSU.asDouble(),self.spc,False,None,False,None) elif self.objType == 'mesh': raySource = om.MFloatPoint(raySource[0], raySource[1], raySource[2]) self.raySourceVector = om.MFloatVector(raySource[0], raySource[1], raySource[2]) self.centerPointVector = om.MFloatVector(self.centerPoint[0],self.centerPoint[1],self.centerPoint[2]) rayDir = om.MFloatPoint(self.centerPointVector - self.raySourceVector) self.rayDirection = om.MFloatVector(rayDir[0], rayDir[1], rayDir[2]) self.hitPoints = om.MFloatPointArray() self.selectionList = om.MSelectionList() self.selectionList.add(surface) self.meshPath = om.MDagPath() self.selectionList.getDagPath(0, self.meshPath) self.meshFn = om.MFnMesh(self.meshPath) #maxDist self.maxDist = maxDistance #other variables self.spc = om.MSpace.kWorld #Get the closest intersection. self.gotHit = self.meshFn.allIntersections(raySource,self.rayDirection,None,None,False,self.spc,self.maxDist,False,None,False,self.hitPoints,None,None,None,None,None) else : raise StandardError,"wrong surface type!" #Return the intersection as a Python list. if self.gotHit: self.returnDict = {} self.hitList = [] self.uvList = [] for i in range( self.hitPoints.length() ): self.hitList.append( [self.hitPoints[i].x, self.hitPoints[i].y, self.hitPoints[i].z]) self.hitMPoint = om.MPoint(self.hitPoints[i]) self.pArray = [0.0,0.0] self.x1 = om.MScriptUtil() self.x1.createFromList(pArray, 2) self.uvPoint = x1.asFloat2Ptr() self.uvSet = None self.uvReturn = self.surfaceFn.getParamAtPoint(self.hitMPoint,self.uvPoint,self.paramU,self.paramV, self.ignoreTrimBoundaries, om.MSpace.kObject, self.kMFnNurbsEpsilon) self.uValue = om.MScriptUtil.getFloat2ArrayItem(self.uvPoint, 0, 0) or False self.vValue = om.MScriptUtil.getFloat2ArrayItem(uvPoint, 0, 1) or False self.uvList.append([self.uValue,self.vValue]) self.returnDict = {'hits':self.hitList,'source':[raySource.x,raySource.y,raySource.z],'uvs':self.uvList} return self.returnDict else: return None except StandardError,error: log.error(">>> surface | raysource | rayDir | error") return None
def collectBlendWeights(skinCls, dagPath, components, dataDic): weights = OpenMaya.MDoubleArray() skinCls.__apimfn__().getBlendWeights(dagPath, components, weights) dataDic['blendWeights'] = [weights[i] for i in range(weights.length())]
def loadWeights(self, skinCluster=None, influenceList=None, componentList=None, normalize=True): ''' Apply the stored skinCluster weights. @param skinCluster: The list of components to apply skinCluster weights to. @type skinCluster: str @param influenceList: The list of skinCluster influences to apply weights for. @type influenceList: list or None @param componentList: The list of components to apply skinCluster weights to. @type componentList: list or None @param normalize: Normalize influence weights. @type normalize: bool ''' # ========== # - Checks - # ========== # Check SkinCluster if not skinCluster: skinCluster = self._data['name'] self.verifySkinCluster(skinCluster) # Check Geometry skinGeo = self._data['affectedGeometry'][0] if not mc.objExists(skinGeo): raise Exception( 'SkinCluster geometry "' + skinGeo + '" does not exist! Use remapGeometry() to load skinCluster data to a different geometry!' ) # Check Influence List if not influenceList: influenceList = self._influenceData.keys() or [] for influence in influenceList: if not influence in mc.skinCluster(skinCluster, q=True, inf=True) or []: raise Exception('Object "' + influence + '" is not a valid influence of skinCluster "' + skinCluster + '"! Unable to load influence weights...') if not self._influenceData.has_key(influence): raise Exception('No influence data stored for "' + influence + '"! Unable to load influence weights...') # Check Component List if not componentList: componentList = glTools.utils.component.getComponentStrList( skinGeo) componentSel = glTools.utils.selection.getSelectionElement( componentList, 0) # Get Component Index List #indexList = OpenMaya.MIntArray() #componentFn = OpenMaya.MFnSingleIndexedComponent(componentSel[1]) #componentFn.getElements(indexList) #componentIndexList = list(indexList) componentIndexList = glTools.utils.component.getSingleIndexComponentList( componentList) componentIndexList = componentIndexList[componentIndexList.keys()[0]] # ===================================== # - Set SkinCluster Influence Weights - # ===================================== # Get Influence Index infIndexArray = OpenMaya.MIntArray() for influence in influenceList: infIndex = glTools.utils.skinCluster.getInfluencePhysicalIndex( skinCluster, influence) infIndexArray.append(infIndex) # Build Weight Array wtArray = OpenMaya.MDoubleArray() oldWtArray = OpenMaya.MDoubleArray() for c in componentIndexList: for i in range(len(influenceList)): if self._influenceData.has_key(influenceList[i]): wtArray.append( self._influenceData[influenceList[i]]['wt'][c]) else: wtArray.append(0.0) # Get skinCluster function set skinFn = glTools.utils.skinCluster.getSkinClusterFn(skinCluster) # Set skinCluster weights skinFn.setWeights(componentSel[0], componentSel[1], infIndexArray, wtArray, normalize, oldWtArray) # ================= # - Return Result - # ================= return list(wtArray)
def bake(instancerName, start, end, progress=None): """ Process an instancer node over the specified frame range, reading the positions and objects. With this data objects are duplicated and positioned to mimic the instancer. With the particle data individual objects can be matched over the different frames and animated. When a particle "dies", the visibility is turned off. :param str instancerName: Name if the instancer to bake :param int start: Start frame :param int end: End frame :param QProgressBar progress: Update ui ( Optional ) :return: Group that contains all of the baked information :rtype: str :raises RuntimeError: When the instancer doesn't exist :raises RuntimeError: When there are no particles attached """ # store all particle information in data variable data = {} # get instance if not cmds.objExists(instancerName): raise RuntimeError("Instancer doesn't exist!") # set visible cmds.setAttr("{0}.visibility".format(instancerName), 1) instancerObj = utils.asMObject(instancerName) instancerDag = utils.asMDagPath(instancerObj) instancer = OpenMayaFX.MFnInstancer(instancerDag) # get particles particleName = cmds.listConnections( "{0}.inputPoints".format(instancerName)) if not particleName: raise RuntimeError("No particles connected!") particleName = particleName[0] particleObj = utils.asMObject(particleName) particleDag = utils.asMDagPath(particleObj) particle = OpenMayaFX.MFnParticleSystem(particleDag) # variables ages = OpenMaya.MDoubleArray() paths = OpenMaya.MDagPathArray() matrices = OpenMaya.MMatrixArray() particleIndices = OpenMaya.MIntArray() pathIndices = OpenMaya.MIntArray() # create container group container = cmds.group(world=True, empty=True, n="{0}_bake_1".format(instancerName)) # loop time for i in range(start, end + 1): # set time cmds.currentTime(i) # query instancer information instancer.allInstances(paths, matrices, particleIndices, pathIndices) # query particle information particle.age(ages) # loop particle instances num = matrices.length() for j in range(num): # get particles index p = particleIndices[j] # get parent parent = paths[pathIndices[j]].fullPathName() # get age age = ages[j] if data.get(p): # get path and age path = data[p].get("path") oldAge = data[p].get("age") oldParent = data[p].get("parent") # check if age is less than previous if age < oldAge: # hide mesh and delete particle id data utils.keyVisibility(path, i, 0) del (data[p]) # check if parent is the same as previous elif parent != oldParent: # hide mesh and delete particle id data utils.keyVisibility(path, i, 0) del (data[p]) # duplicate path if index not in data if not data.get(p): # get parent name parentShort = parent.split("|")[-1].split(":")[-1] # duplicate mesh name = "{0}_{1}_1".format(instancerName, parentShort) path = cmds.duplicate(parent, n=name)[0] path = cmds.parent(path, container)[0] # handle visibility utils.keyVisibility(path, i, 1) # get dag dag = utils.asMDagPath(utils.asMObject(path)) # get matrix transform = utils.asMFnTransform(dag) matrix = transform.transformation().asMatrix() # store variables data[p] = {} data[p]["path"] = path data[p]["dag"] = dag data[p]["matrix"] = matrix data[p]["parent"] = parent # get variables path = data[p].get("path") dag = data[p].get("dag") matrix = data[p].get("matrix") # store age data[p]["age"] = age # set matrix m = matrix * matrices[j] m = OpenMaya.MTransformationMatrix(m) transform = utils.asMFnTransform(dag) transform.set(m) # set keyframes utils.keyTransform(path, i) # update progress if progress: progress.setValue(i + 1 - start) return container
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 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 redoIt(self): # get the vertex to operating on self.component = om.MFnSingleIndexedComponent().create( om.MFn.kMeshVertComponent) om.MFnSingleIndexedComponent(self.component).addElement(self.index) # get surrounding vertices surrWeights = om.MDoubleArray( ) # storing weights of surrounding vertices msInf = om.MScriptUtil() # script util for int pointer infCountPtr = msInf.asUintPtr( ) # unsigned int pointer sotring number of influences on the vertex surrVtxArray = om.MIntArray() # storing sorrounding vertex indices # create iterator mitVtx = om.MItMeshVertex(self.dagPath, self.component) mitVtx.getConnectedVertices(surrVtxArray) surrComponents = om.MFnSingleIndexedComponent().create( om.MFn.kMeshVertComponent) om.MFnSingleIndexedComponent(surrComponents).addElements(surrVtxArray) # read weight from single vertex, store to oldWeights self.fnSkin.getWeights(self.dagPath, self.component, self.oldWeights, infCountPtr) # read weight fromthe surrounding vertices, store to surrWeights self.fnSkin.getWeights(self.dagPath, surrComponents, surrWeights, infCountPtr) # number of influences affecting the operating vertex influenceCount = om.MScriptUtil.getUint(infCountPtr) # reset variable infIndices infIndices_util = om.MScriptUtil() infIndices_util.createFromList(range(0, influenceCount), influenceCount) infIndices_iPtr = infIndices_util.asIntPtr() self.infIndices = om.MIntArray(infIndices_iPtr, influenceCount) # calculate multiplier for each surrounding vertices base on distance # distances = [] # dist_append = distances.append # mPt = om.MPoint # mSpaceKObj = om.MSpace.kObject # fnOrigMesh_getPoint = self.fnOrigMesh.getPoint # get operating vertex point position on the orig mesh # compPt = mPt() # cPt_distTo = compPt.distanceTo # fnOrigMesh_getPoint(self.index, compPt, mSpaceKObj) # loop over each surrounding vertices to get distance to the operating vertex # for sIndx in sorted(surrVtxArray): # sPoint = mPt() # fnOrigMesh_getPoint(sIndx, sPoint, mSpaceKObj) # dist = cPt_distTo(sPoint) # dist_append(dist) # average all the surrounding vertex weights, multiply with the brush value and blend it over the origWeight oldWeight = self.oldWeights values = [] values_append = values.append # pre-calculate what we can before entering the loop surrVtxCount = surrVtxArray.length() pressure = self.pressure pressure_sqr = pressure * pressure pre_mult = (1.0 / surrVtxCount) * (1.0 - pressure) # normalize and invert the distances, make closer distance has more value than the further ones # mults = [(sum(distances)/d)*pressure_sqr for d in distances] # the main weight value calculation loop for i in xrange(0, influenceCount): v = oldWeight[i] * pre_mult for w in xrange(0, surrVtxCount): # v += surrWeights[i + (w*influenceCount)] * mults[w] v += surrWeights[i + (w * influenceCount)] * pressure_sqr values_append(v) # do maintain max influences if maintainMaxInfluences is checked on the skinCluster node if self.maintainMaxInfluences == True: # get indices of the top N values maxIndexs = sorted(range(influenceCount), key=lambda v: values[v], reverse=True)[:self.maxInfluences] maxVals = [0] * influenceCount for i in maxIndexs: maxVals[i] = values[i] else: # else, just use the calculated list maxVals = values # normalize normList = [w / sum(maxVals) for w in maxVals] # cast python list to MDoubleArray # newWeights newWeight_util = om.MScriptUtil() newWeight_util.createFromList(normList, influenceCount) newWeight_dPtr = newWeight_util.asDoublePtr() newWeights = om.MDoubleArray(newWeight_dPtr, influenceCount) # set the final weights throught the skinCluster self.fnSkin.setWeights(self.dagPath, self.component, self.infIndices, newWeights, False, self.oldWeights)
def buildData(self, curve, worldSpace=False): ''' Build NurbsCurveData class. @param curve: Curve to build data from @type curve: str ''' # ========== # - Checks - # ========== # Check Curve if not glTools.utils.curve.isCurve(curve): raise Exception('Object "' + curve + '" is not a vaild NURBS curve node!') # World Space space = OpenMaya.MSpace.kObject if worldSpace: space = OpenMaya.MSpace.kWorld # ============== # - Build Data - # ============== # Start timer timer = mc.timerX() # Get basic curve info self._data['name'] = curve # Get Curve Function Class curveFn = glTools.utils.curve.getCurveFn(curve) # Get Curve Degree and Form self._data['degree'] = curveFn.degreeU() self._data['form'] = int(curveFn.formInU()) # Get Curve Knots knotArray = OpenMaya.MDoubleArray() curveFn.getKnotsInU(knotArray) self._data['knots'] = list(knotArray) # Get Control Vertices cvArray = OpenMaya.MPointArray() curveFn.getCVs(cvArray, space) self._data['cv'] = [(cvArray[i].x, cvArray[i].y, cvArray[i].z) for i in range(cvArray.length())] # Get Edit Points editPt = OPenMaya.MPoint() for u in self._data['knots']: curveFn.getPointAtParam(u, editPt, space) self._data['editPt'].append((editPt.x, editPt.y, editPt.z)) # ================= # - Return Result - # ================= # Print timer result buildTime = mc.timerX(st=timer) print('NurbsCurveData: Data build time for curve "' + curve + '": ' + str(buildTime)) return self._data['name']
class instanceRotate(OpenMayaMPx.MPxCommand): #- Store the base shape for the instances here for undo shapeObj = OpenMaya.MDagPath() #- Store the original rotation values for undo here rotations = OpenMaya.MDoubleArray() def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) #- Store the user selection of the rotation axis (one axis for all of the instances) self.axis = AXIS_X #- Store the number of instances for one shape self.numInstances = 0 #- This method is used to specify whether or not the command is undoable. In #- the base class, it always returns false. If you are writing a command that #- might be eligible for undo, you should override this method. #- After Maya executes the command's doIt method, it will call isUndoable. If #- isUndoable returns true, Maya will retain the instance of the class and pass #- it to Maya's undo manager so that the undoIt and redoIt methods can be called #- when appropriate. If isUndoable returns false, the command instance will be #- immediately destroyed. #def isUndoable(self): # return True #def hasSyntax(self): # return True #- This method should perform a command by setting up internal class data #- and then calling the redoIt method if undo is supported by the command. #- The actual action performed by the command should be done in the redoIt #- method. This is a pure virtual method, and must be overridden in derived #- classes. def doIt(self, args): #- Since all the command actions will be done in the redoIt() method, this #- method will only parse the arguments. redoIt() will not use arguments #- at all. argParser = OpenMaya.MArgParser (self.syntax(),args) numFlags = argParser.numberOfFlagsUsed() if(numFlags != 1): OpenMaya.MGlobal.displayError("Simple Plugs requires one flag argument and a DAG object must be selected") return None else: if(argParser.isFlagSet(ROTATEFLAG) | argParser.isFlagSet(ROTATELONGFLAG)): #- The user enters 1, 2, or 3 to indicate x, y, or z rotation axis flag =argParser.flagArgumentInt(ROTATEFLAG,0) if(flag == AXIS_X): self.axis = AXIS_X elif(flag == AXIS_Y): self.axis = AXIS_Y elif(flag == AXIS_Z): self.axis = AXIS_Z else: OpenMaya.MGlobal.displayError("Invalid axis rotation argument") return None return self.redoIt(args) #- This method should do the actual work of the command based on the internal #- class data only. Internal class data should be set in the doIt method. def redoIt(self, args): OpenMayaMPx.MPxCommand.setResult( "instanceRotate command executed!\n" ) #- This is really where is the intelligence of the command. Here we will #- preform all the actions we wanted to implement for this command. #- Get the active selection in the Maya viewport. selList = OpenMaya.MSelectionList() OpenMaya.MGlobal.getActiveSelectionList(selList) if(selList.isEmpty()): OpenMaya.MGlobal.displayError("A single DAG object must be selected") return None dagPath = OpenMaya.MDagPath() selList.getDagPath(0,dagPath) #- Chances are the user selected the object from the panel view or #- outliner window so the object in the list will actually be a #- transform node... if so we call extendToShape to grab the actual #- shape node from the dagPath #- TODO: Test if this node is a transform node, and if so extend the #- TODO: dagPath to the real shape node. #... #... if(dagPath.isInstanced()): self.shapeObj = dagPath self.rotate(dagPath) else: OpenMaya.MGlobal.displayError("The selected item is not an instanced DAG object") return None #- This method should undo the work done by the redoIt method based on the #- internal class data only. def undoIt(self, args): OpenMaya.MGlobal.displayInfo( "instanceRotate command undone!\n" ) fnDag = MFnDagNode(self.shapeObj) for i in range ( 0, self.numInstances ): currentParent = fnDag.parent(i) fnParent = OpenMaya.MFnDependencyNode(currentParent) rotPlug = fnParent.findPlug("rotate") if (self.axis == AXIS_X): rotxPlug = rotPlug.child(0) rotxPlug.setDouble(self.rotations[i]) elif (self.axis == AXIS_Z): rotzPlug = rotPlug.child(2) rotzPlug.setDouble(self.rotations[i]) else: # AXIS_Y: rotyPlug = rotPlug.child(1) rotyPlug.setDouble(self.rotations[i]) #- Empty the array in case the user chooses redoIt self.rotations.clear() #- Method used by redoIt to assign a 45 degree rotation along a random axis. def rotate( self, dp ): #- The passed-in dag object is a shape object, #- need to find all the parent transform objects. fnDag = OpenMaya.MFnDagNode(dp) #- The number of parents represents the current number of instances. self.numInstances = fnDag.parentCount() for i in range ( 0, self.numInstances ): currentParent = fnDag.parent(i) fnParent = OpenMaya.MFnDependencyNode(currentParent) #- Find the rotate plug, figure out which axis the user opted for #- and set the plug to a random direction. #- TODO: find the plug named 'rotate' rotPlug = #... #- Acquire a random number deciding which direction the 45 degree should be randVal = random.randint(0, 1000) if(randVal % 2 == 0): randVal = 1 else: randVal = -1 print "The randVal is %d " % randVal sys.stdout.write( '\n' ) if (self.axis == AXIS_X): #- TODO: Get the X plug of the 'rotate' plug rotxPlug = #... #- retrieve original rotation and store it in member variable "rotations" origRot = 0 #- TODO: Get the plug value #... self.rotations.append(origRot) #- set new rotation rot = origRot + randVal * ROTATIONVALUE #- TODO: Set the new plug value #... elif (self.axis == AXIS_Z): #- TODO: Get the Z plug of the 'rotate' plug rotzPlug = #... origRot = 0 #- TODO: Get the plug value #... self.rotations.append(origRot) rot = origRot + randVal * ROTATIONVALUE #- TODO: Set the new plug value #... else: # AXIS_Y: - by default, rotate around y axis - TODO: Get the Y plug of the 'rotate' plug rotyPlug = #... origRot = 0 #- TODO: Get the plug value #... self.rotations.append(origRot) rot = origRot + randVal * ROTATIONVALUE
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 __getBlendWeights(self, dagPath, components): weights = OpenMaya.MDoubleArray() self.__mFnScls.getBlendWeights(dagPath, components, weights) return weights
def calculateWeights(self, weights, num): """ Calculate the new weights of the removed indices. The new weights are calculated by trying to remove the influence that is active in the tool. Locked influences, normalization are taken into account as they are set on the skin cluster. :param OpenMaya.MDoubleArray weights: original weights :param int num: Amount of influences per vertex :return: New weights, new influences :rtype: tuple(OpenMaya.MDoubleArray, OpenMaya.MIntArray) """ # variables influenceNew = OpenMaya.MIntArray() weightsNew = OpenMaya.MDoubleArray() # add influences for i in range(num): influenceNew.append(i) # calculate weights for i in range(0, weights.length(), num): weightsVtx = [weights[i + j] for j in range(num)] indexWeight = weights[i + self.index] total = sum(weightsVtx) # if weight that is trying to be removed is only influence # reselect vertex as weights cannot be removed if indexWeight == total: for w in weightsVtx: weightsNew.append(w) continue # remove index weight factor = 1 factorLocked = 1 weightsVtx = [ weights[i + j] if j != self.index else 0.0 for j in range(num) ] # normalize weights if self.normalizeMode == 1: # get total locked weights weightsVtxLocked = sum([ weights[i + j] for j in range(num) if self.influencesLocked[j] ]) # get total to blend total = sum(weightsVtx) - weightsVtxLocked # get multiply factor if weightsVtxLocked >= 1.0 or total == 0.0: factor = 0 factorLocked = 1 / weightsVtxLocked else: factor = (1.0 - weightsVtxLocked) / total # apply multiply factor for j, w in enumerate(weightsVtx): if not self.influencesLocked[j]: weightsNew.append(w * factor) else: weightsNew.append(w * factorLocked) return weightsNew, influenceNew
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 setWeights(self, componentList=[]): ''' Apply the stored skinCluster weights to the specified skinCluster. @param componentList: The list of components to apply skinCluster weights to. @type componentList: str ''' print( '!!! - DEPRICATED: skinClusterData.setWeights()! Use loadWeights() method instead - !!!' ) # ========== # - Checks - # ========== # Check SkinCluster skinCluster = self._data['name'] self.verifySkinCluster(skinCluster) # Check Geometry skinGeo = self._data['affectedGeometry'][0] if not mc.objExists(skinGeo): raise Exception( 'SkinCluster geometry "' + skinGeo + '" does not exist! Use remapGeometry() to load skinCluster data to a different geometry!' ) # Check Component List if not componentList: componentList = glTools.utils.component.getComponentStrList( skinGeo) componentSel = glTools.utils.selection.getSelectionElement( componentList, 0) # Get Component Index List indexList = OpenMaya.MIntArray() componentFn = OpenMaya.MFnSingleIndexedComponent(componentSel[1]) componentFn.getElements(indexList) componentIndexList = list(indexList) # =========================== # - Set SkinCluster Weights - # =========================== # Build influence index array infIndexArray = OpenMaya.MIntArray() influenceList = mc.skinCluster(skinCluster, q=True, inf=True) [infIndexArray.append(i) for i in range(len(influenceList))] # Build master weight array wtArray = OpenMaya.MDoubleArray() oldWtArray = OpenMaya.MDoubleArray() for c in componentIndexList: for i in range(len(influenceList)): if self._influenceData.has_key(influenceList[i]): wtArray.append( self._influenceData[influenceList[i]]['wt'][c]) else: wtArray.append(0.0) # Get skinCluster function set skinFn = glTools.utils.skinCluster.getSkinClusterFn(skinCluster) # Set skinCluster weights skinFn.setWeights(componentSel[0], componentSel[1], infIndexArray, wtArray, False, oldWtArray) # ================= # - Return Result - # ================= return influenceList
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 create_mdouble_array(self, array): mdouble_array = OpenMaya.MDoubleArray() for x in array: mdouble_array.append(x) return mdouble_array
def fillOptimized(): sel = cmds.ls(sl=1) if not sel: print "no mesh selected !" return obj=sel[0] objList = OpenMaya.MSelectionList() objList.add(obj) path = OpenMaya.MDagPath() objList.getDagPath(0,path) path.extendToShape() closest = OpenMaya.MMeshIntersector() closest.create(path.node(),path.inclusiveMatrix()) try: cmds.particleFill(rs=step,maxX=1,maxY=1,maxZ=1,minX=0,minY=0,minZ=0,pd=1.0,cp=True) except RuntimeError: pass part = cmds.ls(sl=1)[0] partShape = cmds.listRelatives(part,shapes=1)[0] nplist = OpenMaya.MSelectionList() nplist.add(partShape) npobj = OpenMaya.MObject() nplist.getDependNode(0,npobj) npnode = OpenMaya.MFnDependencyNode(npobj) nplug = npnode.findPlug("position") nhdl = nplug.asMDataHandle() ndata = OpenMaya.MFnVectorArrayData(nhdl.data()) radii = OpenMaya.MDoubleArray() points = OpenMaya.MVectorArray() points.copy(ndata.array()) cmds.delete(part) mpom = MPointOnMesh() radii_index = {} for p in xrange(points.length()): vec = points[p] point = MPoint(vec) closest.getClosestPoint(point, mpom) closestPoint = mpom.getPoint() radius = point.distanceTo(MPoint(closestPoint)) radii_index[p] = (vec, point, radius) radii_sorted = sorted(radii_index.itervalues(), key=itemgetter(2), reverse=True) newPoints = OpenMaya.MVectorArray() newRadii = OpenMaya.MDoubleArray() pointsRemain = lambda: len(radii_sorted) while pointsRemain(): print "%s problem points still left..." % pointsRemain() vec, p, radius = radii_sorted.pop(0) newPoints.append(vec) newRadii.append(radius*1.2) for i in reversed(xrange(pointsRemain())): vec2, p2, otherRadius = radii_sorted[i] if p.distanceTo(p2) < (otherRadius + radius): del radii_sorted[i] #note: the default nParticle creation mode should be set to "points" part = cmds.nParticle()[1] plist = OpenMaya.MSelectionList() plist.add(part) newNPObj = OpenMaya.MObject() dagPath = OpenMaya.MDagPath() plist.getDependNode(0,newNPObj) plist.getDagPath(0, dagPath) name = dagPath.fullPathName() newNPNode = OpenMaya.MFnDependencyNode(newNPObj) newPosPlug = newNPNode.findPlug("position") newNPHdl = newPosPlug.asMDataHandle() newposdata = OpenMaya.MFnVectorArrayData(newNPHdl.data()) newposdata.set(newPoints) newPosPlug.setMObject(newposdata.object()) prt = newNPNode.findPlug("particleRenderType") prt.setInt(4) isg = newNPNode.findPlug("ignoreSolverGravity") isg.setInt(1) tattr = OpenMaya.MFnTypedAttribute() rpp = tattr.create("radiusPP","rpp",OpenMaya.MFnData.kDoubleArray) newNPNode.addAttribute(rpp) # rppPlug = newNPNode.findPlug("radiusPP") # rpphdl = rppPlug.asMDataHandle() # rppdata = OpenMaya.MFnDoubleArrayData(rpphdl.data()) # rppdata.set(newRadii) # rppPlug.setMObject(rppdata.object()) fnParticleSys = MFnParticleSystem(newNPObj) fnParticleSys.setPerParticleAttribute("radiusPP", newRadii) print "finished."
def get_curve_info(name=False): ''' used to get the curve data from a hand drawn curve in maya - for adding a new curve type to the class structure ''' if not name: name = cmds.ls(sl=True)[0] # sanity check if not cmds.objExists(name): print 'object %s not found, aborting' % name return # check for nurbs curve shape if cmds.nodeType(name) == "nurbsCurve": shape = name else: shpList = cmds.listRelatives(name, s=True) shape = shpList[0] # use the API to get the curve data Mlist = OpenMaya.MSelectionList() OpenMaya.MGlobal.getSelectionListByName(shape, Mlist) dPath = OpenMaya.MDagPath() Mlist.getDagPath(0, dPath) crv = OpenMaya.MFnNurbsCurve(dPath) degree = crv.degree() cvs = OpenMaya.MPointArray() knots = OpenMaya.MDoubleArray() crv.getCVs(cvs) crv.getKnots(knots) # print to the script editor for use print "DEGREE" print degree print "CVS" length = cvs.length() print "[" for i in range(length): print('(' + ` cvs[i][0] ` + ',' + ` cvs[i][1] ` + ',' + ` cvs[i][2] ` + '),') print "]" print "KNOTS" print knots ##################################### # CODE TESTING ##################################### #test = ArcControl() #test = CircleControl() #test.setColour('green') #test.set_position([0,1,0], [0,90,0]) #test.add_offset() #test.hide_rotation() #test.hide_translation() #test.hide_scale() #test.lock_hide("v") #get_curve_info("curve1")
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) cluster_mfn = oma.MFnWeightGeometryFilter(cluster_mobject) # get geometry's type to cluster weights type geo_dag_path = om.MDagPath()
def doSimpleSolver(self): ''' Solve single joint in the x-y plane - first it calculates the angle between the handle and the end-effector. - then it determines which way to rotate the joint. ''' handle_group = self.handleGroup() # return a MIkHandleGroup handle = handle_group.handle(0) # return a MObject handlePath = OpenMaya.MDagPath.getAPathTo( handle) # Determines the Path to the specified DAG Node fnHandle = OpenMayaAnim.MFnIkHandle( handlePath) # argument an Mobject, i supose we use an mdagpath, # for possible duplicated objects # get the position of the end_effector end_effector = OpenMaya.MDagPath() fnHandle.getEffector(end_effector) tran = OpenMaya.MFnTransform(end_effector) effector_position = tran.rotatePivot(OpenMaya.MSpace.kWorld) # get the position of the handle handle_positions = fnHandle.rotatePivot(OpenMaya.MSpace.kWorld) # get the start joint position start_joint = OpenMaya.MDagPath() fnHandle.getStartJoint( start_joint ) # start_joint is filled here with the getStartJoint method start_tramsform = OpenMaya.MFnTransform(start_joint) start_position = start_tramsform.rotatePivot(OpenMaya.MSpace.kWorld) # calculate the rotation angle v1 = start_position - effector_position v2 = start_position - handle_positions angle = v1.angle(v2) # -------- Figure out which way to rotate -------- # # define two vectors U and V as follows # U = EndEffector(E) - StartJoint(S) # N = Normal to U passing through EndEffector # # Clip handle_position to half-plane U to determine the region it # lies in. Use the region to determine the rotation direction. # # U # ^ Region Rotation # | B # (E)---N A C-C-W # A | B C-W # | B # | # (S) # rot = 0.0 # Rotation about z-axis # U and N define a half-plane to clip the handle against u = effector_position - start_position u.normalize() # Get a normal to U zAxis = OpenMaya.MVector(0.0, 0.0, 1.0) N = u ^ zAxis # cross product N.normalize() # P is the handle position vector P = handle_positions - effector_position # Determine the rotation direction PdotN = P[0] * N[0] + P[1] * N[1] if PdotN < 0: rot = angle # counter-clockwise else: rot = -1.0 * angle # clockwise # get and set the Joint Angles jointAngles = OpenMaya.MDoubleArray() try: self._getJointAngles(jointAngles) # here fill jointAngles except: # getting angles failed, do nothing pass else: jointAngles.set(jointAngles[0] + rot, 0) # set rotation in the array self._setJointAngles(jointAngles) # set joint rotation
def testCreases(self): cortexCube = IECoreScene.MeshPrimitive.createBox( imath.Box3f(imath.V3f(-1), imath.V3f(1))) cornerIds = [5] cornerSharpnesses = [10.0] cortexCube.setCorners(IECore.IntVectorData(cornerIds), IECore.FloatVectorData(cornerSharpnesses)) creaseLengths = [3, 2] creaseIds = [1, 2, 3, 4, 5] # note that these are vertex ids creaseSharpnesses = [1, 5] cortexCube.setCreases(IECore.IntVectorData(creaseLengths), IECore.IntVectorData(creaseIds), IECore.FloatVectorData(creaseSharpnesses)) converter = IECoreMaya.ToMayaObjectConverter.create(cortexCube) transform = maya.cmds.createNode("transform") self.assertTrue(converter.convert(transform)) mayaMesh = maya.cmds.listRelatives(transform, shapes=True)[0] l = OpenMaya.MSelectionList() l.add(mayaMesh) p = OpenMaya.MDagPath() l.getDagPath(0, p) fnMesh = OpenMaya.MFnMesh(p) # Test corners cornerIds = OpenMaya.MUintArray() cornerSharpnesses = OpenMaya.MDoubleArray() fnMesh.getCreaseVertices(cornerIds, cornerSharpnesses) testIds = OpenMaya.MUintArray() testIds.append(5) self.assertEqual(cornerIds, testIds) testSharpnesses = OpenMaya.MFloatArray() testSharpnesses.append(10) self.assertEqual(cornerSharpnesses, testSharpnesses) # Test edges edgeIds = OpenMaya.MUintArray() edgeSharpnesses = OpenMaya.MDoubleArray() fnMesh.getCreaseEdges(edgeIds, edgeSharpnesses) util = OpenMaya.MScriptUtil() result = [] for edgeId, sharpness in zip(edgeIds, edgeSharpnesses): edgeVertices = util.asInt2Ptr() fnMesh.getEdgeVertices(edgeId, edgeVertices) result.append((util.getInt2ArrayItem(edgeVertices, 0, 1), util.getInt2ArrayItem(edgeVertices, 0, 0), sharpness)) # we compare sets because maya reorders by edge index self.assertEqual(set(result), set([(1, 2, 1.0), (2, 3, 1.0), (4, 5, 5.0)]))
def setBlendWeights(skinCls, dagPath, components, dataDic): blendWeights = OpenMaya.MDoubleArray(len(dataDic['blendWeights'])) for i, w in enumerate(dataDic['blendWeights']): blendWeights.set(w, i) skinCls.__apimfn__().setBlendWeights(dagPath, components, blendWeights)
def create_anim_curve_node( times, values, node_attr=None, tangent_in_type=OpenMayaAnim.MFnAnimCurve.kTangentGlobal, tangent_out_type=OpenMayaAnim.MFnAnimCurve.kTangentGlobal, anim_type=OpenMayaAnim.MFnAnimCurve.kAnimCurveTL, undo_cache=None): """ Create an animCurve using the Maya API :param times: Time values for the animCurve :type times: list :param values: Values for the animCurve. :type values: list :param node_attr: The 'plug' to connect the animCurve to. :type node_attr: str :param tangent_in_type: The "in" tangent type for keyframes. :param tangent_out_type: The "out" tangent type for keyframes. :param anim_type: The type of animation curve node. :param undo_cache: The Maya AnimCurve Undo Cache data structure. :return: """ if not isinstance(times, list): raise ValueError('times must be a list or sequence type.') if not isinstance(values, list): raise ValueError('times must be a list or sequence type.') if len(times) == 0: raise ValueError('times must have 1 or more values.') if len(values) == 0: raise ValueError('values must have 1 or more values.') if len(times) != len(values): raise ValueError('Number of times and values does not match.') # create anim curve animfn = OpenMayaAnim.MFnAnimCurve() if node_attr is None: animCurve = animfn.create(anim_type) else: # Get the plug to be animated. dst_plug = utils.get_as_plug(node_attr) objs = OpenMaya.MObjectArray() find = OpenMayaAnim.MAnimUtil.findAnimation(dst_plug, objs) if find is True and objs.length() > 0: animfn = OpenMayaAnim.MFnAnimCurve(objs[0]) else: animfn = OpenMayaAnim.MFnAnimCurve() animfn.create(dst_plug) # Copy the times into an MTimeArray and the values into an MDoubleArray. time_array = OpenMaya.MTimeArray() value_array = OpenMaya.MDoubleArray() for time, value in zip(times, values): time_array.append(OpenMaya.MTime(time, OpenMaya.MTime.uiUnit())) value_array.append(value) # force a default undo cache if not undo_cache: undo_cache = OpenMayaAnim.MAnimCurveChange() # Add the keys to the animCurve. animfn.addKeys( time_array, value_array, tangent_in_type, tangent_out_type, False, # overwrite any keys that get in our way undo_cache) return animfn
def get_blend_weights(self, dag_path, components): weights = om.MDoubleArray() self.fn.getBlendWeights(dag_path, components, weights) self.data['blendWeights'] = [ weights[i] for i in xrange(weights.length()) ]
def buildData(self, surface, worldSpace=False): ''' Build NurbsSurfaceData class. @param surface: Surface to build data from @type surface: str ''' # ========== # - Checks - # ========== # Check Surface if not glTools.utils.surface.isSurface(surface): raise Exception('Object "' + surface + '" is not a vaild NURBS surface node!') # World Space space = OpenMaya.MSpace.kObject if worldSpace: space = OpenMaya.MSpace.kWorld # ============== # - Build Data - # ============== # Start timer timer = mc.timerX() # Get basic surface info self._data['name'] = surface # Get Surface Function Class surfaceFn = glTools.utils.surface.getSurfaceFn(surface) # Get Surface Degree and Form self._data['degreeU'] = surfaceFn.degreeU() self._data['degreeV'] = surfaceFn.degreeV() self._data['formU'] = int(surfaceFn.formInU()) self._data['formV'] = int(surfaceFn.formInV()) # Get Surface Knots knotsUarray = OpenMaya.MDoubleArray() knotsVarray = OpenMaya.MDoubleArray() surfaceFn.getKnotsInU(knotsUarray) surfaceFn.getKnotsInV(knotsVarray) self._data['knotsU'] = list(knotsUarray) self._data['knotsV'] = list(knotsVarray) # Get Control Vertices cvArray = OpenMaya.MPointArray() surfaceFn.getCVs(cvArray, space) self._data['cv'] = [(cvArray[i].x, cvArray[i].y, cvArray[i].z) for i in range(cvArray.length())] # ================= # - Return Result - # ================= # Print timer result buildTime = mc.timerX(st=timer) print('NurbsSurfaceData: Data build time for surface "' + surface + '": ' + str(buildTime)) return self._data['name']
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 calculateWeights(self, value, weightsO, weightsC, numI, numC): """ Calculate the new weights of the parsed index. The new weights are calculated by blending the weights of the connected vertices, this is done with the factor of the value. The value is parsed by the context and can range from 0-1 depending on where the point is in the paint brush. Locked influences, normalization and maintaining maximum influences are taken into account as they are set on the skin cluster. :param float value: Blend factor :param OpenMaya.MDoubleArray weightsO: Weights of original :param OpenMaya.MDoubleArray weightsC: Weights of connected :param int numI: Influences of original :param int numC: Influences of connected :return: New weights, new influences :rtype: tuple(OpenMaya.MDoubleArray, OpenMaya.MIntArray) """ # weight variables weightsNew = OpenMaya.MDoubleArray() influenceNew = OpenMaya.MIntArray() # blend weights for i in range(numI): influenceNew.append(i) weightsNew.append(0.0) # if influence is locked dont change value if self.influencesLocked[i]: weightsNew[i] = weightsO[i] continue # blend weights with connected vertices for j in range(i, len(weightsC), numI): w = ((weightsO[i] / numC) * (1 - value)) + ((weightsC[j] / numC) * value) weightsNew[i] += w # force max influences by removing excess weights if self.maintainMaxInfluences: weights = zip(weightsNew, influenceNew) excess = sorted(weights, reverse=True)[self.maxInfluences:] for e in excess: weightsNew[e[1]] = 0.0 # normalize weights to one if self.normalizeMode == 1: # get total locked weights lockedTotal = sum([ weightsNew[i] for i in range(weightsNew.length()) if self.influencesLocked[i] ]) # get total to blend total = sum(weightsNew) - lockedTotal # get multiply factor if lockedTotal >= 1.0 or total == 0.0: factor = 0 else: factor = (1.0 - lockedTotal) / total # apply multiply factor for i in range(weightsNew.length()): if self.influencesLocked[i]: continue weightsNew[i] = weightsNew[i] * factor return weightsNew, influenceNew