[范例]调用 RhinoCommon 给 Brep 中不同的子面赋予不同的双面材质

回答授权 Rhino 用户支持群中的一个问题,如何调用 RhinoCommon 给 Brep 中子面赋予不同的双面材质。

用户遇到的问题主要是,通过 brepObject.Attributes.RenderMaterial = rm0 修改物件的 RenderMaterial 会整体改变 Brep 的材质,而使用 Material 该用户无法将双面材质赋予给子面的同时保持其他面的材质。

这里提供一个范例,重要的地方在范例中注释出来了。

这个范例不会去新建 RenderMaterial,调用已经在 Rhino 中创建好的双面材质,双面材质已经放在下面的 3dm 文件中:

Brep子面材质.3dm (78.8 KB)

using System;
using Rhino;
using Rhino.Commands;
using Rhino.DocObjects;
using Rhino.Geometry;
using Rhino.Input;
using Rhino.Input.Custom;
using Rhino.Render;

Run();

void Run(){
    var doc = RhinoDoc.ActiveDoc;
    ObjRef objRef = null;
    using (GetObject go = new GetObject())
    {
        go.SetCommandPrompt("Select brep object to set face materials to");
        go.GeometryFilter = ObjectType.Brep;
        var goRes = go.Get();
        if (goRes != GetResult.Object)
        {
            return;
        }
        objRef = go.Object(0);
    }

    if (doc.Objects.FindId(objRef.ObjectId) is BrepObject brepObject)
    {
        RenderMaterial rm0 = Rhino.RhinoDoc.ActiveDoc.RenderMaterials[0];
        RenderMaterial rm1 = Rhino.RhinoDoc.ActiveDoc.RenderMaterials[1];

        Material  m0 = rm0.ToMaterial(RenderTexture.TextureGeneration.Allow);
        Material  m1 = rm1.ToMaterial(RenderTexture.TextureGeneration.Allow);
        // 非常重要!!!如果材质是从现有材质列表中选的,必须加上这个,才能关联双面材质等具有子材质的材质。
        m0.RenderMaterialInstanceId = rm0.Id;
        m1.RenderMaterialInstanceId = rm1.Id;
        
        int m0MaterialIndex = doc.Materials.Add(m0);
        // 非常重要,在材质 m1 上查找有没有和 m0 匹配的通道,如果没有,就创建一个
        // 这样才能在给物件赋予 m1 材质的同时,通过通道在子曲面上使用 m0 材质
        int m0ChannelIndex = m1.MaterialChannelIndexFromId(doc.Materials[m0MaterialIndex].Id,true);
        int m1MaterialIndex = doc.Materials.Add(m1);

        brepObject.Attributes.MaterialIndex = m1MaterialIndex;
        brepObject.Attributes.MaterialSource = ObjectMaterialSource.MaterialFromObject;

        Brep brep = brepObject.BrepGeometry;
       for (int i = 0; i < brep.Faces.Count; i++)
                {
                    if (i % 2 == 0)
                        brep.Faces[i].MaterialChannelIndex = m0ChannelIndex;
                    else
                        brep.Faces[i].ClearMaterialChannelIndex();
                }
    
        brepObject.CommitChanges();
    }
}
4 个赞

太给力了,非常感谢。

@Jorin 提供的方法中,需要用8.0版本才有的RenderMaterial.ToMaterial().
我们发现在版本7中,通过通过把renderMaterial的id传入来创建material,也可以解决此问题

var material = new Material
{
RenderMaterialInstanceId=renderMaterial.Id
};
var index = RhinoDoc.Materials.Add(material);
material= RhinoDoc.Materials.FindIndex(index);

1 个赞