Python Programming in maya 1 2 3 4 5 6 7 8 9 10 import maya.cmds as cmdcmds.select(all =True ) cmds.delete() for step in range (40 ): cmds.polyCube(w=10 ,d=3 ,h=0.5 ) cmds.move(3 ,step*0.5 ,0 ) cmds.xform(ws = True ,rotatePivot=(0 ,0 ,0 )) cmds.rotate(0 ,step*10 ,0 )
1. DAG——描述Maya中的功能节点: DAG(Directed Acyclic Graph有向无环图)
Dag Node:Transform
Dag Node:Shape
DG:Dependency Graph依赖图
DAG path,某个对象的DAG path描述从根节点到物体的完整查找路径
MObject(Model Object)
MSelectionList(选择的模型对象列表)
maya.OpenMaya.MSelectionList
创建一个选择列表
在选择列表中添加、移除对象
可遍历
etc
1 2 3 4 5 6 7 8 9 10 11 import maya.OpenMaya as OpenMayamSelectionList = OpenMaya.MSelectionList() mSelectionList.add("<something_Name>" ) mDagPath = OpenMaya.MDagPath() mSelectionList.getDagPath(0 ,mDagPath) print (mDagPath.fullPathName())mObj = OpenMaya.MObject() mSelectionList.getDependNode(0 ,mObj) print (mObj.apiTypeStr())
2. Traversing Hyper Graph in Maya Scene MFn = Model Function Set
MFnMesh表示接收Mesh类型的函数集
create
modify
retrave
add Edge\face,subdivision
MFnDependencyNode:一组函数需要Dependency Node Type的数据,提供函数
create(dependency graph)
modify(dependency graph)
retrave(dependency graph)
可以通过MObj和MDagpath来提供到函数集的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import maya.OpenMaya as OpenMayamSel = OpenMaya.MSelectionList() mSel.add("pPlane1" ) mObj = OpenMaya.MObject() mDagPath = OpenMaya.MDagPath() mSel.getDependNode(0 ,mObj) mSel.getDagPath(0 ,mDagPath) mFnMesh = OpenMaya.MFnMesh(mDagPath) print (mFnMesh.fullPathName())mFnDependNode = OpenMaya.MFnDependencyNode(mObj) print (mFnDependNode.name())
MPlug提供操作功能的类(操作Plug Type)
Plug:节点属性的接口
create
modify
access(通过plug访问属性)
Network Plug: Dependency Node Plug
Non-Network Plug: User Defined Plug
MPlugArray
1 2 3 4 5 6 7 mPlugArray = OpenMaya.MPlugArray() mFnMesh.getConnections(mPlugArray) print (mPlugArray.length())print (mPlugArray[0 ].name())print (mPlugArray[1 ].name())
看看这个就知道是在干嘛了,我们的最终目的是操纵polyPlane1进行细分
通过pPlaneShape1的plug接口,就可以完成
1 2 3 4 5 6 mPlugArray2 = OpenMaya.MPlugArray() mPlugArray[1 ].connectedTo(mPlugArray2,True ,False ) print (mPlugArray2.length())print (mPlugArray2[0 ].name())
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import maya.OpenMaya as OpenMayamSel = OpenMaya.MSelectionList() mSel.add("pPlane1" ) mObj = OpenMaya.MObject() mDagPath = OpenMaya.MDagPath() mSel.getDependNode(0 ,mObj) mSel.getDagPath(0 ,mDagPath) mFnMesh = OpenMaya.MFnMesh(mDagPath) print (mFnMesh.fullPathName())mFnDependNode = OpenMaya.MFnDependencyNode(mObj) print (mFnDependNode.name())mPlugArray = OpenMaya.MPlugArray() mFnMesh.getConnections(mPlugArray) print (mPlugArray.length())print (mPlugArray[0 ].name())print (mPlugArray[1 ].name())mPlugArray2 = OpenMaya.MPlugArray() mPlugArray[1 ].connectedTo(mPlugArray2,True ,False ) print (mPlugArray2.length())print (mPlugArray2[0 ].name())mObj2 = mPlugArray2[0 ].node() mFnDependNode2 = OpenMaya.MFnDependencyNode(mObj2) print (mFnDependNode2.name())mPlug_width = mFnDependNode2.findPlug("width" ) mPlug_height = mFnDependNode2.findPlug("height" ) print (mPlug_width.asInt(),mPlug_height.asInt())mPlug_subWidth = mFnDependNode2.findPlug("subdivisionsWidth" ) mPlug_subHeight = mFnDependNode2.findPlug("subdivisionsHeight" ) mPlug_subWidth.setInt(20 ) mPlug_subHeight.setInt(20 )
3. Command Communication Flow
Command Plugin
函数
初始化/注册Initialization,Registration
Uninitialization/De-registration
把东西注入到Maya core,就是注册
命令插件编写基本流程
定义一个类
创建一个实例
用一个指针指向这个实例
Maya获取这个指针
4. Writing command plugin 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 import maya.OpenMaya as OpenMayaimport maya.OpenMayaMPx as OpenMayaMPximport syscommandName = "pluginCommand" class pluginCommand (OpenMayaMPx.MPxCommand): def __init__ (self ): OpenMayaMPx.MPxCommand.__init__(self ) def doIt (self,argList ): print ("doIt" ) def cmdCreator (): return OpenMayaMPx.asMPxPtr(pluginCommand()) def initializePlugin (mobject ): mplugin = OpenMayaMPx.MFnPlugin(mobject) try : mplugin.registerCommand(commandName,cmdCreator) except : sys.stderr.write("Failed to register command:" + commandName) def uninitializePlugin (mobject ): mplugin = OpenMayaMPx.MFnPlugin(mobject) try : mplugin.deregisterCommand(commandName) except : sys.stderr.write("Failed to deregister command" + commandName)
保存脚本后,在maya中加载插件
Mel,python,mayaUI三种方法
window-setting preferences-pluginManager
1 cmds.loadPlugin("./pluginCommand.py")
5. Maya API Iterators Iterator是一个对象,对数据结构进行遍历
MItSurfaceCV(CVs of Nurbs)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 import maya.OpenMaya as OpenMayadagIterator = OpenMaya.MItDag(OpenMaya.MItDag.kDepthFirst, OpenMaya.MFn.kInvalid) dagNodeFn = OpenMaya.MFnDagNode() while (not dagIterator.isDone()): currentObj = dagIterator.currentItem() depth = dagIterator.depth() dagNodeFn.setObject(currentObj) name = dagNodeFn.name() type = currentObj.apiTypeStr() path = dagNodeFn.fullPathName() printOut = "" for i in range (0 ,depth): printOut += "----->" printOut += name + " : " + type print (printOut) dagIterator.next () =========== World : kWorld ----->persp : kTransform ----->----->perspShape : kCamera ----->top : kTransform ----->----->topShape : kCamera ----->front : kTransform ----->----->frontShape : kCamera ----->side : kTransform ----->----->sideShape : kCamera ----->pCube1 : kTransform ----->----->pCubeShape1 : kMesh ----->----->pCylinder1 : kTransform ----->----->----->pCylinderShape1 : kMesh ----->----->----->pCone1 : kTransform ----->----->----->----->pConeShape1 : kMesh ----->----->----->----->pPlane1 : kTransform ----->----->----->----->----->pPlaneShape1 : kMesh ----->----->----->----->----->pPipe1 : kTransform ----->----->----->----->----->----->pPipeShape1 : kMesh
放到插件的doIt方法里面
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 import maya.OpenMaya as OpenMayaimport maya.OpenMayaMPx as OpenMayaMPximport syscommandName = "printHierarchy" class pluginCommand (OpenMayaMPx.MPxCommand): def __init__ (self ): OpenMayaMPx.MPxCommand.__init__(self ) def doIt (self,argList ): print ("Scene Heirarchy" ) dagIterator = OpenMaya.MItDag(OpenMaya.MItDag.kDepthFirst, OpenMaya.MFn.kInvalid) dagNodeFn = OpenMaya.MFnDagNode() while (not dagIterator.isDone()): currentObj = dagIterator.currentItem() depth = dagIterator.depth() dagNodeFn.setObject(currentObj) name = dagNodeFn.name() type = currentObj.apiTypeStr() path = dagNodeFn.fullPathName() printOut = "" for i in range (0 ,depth): printOut += "----->" printOut += name + " : " + type print (printOut) dagIterator.next () def cmdCreator (): return OpenMayaMPx.asMPxPtr(pluginCommand()) def initializePlugin (mobject ): mplugin = OpenMayaMPx.MFnPlugin(mobject) try : mplugin.registerCommand(commandName,cmdCreator) except : sys.stderr.write("Failed to register command:" + commandName) def uninitializePlugin (mobject ): mplugin = OpenMayaMPx.MFnPlugin(mobject) try : mplugin.deregisterCommand(commandName) except : sys.stderr.write("Failed to deregister command" + commandName)
保存脚本然后
1 2 3 import maya.cmds as cmdscmds.loadPlugin("c:\\Users\\XZYW\\Desktop\\printHierarchy.py" ) cmds.printHierarchy()
插件就可用了,这就是编写插件的方式。
6. Command with Arguments 1 cmds.polySphere("mySphere" ,q = True ,sx = True )
MSyntax
MArgDatabase
是MArgParser的派生类
Parsing
Storing
Retreving
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 import maya.OpenMaya as OpenMayaimport maya.OpenMayaMPx as OpenMayaMPximport sysimport maya.OpenMayaFX as OpenMayaFXcommandName = "vertexParticle" kHelpFlag = "-h" kHelpLongFlag = "-help" kSparseFlag = "-s" kSparseLongFlag = "-sparse" helpMessage = "This command is used to attach a particle on each Vertex of a poly mesh" class pluginCommand (OpenMayaMPx.MPxCommand): sparse = None def __init__ (self ): OpenMayaMPx.MPxCommand.__init__(self ) def argumentParser (self,argList ): syntax = self .syntax() parsedArguments = OpenMaya.MArgDatabase(syntax,argList) if parsedArguments.isFlagSet(kSparseFlag): self .sparse = parsedArguments.flagArgumentDouble(kSparseFlag,0 ) return if parsedArguments.isFlagSet(kSparseLongFlag): self .sparse = parsedArguments.flagArgumentDouble(kSparseLongFlag,0 ) return if parsedArguments.isFlagSet(kHelpFlag): self .setResult(helpMessage) return if parsedArguments.isFlagSet(kHelpLongFlag): self .setResult(helpMessage) return def isUndoable (self ): return True def undoIt (self ): print ("Undo" ) mFnDagNode = OpenMaya.MFnDagNode(self .mObj_particle) mDagMod = OpenMaya.MDagModifier() mDagMod.deleteNode(mFnDagNode.parent(0 )) mDagMod.doIt() return def redoIt (self ): mSel = OpenMaya.MSelectionList() mDagPath = OpenMaya.MDagPath() mFnMesh = OpenMaya.MFnMesh() OpenMaya.MGlobal.getActiveSelectionList(mSel) if mSel.length() >=1 : try : mSel.getDagPath(0 ,mDagPath) mFnMesh.setObject(mDagPath) except : print ("Select a poly mesh" ) return else : print ("Select a poly mesh" ) return mPointArray = OpenMaya.MPointArray() mFnMesh.getPoints(mPointArray, OpenMaya.MSpace.kWorld) mFnParticle = OpenMayaFX.MFnParticleSystem() self .mObj_particle = mFnParticle.create() mFnParticle = OpenMayaFX.MFnParticleSystem(self .mObj_particle) counter = 0 for i in range (mPointArray.length()): if i%self .sparse == 0 : mFnParticle.emit(mPointArray[i]) counter += 1 print ("Total Points:" + str (counter)) mFnParticle.saveInitialState() return def doIt (self,argList ): print ("doIt" ) self .argumentParser(argList) if self .sparse != None : self .redoIt() return def cmdCreator (): return OpenMayaMPx.asMPxPtr(pluginCommand()) def syntaxCreator (): syntax = OpenMaya.MSyntax() syntax.addFlag(kHelpFlag,kHelpLongFlag) syntax.addFlag(kSparseFlag,kSparseLongFlag,OpenMaya.MSyntax.kDouble) return syntax def initializePlugin (mobject ): mplugin = OpenMayaMPx.MFnPlugin(mobject) try : mplugin.registerCommand(commandName,cmdCreator,syntaxCreator) except : sys.stderr.write("Failed to register command:" + commandName) def uninitializePlugin (mobject ): mplugin = OpenMayaMPx.MFnPlugin(mobject) try : mplugin.deregisterCommand(commandName) except : sys.stderr.write("Failed to deregister command" + commandName)
1 2 3 4 range 是生成一个列表 xrange用法与range完全相同,不同的是生成的不是一个list对象,而是一个生成器 在生成很大的数字序列时候,用xrange会比range性能优很多,因为不需要一上来就开辟一块很大的内存空间 xrange和range都在循环的时候使用。
Command Execution
Undo
Redo
每执行一个Command Execution,都会把对应的命令添加到Undo队列
如果Command Execution使用Undo命令,就会把Undo队列中最后面的移到Redo队列上
如果Command Execution使用Redo命令,就会把Redo队列中最后面的移到Undo队列上
好了,写完了这个脚本,看完这集教程,终于发现,它是过时的版本,作者用的还是maya2013,非常恐怖