Docsity
Docsity

Prepare for your exams
Prepare for your exams

Study with the several resources on Docsity


Earn points to download
Earn points to download

Earn points by helping other students or get them with a premium plan


Guidelines and tips
Guidelines and tips

Using the Maya Python API - Programming Concepts for Visual Effects | VSFX 705, Study notes of Typography

Material Type: Notes; Professor: Kesson; Class: Programming Concepts for Visual Effects; Subject: Visual Effects; University: Savannah College of Art and Design; Term: Unknown 1989;

Typology: Study notes

Pre 2010

Uploaded on 08/04/2009

koofers-user-1xo-2
koofers-user-1xo-2 🇺🇸

5

(2)

10 documents

1 / 11

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
API Guide
Using the Maya Python API
It is possible to write basic scripts that use the wrapper, iterator and function set classes of
the Maya API. These scripts can query and manipulate the Maya model but are not fully
integrated into Maya. A scripted plug-in provides a more complex solution that is tightly
integrated into Maya. In this section, we discuss how to write both basic and scripted plug-in
scripts along with standalone scripts.
As this is a Python based API, knowledge of Python is required.
Importing modules
The Maya Python API is contained in a number of Python modules. You must import the
functionality that you wish to use in your script. Additionally, the Maya Python API lives in the
Maya namespace; therefore, an extra prefix is required. To import the OpenMaya module, run
the following:
import maya.OpenMaya
Help on a module or class
Information can be displayed about any of the modules or classes using the help command.
For example, if you wish to display the class information for MVector, use:
help(maya.OpenMaya.MVector)
It is also possible to display the information of an entire module:
help(maya.OpenMaya)
This operation will take a while to return since the OpenMaya module is very large.
Writing scripts
The Maya Python API modules contain the classes that are available for Python programming.
These classes are separated into different categories and have appropriate naming conventions
to signify their association. Classes include:
MFn
Any class with this prefix is a function set used to operate on MObjects of a particular type.
MIt
These classes are iterators and work on MObjects similar to the way a function set does. For
example, MItCurveCV is used to operate on an individual NURBS curve CV (there is no
MFnNurbsCurveCV), or, iteratively, on all the CVs of a curve.
MPx
Classes with this prefix are all “Proxies”, that is, API classes designed for you to derive from and
create your own object types.
pf3
pf4
pf5
pf8
pf9
pfa

Partial preview of the text

Download Using the Maya Python API - Programming Concepts for Visual Effects | VSFX 705 and more Study notes Typography in PDF only on Docsity!

API Guide

Using the Maya Python API

It is possible to write basic scripts that use the wrapper, iterator and function set classes of

the Maya API. These scripts can query and manipulate the Maya model but are not fully

integrated into Maya. A scripted plug-in provides a more complex solution that is tightly

integrated into Maya. In this section, we discuss how to write both basic and scripted plug-in

scripts along with standalone scripts.

As this is a Python based API, knowledge of Python is required.

Importing modules

The Maya Python API is contained in a number of Python modules. You must import the

functionality that you wish to use in your script. Additionally, the Maya Python API lives in the

Maya namespace; therefore, an extra prefix is required. To import the OpenMaya module, run

the following:

import maya.OpenMaya

Help on a module or class

Information can be displayed about any of the modules or classes using the help command.

For example, if you wish to display the class information for MVector, use:

help(maya.OpenMaya.MVector)

It is also possible to display the information of an entire module:

help(maya.OpenMaya)

This operation will take a while to return since the OpenMaya module is very large.

Writing scripts

The Maya Python API modules contain the classes that are available for Python programming.

These classes are separated into different categories and have appropriate naming conventions

to signify their association. Classes include:

MFn

Any class with this prefix is a function set used to operate on MObjects of a particular type.

MIt

These classes are iterators and work on MObjects similar to the way a function set does. For

example, MItCurveCV is used to operate on an individual NURBS curve CV (there is no

MFnNurbsCurveCV), or, iteratively, on all the CVs of a curve.

MPx

Classes with this prefix are all “Proxies”, that is, API classes designed for you to derive from and

create your own object types.

M classes

Most, although not all, of these classes are “Wrappers”. Examples of this class are: MVector,

MIntArray, and so forth.

We can use wrapper and function set classes to write scripts such as the following:

import maya.OpenMaya vector1 = maya.OpenMaya.MVector(0,1,0) vector2 = maya.OpenMaya.MVector(1,0,0) vector3 = maya.OpenMaya.MVector(0,0,2) newVector = vector1 + vector2 + vector print "newVector %f, %f, %f " % (newVector.x, newVector.y, newVector.z)

It is possible to shorten the symbol names used by modifying the import command:

import maya.OpenMaya as OpenMaya vector1 = OpenMaya.MVector(0,1,0)

Scripts can access dependency graph information using the Maya Python API classes. The

following is a script that finds the persp node and prints out its translateX attribute value:

import the OpenMaya module

import maya.OpenMaya as OpenMaya

function that returns a node object given a name

def nameToNode( name ): selectionList = OpenMaya.MSelectionList() selectionList.add( name ) node = OpenMaya.MObject() selectionList.getDependNode( 0, node ) return node

function that finds a plug given a node object and plug name

def nameToNodePlug( attrName, nodeObject ): depNodeFn = OpenMaya.MFnDependencyNode( nodeObject ) attrObject = depNodeFn.attribute( attrName ) plug = OpenMaya.MPlug( nodeObject, attrObject ) return plug

Find the persp camera node

print "Find the persp camera"; perspNode = nameToNode( "persp" ) print "APItype %d" % perspNode.apiType() print "APItype string %s" % perspNode.apiTypeStr()

Print the translateX value

translatePlug = nameToNodePlug( "translateX", perspNode ) print "Plug name: %s" % translatePlug.name() print "Plug value %g" % translatePlug.asDouble()

The example above demonstrates the following:

To instantiate a class, use the fn = OpenMaya.MFnFunctionSet() notation.

MObjects can be created using node = OpenMaya.MObject().

Although Python is a typeless language, you must instantiate the correct type in order

to pass it as a parameter of the class.

Python strings are passed and returned in place of the MString wrapper class.

Note

For the sake of clarity, the example above has omitted error checking.

Scripted plug-ins

Scripted plug-ins allow a developer to create a solution that is tightly coupled with Maya.

Scripted plug-ins allow a developer to support functionality such as the undoing of commands

and the building of appropriate requires lines into the Maya scene file. Another advantage of

using a scripted plug-in is that its functionality is available in both MEL and Python.

loadPlugin helixCmd.py; spHelix();

Writing a scripted plug-in

Writing a scripted plug-in requires the definition of some specialized functions within the

plug-in. The scripted plug-in must:

Define initializePlugin and uninitializePlugin entry points.

Register and unregister the proxy class within these entry points.

Implement creator and initialize methods (as required) which Maya calls to build the

proxy class.

Implement the required functionality of the proxy class. This requires importing the

necessary modules.

The following sections describe these pieces in more detail with examples.

Importing

Python uses the import keyword to include functionality from a module into a script. For

example:

import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys

It is possible for a scripted plug-in to be split among several files. The import command is used

to load the functionality of the secondary file into the scripted plug-in.

import polyModifier

Any secondary scripts must be located in the same directory as the scripted plug-in.

Scripted plug-in initialization

When a scripted plug-in is loaded, Maya searches for an initializePlugin() function in its

definition. Within this function, all proxy nodes are registered:

Initialize the script plug-in

def initializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.registerCommand( kPluginCmdName, cmdCreator ) except: sys.stderr.write( "Failed to register command: %s\n" % kPluginCmdName ) raise

If the initializePlugin() function is not found, the scripted plug-in fails to load. In addition,

during the load, Maya searches for an uninitializePlugin() function. If this is not found, then

the scripted plug-in fails to load.

Scripted plug-in uninitialization

When Maya is attempting to unload the plug-in, the previously found uninitializePlugin()

function is called to unload the resources of the plug-in.

def uninitializePlugin(mobject): mplugin = OpenMayaMPx.MFnPlugin(mobject) try: mplugin.deregisterCommand( kPluginCmdName ) except: sys.stderr.write( "Failed to unregister command: %s\n" % kPluginCmdName ) raise

Creator functions

Creator functions are used to return a derived version of a proxy class to Maya. Virtual methods

are implemented on the derived class which are called from Maya. An example of a class

definition and a creator function is:

class scriptedCommand(OpenMayaMPx.MPxCommand):

...

def cmdCreator(): return OpenMayaMPx.asMPxPtr( scriptedCommand() )

It is very important to call the OpenMayaMPx.asMPxPtr() on the newly created proxy object. This

call transfers ownership of the object from Python to Maya. Program errors will occur if you do

not make this call since Python can unreference this object and destroy it. This will leave a

dangling pointer in Maya.

Class implementation

Implementing a proxy class requires deriving from the Maya Python API object.

class scriptedCommand(OpenMayaMPx.MPxCommand): def init(self): OpenMayaMPx.MPxCommand.init(self) def doIt(self,argList): print "Hello World!"

The scriptedCommand class is derived from OpenMayaMPx.MPxCommand. The constructor or

init method must call the parent class init method. All class methods require self

as the first parameter, followed by the normal argument list. This command’s doIt() method

simply prints out “Hello World!”.

Initialization Functions

Initialization functions are used within scripted plug-ins that define new proxy nodes using the

MPxNode class. The following is an example that demonstrates how to create a simple scripted

plug-in node, the output of which is the sine function.

import math, sys import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx kPluginNodeTypeName = "spSineNode" sineNodeId = OpenMaya.MTypeId(0x8700)

Node definition

class sineNode(OpenMayaMPx.MPxNode):

class variables

input = OpenMaya.MObject() output = OpenMaya.MObject() def init(self): OpenMayaMPx.MPxNode.init(self) def compute(self,plug,dataBlock): if ( plug == sineNode.output ): dataHandle = dataBlock.inputValue( sineNode.input )

inputFloat = dataHandle.asFloat() result = math.sin( inputFloat ) * 10. outputHandle = dataBlock.outputValue( sineNode.output ) outputHandle.setFloat( result ) dataBlock.setClean( plug )

creator

def nodeCreator(): return OpenMayaMPx.asMPxPtr( sineNode() )

initializer

def nodeInitializer():

input

nAttr = OpenMaya.MFnNumericAttribute(); sineNode.input = nAttr.create( "input", "in", OpenMaya.MFnNumericData.kFloat, 0.0 ) nAttr.setStorable(1)

output

nAttr = OpenMaya.MFnNumericAttribute(); sineNode.output = nAttr.create( "output", "out", OpenMaya.MFnNumericData.kFloat, 0.0 )

method is MPxNode::compute(). In this situation, the Python code would return

OpenMaya.kUnknownParameter.

Classes support slicing

All of the number arrays (MIntArray, MUintArray, MUint64Array, MFloatArray, and

MDoubleArray) support Python-style slicing. For example:

import maya.OpenMaya as OpenMaya array = OpenMaya.MUintArray() for i in range(0,9): array.append( i ) array[2:8:2]

# Result:[2, 4, 6]

Accessing static MObjects of an MPx class

The proxy classes provide some standard information to a developer about the node that is

being used. This includes attribute objects that are used to define the node. To access a static

class MObject in the Maya Python API, similar code can be used:

envelope = OpenMayaMPx.cvar.MPxDeformerNode_envelope

After making this call, the envelope will be an MObject for MPxDeformerNode::envelope.

Messages

Message classes are supported in the Maya Python API. A Python function is passed for the

callback. This function must have the exact number of parameters required by the callback

message. If it does not, an exception will occur when the message is invoked and information

will be written to the console. Client data in the form of a python object can also be passed with

most messages. The following is an example of a message:

Message callback

def dagParentAddedCallback( child, parent, clientData ): print "dagParentAddedCallback..." print "\tchild %s" % child.fullPathName() print "\tparent %s" % parent.fullPathName() print "\tclient data %s" % clientData

Create the mesage

def createParentAddedCallback(stringData): try: id = OpenMaya.MDagMessage.addParentAddedCallback( dagParentAddedCallback, stringData ) except: sys.stderr.write( "Failed to install dag parent added callback\n" ) messageIdSet = False else: messageIdSet = True return id

Call the message creator

messageId = createParentAddedCallback( "noData" )

Modify Parameter Values Instead of Using an Assignment

In Python, it is best to modify a parameter rather than using an assignment. The code below contains an assignment and demonstrates how an error can occur: import maya.OpenMaya as OpenMaya def vectorTest(v): lv = OpenMaya.MVector(1,5,9) v = lv print "%g %g %g" % (v.x,v.y,v.z) v = OpenMaya.MVector() vectorTest(v) print “%g %g %g” % (v.x,v.y,v.z)

The second print command will emit all zeroes. In Python, either modify the parameter value or

write the code so that a new value is returned. Rewrite the vectorTest() function as follows:

def vectorTest(v): lv = OpenMaya.MVector(1,5,9) v.x = lv.x v.y = lv.y v.z = lv.z print "%g %g %g" % (v.x,v.y,v.z)

References to Basic Types

The Maya Python API contains many calls in which return values or parameters are references

to basic types such as: int&, char&, float& etc. In the Maya Python API, all references are

treated as pointers. As a result, special calls are required to create, set and access the values of

these items.

A utility class called MScriptUtil that exists in the OpenMaya.py module is used to create, get

and set values of these types.

Commands with Arguments

Commands with arguments must use the MSyntax and MArgParser classes within a scripted

MPxCommand. See the following code for an example:

import maya.OpenMaya as OpenMaya import maya.OpenMayaMPx as OpenMayaMPx import sys, math kPluginCmdName="spHelix" kPitchFlag = "-p" kPitchLongFlag = "-pitch" kRadiusFlag = "-r" kRadiusLongFlag = "-radius"

command

class scriptedCommand(OpenMayaMPx.MPxCommand): def init(self): OpenMayaMPx.MPxCommand.init(self)

def doIt(self, args): deg = 3 ncvs = 20 spans = ncvs - deg nknots = spans+2*deg- radius = 4. pitch = 0.

Parse the arguments.

argData = OpenMaya.MArgDatabase(self.syntax(), args) if argData.isFlagSet(kPitchFlag): pitch = argData.flagArgumentDouble(kPitchFlag, 0) if argData.isFlagSet(kRadiusFlag): radius = argData.flagArgumentDouble(kRadiusFlag, 0) controlVertices = OpenMaya.MPointArray() knotSequences = OpenMaya.MDoubleArray()

Set up cvs and knots for the helix

for i in range(0, ncvs): controlVertices.append( OpenMaya.MPoint( radius * math.cos(i), pitch * i, radius * math.sin(i) ) ) for i in range(0, nknots): knotSequences.append( i )

Now create the curve

curveFn = OpenMaya.MFnNurbsCurve()

nullObj = OpenMaya.MObject() try:

This plugin normally creates the curve by passing in the

cv's. A function to create curves by passing in the ep's

has been added. Set this to False to get that behaviour.

if True: curveFn.create( controlVertices, knotSequences, deg,

OpenMaya.MFnNurbsCurve.kOpen, 0, 0, nullObj )

def init(self): OpenMayaMPx.MPxToolCommand.init(self) self.setCommandString(kPluginCmdName) self.__delta = OpenMaya.MVector() kTrackingDictionary[OpenMayaMPx.asHashable(self)] = self

3. Retrieve self from the dictionary using the pointer.

Code is in a different class

Pointer is returned

newCmd = self._newToolCommand()

Use pointer to get to self of the command

self.__cmd = kTrackingDictionary.get(OpenMayaMPx.asHashable(newCmd), None)

Set the class variable

self.__cmd.setVector(0.0, 0.0, 0.0)

4. Clean up the tracking dictionary.

def del(self): del kTrackingDictionary[OpenMayaMPx.asHashable(self)]

For examples that demonstrate these principles, see the Development Kit.

Operating System Types

There are some methods in the Maya Python API that require operating system

types. As these are not included in Python, a MStreamUtils class is available for creating and

using these type of objects. Please check the Development kit for examples on how to use this

class.

Calling into the Parent class

Often when writing an MPx proxy class, the scripts will require calling into the parent class. This

is done using notation such as the following:

matrix = OpenMayaMPx.MPxTransformationMatrix.asMatrix(self)

Enum values

Enum values are accessed using a moduleName.className.value notation such as:

OpenMaya.MSyntax.kDouble

Using OpenGL

We have provided a wrapper class MGLFunctionTable for using OpenGL functionality in script

on all of our support platforms. To acquire a reference to this class use the following code:

glRenderer = OpenMayaRender.MHardwareRenderer.theRenderer() glFT = glRenderer.glFunctionTable()

Standalone Scripts

It is possible to write standalone scripts that make use of the wrapper classes and function

sets to modify the Maya model. These scripts are run from the command line. A simple “hello

world” standalone script follows:

import maya.standalone import maya.OpenMaya as OpenMaya import sys def main( argv = None ): try: maya.standalone.initialize( name='python' ) except: sys.stderr.write( "Failed in initialize standalone application" )

raise sys.stderr.write( "Hello world! (script output)\n" ) OpenMaya.MGlobal().executeCommand( "print "Hello world! (command script output)\n"" )

if name == "main": main()

After the standalone is initialized, function sets and wrapper classes can be used to create and

modify a Maya model. This script must be run using the Python executable that is supplied

with Maya. For example:

$MAYA_LOCATION/bin/mayapy helloWorld.py