View Full Version : Script crash in 3dsMax 6

10 October 2005, 08:10 PM
I wrote a script (it's a hack job, i know, but it serves its purpose) that imports a custom-converted lgl format into 3dsmax and renders it... in peices. The entire map in 3d is too big to fit into ram at once, so i was forced to chunk up the model into peices and render them separately, and composite them using the environment background image, which is also controlled by this script.

The script itself originally was recursive in nature, and when used on small datasets, worked perfectly. but when i fed it the original model it was deigned to render i started running into system exceptions.

After a LOT of messing around i realized it was related to Garbage Collection. it seems that MaxScript runs GC() automaticly partway through my script execution and promptly causes the script to halt with a system exception. soon after that, if i click certain things (like menus), or run GC() again manually, it tends to crash the program completely. even if i close the program down manually, it STILL brings up the program-crashed dialog with the 'report to discreet' option.

I am beginning to think that what i'm trying to do is impossible for maxscript

If required I will post links to the script AND the datafiles used to run the script. It might just be me.

Oh. I almost forgot. The actual model that i'm trying to render with this map is a model (in 3d) of a recent OPTE scan of the internet. I've been trying for a long time now to render this map in 3d, and this script is the LAST step in my work. i really don't want to be foiled now, because my only other option would be to write a plugin DLL, and i have no idea how to do that.

10 October 2005, 03:24 AM
Doing arithmetic on an undefined variable will cause max to crash like this. Perhaps you are attempting to use variables that max thinks are no longer in scope, causing the garbage collection to get rid of these values, which you are actually still using.

10 October 2005, 05:04 AM
well, i can't be sure this is the case, but would looking at the script help figure that out?

-- Selects file to be parsed and loads it.
lglfile = getopenfilename caption:"Open LGL3 File" types:"LGL File (*.LGL3)|*.lgl3|All Files (*.*)|*.*"
lglstream = memstreammgr.openfile lglfile
-- Parses out the operating path, Which is where all the box tempfiles are.
filepatharray = filterstring lglfile "\\"
lglcounter = 1
filepath = undefined
while filepatharray[lglcounter + 1] != undefined do (
if filepath == undefined then (
filepath = filepatharray[lglcounter]
else (
filepath = filepath + "\\" + filepatharray[lglcounter]
lglcounter = lglcounter + 1
filepath = filepath + "\\"
-- Configures the Environment Map
fileoutputfile = filepath + "render.bmp"
max select all
max delete
useEnvironmentMap = off
render vfb:off outputfile: fileoutputfile
bmap = bitmaptexture filename:fileoutputfile
bmap.coords.mappingtype = 1
bmap.coords.mapping = 4
EnvironmentMap = bmap
useEnvironmentMap = on
-- set camera as reference point.
struct coordinate (x,y,z)
CamPosition = coordinate $camera01.pos.x $camera01.pos.y $camera01.pos.z
boxtracklist = #("1")
boxtracker = 1
--Create array of cylinders and dots.
dotarray = #()
linearray = #()
--initialize the arrays and hide them.
for i=1 to 1000 do (
dotarray[i] = sphere radius:0.02
linearray[i] = cylinder radius:0.01

--Main loop to render the boxes.
while boxtracker != 0 do (
--hide all the items again and reset index to 0
for i=1 to 1000 do (
dotarray[i].visibility = false
linearray[i].visibility = false
dotindex = 0
lineindex = 0
ID = boxtracklist[boxtracker] 0 #seek_set
lglstring = lglstream.readline()
lglwords = filterstring lglstring " "
while lglwords[1] != "open" or lglwords[2] != ID do (
lglstring = lglstream.readline()
lglwords = filterstring lglstring " "
--TEMPORARY CODE START -- prepares to render bounding box.
--boxminx = lglwords[3] as float
--boxminy = lglwords[4] as float
--boxminz = lglwords[5] as float
--boxmaxx = lglwords[6] as float
--boxmaxy = lglwords[7] as float
--boxmaxz = lglwords[8] as float
lglstring = lglstream.readline()
lglwords = filterstring lglstring " "
if lglwords[1] == "close" then (
--TEMPORARY CODE START -- renders bounding box, for debugging purposes.
--xwidth = boxmaxx - boxminx
--ylength = boxmaxy - boxminy
--zheight = boxmaxz - boxminz
--xpos = boxminx + (boxmaxx - boxminx)*0.5
--ypos = boxminy + (boxmaxy - boxminy)*0.5
--zpos = boxminz
--box width:xwidth length:ylength height:zheight pos:[xpos,ypos,zpos]
--print boxtracklist[boxtracker]
--sleep 0.1

--renders the contents of the box.
subfile = filepath + ID + ".tmp"
lglsubstream = memstreammgr.openfile subfile
while lglsubstream.eos() != true do (
lglstring = lglsubstream.readline()
lglwords = filterstring lglstring " "
if lglwords[1] == "dot" then (
--parses dot information
lglwordx = lglwords[2] as float
lglwordx = lglwordx * 1
lglwordy = lglwords[3] as float
lglwordy = lglwordy * 1
lglwordz = lglwords[4] as float
lglwordz = lglwordz * 1
lglwordr = lglwords[5] as float
lglwordg = lglwords[6] as float
lglwordb = lglwords[7] as float
lglwordr = lglwordr * 255
lglwordg = lglwordg * 255
lglwordb = lglwordb * 255
lglcolor = color lglwordr lglwordg lglwordb
graps next sphere in array of spheres
dotindex = dotindex + 1
--sets sphere location and color
dotarray[dotindex].pos = [lglwordx,lglwordy,lglwordz]
dotarray[dotindex].wirecolor = lglcolor
--and finally, makes the sphere visible to the renderer.
dotarray[dotindex].visibility = true
) else ( )
if lglwords[1] == "line" then (
--Parses Line information
lglp1x = lglwords[2] as float
lglp1x = lglp1x * 1
lglp1y = lglwords[3] as float
lglp1y = lglp1y * 1
lglp1z = lglwords[4] as float
lglp1z = lglp1z * 1
lglp2x = lglwords[5] as float
lglp2x = lglp2x * 1
lglp2y = lglwords[6] as float
lglp2y = lglp2y * 1
lglp2z = lglwords[7] as float
lglp2z = lglp2z * 1
lglwordr = lglwords[8] as float
lglwordg = lglwords[9] as float
lglwordb = lglwords[10] as float
lglwordr = lglwordr * 255
lglwordg = lglwordg * 255
lglwordb = lglwordb * 255
lglcolor = color lglwordr lglwordg lglwordb
linelen = sqrt((lglp2x-lglp1x)^2+(lglp2y-lglp1y)^2+(lglp2z-lglp1z)^2)
--grabs the next cylinder in the array of cylinders.
lineindex = lineindex + 1
--resets rotation values
in coordsys world linearray[lineindex].rotation.z_rotation = 0
in coordsys world linearray[lineindex].rotation.y_rotation = 0
in coordsys world linearray[lineindex].rotation.x_rotation = 0
--sets cylinder location, height, and color
linearray[lineindex].pos = [lglp1x,lglp1y,lglp1z]
linearray[lineindex].height = linelen
linearray[lineindex].wirecolor = lglcolor
--does some quick math and calculates new rotation angles.
linelen = sqrt((lglp2x-lglp1x)^2+(lglp2y-lglp1y)^2)
if lglp2x > lglp1x then in coordsys grid linearray[lineindex].rotation.z_rotation = asin((lglp2y-lglp1y)/linelen)
else in coordsys grid linearray[lineindex].rotation.z_rotation = 180 - asin((lglp2y-lglp1y)/linelen)
linelen = sqrt((lglp2x-lglp1x)^2+(lglp2y-lglp1y)^2+(lglp2z-lglp1z)^2)
in coordsys local linearray[lineindex].rotation.y_rotation = 90 - asin((lglp2z-lglp1z)/linelen)
--finally, the cylinder is made visible to the renderer
linearray[lineindex].visibility = true
) else ( )
memstreammgr.close lglsubstream
render frame:#current vfb:off outputfile:fileoutputfile camera:$camera01
boxtracker = boxtracker - 1
else (
-- get id for the first embedded box
ID1 = lglwords[2]
-- find center of that box
boxminx = lglwords[3] as float
boxminy = lglwords[4] as float
boxminz = lglwords[5] as float
boxmaxx = lglwords[6] as float
boxmaxy = lglwords[7] as float
boxmaxz = lglwords[8] as float
center1x = boxminx + (boxmaxx - boxminx)*0.5
center1y = boxminy + (boxmaxy - boxminy)*0.5
center1z = boxminz + (boxmaxz - boxminz)*0.5
-- find close statement for that box
do (
lglstring = lglstream.readline()
lglwords = filterstring lglstring " "
) while lglwords[1] != "close" or lglwords[2] != ID1
-- get id for the second embedded box
lglstring = lglstream.readline()
lglwords = filterstring lglstring " "
ID2 = lglwords[2]
-- find center of that box
boxminx = lglwords[3] as float
boxminy = lglwords[4] as float
boxminz = lglwords[5] as float
boxmaxx = lglwords[6] as float
boxmaxy = lglwords[7] as float
boxmaxz = lglwords[8] as float
center2x = boxminx + (boxmaxx - boxminx)*0.5
center2y = boxminy + (boxmaxy - boxminy)*0.5
center2z = boxminz + (boxmaxz - boxminz)*0.5
-- determine distance to each box center.
distance1 = sqrt( ( pow (center1x-CamPosition.x) 2 ) + ( pow (center1y-CamPosition.y) 2 ) + ( pow (center1z-CamPosition.z) 2 ) )
distance2 = sqrt( ( pow (center2x-CamPosition.x) 2 ) + ( pow (center2y-CamPosition.y) 2 ) + ( pow (center2z-CamPosition.z) 2 ) )
-- pick the further box to render first.
if distance1 >= distance2 then (
boxtracklist[boxtracker] = ID2
boxtracker = boxtracker + 1
boxtracklist[boxtracker] = ID1
else (
boxtracklist[boxtracker] = ID1
boxtracker = boxtracker + 1
boxtracklist[boxtracker] = ID2
memstreammgr.close lglstream

I know, i know, this code isn't the most user friendly thing out there, and it assumes you have already pointed a camera named 'camera01' at the spot where the map will be when the script runs, AND it depends on a custom filetype i generated, but i've tested everything. the file it is rendering IS generated correctly (it's actually a set of files, as the script shows) and it DOES render the first ten-to-twenty of the 'boxes' (peices of the map) correctly before it cops out for apparently no reason, citing 'System exception' as the reason. the code IS reusing the same variables the entire time, but for some reason as the script runs, more and more memory is consumed. adding 'undo off ( )' doesn't seem to fix the problem.

All i can figure out is that the system exception is being thrown when 3dsMax calls garbage collection in the middle of script execution, and locks up. eventually, the entire program crashes.

... any takers?

10 October 2005, 06:51 AM
Would you be able to provide us with an LGL3 file (and whatever else is needed) so we can see the script in action?

10 October 2005, 02:30 AM
Sure. The Rarfile can be found here here: Inside you'll find a 30percent folder with many files. these files represent the map. you'll also find the script, and a max file.

you should just need to open up the max file (it contains a camera, already pointed at area in space the map will be), make sure the camera viewport is selected, and then run the script. don't get confused when a second open file dialog pops up, that's the script asking for the lgl3 file.

while the script runs, it will generate a render.bmp file in the folder with the lgl tempfiles. you can actually watch this as the map is rendered peice by peice.

10 October 2005, 06:44 AM
Sorry for bumping my own thread, but there seemed to be some interest in this, and no responses.

CGTalk Moderation
10 October 2005, 06:44 AM
This thread has been automatically closed as it remained inactive for 12 months. If you wish to continue the discussion, please create a new thread in the appropriate forum.