This article will go through Maya tool development options. We will look at both API and scripting, where main focus will be on scripting comparing MEL, maya.cmds, and PyMel.
Maya API
The API is designed to be as high performing as possible. In the end, your code results in a Maya plug-in. Maya ships with 3 choices for API programming:
- C++ API
- maya.OpenMaya (Python API 1.0)
- maya.api.OpenMaya (Python API 2.0) – Faster & more Pythonic. Newer and still under development.
Next, lets look at Maya scripting.
Maya Scripting
Scripting is a very fast way to develop Maya tools and pipelines and it is iteration friendly. We have three choices when it comes to scripting.
- MEL
- maya.cmds
- pymel
Let’s start by looking at MEL.
MEL
Maya Embedded Language (MEL) has been a part of Maya since it’s initial release in 1998.
Having worked for a long time with MEL, it took me a while to leave the safety of what I knew to embrace Python. Once I did, there was no going back. If you do have to go back – you would feel very sad inside 😀 .
Below is a quick look at the syntax of MEL.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//Mel Syntax string $selection[] = `ls -selection`; print $selection; string $shapes[] = `listRelatives -shapes $selection[0]`; string $type = `nodeType $shapes[0]`; if ($type == "mesh"){ changeSelectMode -component; selectType -polymeshVertex 1; polySelectConstraint -mode 3; polySelectConstraint -where 1 -type 1; polySelectConstraint -mode 0; string $verts[] = `ls -selection -flatten`; select -replace $verts ; } |
Next, we are going to look at the 2 different python scripting choices Maya offers, but first we will take a look at all the nice things we can use in our Maya tools by just switching to Python.
Python
A Python interpreter was added in Maya 8.5 and it brought so many capabilities that MEL scripters had not previously had.
One of Python’s main features is listed in PEP 20 – The Zen Of Python, which is “readability counts”. The truth is, the more readable your code is, the faster you and everyone else can work. Some of the other points listed in PEP 20 are not bad either 🙂
- Readability Counts
- Simple is better than complex
- Complex is better than complicated
- Flat is better than nested
- Sparse is better than dense
- There should be one – and preferably only one – obvious way to do it
- Although that way may not be obvious at first unless you’re Dutch
- If the implementation is hard to explain, it’s a bad idea
- If the implementation is easy to explain, it may be a good idea
Below are a few Python favorites that I could not live without. If you look at the standard Python library, you realize the breadth of things you can do with Python out of the box. If there is something that you can not do, someone has written a library that you can download and use from the Python package index. It is mind numbing how many packages there are out there. There are countless articles out there listing the “best” ones if you Google “best Python package 2017“.
String Formatting
String formatting is great, it allows you to have a better overview over the string you are building (compared to concatenation), as well as it can easily cast to different data types.
1 2 3 4 5 6 7 8 9 10 |
# Python String Formatting myNumber = 43.67 exampleString = 'The chance is %s percent' % myNumber 'The chance is 43.67 percent' # It is also much easier to read, especially when you are building longer strings import getpass # Instead of doing this pathToMyDocs = 'C:/Users/' + getpass.getuser() + '/Documents' # Do this pathToMyDocs = 'C:/Users/%s/Documents' % getpass.getuser() |
List Comprehension
I use list comprehension on a daily basis. I wrote a more in-depth post about list comprehension here. The syntax can be seen below.
1 2 |
# List comprehension (Python sugar) lod0Meshes = [ groupMesh for groupMesh in group.getChildren() if re.search('_lod0', groupMesh.name(), re.I) ] |
Complete File System Package
os.walk – traverses directory structures and while doing so give you three parts of the current path in the loop – filename, directory, and root (full path to the filename). Typically tech artists do a lot of directory crawling when we build pipelines and work flows and os.walk is invaluable for this purpose.
1 2 3 4 5 6 7 |
import os xmlFiles = [] for root, file, dir in os.walk(myPath): fullPath = '%s/%s' % (root, file) 'C:/test/myTest/test.xml' if fullPath.endswith('.xml'): xmlFiles.append(file) |
Built in JSON, XML & SQL Libraries
Having the ability to use the most common data container formats in our Maya tools is key. Element Tree in Python rocks and is very straightforward and easy to use.
In the example below, we parse an XML file, get the tree iterator, get an attribute value, eval getting an attribute (Python trick to enable us to write Python variable types like dictionaries and lists straight into the XML and when evaluated it casts into a the correct type), setting an attribute value, and writing the XML back out.
1 2 3 4 |
Core attributeName="myAttr" attributeName2="['one', 'two', 'three']" /Core |
1 2 3 4 5 6 7 8 9 10 11 |
import xml.etree.ElementTree xmlPath = 'C:/test.xml' testXml = xml.etree.ElementTree.parse(xmlPath) core = testXml.getiterator('Core')[0] attributeNameValue = core.get('attributeName') attributeName2Value = core.get('attrubuteName2') core.set('attributeName', 'modifiedAttr') myList = eval-(attributeName2Value) ['one', 'two', 'three'] type(myList) type 'list' |
1 2 3 4 |
Core attributeName="modifiedAttr" attributeName2="['one', 'two', 'three']" /Core |
maya.cmds
Autodesk introduced maya.cmds in Maya 8.5 and it is the module that ships with Maya that wraps all the MEL commands to Maya’s Python interpreter. The syntax of this module is very MEL like and not very “Pythonic”. Because of this, a movement was born to create a better Python implementation called PyMel.
To clearly illustrate the MEL like structure of maya.cmds, I put the MEL command as a comment before each of the maya.cmds equivalents.
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 |
###### Python Land ######### ##### - Python Wrapped MEL - ##### import maya.cmds selection = maya.cmds.ls(selection=True) maya.cmds.select(selection[0]) #string $selection[] = `ls -selection`; shapes = maya.cmds.listRelatives(selection[0], shapes=True) #string $shapes[] = `listRelatives -shapes $selection[0]`; type = maya.cmds.nodeType(shapes[0]) #string $type = `nodeType $shapes[0]`; if type == 'mesh': maya.cmds.selectMode(component=True) maya.cmds.selectType (polymeshVertex=True) maya.cmds.polySelectConstraint(mode=3) maya.cmds.polySelectConstraint(where=True, type=True) maya.cmds.polySelectConstraint(mode=0) verts = maya.cmds.ls(selection=True, flatten=True) maya.cmds.select(verts, replace=True) #if ($type == "mesh"){ # changeSelectMode -component; # selectType -polymeshVertex 1; # polySelectConstraint -mode 3; # polySelectConstraint -where 1 -type 1; # polySelectConstraint -mode 0; # string $verts[] = `ls -selection -flatten`; # select -replace $verts ; #} |
PyMel
PyMel has shipped with Maya since Maya 2013 and is a “Pythonic” implementation of all the Maya commands. The PyMel classes are object oriented and are very powerful due to the API hybridization that they bring.
The heart of PyMel is the PyNode, which is what you get when you store a selection or do other types of queries. PyMel can cast all of Maya’s object types into a PyNode object that has a tie to the API node itself. Attached to this object is a wide array of methods that are relevant to the type of node that you are dealing with.
Check out the syntax of pymel below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
###### Python Land ######### ##### - Object Oriented - ##### ##### - "Pythonic" - ##### import pymel.core.general selection = pymel.core.general.selected()[0] #selection = maya.cmds.ls(selection=True) shapes = pymel.core.general.listRelatives(selection[0], shapes=True) #shapes = maya.cmds.listRelatives(selection[0], shapes=True) ##### - With Pymel there is a better way - ###### shape = selection.getShape() if selection.getShape().type() == 'mesh': borderVerts = [vert for vert in selection.getShape().verts if vert.isOnBoundary()] pymel.core.general.select(borderVerts, replace=True) |
If you have not checked out pymel and are coding with maya.cmds, do yourself a favor and have a look at the documentation here.
That wraps up this overview of Maya tool development.
Are you already using PyMel? Love it or hate it? Be social and drop a comment below – I always like hearing from fellow tech artists.
Spread the knowledge