ByObject Materials proliferation - I still don't get this


This has been discussed before with some explanations of how things work with ByObject materials in Rhino (@JohnC - I think you were looking into it). But I still don’t understand some of it and running into problems of materials bloating in the file and a performance hit.

Basically, when an object (let’s say - a box) - with ByObject material gets copied several times, based on UI, when I change it’s material, all copies material change accordingly - so in my mind, intuitively, they all should use the same material - no new materials were created in the file, and MaterialEditor shows only one material.
When I delete these copies and Purge materials, the message reads “Purged [n] unused legacy materials”.
What actually gets purged?

The real usability problem with this I am encountering is with a script/plugin, where during script runtime many copies of objects with ByObject material are created and deleted; in the script they are being either used as preview objects, or are a result of custom in-script undo action. All in all, many times after the script finishes, Purge reports 1000s or tens of thousands legacy materials purged. Often Purge halts for good few seconds on this. This is problematic, since the tools I am working on are supposed to be used often, with many objects that potentially have ByObject material, and with this the pile-up of unused materials will create a huge numbers, until the next purge, causing potential very very long system freeze.

I was trying to experiment and test a way around this in the script, by making a temp layer with the material copied from the object, changing the object’s materials to ByLayer, moving it to that layer and removing its original material; then all the copies/mesh extractions etc. would be done with ByLayer material, and once all is cleaned up, the temp layer would be deleted and object back to ByObject material with original material assigned. Unfortunately it does not do anything and Rhino would still create tons of materials, even with the ByLayer material in-script switch.

Here is a test file (simple box with ByObject Custom material): MaterialProliferation_Test.3dm (72.9 KB)
And the test script doing what I described above: MaterialProliferation_Test.rvb (1.8 KB)

Please note that if I run this a few times in a row, the Purge takes longer each time, and the material indices go way way up each time.

Is there anything that can be done to prevent this bloating? Perhaps RhinoScript methods don’t deal well with the new Rhino RDK materials? Would using RDK methods help with limiting this material proliferation?
I am not sure if this is all by design or it is some memory/code leak that could be avoided altogether?
(@andy - perhaps you can offer some advice?)

Thank you,


Hi Jarek, I can give you a quick explanation but someone else might be able to elaborate. RDK materials are shared by objects that have them assigned, but under the hood there are ‘table materials’ which are the native Rhino materials that existed before the RDK was created. Those materials are not shared, so every object using a material has its own material in the material table. All of those materials could reference the same RDK material. The issue is simply that native Rhino materials are not shared, so the table has a tendency to grow. Purge is the way to get rid of the unused ones.

Many of the materials being purged are actually ‘deleted’, that’s to say they have been deleted but not removed from the table; they are merely marked as deleted. I think the original intention was to avoid heavy manipulation of the material table when materials are deleted or otherwise managed. It’s much faster to just mark them as deleted instead of actually deleting them. Put another way, this is an implementation detail that has been made visible to you by the existence of the purge command. I don’t know if anyone is planning to change how this works in Rhino 7, but I can find out. It can’t be changed by making changes to the RDK because it’s a core Rhino issue. It would happen with scripts even if the RDK wasn’t loaded.


Hi John, thanks for explaining this again. I understand that this is some legacy thing that can’t be easily taken care of.
But why would the workaround I am trying not work? (the script attached). I thought once I set the material to ByLayer and then copy and delete, no extra buildup would be created…
If the box from the start has material set ByLayer, all is fine and no extra legacy materials are created; however if I switch this inside the script, the “problem” persists. Do you know if there is anything that makes the script act differently than doing it by hand ?

thanks again!


Hi Jarek,

I don’t know why your workaround doesn’t work. I’m not familiar with this kind of scripting. We need a Rhino core / script guru to have a look at this. I’ll ask @andy about it at our meeting tomorrow.


1 Like

thanks John, much appreciated!


Hi @johnc

I have tested the scripts some more, and it looks like it is not possible to “forget” the ByObject material index, even after setting the object material source to ByLayer.
I expected Call Rhino.ObjectMaterialIndex(a, -1) to reset object material to Unassigned (Default) but it does not work. I know you mentioned RhinoScript is not your thing, but just letting you know that I discovered why the script does not work as expected. Still hoping for a solution - basically I need a way to make object “forget” that it had material ByObject assigned, before making 1000s of its copies in order not to bloat the legacy materials…



Hi Jarek,

I almost suggested that but when I saw Rhino.ObjectMaterialIndex(a, -1) I thought I was wrong. Yes, it’s possible that if the index is not -1 then the behavior will be different. This looks fixable to me. I will discuss it with Andy.


Hi John,

Maybe it is just a bug in the RhinoScript method that fails to remove custom material from object before doing any other operations. I am hopeful then, if you think this can be fixable : )



I have filed a bug report for Andy to look at:

1 Like

Thanks! Looks like you already found the issue in debugger and included a good sample file. Again, I appreciate your help and looking into this.