As posted in another threads years ago, the sceneMaterials array updates itself only on scene save operations. I assume this was done for performance reasons - updating the sceneMaterials array can take a long time and is one of the factors slowing down creation of new objects. In fact, back at Prime Focus we had functions for clearing the sceneMaterials list and rebuilding it. When we had to create 10000 objects with a script, we would clear the array on each iteration and rebuild it just once at the end of the process. Otherwise, the performance would slow down progressively because each new object added causes the WHOLE array to be rebuilt from scratch.
So when you delete an object, its material sticks around in the sceneMaterials array - you could undo the delete and the material would already be there. Until you perform an operation that sends a preSave system notification, all previously created materials will be kept around.
So the hack to get rid of them would be something like
fn [b]getUsedMaterials [/b]target: class: =
if target == unsupplied do target = [b]rootnode [/b]
usedmaterials = #()
if iskindof class Material then usedmaterials = getclassinstances class target:target
else for class in material.classes where class.creatable do
join usedmaterials (getclassinstances class target:target)
matclasses = for class in material.classes where class.creatable collect class
for k = 1 to 100 do
b = box name:(k as string) material:(createinstance matclasses[random 1 matclasses.count])
Actually it is not so much the object creation itself but the material assignment to new and existing objects (esp. existing ones).
Say you have something like my (now defunct) BFF script that runs a MAXScript to recreate a scene. Each time you assign a unique material to an object, that material has to be added to the sceneMaterials list. If you have 10,000 objects with 10,000 unique materials, you get an exponential slowdown because with each new material added, the internal sceneMaterials rebuilding loop has to go one iteration longer. It is equivalent to
for i = 1 to 10000 do for m = 1 to i do ()
Our pipeline scripts mostly updated existing objects and reassigned them materials (as part of Render Pass management). Assigning materials to 10,000 objects without the clearing on each step / rebuilding once at the end was taking several minutes. With the fix, it took around 20-30 seconds. In production where a single scene would require several render passes to be sent to Deadline to render, this saved us many man-hours every day otherwise spent waiting for the submission…
Thanks, that makes sense. One more question though… why bother rebuilding the sceneMaterials array? What would go wrong otherwise? (besides the fact that other scripts would get wrong results when using this value)