[Closed] unknown system exception-out of memory
I’ve been writing a script to turn an editable poly object into an executable maxscript. This is mostly for maxscript practice but it will make it easier to take objects from later versions of max into earlier ones with things intact like ALL UV channels etc. Still early stages at the moment but it seems to work great unless I try to make a script out of a high poly object. I’ve been exporting a 30K poly object which seems to export OK, but when I run the script to remake the poly object, I get an unknown system exception and sometimes it gives me an out of memory error and max will crash and dissapear. Is there a way to clear the memory as I’m building the object? Currently In the script that’s created, I build the vert array then make all the verts of the object, then I build the poly array and build the polys etc etc. As far as other data, I’ve only got the smooth groups and the material IDs up and running so far.
When I wrote the script to start with I didn’t have the “with redraw off” or “undo off” and the 30k poly object worked without a crash but it took 28 mins to rebuild. A friend suggested I add redraw off and undo off and it definately improved the speed of the script a lot on smaller objects, but now I can’t get it to work on larger objects without erroring.
On closer inspection, it seems that it runs out of memory on the polyop.setFaceSmoothGroup loop and I still can’t figure out why.
Here is the script that will export a poly to an executable maxscript.
macroScript ExportPolyToMS
category:"CgRay"
(
try (destroyDialog ExportPolyToMS) catch()
rollout ExportPolyToMS "Export Poly to MS"
(
group "Elements to export"
( checkbox chk_SmGroups "Smooth Groups" checked:true align:#left
checkbox chk_Materials "Material" checked:true align:#left enabled:false
checkbox chk_MatId "Material ID's" checked:true align:#left
checkbox chk_UVs "UV channels" checked:true align:#left enabled:false
checkbox chk_VertCol "Vertex Colors" checked:true align:#left enabled:false
)
button btn_Export "Export Selected"offset:[0,5]
on btn_Export pressed do
( clearlistener()
if (selection.count == 1) and (superclassof $ == geometryclass) and (classof $ != TargetObject) then
(
objectName = $.name
-- set output file
outName = ("F:\\MaxStuff\\scripts\\CgScripts\\exporter\\PolyExport_"+objectName+".ms")
outFile = createfile outName
-- make snapshot of object and turn it to a poly
tempObj = snapshot $
convertTo tempObj PolyMeshObject
-- sets the vertcount and polycount variables
vertCount = polyop.getnumVerts tempObj
polyCount = polyop.getNumFaces tempObj
--start writing the script
format "with redraw off
" to:outFile
format "(
" to:outFile
format "clearlistener()
" to:outFile
format "startTime = timestamp()
" to:outFile
-- writes script to make an empty editable mesh and convert it to a poly
format "newPoly = editable_mesh()
" to:outFile
format "convertTo newPoly PolyMeshObject
" to:outFile
-- writes script to set the vertcount and polycount variables
format "vertCount = %
" vertCount to:outFile
format "polyCount = %
" polyCount to:outFile
fn ConstructArrayThenBuild arrayName loopLength tempObj outfile =
( --builds up the relevant array
format "% = #(" arrayName to:outFile
for i = 1 to looplength do
( case arrayName of
(
"vertArray": ( tempData = polyop.getvert tempObj i)
"polyArray": ( tempData = polyop.getFaceVerts tempObj i)
"smoothGroupArray": ( tempData = polyop.getFaceSmoothGroup tempObj i)
"matIdArray": ( tempData = polyop.getFaceMatID tempObj i)
)
format "%" tempData to:outFile
if i != looplength then
(
format "," to:outFile
)
)
format ")
"to:outFile
-- writes script that will build the relevant element
format "undo off
" looplength to:outFile
format "(
" to:outFile
format " for i = 1 to % do
" looplength to:outFile
format " (
" to:outFile
case arrayName of
(
"vertArray": ( format " polyop.createVert newPoly vertArray[i]
" to:outFile)
"polyArray": ( format " polyop.createPolygon newPoly polyArray[i]
" to:outFile)
"smoothGroupArray": ( format " polyop.setFaceSmoothGroup newPoly i smoothGroupArray[i]
" to:outFile)
"matIdArray": ( format " polyop.setFaceMatID newPoly i matIdArray[i]
" to:outFile)
)
format " )
" to:outFile
format ")
" to:outFile
)
-- sends vert related info to the ConstructArrayThenBuild function
arrayName = "vertArray"
looplength = vertCount
polyOpType = "poVert"
ConstructArrayThenBuild arrayName loopLength tempObj outfile
-- sends poly related info to the ConstructArrayThenBuild function
arrayName = "polyArray"
looplength = polyCount
polyOpType = "poPoly"
ConstructArrayThenBuild arrayName loopLength tempObj outfile
if chk_SmGroups.state then
(
-- sends smoothing group related info to the ConstructArrayThenBuild function
arrayName = "smoothGroupArray"
looplength = polyCount
polyOpType = "poFaceSmoothGroup"
ConstructArrayThenBuild arrayName loopLength tempObj outfile
)
if chk_MatId.state then
(
-- sends material ID related info to the ConstructArrayThenBuild function
arrayName = "matIdArray"
looplength = polyCount
polyOpType = "poFaceMatID"
ConstructArrayThenBuild arrayName loopLength tempObj outfile
)
format "update newPoly
" to:outFile
-- writes script that calculates total time spent building polyobject and prints to listener
format "endTime = timestamp()
"to:outFile
format "duration = (endTime - startTime)/1000
" to:outFile
format "print duration
" to:outFile
format ")
" to:outFile
close outFile
delete tempObj
)
else
(
messagebox "Select one geometry object to export" title:"Selection Error"
)
)
)
createdialog ExportPolyToMS
)
Things like gc() might help, but it will only clear the maxscript buffer.
You might also want to check the maxscript heap size just in case.
Can’t say if any of these will make a difference, but worth a check
Cheers
Shane
I would go look at Bobo’s BFF script, since it does alot of this and has been working in most cases since Max 5.
-Eric
Shane, thanks for that. I have been trying the gc() and it seems to change nothing. I just can’t figure out why it’s the smoothinggroup part of the script that’s causing the problem. The verts,polys and MatID’s all rebuild fine with no memory blowout.
PixelMonkey:
Yes, it’s all well and good to just use someone else’s script, but that doesn’t help me get any better at maxscripting and the main reason I’m doing this is for the practice.
Actually I think the idea was to LOOK into how I have implemented the same concept without any memory overhead even with several millions of polygons. The initial implementation of BFF suffered from the same problem and I had to do something about it.
Basically, trying to write out an array as script and then read that array back will hit memory limits because all vertex/poly etc. data has to fit in memory at once. You could increase the HeapSize (on my machines it is typically set to either 64MB or 128MB, when the default shipping settings are 7.5MB – I never get any memory related errors), but the real trick is to write the data in such a way that you could rebuild the object one vertex at a time without keeping anything in memory…
Just an idea…
As Bobo stated I was reccommending that you look at the technique that he uses. Most of the stuff I have learned when it comes to Maxscript comes from the help file, and others scripts. Also, how does looking through others work differ from asking for help here? You are still getting the answer from someone who has already solved the issue in one way or another.
-Eric
Very sorry about that Eric, I obviously read the post wrong. I’ll have another look at BFF. Although I’m not yet at the point where I can decipher other people’s structure very well. I often still have problems when looking at my own past scripts.
I’m still very confused as to why everything works fine except for the smoothing group part. Or would that just happen to be the point where maxscript runs out of memory and somehow starts to chew thru the rest of the 2Gb in less than 10 seconds?
Bobo: Thanks for the guidance.
The first incarnation of my script didn’t write loops or use arrays, it just wrote every line out as it went. The resulting scripts were about twice the size, but do you think going back to that method would help with the problems I’m having now?
Cheers,
Cg.
The main idea I am trying to convey is that you can create an object in memory that already has the number of vertices and faces of the final object to be imported, just with the wrong values. Of course, I was exporting EPoly objects implicitly, because when BFF was first written, it meant “Back From Five” and was supposed to move data from Max 5 to Max 3 where there were no Editable Poly objects at all! So I converted the EPoly to EMesh, exported the mesh and if the target platform supported EPoly, after setting all data including Edge Visibility, I tried to convert the result to EPoly, which leads to about the same result.
So for the mesh, MAXScript allows you to say mesh numverts:N numfaces:NN and you would get a mesh that has the correct number of vertices and faces, but no valid topology. All vertices would have the values [0,0,0] and the faces would not be set either.
So the importer code would first create such an object in the scene, then set each vertex to the correct value using setVert(), then set each face to its correct value using setFace(). Since the initial mesh is already in memory and has all the structures there, just containign wrong data, this is the only memory overhead you get. Once the object is created and if it can fit in the Max memory, there is no further MAXScript-related overhead because all you do is read data from the file and call setVert() or setFace(), but you don’t keep the data around, you set it in the mesh and discard immediately.
To do so, I have a separate BFF file which contains only the data, and an .MS file which runs the reading loop. But you could save out a bunch of lines like
setVert theMesh 1 [1.0,2.0,3.0]
setVert theMesh 2 [3.0,4.0,5.0]
…
and so on and if theMesh is defined globally, it would do the same, but it would be much longer. Of course, if you attempt to fileIn() the file, it could run out of memory because MAXScript would parse it as if it were an actual script and there are limits to how much it can evaluate at a time. But if you run a loop to read each line and call execute() on it to evaluate the code line by line, it would be slower, but would require only as much memory as the line needs.
In my implementation, the data would be output like
1.0,2.0,3.0
3.0,4.0,5.0
…
and the loop would do
for i = 1 to numLines do setVert theMesh [(readValue theFile),(readValue theFile),(readValue theFile)]
But I hope you get the idea…
Wow. I can’t thank you enough for your time and effort helping me with this. I’m extremely greatful.
I did also go back and have a look at the way BFF works. The first time I had a look I just looked at your script and felt very lost, but this time I actually ran it on an object to see what the result was. Very clever way to do things indeed.
Thanks again,
Cg.