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:
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.
Please only report comments that are spam or abusive.
19 Comments
ctedin1
Posted 2 December 2010 11:31 pm
Christopher Diggins
Posted 3 December 2010 12:35 am
Insanto
Posted 3 December 2010 8:34 am
Christopher Diggins
Posted 3 December 2010 3:29 pm
>> 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
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
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
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 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
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
Christopher Diggins
Posted 8 December 2010 12:47 am
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 done to both you and Marcel.
Light
Posted 8 December 2010 5:59 pm
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
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
Cheers,
Light
spacefrog
Posted 11 December 2010 6:23 am
http://usa.autodesk.com/adsk/servlet/index?siteID=123112&id=7481355
Christopher Diggins
Posted 10 June 2011 4:24 pm
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 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
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. Login or Register here