Oct 4 2013

Python in 3ds Max 2014 first impressions..

Well folks, it’s finally here… just a few days ago Autodesk released it’s 3dsmax 2014 extension to those who are members of the subscription program.

This extension release is something that I’ve been very excited about ,and have been looking forward to  ever since the new features were first announced.

Well thankfully the wait is over. I’ve spent some time today checking out the new implementation trying to figure out what this update will mean to future mango development for 3ds max (which I would rather do in python and PySide so that apps can float between Max, Maya, Nuke).

Anyway here are some of my first impressions along with some snippets from today’s familiarization session, I hope they might be insightful.

This is not Blur Python

While evaluating the new python implementation in max 2014, it becomes very hard not to compare it to Blur python. They are both CPython implementations. But that’s about where the similarities end. If you have experience working with Blur Python this first installment of 3dsmax python by autodesk is going to be somewhat of hard pill to swallow.
Unlike Py3dsMax(blur python), maxPlus (autodesk python) does not really expose the same set of libraries and methods that people familiar with maxscript already know and love. Instead it exposed a very small (it’s actually pretty large) subset of the max SDK, and relies heavily on the idea, that programers will do most of the max interactions by writing python string containing max script code.
This string are then to be evaluated by “maxPlus.Core.EvalMAXScript” python method. In my opinion this will alienate allot of people.

  • Those who are familiar with maxscript but are new to python will have to learn a whole new way of working with the limited set of exposed functions, and a brand new methodology behind creating and manipulating objects and data in max. Everything you know about max-script is now obsolete.
  •  Those who looked at python as a bridge to write tools for max with out having to learn maxscript will still have to learn maxscript to access the majority of functions and methods available via maxscript.

I’m hoping that the awkwardness of MaxPlus is just due to it’s infancy, and that in the next year or so it will be expanded to equal or even best blur python. At first glance it seems Autodesk really did the bare minimum. We can only hope that this was a time limitation, and that they will continue to devote time to growing the max python ecosystem.

No Python.import

One of Blur Python’s coolest features was the ability to import python modules right into maxscript via the “python.import” method.
This was really great for production, since any max scripter could use python libraries straight in maxscript with out knowing anything about python. For anyone that has used this feature to quickly harness the power of python external libraries inside of their native maxscript code, this will more than likely be very sad news. I really hope Autodesk can bring this feature back since it opens up the power of python to a much larger sets of users.

Where is PySide/PyQt?

Well not surprisingly Autodesk has decided not include PySide or PyQt with it’s new implementation of Python. The fact that PySide doesn’t come integrated with this first release of python is incredibly disappointing. Especially since I have been running Blur Python (Without Qt) in 2014 for months now, the Autodesk implementation of Python is a major downgrade when compared to Blur Python. This alone will keep me from upgrading current mango clients to this new extension (mango currently uses blur Python).

I really hope that they will spend sometime integrating PySide by the time 3ds max 2015 comes out. Switching from Py3dsMax (Blur Python) to MaxPlus (Autodesk Python) is going to be painful, but a properly supported PySide module would really make the switch worth it.

DIY PySide?

While Autodesk failed to give us an easy to use PySide implemention similar to the ones natively supported in Nuke and Maya, they were nice enough to include some documentation that the more technically inclined can use to compile PySide (that’s right! you going to compile stuff!!) against the proper builds of qt and python that are now bundled with max (Python 2.7.3, Qt 4.8.2). From the documentation hints, I was able to actually make my own image of PySide that allows me to start using Qt inside of 3dsmax 2014. This process while a bit technical and esoteric, is actually not to difficult and requires zero programing experience, I recommend that anyone interested actually try it. If you are too lazy to do it your self,  you can try using my compiled installer (use it at your own risk) , which can be found here .
After installing my newly compiled PySide build, I set to do some basic testing using the following snippets. My initial test was just a QMessageBox…

st = "
import sys
import MaxPlus
from PySide import QtGui, QtCore
msg = 'hello'

n = MaxPlus.Core.GetRootNode()
msg = 'objects in scene:\\n'
for c in n.Children:
	msg += '%s%s%s' % ('\\t',c.Name,'\\n')

msg = str(msg)

app = QtGui.QApplication.instance()
if app == None:
	app = QtGui.QApplication([])

QtGui.QMessageBox.about(None,'PySide',msg)
"
python.execute st

This messagebox was just a way to test that the PySide was actually being loaded and working in max, and that python could collect some data from max and pass it to Qt.

While I was writing this snippet there were a few things that I noticed that seem strange.

  • Modal windows have no effect on the max session. It’s not really clear to me how to parent Qt windows to the max application it self. So modal windows which would usually freeze max until the user close the dialog are not actually freezing max.
  • Executing a QApplication is not needed, doing so actually really screws up the max environment, the behavior makes seem as if qt and python are not running on the main max thread. But I’m more than likely just missing a step.

Other than those strange oddities PySide seems to actually be working. Even with out executing the QApplication I can launch dialogs add widgets via the .show() and exec_() methods. exec_() seems to have absolutely no effect on the max session itself (same as qmessagebox) which is very strange.

Here’s my second test a simple Dialog snippet example…

st = "
from PySide import QtCore, QtGui

class mApp(QtGui.QDialog):
	def __init__(self,parent=None):
		super(mApp,self).__init__(parent)
		vL = QtGui.QVBoxLayout(self)
		for i in range(5):
			cb = QtGui.QComboBox(self)
			vL.addWidget(cb)
		btn = QtGui.QPushButton(self)
		vL.addWidget(btn)
		btn.setText('press me')
		btn.clicked.connect(lambda:QtGui.QMessageBox.about(self,'Modal Test','is this modal?'))

app = QtGui.QApplication.instance()
if app == None:
	app = QtGui.QApplication([''])

ui = mApp()
ui.show()

"
python.execute st

here’s what it looks like..

 

Conclusion

Even though Autodesk’s first version of Python for max leaves a lot to be desired, I’m vary happy that Autodesk has actually taken on the task of bringing this very important feature to max. Not having to depend on a 3rd party to provided python support will make it much easier for studios to migrate to feature version of 3ds max with out fear of breaking their pipeline. With today’s need for python and Qt in the never ending realm of unified pipelines an awkward implementation of python, and a ghetto home brew of PySide are much better than NO PYTHON and NO PYSIDE.

I’m looking forward to experimenting with Mango and 3ds Max using this setup, and seeing what new knowledge tips and tricks the community will bring forth in the upcoming months…

Until next time..

Stay frosty my friends :)

8 Responses to “Python in 3ds Max 2014 first impressions..”

  • Jase Says:

    Nice write up!

    I’ve been implemented max2014 api’s for some of my tools that are currently being used in max (with blur python) as well as maya, nuke, houdini etc.

    So far i’ve been able to get access to everything I need through MaxPlus (silly name imo).

    I’ve got similar issues as you with PyQt though. The dialog boxes will work correctly as they manage to launch their own event loop seperate to a QApplication.

    In order to get your windows parent to the max ui you’ll need to cast them as a QWidget. You can dig this out of the blur code but it means building QWinMigrate yourself in order to cast the window correctly.

    Gotta get the PyQt event loop working correctly first though. I’m unsure how to do this though. I’ve tried different threads, QTimers in the main thread. Any ideas here?

    Jase

    • Los Says:

      Hey Jase!
      thanks for the comment :)
      after having some time to review the class reference of maxPlus, i realized just how much maxPlus actually exposed to python,there’s allot more there than i originally thought, i still think that the sdk will alienate allot of people who are used to the functions and methods available through maxscript.. I’m hoping to see a MaxPLus.mxs module in the future, that will be similar to Maya.cmds (expose the native script commands)..
      as far as my experimentation with PySide (i went with PySide vs PyQt seance nuke and maya now fully support it)… I really think that unlike blur python, autodesk python is running on a separate thread outside of Max’s main thread…

      it’s the only way i could explain the following behavior..

      if i run the code…

      st = ”
      import sys
      import MaxPlus
      from PySide import QtGui, QtCore
      def test():
      app = QtGui.QApplication.instance()
      if app == None:
      app = QtGui.QApplication([''])

      QtGui.QMessageBox.about(None,”,’#1′)
      QtGui.QMessageBox.about(None,”,’#2′)

      test()

      python.execute st

      The first message box pops up.. which halts python it’s self until the user closes the message box, but you can still manipulate max it’s self! create objects move the viewport etc. seance this is happening inside of a python method which is properly halting until the user interacts with the message box (at which point the next line in the script fires a second message box) i can only assume that python is not running on the main thread, what do you think? i wonder if the SDK centric implementation has something to do with that? seance running python on a separate thread by default would allow scripters to write tools that interact the max session in non-modal fashion.. which was not really possible in maxscript (at least not with out the use of a rollout and a timer).
      anyway I’m just starting to play around with python and maxPlus in 2014… I’m hoping to have a better understanding of things in the following weeks, in the other hand it sounds like you have a good head start your self :)
      cheers,
      Los

      • Jase Says:

        Hey Los,

        I’ve finished filling out the functional api’s now and have found that there’s access to most things i need. Matrix getting/setting, modifier stack control for point caching, object creation, scene hierarchy queries and manipulation. Seems to be mostly there. I’ve had to do a few max script calls in places though. Have you found out how to set appData on objects through the new lib? I’m doing a max script call for that which is a bit annoying.

        I’m not sure what thread the python interpreter is running in but it seems a little weird. I’ve been trying to launch PyQt in a separate python thread with no luck. Here’s a test I’ve tried:

        ===========================
        cmd = ”

        import threading
        import time

        class my_thread(threading.Thread):
        def __init__(self):
        threading.Thread.__init__(self)
        self.count = 0

        def run(self):
        while True:
        self.count += 1
        time.sleep(0.1)

        t = my_thread()
        t.start()
        print t.count

        python.execute cmd
        =============================

        Its a pretty basic thread that adds to a counter. when you print t.count it should tell you how many iterations the thread has done. Oddly enough after initialising the thread and querying the count again it hasn’t incremented like you’d expect. The only time it increments is when you send commands to the python interpreter.

        Its almost as if the python interpreter is sitting there in a blocked state rather then being a constantly running interactive process.

        What are your thoughts?

        I’m so close to having our pipe tools up and running! haha

        Jase

  • Sparadrap Says:

    Hi !

    Thanks for this complete review: it’s actually hard to find reactions and informations about python in max.
    But i can’t install pyside, using your installer: i must have missed a step. I only installed:
    - 3dsMax 2014 extension
    - python 2.7.3
    - and your PySide-3dsMax2014.exe
    Did i forget something ? Have you done a specific operation on the regedit, as the documentation said ?

    Thanks you very much ;)

    • Los Says:

      Make sure to make a windows environment variable called “pythonpath”
      And add c:\python27\lib\site-packages path to it..
      I’ll will write up more detailed instruction when u get a chance.
      Cheers,
      Los

  • Sparadrap Says:

    Hi !
    Thanks for the answer, i finally manage to install pyside, following yout instructions ! (Thanks you ;) )

    I have an other question:

    Why are you using
    “app = QGui.QApplication.instance”
    instead of:
    “app = QGui.QApplication(sys.argv)”
    ?
    I know this last doesn’t work, but i can’t understand why…

    • Los Says:

      if you declare variables at the global level in python they are not flushed out until you close max and restart it again (same as in maxscript)…
      this means that some other script has already created a QApplication it will be lingering in the background…
      If one already exists, it is much better to capture that one (via QApplication.instance) and continue working, than it is to create a new instance…
      Qt only allows for one QApplication to run during the python session… so all dialog windows widgets should run under that…

Leave a Reply