Custom RenderMaterial Dispose Function called several times even if the material is not present, and not called when intended

Hello there!

Im sorry if the title is is a bit convoluted, and somewhat long.

Im marking the actual questions per se in bold, though I think their context is necessary.

I’ve been messing around with the rendermaterials and been trying for them to generate some custom info, in an external container, that was supposed to be deleted when the material is deleted from the scene. For that I overloaded the Dispose function to delete the external info from its container.

When I saw that the data were not deleting properly, I proceeded to debug and discovered a couple of things. First, there is a lot of calls being done to my custom RenderMaterial even if its not present in the scene, and this is messing somewhat with my external data by adding extra unnecessary instances. Why is the RenderMaterial constructor being called up to six times to generate a single render material?

This gets cleand up eventually when the corresponding dispose functions get called, but in certain cases (due to code on my side) it leads to undeleted info.

The trouble comes when, even it the material is deleted successfully from the material list on the UI, my data don’t dissapear properly.

I imagine the material might not be deleted for Undo/redo purposes, but if that is so, how would you suggest me getting my data deleted? I can manage the undo/redo on my side, but I’m somewhat confused on how would I get the proper events to signal me to do so and why the materials are created so many times.

Thanks in advance

You have to understand that the lifetime of a single RenderMaterial object does not correspond to the lifetime of a material in the material editor. It just doesn’t work like that.

Your material will be copied and queried all as part of the standard running of Rhino. For example, when we present a list of material types, we will create an instance of your material in order to query it for properties and so on.

You must follow the rules for attaching data - typically using fields.

Actually, the data don’t need to be attached per se to the class; I only bonded the creation and deletion of said data to the Material’s life cycle because I was unable to find the signals or events that are raised whenever a material is created or destroyed from within the user interface.

I know that a Change Queue might offer this functionality, but I was under the impression that it was intended for real time previews of renders engines, though maybe it could be hacked for this… And it would be somewhat wierd for the undo redo, that i might as well hack anyway.

Regardless, I’ve also seen that custom undo redo commands exist, and that could work if I were able to raise an event whenever the materials are deleted from the ui?

Im just a bit at a loss here, and open to further suggestions regarding how to do this really.

To be precise, what I need is to create data alongside a render material in a secondary structure which allows by itself for undo redo, and be able to delete them properly when the user intends to make the material dissapear from the scene, if that makes sense.

You need to use fields for this - in RhinoCommon at least.

Is it possible to add custom data types for these fields? Or to create a custom render content?

I’ve tried inheriting from the class RenderContent in order to create a custom field, but it would seem the constructor is not exposed.

What kind of data are you looking for?

A custom class that encapsulates native code data.

There is no such mechanism per se. You’ll have to use the Fields dictionary to set primitive data: strings, colors, vectors and integrals. You could write several functions that seed your custom class instances with data from these fields, and vice versa commit from your custom class to the fields.

That would be easy enough for some cases, but my data fields are not fixed during runtime which means I’m not quite sure about how I would manage a Field list that dynamically changes its components. That still would leave the issue about generation/destruction, which is the one that concerns me more, as I can manage the field settings from outside the material per se, but I seem unable to find any way to be aware of the material’s life cycle…

And @andy, I already took a look at the samples, but the info they provide is the one I’m already using to create my material. I took a look to the RhinoCycles implementation of the material, but it would seem to me that they are more focused on the field’s implementation proposed by @nathanletwory, which is not my preferred, albeit seemingly the only, option.

To track better what happens to RenderMaterials you may want to subscribe to the RhinoDoc.RenderMaterialsTableEvent through which you will get RhinoDoc.RenderMaterialAssignmentChangedEventArgs. This should give you a better handle on your RenderMaterials.

Edit: Note that events on these trigger only when a material is actually used in the scene, i.e. assigned to an object. Just adding a material to the material editor won’t trigger events on this table, for that you’d subscribe to RhinoDoc.MaterialTableEvent
Edit2: subscribe to these events in your plug-ins OnLoad implementation.

1 Like

That sounds more like it! I’ll give it a try and let you know if this is what I need, but it’s promising. Thanks for the swift responses @andy and @nathanletwory :star_struck: