Conclusions
We have been
using this solution at Vicarious Visions for one year. We have shipped one Nintendo DS
project, Kung Fu Panda, and are currently supporting three
ongoing Nintendo DS projects and one Xbox 360 / PlayStation 3 project.
Overall, we have
had great success using this solution. We have been able to leverage the
various systems that 3DS Max provides to alleviate redundant work, which we
would have needed to do if we had built a system from scratch. There are
factors to consider before integrating existing toolchains with 3DS Max, but
they are no different from any other large-scale integration project.
Integrating 3DS Max with .NET allows for two distinct disciplines, namely
technical art and engineering, to work together cooperatively in developing
programs, rather than working in isolation.
In the end,
integrating .NET applications with 3DS Max through MaxScript consolidates a
great deal of functionality from different applications within a single user
interface that artists and designers are already comfortable using.
Downloads and
Documentation
MaxScript Help
File Sections
-
DotNet in MaxScript
-
Registering Windows SystemEvents Callbacks Using DotNet
-
Loading Assemblies
MSDN .NET
Framework
-
http://msdn2.microsoft.com/en-us/netframework/default.aspx
Microsoft Visual
C# 2005 Express Edition
-
http://msdn2.microsoft.com/en-us/express/aa975050.aspx
Appendix I: Benchmark Source Code
MaxScript Code
function maxscript_test_fn input_array =
(
accum = 0;
for val in input_array do
(
accum += val;
)
accum;
)
DotNet.LoadAssembly "Benchmark.dll";
function benchmarkDotNet samplesize:10000 testlength:10 verbose:false =
(
dot_net_object = DotNetObject "Benchmark.BenchmarkClass";
[Get a reference directly to the method, avoid name lookup; matches native MaxScript behavior more closely.]
dot_net_object_test_fn = dot_net_object.Test;
sample_data = #();
for i = 1 to samplesize do
(
sample_data[i] = (random 0 10) as Integer;
)
[Make a result buffer to avoid any 'lazy evaluation' optimizations MaxScript might do because nothing is using the return value of the function. Also pre-allocate the array to prevent any runtime allocation which may affect one of the loops.]
result_buffer = #();
for i = 1 to testlength do
(
result_buffer[i] = 0;
)
timer1 = timeStamp();
for i = 1 to testlength do
(
result_buffer[i] = maxscript_test_fn sample_data;
)
timer2 = timeStamp();
for i = 1 to testlength do
(
result_buffer[i] = dot_net_object_test_fn sample_data;
)
timer3 = timeStamp();
maxscript_time = timer2 - timer1;
dot_net_time = timer3 - timer2;
if (verbose == true) then
(
format "Results:\n";
format "\tMaxScript : %ms\n" maxscript_time;
format "\tDotNetObject : %ms\n" dot_net_time;
)
#(maxscript_time, dot_net_time);
)
function runFullBenchmark =
(
sample_sizes = #(16, 1024, 131072);
test_lengths = #(10, 100, 1000);
for test_length in test_lengths do
(
for sample_size in sample_sizes do
(
time_results = benchmarkDotNet samplesize:sample_size \
testlength:test_length;
format "[size=%, length=%]\tMS:%\tDN:%\n" sample_size \
test_length time_results[1] time_results[2];
)
)
)
C# Code
using System;
namespace Benchmark
{
public class BenchmarkClass
{
public int Test(int[] buffer)
{
int accum = 0;
for (int i = 0; i < buffer.Length; i++)
{
accum += buffer[i];
}
return accum;
}
}
}
|
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.