[Closed] sceneMaterials array not self-managing?
Is this the expected result? I was under the impression that the sceneMaterials array only contains the materials currently in the scene, not any material that was created.
WARNING: resetMaxFile #noprompt
resetMaxFile #noprompt
gc()
myBox = box()
format "SceneMaterials before: %
" sceneMaterials.count
for i = 1 to 100 do myBox.material = standard()
format "SceneMaterials after: %
" sceneMaterials.count
SceneMaterials before: 0
SceneMaterials after: 100
Is there any way to prune the sceneMaterials array other than determining by myself which materials are in use and deleting them from the array?
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
tempFile = GetDir #temp + "\\_temp.max"
saveNodes #() tempFile
deleteFile tempFile
Thanks for your explanation, Bobo. I was wondering if you could explain one of your statements further:
These two sentences put together confused me a bit. I understand that the sceneMaterials array checks the validity of its contents before save operations, but what exactly happens on object creation?
there is some function that might be helpful :
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)
)
usedmaterials
)
/*
resetMaxFile #noprompt
gc()
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])
)
getUsedMaterials()
*/
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)
The last comment was the reason – we did not want another script to think there were no materials in the scene. Updating just once did not take that long – probably 500ms for 10K objects.
I’d love to learn more about this workflow, this is very similar to the pipeline I’m trying to create at the moment. The GI Joe videos that Prime Focus were incredibly interesting.
How did it deal with rigs? Was everything point cached?
Did you write out all light includes/excludes to files?
Did everything go through this pipeline or were certain renders done in the typical rendering fashion?