Download presentation
Presentation is loading. Please wait.
Published byMarjory Nelson Modified over 9 years ago
1
© 2007 Autodesk1 Python in Maya 1.Maya Python API Scripts write scripts that access functionality previously available only through the C++ API 1.Maya Python API Scripted Plug-ins define new commands, nodes, etc using Python like C++ plug-ins written in Python 2.Maya Python Standalone Apps like MLibrary-based C++ apps, but written in Python Non UI 3.Using UI with Python in Maya
2
© 2007 Autodesk2 Maya Python API Plug-ins.... Define a Python module containing initializePlugin(), uninitializePlugin() functions def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand("foo", cmdCreator) except: sys.stderr.write( "Failed to unregister" ) raise
3
© 2007 Autodesk3 Maya Python API Plug-ins.... Load from Plug-in Manager or loadPlugin command maya.cmds.loadPlugin( "C:/foo.py" )
4
© 2007 Autodesk4 Maya Python API Plug-ins.... Can be split into multiple files Import other modules Not on PYTHONPATH Additional modules must be in same directory Load mechanism pushes and pops sys path
5
© 2007 Autodesk5 Python API: Deriving from Proxies Similar setup to C++ plug-ins class scriptedCommand(OpenMayaMPx.MPxCommand): def __init__(self): OpenMayaMPx.MPxCommand.__init__(self) def doIt(self,argList): print "Hello World!" Parameter: self same as this in C++
6
© 2007 Autodesk6 Python API: Creators/Initializers Similar to C++ plug-ins Pass Python function to MFnPlugin methods (cmdCreator to registerCommand() ) Ownership is important
7
© 2007 Autodesk7 Python API: Creators/Initializers… Ownership is important Use OpenMayaMPx.asMPxPtr() Xfers ownership of newly-created command or node objects to Maya def cmdCreator(): return OpenMayaMPx.asMPxPtr(scriptedCommand())
8
© 2007 Autodesk8 Python API: Enums Enums not individual types as in C++ Instead, access as integer class members Python help() is useful to look at class setup help( maya.OpenMaya.MSyntax ) [....] | kNoArg = 1 | | kNone = 1 | | kSelectionItem = 10 |
9
© 2007 Autodesk9 Python API: O/S Types types are not in Python Required by some Maya API classes Example: MPxData::writeASCII( std:ostream& out ) Use MStreamUtils in Python for this: class blindDoubleData( OpenMayaMPx.MPxData ): [...] def writeASCII( self, out ): OpenMaya.MStreamUtils.writeDouble( out, self.__val, False )
10
© 2007 Autodesk10 Python API: Examples Most code translates readily from C++ to Python # DG modifier to change perspective camera translateX import maya.OpenMaya as om sel = om.MSelectionList() om.MGlobal.getSelectionListByName( "persp“, sel ) dagPath = om.MDagPath() sel.getDagPath( 0, dagPath ) dagPath.fullPathName() # Result: |persp # mod = om.MDGModifier() mod.commandToExecute( "setAttr persp.tx 5" ) mod.doIt() maya.cmds.getAttr( "persp.tx" ) # Result: 5 # mod.undoIt() # Result: 28 #
11
© 2007 Autodesk11 Python API: Examples Commands with arguments must use the MSyntax and MArgParser classes within a scripted MpxCommand: devkit/plug-ins/scripted/helixCmd.py
12
© 2007 Autodesk12
13
© 2007 Autodesk13 Python API: Differences vs C++ No MStatus class - use exceptions instead try: fnPlugin.registerCommand( “spLs", cmdCreator ) except: sys.stderr.write( "Command registration failed") raise Catch error if registerCommand() fails
14
© 2007 Autodesk14 Python API: Differences vs C++ Detect error but allow code to keep running try: fnPlugin.registerCommand( “spLs", cmdCreator ) except: sys.stderr.write( "Command registration failed") pass Keyword pass used instead of raise
15
© 2007 Autodesk15 Python API: Differences vs C++ MStatus-like values used in specific situation Return value of MPxNode::compute() return maya.OpenMaya.kUnknownParameter
16
© 2007 Autodesk16 Python API: Differences vs C++ MString and MStringArray classes have been replaced by Python native strings and string lists import maya.OpenMaya as om sel = om.MSelectionList(); om.MGlobal.getSelectionListByName( "persp", sel ) path = om.MDagPath() sel.getDagPath(0, path ) myString = path.fullPathName() print "Path is %s" % myString # Path is |persp # myStrings = [] sel.getSelectionStrings( myStrings ) print myStrings # [u'persp'] # Makes for simpler code
17
© 2007 Autodesk17 Python API: Differences vs C++ Maya doc: en_US/API/class_m_script_util.html Python does not have a concept of pointers Use MScriptUtils for working with pointers and references Reference treated as a pointer MScriptUtils creates objects that can be passed as pointer or reference parameters convenience methods for transferring values between these objects and native Python datatypes
18
© 2007 Autodesk18 Python API: MScriptUtils (C++) int MImage::getSize( unsigned int& width, unsigned int& height ) (Python) img = OpenMaya.MImage() img.create( 512, 256 ) util = OpenMaya.MScriptUtil(0) util2 = OpenMaya.MScriptUtil(0) wPtr = util.asUintPtr() # creates a ptr object hPtr = util2.asUintPtr() # creates another ptr object OpenMaya.MScriptUtil.setUint( wPtr, 0 ) OpenMaya.MScriptUtil.setUint( hPtr, 0 ) img.getSize( wPtr, hPtr ) width = OpenMaya.MScriptUtil.getUint( wPtr ) # 512 height = OpenMaya.MScriptUtil.getUint( hPtr ) # 256
19
© 2007 Autodesk19 Python API: More MScriptUtils.... Another example: working with arrays (C++) int MImage::setDepthMap( const MFloatArray& depth, unsigned int width, unsigned int height ) float *MImage::depthMap( MStatus *returnStatus ) const (Python) img = OpenMaya.MImage() img.create( 512, 256 ) depthArray = [] for i in range(0,512*256): depthArray.append( i ) su = OpenMaya.MScriptUtil() su.createFromList( depthArray, 512*256 ) img.setDepthMap( su.asFloatPtr(), 512, 256 ) readBack = img.depthMap() for i in range( 0, 512*256 ): readDepth = OpenMaya.MScriptUtil.getFloatArrayItem(readBack, i ) if( readDepth != i ): print( "Depth error" )
20
© 2007 Autodesk20 Python API Scripts Discussed using maya.cmds in Script Editor and modules and maya.OpenMaya* in Python scripted plug-ins separately Same usage distinctions as C++/MEL With Python, the line between a "script" and a "plug-in" is blurred Can access maya.OpenMaya* API classes outside of a scripted plug-in
21
© 2007 Autodesk21 Python API Scripts: Example Example that accesses the MFnMesh ray-mesh intersection functionality Casts a ray along a given linear NURBS curve and places a sphere at the point where the curve intersects a mesh
22
© 2007 Autodesk22 Python API Scripts: Example #devkit/plug-ins/scripted/meshIntersect.py import maya.cmds as mc import maya.OpenMaya as om def meshIntersect_doIt(*args): (mesh, curve) = getSelected() # get ray start/end fnCurve = om.MFnNurbsCurve( curve ) numCVs = fnCurve.numCVs() curveStart = mc.pointPosition( curve.fullPathName() + ".cv[0]", w=True ); curveEnd = mc.pointPosition( curve.fullPathName() + (".cv[%d]" % numCVs), w=True ); source = om.MFloatPoint(curveStart[0], curveStart[1], curveStart[2]) dir = om.MFloatVector(curveEnd[0]-source.x, curveEnd[1]-source.y, curveEnd[2]- source.z ) # cast ray hitPoint = om.MFloatPoint() fnMesh = om.MFnMesh( mesh ) hit = fnMesh.closestIntersection( source, dir, None, None, True, om.MSpace.kWorld, 1.0, True, None, hitPt, None, None, None, None, None ); # implement result if( hit ): mm.eval( "polySphere -r 0.1; move %f %f %f" % (hitPt.x, hitPt.y, hitPt.z) )
23
© 2007 Autodesk23 Python API Scripts: Caveats Careful about undo API functionality is not automatically undoable in the same way that MEL commands are With Python API code operating outside of an MPxCommand- derived class, there is no formal interface to allow you to implement your own undo behaviour Careful with scripted plug-ins Importing the.py file is not the same as loading it from the Plug-in Manager Will not register new commands/nodes
24
© 2007 Autodesk24 Maya Python Standalones Autodesk provide the maya.standalone module for Creating standalone Maya command-line apps Similar to MLibrary-based standalone apps created with C++ Python-based standalones are platform independent Run using: mayapy Python interpreter that ships with Maya
25
© 2007 Autodesk25 Standalone Example Sample application defaultShading.py Opens a Maya file Assigns the default shader to all meshes Saves the scene Written as a standalone Maya Python application Uses the optparse Python module for command line parsing Could be done platform-independently with MEL and "mayabatch - cmd“ Putting together proper command string can be difficult Could also be done in C++ as an MLibrary-based app
26
© 2007 Autodesk26 Standalone Example..... from optparse import OptionParser [...other imports...] def assignDefaultShader( srcFile, dstFile ): [...] def main( argv = None ): parser = OptionParser() parser.add_option("-s", "--sourceFile", dest="srcFile", help="process SOURCEFILENAME") parser.add_option("-d", "--destFile", dest="dstFile", help="save to DESTFILENAME") (options,args) = parser.parse_args() maya.standalone.initialize( name='python' ) assignDefaultShader( options.srcFile, options.dstFile ) if __name__ == "__main__": main(sys.argv[1:])
27
© 2007 Autodesk27 Running the Standalone Example C:> mayapy defaultShading.py --help usage: defaultShading.py [options] options: -h, --help show this help message and exit -s SOURCEFILENAME, --sourceFile=SOURCEFILENAME process SOURCEFILENAME -d DESTFILENAME, --destFile=DESTFILENAME save to DESTFILENAME C:> mayapy defaultShading.py -s "C:/foo.mb" -d "C:/bar.mb" processed C:/foo.mb into C:/bar.mb
28
© 2007 Autodesk28 Using External Python Interpreters Can use Maya Python package in any Python 2.4.3 interpreter Just need to configure a few variables: Put Maya site-packages directory in sys.path Set MAYA_LOCATION Put Maya bin directory in PATH environment variable mayapy interpreter does all this automatically for you
29
© 2007 Autodesk29 External Python Interpreters..... Can do all this setup on the fly - recode our previous standalone example # Running from a script file if __name__ == "__main__": if( not os.environ.has_key("MAYA_LOCATION") ): print( "External Python interpreter - initialize Maya paths" ) mayaDir = "C:\\Program Files\\Autodesk\\Maya8.5" sys.path.append( mayaDir + "\\Python\\Lib\\site-packages" ) os.environ["MAYA_LOCATION"] = mayaDir os.environ["PATH"] = os.environ["PATH"] + ";" + mayaDir + "\\bin" else: print( "mayapy interpreter - paths already initialized" ) import maya.standalone maya.standalone.initialize( name='python' ) import maya.cmds as mc import maya.OpenMaya as om import maya.mel as mm main(sys.argv[1:])
30
© 2007 Autodesk30 External Python Interpreters..... C:> mayapy defaultShading2.py -s foo.mb -d bar.mb mayapy interpreter - paths already initialized Processed foo.mb into bar.mb C:> python defaultShading2.py -s foo.mb -d bar.mb External Python interpreter - initialize Maya paths Processed foo.mb into bar.mb Why do this? So that you can write (standalone) Maya Python scripts in your chosen external Python IDE
31
© 2007 Autodesk31 Example: Using the loadUI command # devkit/scripts/createDialog.py # devkit/scripts/createDialog_py.ui dialog = cmds.loadUI(uiFile='/q/devkit/scripts/createDialog_py.ui') cmds.showWindow(dialog)
32
© 2007 Autodesk32 Example: Using PyQt # devkit/scripts/qtWindow.py import sip import maya.OpenMayaUI as mui from PyQt4.QtCore import * from PyQt4.QtGui import * def getMayaWindow(): ptr = mui.MQtUtil.mainWindow() return sip.wrapinstance(long(ptr), QObject) class Form(QDialog): def __init__(self, parent=None): super(Form, self).__init__(parent) self.setObjectName('mainUI') self.mainLayout = QVBoxLayout(self) self.myButton = QPushButton('myButton') self.mainLayout.addWidget(self.myButton) global app global form app = qApp form = Form(getMayaWindow()) form.show()
33
© 2007 Autodesk33 Example: OpenGL from Python Easy to create MPxLocator- based nodes with custom draw routines in Python Access OpenGL through GL function table provided by the API
34
© 2007 Autodesk34 Example: OpenGL from Python....... import maya.OpenMayaRender as OpenMayaRender glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() glFT = glRenderer.glFunctionTable() class pyLocatorNode( OpenMayaMPx.MPxLocatorNode ): [.....] def draw( self, view, path, style, status ): view.beginGL() glFT.glDisable(OpenMayaRender.MGL_LIGHTING) glFT.glBegin(OpenMayaRender.MGL_LINES) glFT.glColor3f( 1.0, 0.0, 0.0 ) glFT.glVertex3f( 0.0, 0.0, 0.0 ) glFT.glVertex3f( 3.0, 0.0, 0.0 ) glFT.glColor3f( 0.0, 1.0, 0.0 ) glFT.glVertex3f( 0.0, 0.0, 0.0 ) glFT.glVertex3f( 0.0, 3.0, 0.0 ) glFT.glColor3f( 0.0, 0.0, 1.0 ) glFT.glVertex3f( 0.0, 0.0, 0.0 ) glFT.glVertex3f( 0.0, 0.0, 3.0 ) glFT.glEnd() glFT.glEnable(OpenMayaRender.MGL_LIGHTING) view.endGL()
35
© 2007 Autodesk35 Example: Multi-threading Python has a convenient module for creating and managing multiple threads import threading class MyThread( threading.Thread ): def run( self ): doSomeStuff() MyThread().start()
36
© 2007 Autodesk36 Example: Multithreading..... Maya API, Command Engine, and DG are not thread-safe maya.cmds Throws an exception when called from outside the main thread maya.OpenMaya* functionality Exhibit undesirable behaviour when called from outside the main thread maya.utils.executeInMainThreadWithResult() Allows safe execution of a Python command from outside the main thread
37
© 2007 Autodesk37 Example: Multithreading...... Using Python's threading and socket libraries: Create a simple Command Port replacement Spawn a thread that: opens a socket listens for Python commands runs them
38
© 2007 Autodesk38 Example: fakeCommandPort # Location: devkit/scripts/fakeCommandPort.py def openSocket(portNum): mySocket = socket.socket ( socket.AF_INET, socket.SOCK_STREAM ) mySocket.bind ( ( '', portNum ) ) mySocket.listen ( 1 ) channel, details = mySocket.accept() msg = channel.recv(4096) res = maya.utils.executeInMainThreadWithResult( msg ) resString = pickle.dumps(res) # serialize data structure channel.send( resString ) channel.close() class CmdPortThread( threading.Thread ): def run( self ): openSocket(5722) def fakeCommandPort(): CmdPortThread().start()
39
© 2007 Autodesk39 Example: Multithreading...... From Maya Run fakeCommandPort() to start the server Uses the "pickle" library to serialize Python data structures for transmission over the network and reconstruct on the client side From an external Python interpreter, do: s=socket.socket( socket.AF_INET, socket.SOCK_STREAM ) s.connect( ('localhost',5722) ) s.send( “maya.cmds.ls()” ) resultBuf = s.recv(4096) result = pickle.loads(resultBuf) # restore serialized structure # [u'time1',....] #
40
© 2007 Autodesk40 End
Similar presentations
© 2025 SlidePlayer.com Inc.
All rights reserved.