[Closed] Scene material count not resetting
I wrote a simple script that inserts AutoCAD objects into 3ds max then checks if a new material is added and if one is added, it then modifies that material. I do this by getting the material count (sceneMaterials.count) then the import command, then (sceneMaterials.count) again, then it does FOR TO DO on each material name from starting from the original count (+ 1) to the new material count.
It all works great except about 20% of the time I immediately erase all the imported objects for various reasons (1 being that when I wblocked out of AutoCAD the ucs wasn’t set to the world for example). Anyways, the (sceneMaterials.count) does not reset after I erase the objects even though the newly added materials do not exist anywhere in 3ds max, I cannot figure it out. If I reopen the Max file, then the material count is correct, otherwise it still thinks that the newly added materials still exist even though they don’t.
Is there a way to reset the scene material count via Maxscript ?
Thanks
The issue is that since the sceneMaterials system global can be slow to rebuild (Max has to do an iteration over the scene tree to collect the actual materials), the developers decided to update it only on file I/O operations where it would not affect performance.
While there is no built in function to force the update, you can hack it by forcing Max to think you performed a file I/O operation that would normally trigger such an update. What I usually do is something like
tempFile = GetDir #temp + "/_tempSceneMaterialsHack.max"
saveNodes #() tempFile
deleteFile tempFile
SaveNodes() is the MAXScript equivalent of File > Save Selected…, but you can pass #() as argument and it will save zero objects in an empty .MAX file. 3dsMax will think you actually saved something and will update the sceneMaterials as a side effect. Then you just clean up the temp. file and move on…
For example,
resetMaxFile #noprompt --reset the scene
sceneMaterials.count --> 0 --check the material count, it is 0
for i = 1 to 10 do teapot material:(standardMaterial()) --create 10 objects with materials
sceneMaterials.count --> 10 --check the count, it is 10 as expected
delete objects -- delete all objects
sceneMaterials.count --> 10 --still the same count!
--now run the hack
tempFile = GetDir #temp + "/_tempSceneMaterialsHack.max"
saveNodes #() tempFile
deleteFile tempFile
--check again:
sceneMaterials.count --> 0 --SUCCESS!
holdMaxFile() seems to update the sceneMaterials too.
format "nodes:% sceneMaterials:%
" objects.count sceneMaterials.count
delete objects
holdMaxFile()
format "nodes:% sceneMaterials:%
" objects.count sceneMaterials.count
Anything performing saving will trigger the update, but if the scene contains 1GB of data to be written, holdMaxFile() will be significantly slower than (saveNodes #() “somepath”). Hence my suggestion
Additionally the following code will ’empty” the sceneMaterials array, even if there are nodes in the scene using materials:
for j = sceneMaterials.count to 1 by -1 do deleteitem sceneMaterials j
Or you could update the sceneMaterials with:
fn UpdateSceneMaterials =
(
usedMaterials = for node in objects collect node.material
for j = sceneMaterials.count to 1 by -1 where (finditem usedMaterials sceneMaterials[j] == 0) do deleteitem sceneMaterials j
)
That’s true for the first loop but the function UpdateSceneMaterials() (unoptimized) should update it correctly.
For some reason I was under the impression that what the OP wanted was to reset the sceneMaterials to 0 because there were no nodes left on the scene. But re reading the post I might got it all wrong and what is needed is to reset the sceneMaterials its previous state.
Yes. As commented to Branko, I was under the impression that there were no nodes left on the scene, and thought that holding an empty scene would be good. But as you say, if there is some information on the scene, as it appears to be, your solution is much better, even much less than 1GB
Thanks for the info guys, I used the savenodes method, work perfectly. Some more info on the subject is that the (objects.count) method resets itself on the fly, I use that in the same script just to select all the items that were just imported (that’s why I wrote the script in the first place), that was very frustrating especially if you accidently imported a load of stuff by accident. When you merge a Max file, it selects everything merged, when you import something else, not selected.
the reason for the system to hold unused scene materials is only a case if deleted object could be ‘undoed’.
i’m using both savenodes and just save the file… i prefer to save a file. it makes sometimes more sense for me. because anyway after a merging the undo stack is wiped… it’s kinda the right moment to save the file