The pymxs Python module provides a wrapper for the MAXScript engine, and exposes virtually all the interfaces, globals, and classes available in MAXScript.
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.
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)
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
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.
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"))
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.
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