Max geometry esporter in C#


#1

Hi, my problem is to make a tool that exports large files (about 20MB), i already made it with maxscript but the heapsize increase untill 100MB, the script is very slow and if i want add a Edit_Normal modifier i must wait about 10 min !!!
I noticed that using C# or esternal .dll can do very fast the same operations… so i decided to learn c#, I’m still a novice but I think I understand how it works; I don’t want use C/C++… isn’t a simple language for my purpose.
I already use dotnet into maxscript: http://forums.cgsociety.org/showthread.php?f=98&t=1020505&page=2&pp=15 to use an esternal dll decompressor.

My purpose is to delegate exporting geometric data (which slows a lot) with a esternal c# code, and write with maxscript only other simple data and value, because i already made some function like name sorting, texture name ecc…

I watch this tutorial http://vimeo.com/11191227 and i installed autodesk_max1_2_8_0_offline_install.exe for max2011 32bit
But i need help to understand how to pass a editable_mesh’s node into c# and found the maxscript’s function like: getNormal , getVerts , getFace etc…

using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using Autodesk.Max;
 using Autodesk.Max.Plugins;
 
 namespace Gamelibrary
 {
 	public class GeometryEsporter
 	{
 		static string WriteGeometryData (INode tmesh ; FileIOType fout)
 		{
 			/*  write faces, vertex , normals , tangents , binormals , uvw , vcolor to
 			 *  fout but with fout = open "mydgamedata.mesh" "wb" passed in maxscript
 			 */
 		   return "OK"
 		}
 	}
 }
 

Thanks anyway for your interest , I believe that this example can be very useful to “break the ice” with max > .NET scripts


#2

Visual C#:

namespace Gamelibrary
 {
 	using System;
 	using System.Diagnostics;
 	using System.Runtime.InteropServices;
 	using System.IO;
 
 	using Autodesk.Max.Plugins;
 
 	public class GeometryEsporter
 	{
 		public string WriteGeometryData (INode tmesh)
 		{
 			return tmesh.Name;
 		}
 	}
 }
 

Maxscript:

(
 clearListener()
 local ScriptDir = getFilenamePath (getSourceFileName())
 local dll = dotnet.loadAssembly @"C:\Documents and Settings\Admin\Documenti\Visual Studio 2010\Projects\ClassLibrary1\ClassLibrary1\ClassLibrary1.dll"
 local esp = dll.createInstance("Gamelibrary.GeometryEsporter")
 showMethods esp
 showProperties esp
 result = esp.WriteGeometryData $
 print result
 )

a simple:

public string WriteGeometryData (string nome) {return nome;}

work but this return:
– result: undefined
– Runtime error: No method found which matched argument list

How can i pass one node or node selection to work with them ? and why i must load Autodesk.Max.dll ? i must compile it for each existing version of 3dstudio ?


#3

if you’re going to go to that kind of trouble just cut out the middle man altogether, write it as a export plugin using c++. lots of examples in the SDK, pretty easy really. you can even use a proper step by step debugger if you have problem with your code.


#4

i think c++ sdk is the only solution, why don’t exist some simple example for C# (without always a plugin derived…)? is a simple language.


#5

The C# library you’re using is “simply” a wrapper for the SDK. So the C++ examples you’ll find in the SDK will largely apply to your library too.


#6

I would start by posting your maxscript version and trying to understand why it’s so slow. It doesn’t sound like a 20MB file should take that long to export.


#7

i’m agreed with lo. it can’t be so slow…


#8

I think a script I found that exports the data to XAML did it in only a few seconds or something with a filesize of around that.

http://blogs.microsoft.co.il/blogs/maxim/archive/2009/03/31/daily-tip-how-to-import-3d-model-to-wpf-from-3d-max.aspx


#9

Thanks for interest :slight_smile: , so:
this is my work : http://www.twcenter.net/forums/downloads.php?do=file&id=3311
I have to manage files with more than 1 million of vertices (world files of 20 MB) what required about 1-2 minutes to import and export and increase the heapsize about to 90 MB !!! (there are also two video what show this)
The maxscript version is optimized and work fast but not enough because:

  1. for 2 milion of vertices (the bigger case with a 40 MB of file) i must wait 5-6 minutes
  2. i disabled the Edit_Normal modifier creation, increse the time to x20 !!! so i can’t save normals but isn’t important.
  3. menage and build some fast algorithm to work with vertex list in maxscript isn’t possible, example for Lzo decompression (http://forums.cgsociety.org/showthread.php?f=98&t=1020505&page=2&pp=15) i add two function to delegate all array’s operation, and maxscript thanked mewithout increase heapsize and with x10 time fast XD!!!

But the issue:
I know a little C#, the essential , isn’t difficult for my purpose… some little difference with C, but when i saw the tutorial my head exploded T_T, the .Net version is more appreciated for my little brain !
:hmm::wip:
On internet there aren’t ONE tutorial or source code for a simple mesh esporter… i wan’t plugin extension because the tool must work without problem for a lot of 3dstudio’s version (max9 to max2012… max2013 isn’t a problem : the world end :slight_smile: ) and because i don’t want save dll into plugin folders.


#10

can you post just the code for the exporter? those are some huge scripts and will take people time to locate your exact code.


#11

if the community is interested we can organize some sort of brain-storming: HOW TO DO IT FAST AND MEMORY SAFE
my guess is for 10,000,000 verts the export of faces, vert positions, vert uvw, verts normals has to be about ~20-30 secs using just pure mxs solution…


#12

WHAT AN WONDERFUL IDEA!


#13

if the community is interested we can organize some sort of brain-storming: HOW TO DO IT FAST AND MEMORY SAFE
my guess is for 10,000,000 verts the export of faces, vert positions, vert uvw, verts normals has to be about ~20-30 secs using just pure mxs solution…

make it “next gen” and add binormals, tangents, second uv’s and vertex colour.


#14

i think it’s a good idea… you will show us how to get vertex tangent.


#15

easy, do it as a plugin.


#16

any way… just show.


#17

what the code you would use in a plugin ?


#18
    one moment, this is off-topic because the maxscript code don't have issue but 
    "a lot of fast function" = "one slow script".

If you are interested this is the heart of geometry section of world_class.ms file:
[left] Struct StructureClass , the fn getGeometry and fn setGeometry are the two functions what work with 3dstudio mesh and fn read fin and fn write fout are the two function what import and export to BinStream.
For the getGeometry section the code is saved in geometry_class.ms > Struct GetGameGeometry > fn get_method1.
For example 30 objects with 60000 total vertex this function need about 2000 ms to build VertsData,NormalData,TangData,UVData 's arrays.
To save it with fn getGeometry + fn write fout only about 200 ms.
But ,if you multiply 2 structure x 30 complex , you obtain (2000+200)230 = 132000 ms = 2-3 minutes.
I’m sure that this 2000 ms is because 3dstudio array use a lot of memory, the game limit is 65536 but when i work with 80000 array’s elements maxscript slow a lot… if i convert to .dll i’m sure to reduce the script time about x20 !!

I’d really like to convert all to.net assemblies, because i know maxscript and c#… the only issue is that i don’t understand how communicate max scene with .net assembly :banghead:, the dll return always Runtime error: No method found which matched argument list, i write exactly as tutorial…[/left]


#19

i’m personally using c++ for this kind of things. i told many times on this forum that is the best way to get true export is to use max sdk. and i don’t understand way you keep beating a dead horse.
only thing that i asked you is to show a little code how to get vertex tangent.


#20

if you insist…

void MeshObj::CreateVertexList(S3DVertex* outverts, material_info& m)
 {
 	int index = 0;
 	int matid_counter = 0;
 	FaceEx* f;
 	TVFace mapface;
 
 	for(int i=0; i < number_of_faces;i++)
 	{
 // for all faces of material matid
 
 		f = mesh->GetFace(i);
 		if(f->matID == m.id)
 		{
 			index = 3 * matid_counter;
 			mesh->GetMapFaceIndex(MAPCHANNEL_2,i,mapface.t);
 
 			for(int j = 0; j < 3; j++)
 			{
 				int tbIndex = mesh->GetFaceVertexTangentBinormal(i, j); 
 				m.bbox += mesh->GetVertex(f->vert[j],true); // expand the bounding box
 				outverts[index].pos = vector3d(mesh->GetVertex(f->vert[j],true));
 				outverts[index].normal = vector3d(mesh->GetNormal(f->norm[j],true));
 				outverts[index].tangent = vector3d(tm.VectorTransform(mesh->GetTangent(tbIndex)));
 				outverts[index].binormal = vector3d(tm.VectorTransform(mesh->GetBinormal(tbIndex)));
 				Point3 vcolour;
 				if(mesh->GetColorVertex(f->color[j],vcolour))
 					outverts[index].color = SColor(vcolour);
 				else // set the vertex colour to white
 					outverts[index].color = SColor(255,255,255,255);
 				float alpha;
 				if(mesh->GetAlphaVertex(f->alpha[j],alpha))
 					outverts[index].color.setAlpha(alpha);
 				outverts[index].tcoord1 = vector2d(mesh->GetTexVertex(f->texCoord[j]));
 				outverts[index].tcoord2 = vector2d(mesh->GetMapVertex(MAPCHANNEL_2,mapface.t[j]));
 				outverts[index].vertindex = f->vert[j];
 				index++;
 			}
 			matid_counter++;
 		}
 	}
 }

this is the function i use to collect all the geometry info of a particular material id from a max mesh, mesh is an IGameMesh* and tm is the inverse tranform of the object so the tangent and binormal are in local space. The Initial outverts array is the “worse case” array which is then optimized later.