Correspondence between material index/materials?

I have mentioned this before in another post, but maybe it got lost in the noise…

I have files that have many more material indices than actual materials. For example the current file has 6 materials assigned to objects - everything else has been purged - but there are 21 material indices… Many of the extras point to the same material. How is this possible? I thought the material index was supposed to be a unique identifier of the material?

If I go into the materials panel and right click on the material and choose “Select object(s)”, all of the objects that this material is applied to are selected. So somehow the correspondence is there and recognized by Rhino. If it’s not using the material index, how is this done? Surely not by name, as you can have multiple materials with different characteristics that have the same name…

I’m simply trying to find a reliable scripted solution to get the collection of objects with the same material in the file as the manual “right click-select objects” does.

Thanks, --Mitch

1 Like

Can we see the file. Feel free to email it to me (dale@mcneel.com) directly if you want…

– Dale

File sent via e-mail…

To cut a long story short, as of V5, material indices in the material table are not shared amonst objects or layers. Each object or layer (which has a non-default material, or a material source that does not require a material index) has a unique entry in the material table.

The materials you see in the material editor are not CRhinoMaterial / ON_Material. They are RDK materials, and you will need to use the RDK SDK to manipulate them.

  • Andy

So that means that once I apply the same material onto different objects in a given file, that there’s no way afterwards to find the objects that share that “same” material via normal Rhino commands or some form of scripting? :frowning:

(having a material by layer is out of the question in most cases)

Or to pose the question another way - if I have just one material in the “library”, but it’s applied to 100 objects, how do I change the color/gloss/etc. of the material on ALL of the objects simultaneously via a script?

–Mitch

Hi Mitch, without scripting, why not use -_SelMaterialName (in case you´ve given your materials a name) to find selectable objects with that material name. In case of locked or hidden objects, you could iterate and compare material names, then change the applied material properties. Tedious and slow, i know…but it should work. :wink:

c.

Hi Clement,

That’s a good idea if you have uniquely named materials in the file, thanks… You can also get this via RhinoCommon by drilling down in the document materials table to get at the material names and grab all of the indices associated with the same name. However, that also exposes the flip side of the problem…

Rhino currently allows you to have as many like-named materials as you want in the same file. The same material name can refer to more than one material - hundreds in fact. And if you don’t name your materials you can end up with whole bunches of materials all named “(unnamed)”…

All this can be avoided, of course, if you are the master of your file and are systematic about naming things… However in this particular case, I am working in a “conglomerate” file created by importing files from 150+ individual users (students), each of which has named their materials in their own way - or not at all…

All this just seems highly chaotic from a programming standpoint where we are normally accustomed to having unique identifiers for objects…

–Mitch

1 Like

absolutely, and for materials. The material indexing behaviour makes it too complicated to script simple material changes. On the other hand, it makes material changes on the user side easier as you can change various parameters individually without creating a new material for every change, it seems Rhino then takes care of it by using different indexes. I´m not shure what is better.

c.

Hello @Helvetosaur
I know that this question is outdated but here is a solution to your question:

In Grasshopper C# script you can write the following code to get objects with similar materials

  //get current document
  var myDoc = Rhino.RhinoDoc.OpenDocuments()[0];
  
  //Get all objects in current document
  var myObjects = myDoc.Objects;
  
  //Get objects of type mesh
  var myMeshes = myObjects.GetObjectList(ObjectType.Mesh);

  //Grouping Meshes by similar materials
  var myMeshGroups = myMeshes.GroupBy(c => c.GetMaterial(true).Name);

  //Selecting the first group of meshes that have similar material
  myObjects.Select(myMeshGroups.ElementAt(0).Select(d => d.Id));

Instead of using Name you should get the RenderMaterial, and use its RenderHash instead as grouping selector.

http://developer.rhino3d.com/api/RhinoCommon/html/P_Rhino_DocObjects_Material_RenderMaterial.htm

http://developer.rhino3d.com/api/RhinoCommon/html/P_Rhino_Render_RenderContent_RenderHash.htm

1 Like

Thanks @nathanletwory
I had a rhino file with about 30 materials in the material editor… but when I try to access them using a script, I find more than 3000 materials with repeated names but different indices and ids
Until now I don’t know why there are 3000 mats … But I managed to do this workaround after researching and reading some documentations

I didn’t know about the RenderHash. So, what you suggest here is using RenderMaterial.RenderHash instead of Name.

Here is the updated code, for anyone who might need it:

  //get current document
  var myDoc = Rhino.RhinoDoc.OpenDocuments()[0];
  
  //Get all objects in current document
  var myObjects = myDoc.Objects;
  
  //Get objects of type mesh
  var myMeshes = myObjects.GetObjectList(ObjectType.Mesh);

  //Grouping Meshes by similar materials
  var myMeshGroups = myMeshes.GroupBy(c => c.GetMaterial(true).RenderMaterial.RenderHash);

  //Selecting the first group of meshes that have similar material
  myObjects.Select(myMeshGroups.ElementAt(0).Select(d => d.Id));