3ds Max Python with splice of .NET

posted in: Blog | 3

Python is the most common used language for pipeline tools in the CG industry, but 3ds Max always fell behind in this respect. Only with the advent of MaxPlus, did we got a Python integration in 3ds Max, out of the box (there is BlurPython which is great but it’s not for the faint hearted).

By now, you should have accumulated some .NET libraries that you use in MAXScript. We also accumulated some, and since we want to reuse them in Python, instead of rebuilding them from scratch in Python, we made a small tweak on a OpenSource project called pythonnet. This project allows you to integrate CPython and .NET, “importing” Assemblies as if they were normal python modules. This integration is quite well made, and you can use delegate, events, properties, interfaces, and so on.

Here is a tool that we are working, running in normal MAXScript, and Python inside 3ds Max 2016, both use the same .NET Nyx backend :), but that is for another time.

nyx_omen_test

 

As a simple example, we will be using .NET Form’s, System.Drawing, and a wrapper around the Desktop Window Manager. We will create a viewport cloner, using this API’s using python.

 

 

First we need to setup our project so that pythonnet module is findable inside 3ds Max. We do this by adding the path to the folder that contains both clr.pyd, and PythonRuntime.dll to the sys.path.

try:
    import clr
except:
    import sys
    import os
    libs = os.path.join(os.path.dirname(__file__), 'libs')
    sys.path.append(libs)
    import clr

We use the try catch to avoid adding multiple times the folder to the path, or if you end up adding this to the PYTHONPATH, there is no need to “force” this path adding.

Next we will start importing our .NET machinery, we do this by adding a reference to the dll’s, like in a .NET project. Notice that the dll’s are search in the sys.path (the core libraries are automatic added), so if you want to add new assemblies, make sure they can be found.

clr.AddReference('Dwm')
clr.AddReference("System.Windows.Forms")

We can start importing the .NET namespace, and that’s really simple, it’s like importing Python modules.

from Dwm import ThumbnailEx as Thumb
from Dwm import DwmMessage as Msg
from Dwm import Win32
import System.Windows.Forms as WinForms
from System.Drawing import Rectangle, Size
import System

Aliases are permitted as you can see above. Next we will create a new WinForm to hold the Area for the DwmThumbnail, and that’s really simple, you just inherit from a Form our new class.

class MainWindow(WinForms.Form):
    '''Our main window Form. We can inherit from any .NET class'''
    def __init__(self):
        ''' Constructor for the From '''
        self.TopMost = True  #  Access to class properties
        self.Height = 400
        # Adds to the static class to avoid garbage collection
        _GCProtector.widgets.append(self)
        # Registering for events is as easy as in normal C#
        self.Load += self.LoadEvent 

The Python constructor is matched into a .NET internally by pythonnet. We start to so cool stuff, like listening to an event, the syntax is the same we would use in C#.

Another interesting thing is that we can overload any virtual method, just by defining it, like we do for the OnClosing.

class MainWindow(WinForms.Form):
    '''Our main window Form. We can inherit from any .NET class'''
    def __init__(self):
        ''' Constructor for the From '''
        self.TopMost = True  #  Access to class properties
        self.Height = 400
        # Adds to the static class to avoid garbage collection
        _GCProtector.widgets.append(self)
        # Registering for events is as easy as in normal C#
        self.Load += self.LoadEvent

I won’t go much further into the code, and let you guys explore and have fun, it’s all commented. But as a note, we need to add our Form into a static member so it doesn’t get garbage collect, this is the same that we do with Qt.

 

Download: ViewportClone

 

GitHub repository:

https://github.com/ycdivfx/MaxPythonNetSample – Demo project for the article

https://github.com/pythonnet/pythonnet – Pythonnet repository

https://github.com/vladris/DWM – Desktop Window Manager .NET wrapper

3 Responses

  1. […] 3ds Max® (2014+Ext1 and above) in the same way you do with MAXScript scripts. Check our blog post 3ds Max Python with splice of .NET to see it in […]

  2. bünyamin araz
    | Reply

    hello ı can try to run this script not works in 3ds max 2017

    can you update or how can you help me ? ı know basic macscript and python

    • WF
      | Reply

      Why is it running?
      “Error scanning assembly DevExpress.XtraTreeList.v14.1”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.