Has anyone been able to query Max scene elements through python?
Basic things like get selected objects, or get the joints in the scene into a python array?
example:
myArray = []
mx.command_from_python('for i in $ do ("python.myArray.append(i)")')
#so I could later do something like
for obj in myArray:
print obj
I really don’t know much about MaxScript, but for my tool, where I need to make a list of cameras to extract values from, I had to create the array inside Max and then call it from Python.
(the MaxDo is just a shorter name from the earlier example using DoSomething)
conn.MaxDo(‘myMaxArray = #()’) # create array in Max
conn.MaxDo(‘myMaxArray[1]’) # access the first element in your Python code
Thanks for the ideas
90% of the time I am dealing with arrays, I need the size and looping abilities. So calling a max array doesn’t seem too valuable since I can’t
for i in myArray:
print i
But I do like the idea of getting a string from Max and parsing the crap out of that. Especially since python is pretty good dealing with strings.
If you’re using COM to connect to Max using Python, you’re going to be limited to the data types that COM supports for return values. Offhand, I believe the supported types coming from Max are string, float, integer, boolean, color and one-dimensional arrays of those same types.
In any case, if you issue a command from Python that would normally return an data type that’s specific to 3ds Max (such as Color, Node, quat, etc), the COM layer will throw an error.
I’ve dealt with this in my Python-Max tools by creating a function that acts like a little layer between Python and MaxScript. If the command executed returns a value that’s not one of the native COM types, it casts the value to a string before sending it back to Python. That way the Python code has the option of doing something useful with it instead of being faced with a useless error. The wrapper function is then what’s exposed over COM, or some other function that uses it.
For instance, a node value in MaxScript would normally look like this:
$Teapot:Teapot01 @ [-36.208855,-22.871155,0.000000]
A Python script using a type-casting wrapper would know that wasn’t a supported COM type, and convert it to a string. The Python script would instead get this back:
“$Teapot:Teapot01 @ [-36.208855,-22.871155,0.000000]”
You can’t interact with that in Python the same way you would in MaxScript, but you do have some info to work with (object’s type, name, position). You just need to parse it from the string.
Attached is a small MaxScript I wrote for my GDC talk last year. There’s one function for converting Max-specific data types to something COM can grok, and another that takes requests from Python and actually executes the commands, calling the convert function as needed. The second function is also registered as a COM object for your Python tools to use.
checkout the “[b][b]SafeArrayWrapper” class in MaxScript. I’ve passed arrays that way…
[/b][/b]
Again, I’m no wiz’ at this, but I believe you can get the content of a MaxArray to Python and work with it: myPyContainer = conn.MaxDo(‘myMaxArray’). I say container because I “think” you will get a tuple, not an array. You should be able to then loop through it, or even change it to an array for your needs.
Thanks guys! Here is a snippet to return selected objects to python, not pretty, but moving in the correct direction.
*This is using vScourge lovely Max COM
import win32com.client
mx = win32com.client.Dispatch('Max.Application')
mx._FlagAsMethod('command_from_python')
mx.command_from_python ('myArray = #()')
mx.command_from_python ('for o in selection do (append myArray o)')
nArray= (mx.command_from_python('myArray'))
for i in nArray:
print i
Unfortunately my Maxscripting is very very weak. I am a Maya/Mel scripter with some good knowledge in Python, and this new project requires maxscripting so I am trying to avoid completely learning a new language if possible!
Yes, you’ll get arrays back as tuples, as long as they contain data types supported by COM, or you put a convert-to-string function in front of it like the script I posted above.
I’ve also noticed Max will cause COM to throw an error if the array its sending is empty. The script I posted above gets around this by checking before returning the value, and sending a special string back to Python you can then turn into an empty list, tuple, etc.
True. I need to clarify that anything I have posted is based on the scripts provided by Adam. Definitively a life safer.
While I’m at it, anyone has noticed rounding issues between Max and Python? In my example, I was converting cameras to .chan. I noticed that the precision of the decimal values where different (around the 4th or 5th number). I compared the output from the original Maxscript and my script where I tried to do the manip in Python, and I got different numbers. In the end, I just did the manip of the numbers inside Max and passed the value back to Python.
You mean stuff like this?
>>> 18.49 * 100
1848.9999999999998
>>> 0.1
0.10000000000000001
Most languages (machines, actually) work this way, but some sorta hide it more than others. MaxScript, for instance, is a little less obvious about it. Here’s a somewhat long explanation:
Hi! I am interested in using Python in Max. I am trying to get the example in the first post to work.
I run the MaxScript, and it returns “OK”. So that’s okay.
Then I run the Python script, and it runs, nothing happens. No box appears in Max… but no errors either… it blinks briefly and then it just goes onto the next line ready for another entry.
I’ve never used Python before, am I doing something wrong?
I’m on XP, using Python 2.6.1 with the win32 module it says you need, and Max 9 with SP2.
Thanks!
Could you show us the Max and Python code you are running? That could help us see what you might be missing.
You mentioned being new to Python. There is a lot of learning material outthere, but it also can be too much to look at for a newcomer. Do you have a background in scripting or programming in a different language? Based on this, we could give you a few pointers to what resources could help you learn Python.
Cheers. nico
[b]
It’s a copy of the code from the first post with the comments removed:
The Max part, which when run, returns “OK”:[/b]
fn DoSomething obj = ( try(
[indent] execute obj
[/indent][indent] return true
[/indent] )catch(
[indent] return false
[/indent][indent] )
[/indent] )
registerOLEInterface #(DoSomething)
The python part, which throws no errors, but fails to do anything:
import win32com.client
conn = win32com.client.Dispatch(“MAX.Application.9”)
conn._FlagAsMethod(“DoSomething”)
conn.DoSomething(“Box()”)
I know quite a bit of MEL and some C++. I also know a little MaxScript. I’d say I’m probably an intermediate user. I understand how code works, and can look up things if I don’t know them. The weird thing about Python is the use of indenting as a way of demarcating code blocks, as opposed to using parenthesis, etc. I’m not indenting any of the lines in the Python part, and I don’t know if maybe I’m missing something, or maybe I’m not running it the right way in the Idle interface? I type it in, and hit return, but it doens’t do anything. I’ve managed to get some simple code (i.e. “hello world” type stuff) to work in Python. So, I don’t know
I copied and pasted your code, with the exception of the MAX.Application version, and everything worked fine.
Have your registered Max properly? Adam has shared some great code that does it for you – and other things (I like his code as it allows you to share data between Max and Python). Look up his page and download the zip file and look under 6_COM:
http://techarttiki.blogspot.com/2008/03/gdc-wrap-up.html
As for learning Python, if you have experience with other languages, why not start with the official Python docs/tutorial, and look up some of the online books. Dive Into Python is fun if you already know how to code, and I also like the O’Reilly books. I’m not a programmer myself, but I like to learn by looking at people’s code as well. Online forums are a good place for this.
Forgive me for my ignorance guys. I use Python in Maya and used maxscript for years but have yet to try Python in Max. I am trying to get the code on post 93 to work link here:
http://forums.cgsociety.org/showpost.php?p=4686517&postcount=93
The python and maxscript works. But I am not clear on how I am to execute this process. I have Python 1.6 installed now. I opened up 3ds max and I opened up the IDLE Python Shell. I copy/paste the Python code into the Shell which executes with no errors.
Then in max I run the maxscript portion. Which prints this:
GetComObj()
“error create ole object”
Rollout:pyprompt
“error create ole object”
true
I type this into the top portion of the UI:
foo = 10
And I press the submit button. And now it errors and prints this:
GetComObj()– Error occurred in btn_submit.pressed()
– Frame:
– t: undefined
>> MAXScript Rollout Handler Exception: – Unknown property: “RunCom” in false <<
“error create ole object”
Rollout:pyprompt
“error create ole object”
true
What am I doing wrong?