[Closed] Convert DotNet objects to MaxScript
Hi all.
I found this weekend this thread form @sinokgr and I decided to play with:
http://forums.cgsociety.org/showthread.php?t=1138801
I’ve managed to get from C# a “mesh object” (dotNetObject:Autodesk.Max.Wrappers.Mesh) to MaxScript. But I’m not able to asign it to a node with MaxScript. I suppose I have to convert it to a “true” mesh.
Here are the codes:
C# code (nearly the same as the mentioned thread):
using Autodesk.Max;
namespace exportMesh
{
static public class Class1
{
static IGlobal global = GlobalInterface.Instance;
static private ITriObject GetTriObjectFromNode(IINode node)
{
IObject obj = node.EvalWorldState(0, true).Obj;
IClass_ID myClass = global.Class_ID.Create(9, 0);
if (obj.CanConvertToType(myClass) == 1)
{
ITriObject tri = (ITriObject)obj.ConvertToType(0, myClass);
return tri;
}
else
{
return null;
}
}
// Function that returns a modified mesh
static public IMesh exportMesh(uint handle)
{
IINode node = global.COREInterface.GetINodeByHandle(handle);
IMesh myMesh = GetTriObjectFromNode(node).Mesh_;
//Do something with the mesh
return (myMesh);
}
}
}
And here’s the MaxScript code:
(
Global a
--Load assembly
dotNet.loadAssembly @"D:\Pruebas\3DMax\C#\ClassLibrary1_PruebaMax02.dll"
--Prepare scene
delete objects
myTeapot = teapot()
addModifier myTeapot (turboSmooth iterations:3)
--CS
t = timestamp()
a =(dotnetclass "exportMesh.Class1").exportMesh myTeapot.inode.handle
format "CS took %s
" ((timestamp() - t)*.001)
format "a = %
" a
format "ClassOf a: %
" (classOf a)
)
And I get this result:
CS took 0.005s
a = dotNetObject:Autodesk.Max.Wrappers.Mesh
ClassOf a: dotNetObject
So I can ask in the listener for lots of things (a.numverts, a.numfaces, …) but I don’t know how to use this mesh:
nd = Editable_Mesh()
nd.mesh = a >>> throws an error “– Unable to convert: dotNetObject:Autodesk.Max.Wrappers.Mesh to type: Mesh”
Any suggestions? Is it possible to use this dotNetObject as a MaxScript mesh?
Thanks a lot for your help.
Any ideas in how to get the mesh via C#?
This could make my script faster by 1000%!!
Passing MaxObjects to C# and viceversa through rootNode Custom Attributes.
-- Adding void CA to rootNode
(
CA_MxsNETConnect = attributes CA_MxsNETConnect attribID:#(0x11aa99ff, 0x1234abcd)
(
parameters params
(
T_MaxObject type:#maxObjectTab tabSizeVariable:true
T_Node type:#nodeTab tabSizeVariable:true
T_Point3 type:#point3Tab tabSizeVariable:true
T_Matrix3 type:#matrix3Tab tabSizeVariable:true
T_Material type:#materialTab tabSizeVariable:true
T_TextureMap type:#texturemapTab tabSizeVariable:true
T_Bitmap type:#bitmapTab tabSizeVariable:true
)
)
try (custAttributes.delete rootNode CA_MxsNETConnect baseObject:false) catch ()
custAttributes.add rootNode CA_MxsNETConnect baseObject:false
)
(
----------------------------------------
-- Example passing nodes and maxObjects to C#
try (rootNode.CA_MxsNETConnect) catch (custAttributes.add rootNode CA_MxsNETConnect baseObject:false)
theNodes = selection as array
rootNode.CA_MxsNETConnect.T_Node = theNodes
rootNode.CA_MxsNETConnect.T_MaxObject = (for o in theNodes collect copy o.baseobject)
dotNet.loadAssembly @"C:\......\SDKNETUtilities.dll"
(dotnetclass "SDKNETUtilities.MxsNETConnectClass").CA_MxsNETConnect()
----------------------------------------
)
And then in C#
using System;
using System.Collections.Generic;
using Autodesk.Max;
namespace SDKNETUtilities
{
class MxsNETConnectClass
{
// Method to obtain the ParamBlock2 of the Custom Attribute 'CA_MxsNETConnect attribID:#(0x11aa99ff, 0x1234abcd)'
// applied to scene RootNode
static public IIParamBlock2 GetCA_MxsNETConnect()
{
IGlobal global = GlobalInterface.Instance;
IInterface14 ip = global.COREInterface14;
IINode rootNode = ip.RootNode;
IClass_ID CA_Class = global.Class_ID.Create(0x11aa99ff, 0x1234abcd);
IICustAttribContainer CAC = rootNode.CustAttribContainer;
int numCA = CAC.NumCustAttribs;
int CA_Id = -1;
ICustAttrib CA;
for (int ca = 0; ca < numCA; ca++)
{
CA = CAC.GetCustAttrib(ca);
if (CA.ClassID.PartA == CA_Class.PartA && CA.ClassID.PartB == CA_Class.PartB)
{
CA_Id = ca;
break;
}
}
if (CA_Id == -1)
{
return null;
}
CA = CAC.GetCustAttrib(CA_Id);
IIParamBlock2 param = CA.GetParamBlock(0);
return param;
}
static public void CA_MxsNETConnect()
{
IIParamBlock2 param = GetCA_MxsNETConnect();
if (param == null)
{
return;
}
////////////////////////////////////////////////////////////
// Example1 to retrieve a #MaxObject that is an Edtable_Mesh (it's the first parameter => id=0)
IReferenceTarget rf = param.GetReferenceTarget(0, 0, 0); // First 0 is because #MaxObject are the first parameter
// Second 0 is time at 0
// Third 0 is first MaxObject in the #MaxObjectTab array
ITriObject tri = (ITriObject)rf;
IMesh mm = tri.Mesh_; // Retrieve the mesh of the Editable_Mesh
int numverts = mm.NumVerts_;
//WriteLine("numVerts= " + numverts);
// Example2 to retrieve all nodes held in the #nodeTab parameter (it's the second parameter => id=1)
int numNodes = param.Count(1);
List<IINode> theNodes = new List<IINode>(numNodes);
for (int i = 0; i < numNodes; i++)
{
theNodes.Add(param.GetINode(1, 0, i));
//WriteLine("Node " + i + ": " + theNodes[i].Name);
}
// Example3 to return a node to the #nodeTab parameter (in this case, the last node to the first place)
bool done = param.SetValue(1, 0, theNodes[numNodes - 1], 0);
////////////////////////////////////////////////////////////
}
}
}
It’s so easy… what I’m missing?
Wonder if it is possible to determine Value class before casting? I mean anything better than the Tag.Name comparison.
static public IMesh GetMeshFromMaxscriptVariable( string global_var_name )
{
using ( ICharStream cs = GlobalInterface.Instance.StringStream.Create( global_var_name ) )
using ( IValue value = GlobalInterface.Instance.ExecuteScript( cs, true ) )
{
if ( value.Tag.Name == "TriMesh" )
{
return value.ToMesh;
}
else
{
return null;
}
}
}
why don’t you assign the mesh to the node in c# and return that to mxs ?
in the sdk it would be
TriObject* tobj = CreateNewTriObject();
if(!tobj) // do something else
Mesh& mesh = tobj .GetMesh();
// build it's mesh....
mesh = modmesh; // or what ever
INode* node = GetCOREInterface()->CreateObjectNode(tobj);
Well, the question is really about determining ValueMetaClass of Values that ExecuteScript returns.
What if I want to pass TriMesh that I got from snapshotasmesh and BitArray from mxs to the other side?
With the use of auxiliary global variable it is possible to transfer almost anything to the dotnet side back and forth. Even the structs are passed successfully. I can read and assign props. That is not a problem.
But I need some convenient way to check that the variable types are correct.
Something similar to this, but using C#
#define is_mesh(v) ((DbgVerify(!is_sourcepositionwrapper(v)), (v))->tag == class_tag(MeshValue))
I couldn’t find much info about MeshValue and the way we should check for any other Value types.
I’m sorry, but what top code are you talking about?
It must be my poor english, but I have no intent to create any mesh whatsoever. I want to pass maxscript variables to c# and use them for calculations, change their type, assign any other value to them, etc…
The question is how to get a class of underlying maxscript value of Value that is returned from ExecuteScript function on c# side?