During
integration, we encountered and overcame a variety of issues. These issues can be
put into one of two categories: design issues and runtime issues.
The first design
issue encountered was the cross-disciplinary nature of the work. It is highly
unlikely that a single person would possess all of the knowledge needed to
construct any MaxScript-.NET hybrid solution. In order to have an integrated
system between .NET and MaxScript you will need people who are very adept at
MaxScript, the .NET framework, and have a clear understanding of how to use 3DS
Max from a user's perspective. We have achieved great success by having a
MaxScripter work with a .NET programmer to implement features in tandem. The
.NET programmer writes the underlying functionality the MaxScripter is looking
for, and the MaxScripter will bring this functionality to the user through 3DS
Max.
Another design
issue comes up when deciding how to divide functionality between MaxScript and
.NET applications. MaxScript is an obvious choice for anything directly
associated with 3DS Max, but if the capabilities of MaxScript overlaps with
.NET, a decision needs to be made regarding where the implementation should
lie.
Over the course
of development we settled on pushing as much functionality as possible to the
.NET side of the fence to optimize performance. The only caveat for our systems
is that hacks should always live in MaxScript. Containing project-specific hacks in
MaxScript means there is no need to recompile when hacks are injected and our
core toolchain is not littered with special cases for specific projects and
platforms.
The last design
issue we will cover may seem obvious, but is important nonetheless. Namely, in order
to integrate .NET applications with 3DS Max, the tools and programs in question
must be developed within the .NET Framework. For some developers, integration
with 3DS Max may mean rewriting thousands of lines of code within .NET, and each
developer will need to assess how reasonable that would be to achieve. In the
event a developer wants to attempt adapting an older tool chain to work with
3DS Max, there is another option available.
It is possible to
build a .NET layer that lives between the unmanaged tools and 3DS Max to be
accessed by MaxScript. This solution provides the ability to tightly control
what objects, methods and events are exposed to MaxScript because only data
living in the .NET layer will be accessible.
However, even if old tools cannot be revised for integration, if
developers keep .NET in mind when creating new tools this option will be
available down the road.
Now that we have
covered the major design issues encountered it is time to look at unexpected
runtime behaviors and how to overcome them.
Integrating a
program as large as 3DS Max with .NET applications through MaxScript can have unforseen
results at runtime. It needs to be understood that when integrating .NET programs
with 3DS Max there are actually two distinct runtimes executing within the same
process. This coexitence of rutimes is not always compatible.
MaxScript has a
garbage collector responsible for cleaning up objects that it deems ready for
deletion. The algorithms used by the garbage collector are not always correct
when dealing with .NET objects. In some cases .NET objects and controls may be
deleted by the MaxScript garbage collector while they are still in use, and there are steps that can be taken to
help prevent this issue from happening.
One observable
side effect of an aggressive garbage collection is that .NET events will stop
triggering MaxScript functions. The most reliable solution to the collection
issue is using the keyword static in .NET application code on events and other
objects that should not be deleted when a collection occurs. Another way to
help the garabage collector is to ensure that the initial MaxScript heap memory
is set well above the default of 7.5 megabytes. Through research with our
systems we have found an initial MaxScript heap of at least 128 megabytes will
ensure stability for the end user.
The final rutime
challenge we address is about 3DS Max accelerators. The 3DS Max documentation notes
that because 3DS Max does not know whether a control should receive input focus,
it will maintain accelerators all the time. When developing .NET controls that
require keyboard focus to operate correctly, the 3DS Max accelerators should be
disabled on a timer-based schedule. An event fired by a .NET control once a
second that notifies MaxScript to disable accelerators is the solution we have
arrived at for maintianing keyboard focus.
As usual, I appreciate the quality of your feature articles very much. As a small point of critique: For articles with long code sections, could you please make an effort at formatting those to a more readable form. As I've seen blog software do this automatically, my guess is a large online offering such as yours has appropriate solutions at hand.
Much obliged.
Klaus - looks to me that the main issue is the in-code comments overflowing lines on the code excerpt on Page 3, correct? Going to see if we can fix that, thanks.
The .NET integration-features that have been introduced into MAX is a step in the right direction, but there are some shortcomings that may benefit from the act of being brought to the surface, in case someone out there were dancing a mazurka of joy, thinking they could throw out the MAX sdk come blue morning.
The ability to interface with MAX datatypes from the .NET assembly is practically nonexistant. As a result, shuffling large portions of data to the .NET-side therefore requires iterating the data. This e.g. hardens the possibilities of quickly performing a very common plugin task: munching geometry.
Hopefully, integration will become a bit tighter in the future, although I would rather prefer they put their weight on making MAXscript run faster.
I made a level editor in 3DS Max 5/6 back in 2003/2004. We were using Renderware as middleware. There were two main components to the editor I had made. Level building and ai/gameplay related data. I used 3DS Max purely as a user interface and a nice render interface. Artists would export the models from 3DS Max to Renderware specific format and put all of these into a library. Levels were built by placing an art asset from the library. I would save the level to Rendeware's level format by refering only to the asset id (name). The ai/game play artists would build the path nodes and place gameplay data using 3ds Max nodes that I had built after deriving from the 3DS Max Dummy objects. All of the ai and gameplay data was stored in XML files (used Xerces to parse the data). Come to think of it the most difficult part of it was to import Renderware 3D mesh data into 3DS Max and displaying it as 3DS Max geometry.
I had such a bad time with making the UI for the tool. I could never make it as good as I would have liked.
IIRC Maxscript cannot access everything that's visible in the UI. For example I had issues with using the "loft" tool in Maxscript. Not sure if anything's changed now. I used Maxscript essentially for raising events and for the UI. The majority of the work was done in the 3DS Max Plugins.
Could you tell us something about the formats in which you had exported the data from 3DS Max?
From the article:
"For some developers, integration with 3DS Max may mean rewriting thousands of lines of code within .NET, and each developer will need to assess how reasonable that would be to achieve."
I've been in positions where I needed to get a lot of old C code into C#. Lucky for me, it was in a DLL, and C# makes running DLL functions relatively easy with platform invoke. Microsoft has a tutorial at http://msdn.microsoft.com/en-us/library/aa288468.aspx.
You'll have to marshal data between the DLL and your C# code, but there ends up being about 10 basic types of marshals (string, array, pointers, etc etc), and once you've got a handle on them, building a class that will run all your DLL functions for you becomes pretty easy.
Anyways, just my two cents. With platform invoke, you'll still have to write a good bit of C# code, but you don't have to rewrite (and re-debug) the code that does most of the work.
Much obliged.
This is actually not quite right :-)
http://msdn.microsoft.com/en-us/library/y31yhkeb(VS.80).aspx
The .NET integration-features that have been introduced into MAX is a step in the right direction, but there are some shortcomings that may benefit from the act of being brought to the surface, in case someone out there were dancing a mazurka of joy, thinking they could throw out the MAX sdk come blue morning.
The ability to interface with MAX datatypes from the .NET assembly is practically nonexistant. As a result, shuffling large portions of data to the .NET-side therefore requires iterating the data. This e.g. hardens the possibilities of quickly performing a very common plugin task: munching geometry.
Hopefully, integration will become a bit tighter in the future, although I would rather prefer they put their weight on making MAXscript run faster.
I had such a bad time with making the UI for the tool. I could never make it as good as I would have liked.
IIRC Maxscript cannot access everything that's visible in the UI. For example I had issues with using the "loft" tool in Maxscript. Not sure if anything's changed now. I used Maxscript essentially for raising events and for the UI. The majority of the work was done in the 3DS Max Plugins.
Could you tell us something about the formats in which you had exported the data from 3DS Max?
"For some developers, integration with 3DS Max may mean rewriting thousands of lines of code within .NET, and each developer will need to assess how reasonable that would be to achieve."
I've been in positions where I needed to get a lot of old C code into C#. Lucky for me, it was in a DLL, and C# makes running DLL functions relatively easy with platform invoke. Microsoft has a tutorial at http://msdn.microsoft.com/en-us/library/aa288468.aspx.
You'll have to marshal data between the DLL and your C# code, but there ends up being about 10 basic types of marshals (string, array, pointers, etc etc), and once you've got a handle on them, building a class that will run all your DLL functions for you becomes pretty easy.
Anyways, just my two cents. With platform invoke, you'll still have to write a good bit of C# code, but you don't have to rewrite (and re-debug) the code that does most of the work.