I believe the leaking in the .Net function is caused by the IPoint3 creation. I tried the following and the memory keeps calm and low. I didn’t even needed to dispose any object or gc(), but it might be required.
I've tried 1000 calls on a 100K object.
public void GradeMesh()
{
IObject obj = node.EvalWorldState(ip.Time, true).Obj;
IClass_ID cid = global.Class_ID.Create((uint)BuiltInClassIDA.TRIOBJ_CLASS_ID, 0);
if (obj.CanConvertToType(cid) != 0)
{
ITriObject triMesh = obj.ConvertToType(ip.Time, cid) as ITriObject;
IMesh mesh = triMesh.Mesh;
IList<IPoint3> mapVerts = mesh.MapVerts(Channel);
int numMapVerts = mesh.GetNumMapVerts(Channel);
IPoint3 Pt1 = global.Point3.Create(1, 0, 0);
IPoint3 Pt2 = global.Point3.Create(1, 1, 1);
for (int i = 0; i < numMapVerts; i++)
{
IPoint3 vertex = mesh.GetVert(i);
IPoint3 mapVert = mapVerts[i];
float r = mapVert.X * 255.0f;
float g = mapVert.Y * 255.0f;
float b = mapVert.Z * 255.0f;
if (vertex.Z > HeightThreshold)
{
Pt1.Y = Math.Max(0, (g - FadeInValue) / 255);
Pt1.Z = Math.Max(0, (b - FadeInValue) / 255);
mesh.SetMapVert(Channel, i, Pt1);
}
else if (g < 255)
{
if (g + FadeOutValue > 255)
{
mesh.SetMapVert(Channel, i, Pt2);
}else{
Pt1.Y = (g + FadeOutValue) / 255;
Pt1.Z = (g + FadeOutValue) / 255;
mesh.SetMapVert(Channel, i, Pt1);
}
}
}
// triMesh.Dispose();
// mesh.Dispose();
}
// obj.Dispose();
}
Thanks! I will test it when I get back from work. I noticed that the IPoint3 also implements IDisposable, so i’ll call that one too.
Disposing the IPoint3 also seems to prevent the leaking, but the function seems to run twice as slow when creating/disposing the IPoint3 than if I just overwrite the values as shown in the code above.
Overwriting IPoint3 values (1000 calls to GradeMesh())
– time:5135 ram:95864L verts:100002
Creating IPoint3 (1000 calls to GradeMesh())
– time:9889 ram:95864L verts:100002
I noticed that the IPoint3 also implements IDisposable, so i'll call that one too.
Why on earth would they implement Point3 as a class, not to mention one which requires disposal???
It’s 3 freaking floats!
i was missing…
i was taking about poly methods:
(
delete objects
node = converttopoly (geosphere segments:20)
t1 = timestamp()
m1 = heapfree
setmapvert = polyop.setmapvert
for v=1 to node.numverts do setmapvert node 1 v red
format "map > verts:% time:% memory:%
" node.numverts (timestamp() - t1) (m1 - heapfree)
gc()
t1 = timestamp()
m1 = heapfree
setvertcolor = polyop.setvertcolor
for v=1 to node.numverts do setvertcolor node 1 v red
format "col > verts:% time:% memory:%
" node.numverts (timestamp() - t1) (m1 - heapfree)
)
Shouldn’t you also be disposing the IList<IPoint3> returned from mesh.MapVerts(Channel) and the IPoint3’s returned from mesh.GetVert(i)?
I would suppose you would have to dispose everything that is disposable.
In this case, GetVert() does not cause any memory leaking at all, so I tried to not dispose anything and see what was causing the leaking.
It appears that the leaking is directly related to the IPoint3 creation, and so I would assume it also happens with any other class too. For example IPoint2 has the same problem.
Also Creating/Disposing seems to be much slower than overwriting, so I would personally just go with Creating the IPoint3 once and overwrite its values later. This way I think you can also omit disposing it without any worries.
As far as I can tell, IPoint3 doesn’t really contain the X,Y,Z data, it’s just a wrapper around a pointer to a native Point3 in unmanaged memory. I think what you’re disposing is actually the pointer reference.
Or maybe it’s telling the unmanaged memory manager to free the native Point3? I don’t know. I’d check the documentation if one existed.
Looking to optimize this further for real-time revisualization, I tried another approach. I haven’t looked at the level of protection of the SetMapVert() method, but I am sure the following is not recommended. However if this is for yourself and you don’t find any bugs, it might speed up the preview.
I’ve noticed that you can directly overwrite the mapVerts List, so you don’t even need to create a “dummy” IPoint3 and overwrite it, just overwrite the mapVerts List directly as follow:
public void GradeMesh()
{
IObject obj = node.EvalWorldState(ip.Time, true).Obj;
IClass_ID cid = global.Class_ID.Create((uint)BuiltInClassIDA.TRIOBJ_CLASS_ID, 0);
if (obj.CanConvertToType(cid) != 0)
{
ITriObject triMesh = obj.ConvertToType(ip.Time, cid) as ITriObject;
IMesh mesh = triMesh.Mesh;
IList<IPoint3> mapVerts = mesh.MapVerts(Channel);
int numMapVerts = mesh.GetNumMapVerts(Channel);
IPoint3 Pt1 = global.Point3.Create(1, 1, 1);
for (int i = 0; i < numMapVerts; i++)
{
IPoint3 vertex = mesh.GetVert(i);
IPoint3 mapVert = mapVerts[i];
//float r = mapVert.X * 255.0f;
float g = mapVert.Y * 255.0f;
float b = mapVert.Z * 255.0f;
if (vertex.Z > HeightThreshold)
{
mapVert.X = 1;
mapVert.Y = Math.Max(0, (g - FadeInValue) / 255);
mapVert.Z = Math.Max(0, (b - FadeInValue) / 255);
mapVerts[i] = mapVert;
}
else if (g < 255)
{
if (g + FadeOutValue > 255)
{
mapVerts[i] = Pt1;
}else{
mapVert.X = 1;
mapVert.Y = (g + FadeOutValue) / 255;
mapVert.Z = (g + FadeOutValue) / 255;
mapVerts[i] = mapVert;
}
}
}
}
}
This seems to perform 50% faster than the previous improvement which makes it around 3 times faster than creating the points and with no memory leaking.
I’ve tried with a static mesh and the improvement is noticeable, but when running an animated mesh, the performance is capped by Max itself, so I got 80FPS on a 120K mesh with or without changing the vertex colors which indicates that the function is very efficient.
I’ve tried different meshes and animations with no problems at all, no memory leaking, no crash and the performance keeps as good as playing the animation alone. In all cases the FPS appears to be capped wither by the internal mesh update or by the viewport redrawing.
for every map vertex in the loop you multiply g and b values by 255 and later divide them by 255. you do it only because fade-in and out values come in the function in range [0,255].
it would be better just re-range them as [0,1] (divide them before loop by 255) and not touch map vert values at all.
I would had been surprised if avoiding the multiplications and divisions in this case would cause such a huge performance impact. So I tried it and as far as I can see it doesnt speed up the function at all.
another thing i don’t like is:
for (int i = 0; i < numMapVerts; i++)
{
IPoint3 vertex = mesh.GetVert(i);
IPoint3 mapVert = mapVerts[i];
...
it means you always expect to have the same number of geo and map verts. it’s a very specific case. is it a requirement of your tool? if so you have to check it before the function use.
That is a good point.
I can’t tell you much about the requirements of the tool, I was just helping a guy to speed it up, and basically converted each maxscript line to .net :). The idea is to create a mask for foam on animated oceans. I guess the next step is to add more criteria when checking if a vertex should be colored, such as speed and angles etc.
Thank you Håvard, I now have a better idea of what this tool could be used for. Will try with an ocean.
Beautiful!
Tried with an animated ocean and it works wonderful. Perfect for creating foam masks, among other things.
Performance is great, I don’t think it needs any further optimizations. After all, the ocean I tried is another example that probes the FPS are capped by the animation itself and not by coloring the vertices with this function.
If it is for previewing you can just initialize the default map faces and it should work.