• 1/3

The MaxSharp Project: Python and C# from 3ds Max 2011

Posted by Christopher Diggins, 30 November 2010 7:00 pm

Recently we posted on the Autodesk Developer Network an experimental library we have been developing in conjunction with EPHERE called MaxSharp. MaxSharp provides a simplified wrapper around the 3ds Max 2011 API that can be used from both Python and C#. If you are an ADN Sparks member you can download it from this url. Be aware that because this is a research project you can't redistribute the DLLs, but you can still use them for your own internal use.  

As many of you know in 3ds Max 2011 we added technology for safely loading .NET assemblies and creating custom user actions in .NET (via the CUIActionCommandAdapter class). However exposure of the 3ds Max API to .NET remained limited to only a handful of classes in the ManagedService assembly.

This meant that if you wanted to use the 3ds Max SDK from a .NET assembly you would have to manually expose API elements (e.g. classes and functions) to .NET via C++/CLI or else use the infamous PInvoke API. The other alternative was to use a 3rd party library such as the Max .NET library from EPHERE.

While Max .NET saves developers a lot of time, it mimics the structure of the C++ SDK. This has two problems: 1) it is not the kind of API that a C# or Python user would expect, and 2) it is very hard to learn for new developers.

Let’s contrast how you would build a Teapot and move it using Max .NET with MAXScript. In Max .NET you basically have to write C# code like you would if using the 3ds Max SDK from C++ (note we use the “var” keyword of C# 3.0 of later to infer the variable types, and make it more script-like):

void DemoTeapotHardWay(IGlobal global) { 
    var cid = global.Class_ID.Create((uint)BuiltInClassIDA.TEAPOT_CLASS_ID, 
      (uint)BuiltInClassIDB.TEAPOT_CLASS_ID); 
    var obj = global.CreateInstance(SClass_ID.Geomobject, cid) as IObject; 
    var n = global.COREInterface.CreateObjectNode(obj); 
    var ps = obj.ParamBlock; 
    ps.SetValue(0, global.COREInterface.Time, 20.0f); 
    n.Move(global.COREInterface.Time, global.Matrix3.Create(), 
        global.Point3.Create(20, 20, 0), true, true, 0, true); 
} 

Now compare the same code in MAXScript:

obj = teapot()
obj.radius = 20.0f;
obj.position = [20, 20, 0]

To be fair the Max .NET library does more than just expose the C++ API to .NET. In addition to other things it provides the ability to write various plug-in types other than global utilities or user actions (e.g. controllers, geometric objects, etc.) entirely .NET. It also comes with a rather interesting remoting library, but that is out of the scope of this post.

My dream for quite some time was to develop an API that would be nearly as easy to use from C# and Python as MAXScript is. I posted the results of some experimentation in a previous blog post over a year ago. Thanks to a recent collaboration with EPHERE, we now have the MaxSharp project.

MaxSharp does three things for .NET developers:

  1. It exposes a large chunk of the C++ API to .NET via the Autodesk.Max.dll. This assembly is not documented but can be examined using the Object Browser in Visual Studio.
  2. It provides a high-level API that resembles what one would expect when using a .NET library or a Python scripting API. This is the MaxSharp.dll.
  3. It makes it easy for people to write Python scripts that use much of the 3ds Max API. This is done via a “RunPython” function exposed to MAXScript (see MaxSharp.ms in the startup folder of the installation), and via a sample user action (see MaxSharpDemo.dll or the accompanying source code).

Here is the MaxSharp approach to creating and moving a teapot from C#:

var obj = Primitives.Teapot.Create();
obj["radius"] = 10.0f;
obj.Node.Move(Point3(20, 20, 0));

The Python version is very similar:

obj = Primitives.Teapot.Create()
obj["radius"] = 10.0
obj.Node.Move(Point3(20, 20, 0))

While this is all extremely cool (well at least for programming geeks like me) there are some important caveats to using MaxSharp. I did include a number of C# and Python samples in the distribution but as you start to use it an industrial scenario you may realize that the exposed API still comes up relatively short when compared to MAXScript. This is why the project only has a limited release as a research project.

All is not doom and gloom: almost every class in the MaxSharp assembly provides a public property from the low-level Autodesk.Max.dll, which contains a significantly more comprehensive list of attributes and methods. This means that if you are not faint of heart and are missing some functionality in the MaxSharp.dll you can get to it by rooting around in the Autodesk.Max.dll using the Visual Studio object browser and the 3ds Max SDK documentation as a guide.

For some people the ability to use MaxSharp to run Python is by itself a pretty big win. For others the advantages may be a bit less obvious, especially since there is already MAXScript. I find Python to be a powerful technology because of the large number of preexisting Python modules and the huge pool of people and forums you can get support from.

Technically MaxSharp only supports IronPython which has some small differences from standard Python (as implemented in CPython). You can see a partial list of differences here. I should point out that there is one big win from using IronPython, which is the ability to use a Visual Studio debugger to set breakpoints and inspect variables. This is made possible via a tool called IronPython Studio. For fun I posted a video showing the process of attaching the debugger to 3ds Max and setting a breakpoint in a Python script here.

If you aren’t already an ADN Sparks member and want more information or just desperately want to get your hands on this exciting new technology then check out the ADN Sparks home page.

19 Comments

ctedin1

Posted 2 December 2010 11:31 pm

Nope. Mine does the same. Maybe this page was coded in Python, rather than HTML and CSS. ;-)

Christopher Diggins

Posted 3 December 2010 12:35 am

Thanks for letting me know about this guys. It should be fixed now.

Insanto

Posted 3 December 2010 8:34 am

verry nice, finally a good reason to learn python

Christopher Diggins

Posted 3 December 2010 3:29 pm

Thanks for the positive support everyone!

>> Besides, you can use some Python modules in IPy

At the risk of being overly nitpicky, this phrase may be interpreted as if only a small subset of Python is supported. The truth is that most (as opposed to some) Python modules are supported in IronPython. IronPython comes with its own library of over 500 Python modules. Many of them (if not all) are written in plain old Python.

>> Will things like NumPy typically work or not?

NumPy is a CPython extension written in C, not Python. Nonetheless it is supported via IronClad as Loocas indicated (http://code.google.com/p/ironclad/ ).

While compiled CPython extensions are not supported natively by IronPython, IronPython on the other hand supports most of the libraries in the .NET framework. In fact it can easily execute code from any arbitrary .NET assembly. In my experience it is significantly easier to extend IronPython (e.g. using C#/C++ CLI/VB/etc.) than it is to extend CPython.

>> I'd love a true, native Python support in Max and I'd consider that the most significant feature of modern Max. Mainly for pipeline integration (playing with the big toys) as that's where Max is lacking the most (in comparison to the other big names: Maya, Houdini, even Softimage).

I'm not sure I see any advantage of native Python support over IronPython support. Personally I am way more excited about Python support via .NET, because of the excellent performance and the flexibility. We aren't just talking about Python here, MaxSharp provides a nice API for controlling MAXScript that can be used (with only a tiny bit of hacking) from JavaScript, Ruby, VB, Lisp, and more (http://en.wikipedia.org/wiki/List_of_CLI_languages )!

So let me toss you a friendly challenge: show me something you think could be done only via "native" Python, or that you think would be easier or more efficient. In response I'll try to build an equivalent or improved system via .NET and IronPython. :-)

Martin Breidt

Posted 3 December 2010 3:48 pm

From my POV, being able to extend IronPython is not as important as being able to use the large code base out there that 'normal' Python users can use. I applaud the effort outlined here, but why do you approach it in such a Microsoft-heavy direction? To me, the key thing with Python is that it is open-source, widely used and already has solutions for a wide range of problems.

IMHO, the key to adding Python to 3ds Max is: being compatible with other Python solutions.

Regarding your challenge: Take NumPy, SciPy or PIL - these are probably some of the most extensively used Python libraries (at least in my small part of the world) and their functionality would augment 3ds Max to great extent. The first two seem to be a target to IronClad, so maybe that's a non-issue?

Christopher Diggins

Posted 3 December 2010 4:36 pm

>> From my POV, being able to extend IronPython is not as important as being able to use the large code base out there that 'normal' Python users can use.

This is exactly what IronPython strives to do, and what I tried to convey in my comment. IronPython supports as much of Python as was possible given the somewhat ambiguous nature of the language definition, and continually strives for maximum interoperability with CPython (which is considered the "reference" implementation). CPython and IronPython are just two different implementations of the same language, each with their own custom extensions.

To summarize: virtually any Python code you run that doesn't rely on implementation specific extensions will run equivalently in both CPython and IronPython.

> I applaud the effort outlined here, but why do you approach it in such a Microsoft-heavy direction?

IronPython is no longer being managed by Microsoft, it has been recently opened up to the entire community. I don't agree that there is anything "Microsoft-heavy" about it.

>> To me, the key thing with Python is that it is open-source, widely used and already has solutions for a wide range of problems.

IronPython is now completely open-sourced (see http://ironpython.net/ ). It is also compatible with a huge number of pre-existing Python solutions.

>> IMHO, the key to adding Python to 3ds Max is: being compatible with other Python solutions.

I agree. IronPython does an excellent job of this.

>> Regarding your challenge: Take NumPy, SciPy or PIL - these are probably some of the most extensively used Python libraries (at least in my small part of the world) and their functionality would augment 3ds Max to great extent. The first two seem to be a target to IronClad, so maybe that's a non-issue?

Yes. The first two are non-issues.

However PIL is actually a pretty good challenge. A quick Google search revealed "Parts of PIL should work with IronPython if you're willing to import ironclad first" (http://lists.ironpython.com/pipermail/users-ironpython.com/2009-October/011471.html ).

Let me ask you how do or would you use PIL in your pipeline? My quick and dirty solution would be to switch in mid-processing from IronPython and CPython. Save your image out to a file (or possibly a memory mapped file if performance is a concern), make a system call to request CPython to do the image processing on the file and then return back to IronPython.

While I agree having to call CPython from IronPython is inelegant. It is not going to be necessary often, and at least you still get to do all of your programming in Python. But let me emphasize that modules like PIL which can't be run in IronPython are the exception not the rule.

Christopher Diggins

Posted 3 December 2010 4:38 pm

>> Chris, you missunderstood me! I'm a 100% supporter of IronPython. What I actually meant by "native Python support in Max" is the language itself, not an interpreter and by "native" I meant being able to directly write code in Python inside the ProEditor in Max.

I'm very sorry that I misunderstood you, thanks for clarifying! I got a bit defensive because our product management team might have thought you were implying that MaxSharp was the wrong way to support Python. :-)

Martin Breidt

Posted 3 December 2010 6:53 pm

>> To summarize: virtually any Python code you run that doesn't rely on implementation specific extensions will run equivalently in both CPython and IronPython.

To me, it is a bit unclear where this applies and where not. Looking at the webpages of IronPython and IronClad, I see quite a bit of careful wording and have no idea whether the differences/problems described there will affect me when I will try to use this. Maybe this is all clear to a seasoned Python developer.

>> I don't agree that there is anything "Microsoft-heavy" about it.

Well, the IronPython web page mentions .NET, CLR, Silverlight, Visual Studio - all of which are of MS origin and probably not used in the 'normal' Python community.

>> NumPy and SciPy are non-issues

The IronClad page says that numpy.distutils don't work, for example, which are used to support Fortran modules - something that is not too uncommon in numerical algebra (BLAS/LAPACK). I am just concerned at which point this will break existing code.

>> PIL

Most functions of PIL probably could be replaced by some .NET function, but this requires rewriting code. Same for saving an intermediate image and calling PIL via CPython. As I said, I think it is important to allow people to directly use existing Python programs without changes.

How does Maya integrate Python? If I remember correctly, they have a 'normal' Python 2.5 distribution?

FWIW, other Python libraries of potential interest that seem to make use of the C interface: RPly, cgkit, PyTables, pygsl, VTK python.

Christopher Diggins

Posted 3 December 2010 7:34 pm

>> The obj object seems to be a dictionary? Is that right?

Actually it isn't. It is an object that overloads the [] operator to provide access to parameters stored in a "ParamBlock2". Those particular parameters can be accessed by name or by the index. You can get a list of the parameters as follows:

def OutputNodeObjectParams(node, lines):
__if node is None: return
__lines.append('Node ' + node.Name)
__o = node.Object
__if o is None: return
__for p in o.Params:
____lines.append('Parameter ' + p.Name + ' = ' + str(p.Value))

(these comments don't allow me to properly indent, so I use '_' for leading whitespace.)
>> Are regular properties supported? I mean, something like:

Yes.

>> obj.Node.Radius = 10. or even better obj.Radius = 10. is it supported?

Well not in the case of Radius, because nodes don't consistently have a radius (this is a design decision). You can however say:

obj.Node.Color = Colors.Blue

or

obj.Node.Selected = false

Does this make sense? I am currently considering changing the design so that specific common primitive types have their ParamBlock parameter built-in.

Light

Posted 7 December 2010 11:26 pm

This is Marsel's work. I told everyone at work, that his stuff was gold, and see what happened. The man is a true genius. This is gonna change everything in tools development.

Christopher Diggins

Posted 8 December 2010 12:47 am

>> This is Marsel's work.

No not entirely. Marsel created the low-level exposure of the 3ds Max SDK. I coded most of the high-level layer of MaxSharp by myself. To illustrate the difference between the two layers consider here is what you would have to do without any high-level wrapper:

void DemoTeapotHardWay(IGlobal global) {
__IClass_ID cid = global.Class_ID.Create((uint)BuiltInClassIDA.TEAPOT_CLASS_ID, (uint)BuiltInClassIDB.TEAPOT_CLASS_ID);
__IObject obj = global.CreateInstance(SClass_ID.Geomobject, cid) as IObject;
__IINode n = global.COREInterface.CreateObjectNode(obj);
__IIParamArray ps = obj.ParamBlock;
__ps.SetValue(0, global.COREInterface.Time, 20.0f);
__n.Move(global.COREInterface.Time, global.Matrix3.Create(), global.Point3.Create(20, 20, 0), true, true, 0, true);
}

Here is the same code using the high-level MaxSharp:

void CreateTeapot() {
__PrimGeomObject teapot = Primitives.Teapot.Create();
__teapot["radius"] = 20.0f;
__teapot.Node.Move(new Point3(20, 20, 20));
}


pen

Posted 8 December 2010 1:00 am

Well I have to say that this is really going to change things finally. It has been a pain to work with Py pipelines in Max and now it will all be opened up. I really like the idea of C# there now as well as that is getting used more and more for complex UI work and it can now go even further.

Well done to both you and Marcel.

Light

Posted 8 December 2010 5:59 pm

Hey Chris, sorry wasn't aware of anyone else's contributions. Based on my previous conversations with Marsel, he told me he will wrap his high level constructs in a separate assembly to simplify the SDK programming. Basically things he used for his other projects like zookeeper. I even sent him some samples where things like scene selections were IEnumerable, etc. Just thought he finally did it and sold/license it to Autodesk where Autodesk renamed it to MaxSharp.

But if you did the high level stuff, good work for sure.

Btw do you guys accept any feedback on your high level assembly? Things that could potentially improve it further.




Thanks,
Light

Christopher Diggins

Posted 8 December 2010 6:32 pm

>> Btw do you guys accept any feedback on your high level assembly? Things that could potentially improve it further.

Yes we definitely do. Please provide your comments via ADN Sparks DevHelp Online (DHO). Alternatively you can email me: firstname.lastname@autodesk.com.


Light

Posted 8 December 2010 6:39 pm

Thanks Chris, not sure if we are a Sparks member, but I will email you for some suggestions I have.




Cheers,
Light

spacefrog

Posted 11 December 2010 6:23 am

I agree with loocas here - why is this all happening behind closed doors and only accessable for at least >1k fee per year ? This is not effortable for a small indie like me... . I really do hope that this will see the light of the public soon and some download will be posted on 3ds Max Developer Center
http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=7481355

Christopher Diggins

Posted 10 June 2011 4:24 pm

>> Any news on how far this has come from a "should I consider an upgrade to max 2012" & C# programmers POV? Redistribution? Still research? Full API exposure? und so weiter...

This is not part of 3ds Max 2012. There also hasn't been any development lately on the MaxSharp version we released via ADN. Note that while MaxSharp has a high-level API it does provide a lower-level full API exposure. Its just that the details of accessing the low-level API are undocumented.

That said we are actively investigating how we can leverage this technology for all customers, so please stay tuned.

Christopher Diggins

Posted 6 December 2011 8:24 am

>> This means, in this case, AD did't ever "try" to meet the needs of it's customers,

This is correct. We have not tried to address the needs of the Python users. On our ADN survey for the last several years, better .NET support far outweighed the desire for Python support (let alone CPython support). This is part of the reason we released the improved .NET SDK.

The primary goal of MaxSharp was NOT to enable Python scripting, but to improve the .NET experience. The fact that it could improve the IronPython experience is a side-effect that I wanted to publicize.

>> So what people are REALLY after, when you get down to it, is having python serve as a cross-application-abstraction-layer, which is what Blur had started doing between 3ds-max and softimage.

Yes I am aware of that.

We are doing some experimentation in this area, and I am exploring a slightly different approach than the one used by Blur studio. Strictly speaking CPython exposure of 3ds Max is not necessary for this, but of course there are certain advantages which I am aware of. For example if 3ds Max supported CPython then PyQT could be used for UI development across products.

>> So you may choose look at it childishly, and see it as an even bigger blow to the ego (they succeeded, we didn't ever try...) - which would take you on a rout of making your own solution, or you may choose to look at it from a more mature stand-point,

You are jumping to conclusions and attributing a lot of negative characteristics and motivations. To be honest I find this very disrespectful.

We are in the process of considering multiple approaches to addressing the desire for our customers to use Python in 3ds Max.

jfyelle

Posted 6 December 2011 7:25 pm

>>So far, you seem to only ascertain my worries, in terms of AD's current direction for 3ds-max regarding CPython...

Look, I read the whole thread and really get your opinion, but it won't replace our usage metrics.

The 3ds Max C++ SDK is the mainstay for any development around 3ds Max today.
Maxscript is quite useful and accounts for a sizable piece of our core and is used a lot externally as well.
The .net API is young, fresh and in incubation mode right now. Development-wise, it supports IronPython more easily than CPython. Fact of life.
It's not impossible to provide clean CPython support, it's just that to work we would need to drop other useful things we're doing.
Chris also told in his last comment he is working on something pythonic worthy of interest. Stay tuned.

Meanwhile, can we agree we are fortunate to have someone such as him to open us a path. Right?

FWW, 3ds Max works flawlessly on Parallel 7.

thanks,
Jean-Francois Yelle, 3ds Max PM

Add Your Comment

You must be logged in to post a comment.

Please only report comments that are spam or abusive.