Assign material to brepfaces

Hi,

I’m attempting to assign materials directly to brepFaces. I can’t find any methods that fit, and feel like I’ve looked everywhere: the object, the face, and everything in between. Is it simply not possible without exploding it into a polymesh, and assigning on a per-object basis?

Best,
Aske

Hi @aske,

There is certainly a way of doing this in C++:

cmdSamplePerFaceMaterial.cpp

Thus far, I haven’t found a way of doing this in RhinoCommon. @nathanletwory is this something you know about?

– Dale

1 Like

Thanks for the reply!

As far as I can read the C++ sample, you add a channel to the material, then select that channel on the brepFace. In C# there is nothing called anything with material or channel on brepfaces that I can see. I also can’t see channels being present on materials but maybe I’m looking in the wrong place.

Hi @aske,

I’ve logged this issue. Hopefully we can get something added.

https://mcneel.myjetbrains.com/youtrack/issue/RH-57389

– Dale

2 Likes

Hey @Jussi_Aaltonen

Can I hope for this to be looked at, or is it not a priority so I should explore alternatives?

Best,
Aske

Hi @aske, there aren’t any alternatives that I can think of. So we’ll try to get it done.

1 Like

Thanks for the update! I won’t start messing with PInvoke then :slight_smile:

RH-57389 is fixed in the latest Service Release Candidate

2 Likes

Hi @aske, I’ve added sample code for setting brep face materials:

2 Likes

Thanks Jussi! These kind of examples are super valuable so us users don’t have to go asking on the forums all the time! Keep it up! :tada:

1 Like

Hi @Jussi_Aaltonen ,
I am trying to do something similar but instead of using ActiveDoc.Materials, I am using Render.RenderMaterials as I wish to use materials that have not been added to objects yet but are still available in the library. any solutions to apply RenderMaterial to a brepFace instead?

Thanks
Srujan

As far as I know you need to add the material to the document before you can use it as brep face material. I’m trying to find someone with more insight to this.

You also need a Material in RhinoDoc.Materials referencing each RenderMaterial. Then you can set up the brep face materials just like in the example. I need to check how to create those Materials correctly.

thanks for getting back.
I added the materials with proper material channels as shown in the example.

I am trying to achieve a PaintBucket style command where I will be able to select N number of subelements (also accepts entire objects which works fine but right now I am concerned about subelements).
Each subelement could belong to a different brep.
And i want to apply a selected material to those brep faces only.

// Loop through all selected objects
for (int i = 0; i < gs.ObjectCount; i++)
{
    ObjRef objRef = gs.Object(i); // Get each selected object
    RhinoObject rhinoObj = objRef.Object(); // Get the RhinoObject


    // Apply the material or perform operations on the rhinoObj
    if (applyToSubelement && objRef.GeometryComponentIndex.ComponentIndexType == ComponentIndexType.BrepFace)
    {
        // Handle subelement (BrepFace) material application
        var brep = objRef.Brep();
        if (brep == null) continue;

        // Get the face index from the selected component
        int brepFaceIndex = objRef.GeometryComponentIndex.Index;
        BrepFace brepFace = brep.Faces[brepFaceIndex];
        var parentObjMaterialIndex = rhinoObj.Attributes.MaterialIndex;
        var parentObjectMaterial = new Material(doc.Materials[parentObjMaterialIndex]);

        // default channel index
        int selectedMaterialChannelIndex = -1;

        // check if renderMaterial exists in the doc.Materials table or else add the material
        var selectedDocMaterial = doc.Materials.FirstOrDefault(docMat => docMat.Id == selectedRenderMaterial.Id);

        var selectedDocMaterialIndex = selectedDocMaterial == null ? doc.Materials.Add(selectedRenderMaterial.ToMaterial(RenderTexture.TextureGeneration.Allow)) : selectedDocMaterial.Index;
        selectedMaterialChannelIndex = parentObjectMaterial.MaterialChannelIndexFromId(doc.Materials[selectedDocMaterialIndex].Id, true);

        var modifiedParentObjectMaterialIndex = doc.Materials.Add(parentObjectMaterial);


        // Apply the material to the BrepFace
        rhinoObj.Attributes.MaterialIndex = modifiedParentObjectMaterialIndex;
        rhinoObj.Attributes.MaterialSource = ObjectMaterialSource.MaterialFromObject; // Use material from parent

        // apply the material channel index to the brepface
        brepFace.MaterialChannelIndex = selectedMaterialChannelIndex;

        // Commit changes
        RhinoApp.WriteLine($"Material applied to BrepFace (index: {brepFaceIndex}).");

    }
    else
    {
        // Apply material to the entire object
        rhinoObj.Attributes.MaterialSource = ObjectMaterialSource.MaterialFromObject;
        rhinoObj.Attributes.RenderMaterial = selectedRenderMaterial;
    }
    rhinoObj.CommitChanges();
}

this does not work yet but its a start. I was hoping to understand how to apply materials to individual brep faces regardless of if they belonged to single or multiple breps.

I made another topic here to continue the conversation. Thanks again