Have trouble assigning materials to brep face

I’m trying to use C# to assign a material to a Face of a Brep.I have written the following code.This code is part of an exitable infinite loop in which the user gets a brep face each loop.

The code example I got from here about how to assign a material to a brep face.

All of the following statements compile and run correctly when debugged, and the value of face.MaterialChannelIndex has indeed been changed(in the monitor). MaterialChannelIndex reverts to its previous value at the start of the next loop. And the face is not assigned a material.

Did I do something wrong?Can anyone give any advice? Thank you very much! :grinning:

// assigning material to brep face

  BrepFace face = objRef.Face();  // objRef is returned by GetObject.Object(0), which refs a brep face
  Material topMaterial = doc.Materials.FindIndex(rhObj.Attributes.MaterialIndex); // rhObj is returned by objRef.Object();
  int channelIndex = topMaterial.MaterialChannelIndexFromId(objMaterial.Id, true);  // objMaterial is a Material instance got from other rhinoObj.
  int newTopMaterialIndex = doc.Materials.Add(topMaterial);
  rhObj.Attributes.MaterialIndex = newTopMaterialIndex;
  face.MaterialChannelIndex = channelIndex;
  rhObj.CommitChanges();

Hi @1071969980,

Did you build and run the sample you reference? Does it work?

– Dale

Yes, I built and ran it without returning any exceptions. (Except when topMaterial is the default material, which is not available.)
In further testing, I found something strange:
I assigned Material A and Material B to the two cubes separately (via Rhino’s UI). Then when I try to assign Material A (as the oMaterial in the code example above) to the child face of Cube B(via Code example above ), it works. But when I do the same on them and try to assign material A to the other side of cube B, it fails and runs with a channelIndex = 12 (or some other weird value, it should be 1?) .

Material topMaterial = doc.Materials.FindIndex(rhObj.Attributes.MaterialIndex); // rhObj is returned by objRef.Object();

I guess the problem might be in this line. when there are multiple materials on a brep, does this not return the topmost material (maybe we call it The Mix Material), but just the material with channelIndex = 0.
BTW, I also tried the example code on github and it works fine.

The design of the Marterial Channel is very confusing to me. Is there a better way to use it in the cpp SDK?

@nathanletwory - is this something you can help with?

I’ll check tomorrow. I haven’t done sub-object material assigment via code before, but a good moment to look into it!

@1071969980 can you post the code for entire loop as context? That way we can see how you are approaching this task.

1 Like
var gobj = new GetObject();
gobj.SubObjectSelect = true;
gobj.Get();

var objRef = gobj.Object(0);
var rhObj = objRef.Object();

var materialID = rhObj.Attributes.MaterialIndex;
var objMaterial = doc.Materials.FindIndex(materialID);

while(true)
{
     gobj.Get();
     if (materialID != -1)
     {
         ObjRef objRef = gobj.Object(0);
         RhinoObject rhObj = doc.Objects.FindId(objRef.ObjectId);
         BrepFace face =((BrepObject)rhObj).BrepGeometry.Faces[objRef.GeometryComponentIndex.Index];
         Material topMaterial = doc.Materials.FindIndex(rhObj.Attributes.MaterialIndex); 
         int channelIndex = topMaterial.MaterialChannelIndexFromId(objMaterial.Id, true);  
         topMaterial.CommitChanges();
         face.MaterialChannelIndex = channelIndex;
         rhObj.CommitChanges();
     }
}

This is part of the code I’m currently testing, and for the sake of brevity, I’ve removed some code about exception handling and extra options. Thanks in advance.

BTW, I found that ObjRef.Face() seems to return a copy rather than the original face instance

@1071969980 , thank you for the code.

Before writing any code myself a couple of observations:

  1. you should reassign materialID and objMaterial each time you do gobj.Get()
  2. materialID of -1 means default material is in use. You still should be able to set sub-object materials

I’ll continue further investigation of your code tomorrow morning, it is already 10 past 10 - bed time!

FYI, I am looking into this, but it is rather hairy. It’ll take a moment to get some code together that works. That said we are working on improving the SDK for setting materials to objects and subobjects using the RDK part of our SDK, using Rhino.Render.RenderMaterial instead of Rhino.DocObjects.Material.

Still looking into this, but with the current code it is going to be very challenging. Co-workers are typing in code for Rhino 7 that should facilitate this kind of operation much better. It still won’t be great due to the design and implementation of our RhinoCommon SDK, but it will be better than what we have now.

Anyway, going back to getting some code working.

Thank you for the efforts you and your colleagues have made. I will continue to try some new approaches as well. Waiting for your good advancement. :smiling_face_with_three_hearts: