[Modo] Scripting Advice

Hey all,

I’m in a position to be writing tools for Modo, and I’m having trouble finding scripting resources and documentation. Anyone have any links/advice they’ll share for scripting in Modo?

I’m comfortable with Python and have started writing in Python, but the documentation on their python module seems to be lacking built-in support.

The standard place for the scripting docs (on windows) is
C:/Program Files/Luxology/modo 501/help/Scripting_and_Commands.pdf
It’s useful when you start diving into scripting but later on your best bet
will be the forums: http://forums.luxology.com/forum.aspx?f=119

Inside modo find the “Command History” panel where you can see what
you’ve done by clicking but in command form , all available commands and
the results of executed commands. (I also have the Event log visible.)
With these you can often act out a sequence of actions and then simply
copy-paste the commands from the History panel to your script (with the
language specific lx() functions of course).

As for Python, no idea how well that works, I only used Lua. It had a few
hiccups but was fine most of the time.

A bunch of our modelers have moved over to Modo, so we’ve started supporting them with tools.

We use Python. We ended up writing a ton of modules for interacting with the built-in macro system in a way that feels object-oriented even though under the hood Modo’s scene organization is completely different. It wasn’t a small undertaking by any means. We use approximately one python command out of the lx module: eval. You pretty much just have to learn the command macros and do a lot of string processing :wink:

The first advice I have is to make sure you understand how object queries can influence subsequent macro commands. In many cases, querying a basic property of an object puts it in focus, or selects it, or however you’d like to think of it. Subsequent commands rely on that previous “selection” in order to know which object to reference when executing. For example, if I want to find out information about a channel on an object “mesh013”, I’d first “select” the object like so (in python):

lx.eval( "!query sceneservice item.ID ? mesh013" )

I’m not even bothering to store the item’s ID. Actually I already know it – it’s mesh013. So this would be a silly and pointless query if it weren’t necessary to “select” this object. In this case I could be querying anything about mesh013, name, id, whatever. I have to do this only because there is no explicit way to specify an object in the next query, where I find out the first channel’s name:

channelName = lx.eval( "!query sceneservice channel.name ? 0" )

I’ve also gotten into the habit of indiscriminate use of the exclamation point, as you can see above. It suppresses dialogs including error dialogs for the specific command you just ran. Double exclamation points suppress all dialogs, so if the command you ran has sub-commands, all their dialogs are also suppressed.

What else? Well, in the current version of Modo, each time you run a python script a new instance of python is opened, and it shuts down when script execution ends. This has a couple of effects. Obviously, there’s no scripted variable persistence. You can store data if necessary in user values. Less obvious: if you’re attaching a debugger you need to make sure it isn’t set up to expect a persistent connection.

We spent a ton of time just testing and running through individual commands. Not everything works the way you’d expect, and some things are actually not fully functional. So as you test, be aware that you need to test not just your code but the commands themselves to make sure you’re getting what you expect. The documentation isn’t fully accurate in all cases and there are still bugs because honestly the command system is not well exercised by the vast majority of Modo users. Modo scripters are a very very small community. But if we grow things can only improve, so it’s cool that you’re interested.

That’s the best advice I’ve got. Let me know if you have specific questions. Having been through setting up the foundation for our Python tools in Modo as well as having written some end-user-facing scripts, I know all sorts of interesting things.

A few random tips:

Turn off “Slip UV” before transforming a mesh:

lxeval("!tool.attr xfrm.transform lockUV false")

Back in 501 selecting a layer was somewhat unreliable so I
had to do it in two different ways:

lx("select.layer "..layerIndex.." set")
lxq("query layerservice layer.name ? "..layerIndex)

The following command switches to a 3D view so invoked transform
tools work in 3D data even if the user started the script
from a UV view:

lxeval("tool.viewType xyz")

Certain commands executed from a script do not change the
scene data visible to the script, they only become visible when
the main viewports are redrawn. (Or something like that.)
I ran into this when my script applied a morph map then froze
the SDS: the freezing ran on the original, morph-less state until
I forced out a view update right after the morph application:

lx("scene.saveAs \"C:\" $LXOB false")

Ugly hack, creates a ‘Save failed’ error popup but it also updates
the data the script working with. Click OK and let the script finish.

http://www.matt-cox.co.uk/blog/2013/2/17/queryable-commands