3ds max crashes when I run my script. A windows Error message box is produced (by the process "Windows Problem Reporting"). There are no errors produced in Maxscript (the listener does not display any errors during script run-time). CPU and RAM usage are at acceptable levels during script run-time. My script worked without crashed and produced the required results on a smaller scene (10-20 objects) with only standard primitive objects. The error/crash occurs on a larger scene containing 4051 polygonal objects. The script looks at all objects, finds identical objects and deletes all but one of the identical objects leaving you with a scene without any duplicate objects).
When running the script on a scene containing 4051 objects windows gives me an error message box ; "3ds max has stopped working - A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available." During script run-time RAM and CPU usage of 3ds max remain acceptable (according to task manager)(30-40% CPU (i5-6600k) and 3-4GB RAM out of 16GB).
Image of the 'Windows Problem Reporting' error message box:
How the process looks in task manager:
Image of CPU/RAM usage of 3ds max during script runtime:
Note: after the error messagebox has appeared 3ds max's RAM/CPU/DISK usage drop to near zero values. After the error message box appears windows gives me no other choice than to close 3ds max.
I've let the script run a lot of times to check if the error message occurred at the same object each run, this was not the case, the error message occurred at a different object (when a different object was being processed by the script) each time I ran the script. The script tends to crash when it is comparing the first object in the scene ("Mesh_000") to another object in the scene with a mesh number in between "700" and "900". The following array contains the index of the mesh on which my script crashed during some of the tests I've performed: #(805,832,733,766,877). The script runs for 10-20 minutes before crashing.
The .max scene which causes the error can be found here: larger .max scene which causes error
The script works like this(pseudo code):
duplicate_objs = #()
meshes_array = Collect all meshes in scene
for mesh in meshes_array do(
Compare mesh to all other meshes in meshes_array
if an identical mesh is found do(append duplicate_objs identical_mesh)
)
--Delete all the duplicate meshes:
delete duplicate_objs
The code for my script: fn fn_construct_objs_array x = ( clearselection() select geometry deselect helpers objs = selection as array checked_objs_list = #() items_to_delete_from_objs = #() )
fn fn_delete_duplicates equal_pos_boolean =( --print "DELETING DUPLICATES" obj_dups = #()
ConvertTo objs[1] Editable_Poly
PolyCount_src = polyop.getNumFaces objs[1]
TriCount_src = (objs[1].mesh.numFaces)
VertCount_src = (getnumverts objs[1])
Position_src = objs[1].pos
for i in 1 to objs.count do(
if i <= objs.count and objs[i] != objs[1] do(
format "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n--> Comp. original obj (%) to comparison-obj(%) \n" objs[1] objs[i]
ConvertTo objs[i] Editable_Poly
PolyCount = polyop.getNumFaces objs[i]
Tricount = (objs[i].mesh.numFaces)
Position = objs[i].pos
VertCount = (getnumverts objs[i])
if(Tricount == Tricount_src and PolyCount == PolyCount_src and VertCount == VertCount_src and ( if equal_pos_boolean then( Position == Position_src)else(true) )) do(
if((finditem checked_objs_list (objs[i]) == 0) ) do(
appendifunique obj_dups objs[i]; --print "||||||||||||||||||||| FOUND DUPLICATE OBJECT |||||||||||||||||||||| \n"
appendifunique checked_objs_list objs[i]
append items_to_delete_from_objs objs[i]
)-- end if(finditem checked_objs_array objs[i] == 0 ) do(
)-- end if(Tricount == Tricount_src and PolyCount == PolyCount_src and VertCount == VertCount_src and ( if equal_pos_boolean then( Position == Position_src)else(true) )) do(
)-- end if i <= objs.count(
)
for item in items_to_delete_from_objs do(
deleteitem objs (finditem objs item)
)
items_to_delete_from_objs = #()
deleteitem objs 1
for duplicate in obj_dups do(delete duplicate)
if objs.count > 0 do (
--format "objs left to process = % \n" objs.count ;
fn_delete_duplicates equal_pos_boolean
)--end if objs.count > 0 do(
)--end fn_delete_duplicates
fn_construct_objs_array 1
fn_delete_duplicates true
Note: meshes being identical is (in this context) defined as the meshes having the same polycount, vertcount, edgecount, position.
I'm bad at debugging others' code, so again just a quick glance - I'd definitely avoid for loop in for duplicate in obj_dups do(delete duplicate)
, delete
is a mapped function and you can pass a collection as an argument to it. That way, there won't be so many scene explorer updates and it should be much faster. I'd also prefer iteration over recursion. All in all, this is how I'd write it:
struct objInfo
(
obj, polyCount, vertCount, pos,
fn isSamePos pos1 pos2 eps:1e-6 =
(
local diff = pos2 - pos1
dot diff diff < eps
),
fn isEqual info checkPos:off =
(
this.vertCount == info.vertCount and
this.polyCount == info.polyCount and
(not checkPos or isSamePos this.pos info.pos)
),
on create do
(
local polyVertCount = getPolygonCount obj
polyCount = polyVertCount[1]
vertCount = polyVertCount[2]
pos = obj.pos
)
)
fn collectDuplicates checkPos:off =
(
items = for obj in geometry collect objInfo obj:obj
itemCount = items.count
collected = #{}
duplicates = #()
for item = 1 to itemCount where not collected[item] do
(
local current = items[item]
for nextItem = item + 1 to itemCount
where not collected[nextItem] and
(
local next = items[nextItem]
next.isEqual current checkPos:checkPos
)
do
(
append duplicates next.obj
append collected nextItem
)
)
return duplicates
)
delete (collectDuplicates checkPos:off)