pymxs API Introduction

The pymxs Python module provides a wrapper for the MAXScript engine, and exposes virtually all the interfaces, globals, and classes available in MAXScript.

Using the MAXScript Runtime in Python

The pymxs module exposes the MAXScript runtime, and all the global symbols it contains, to Python scripts. The runtime is dynamic, so global objects created in MAXScript are subsequently available to pymxs.runtime.

The names of objects available in the pymxs.runtime module correspond to MAXScript globals. So, for example, to create a teapot you can use the MAXScript Teapot() constructor like this:

>>> import pymxs
>>> rt = pymxs.runtime
>>> t = rt.Teapot()
>>> rt.classOf(t)
<GeometryClass<Teapot>>

Note: To print output in pymxs, use the pymxs.print_() function. This is provided because the "print" function in MAXScript conflicts with the Python print statement.

MAXScript Context Expressions

The pymxs module exposes MAXScript context expressions that can be used in conjunction with the Python with statement. These expressions are:

For example, to create a teapot and animate it:

import pymxs
at = pymxs.attime
rt = pymxs.runtime
t = rt.Teapot()

with pymxs.animate(True):
with at(1):
    t.pos = rt.Point3(2,2,2)
with at(12):
    t.pos = rt.Point3(10, 10, 10)
with at(21):
    t.pos = rt.Point3(20,20,20)

MAXScript Undo System

The undo system is exposed in pymxs with:

As with MAXScript, operations run through pymxs are not recorded by the undo system. Undo must be specifically enabled. Undoable pymxs operations appear as items labeled MAXScript in the 3ds Max Undo menu.

For example, to create a teapot, change its position, and then undo the change:

import pymxs
rt = pymxs.runtime
# this will not be undoable:
with pymxs.undo(False):
    t = rt.Teapot()

with pymxs.undo(True):
    t.pos = rt.Point3(20,20,20)

pymxs.run_undo() # undo the position
pymxs.run_redo() # redo the position

MAXScript Type Marshalling

For simple types such as integers, floats and strings, pymxs has a direct reference to the data, and these values can be obtained and set directly.

For complex types such as Array, pymxs wraps these objects with a MXSWrapper object, pymxs.MXSWrapperBase. For example:

import pymxs
rt = pymxs.runtime

# Create and visit a MaxScript Array
rt.execute(" gma = #(1,2,3)")
print rt.gma    #output: #(1,2,3)
len(rt.gma)    #output: 3
rt.gma[1] = 999
rt.Print(rt.gma[1])    #output: 999
l = list(rt.gma) #[1,999,3]
l[2] = 888
print l    #output: [1, 888, 3]
print rt.gma   # output: #(1, 999, 3)

# Create a MaxScript Array via python sequence
ma = rt.Array(*(1, 2, 3))
print ma    #output: #(1,2,3)

For a complete demonstration of how to create, manipulate and cast complex MAXScript types in Python, see the demoPyMXSTypeInterop.py example.

MAXScript Names

Name values in MAXScript can be referenced with pymxs.runtime.Name. For example, to use toolmode.coordsys world:

pymxs.runtime.toolMode.coordsys(pymxs.runtime.Name("world"))

Multi-threading With MAXScript

You cannot call pymxs.runtime commands directly on a worker thread, as this will cause a runtime exception. However, pymxs has a mxstoken() function to support multi-threading by providing a synchronization mechanism between worker threads.

For an example of this approach, see the example <maxdirectory>\scripts\Python\demoMXSToken.py.

By-Reference Parameter Handling

Values passed back to Python from pymxs MAXScript functions that take a by-reference parameter, can be translated to Python values using the pymxs.mxsreference() function. Note that this is supported for types other than Python lists.

For example:

import MaxPlus
rt = pymxs.runtime

MaxPlus.Core.EvalMAXScript("mySphere2 = sphere()")
MaxPlus.Core.EvalMAXScript("myType = #reference")
MaxPlus.Core.EvalMAXScript("myResultArray = Array()")

myReturnedList = []
rt.maxOps.cloneNodes(rt.mySphere2,  cloneType=rt.myType, newNodes=pymxs.mxsreference(myReturnedList))
print "python array: "
print myReturnedList

rt.maxOps.cloneNodes(rt.mySphere2,  cloneType=rt.myType, newNodes=pymxs.mxsreference(rt.myResultArray))
print "runtime array: "
print rt.myResultArray

Note: for variables other than Python lists, the variable must be visible in the pymxs.runtime context. For example, to pass a variable of type Color:

import pymxs
rt = pymxs.runtime
MaxPlus.Core.EvalMAXScript("myColor = color 100 10 10")
print rt.myColor
rt.maxOps.colorById(2,pymxs.mxsreference(rt.myColor))
print rt.myColor

Whereas, this approach will not work:

import pymxs
rt = pymxs.runtime
myColor=rt.color(10,10,10)
print myColor
rt.maxOps.colorById(2,pymxs.mxsreference(myColor))
print myColor