You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中为同一物体的内外网格分配不同材质

解决Unity中同一物体双Mesh分别分配材质的问题

嘿,先给你指出代码里的一个关键问题:你现在是用GetComponent<MeshFilter>()获取同一个MeshFilter来赋值轮廓Mesh,这会直接把之前的内部Mesh覆盖掉,等于白忙活啦!要实现两个Mesh共存并分别用不同材质,有两种简单可行的方案,我给你详细说:

方案一:用两个MeshFilter组件(最直接)

这个方法完全适配你已经在Mesh Renderer里准备好两个材质的场景,步骤很简单:

  1. 给物体新增一个MeshFilter组件(别复用原来的那个)
  2. 分别给两个MeshFilter赋值内部Mesh和轮廓Mesh
  3. Mesh Renderer会自动按MeshFilter的组件顺序分配材质——第一个MeshFilter用第一个材质,第二个用第二个

修改后的完整代码:

void BoxMesh(float width, float height, float OLwidth) {
    // 内部Mesh的MeshFilter(用物体原本的)
    MeshFilter innerMeshFilter = GetComponent<MeshFilter>();
    Mesh innerMesh = new Mesh();
    innerMeshFilter.mesh = innerMesh;

    // 轮廓Mesh的MeshFilter:新增一个组件
    MeshFilter outlineMeshFilter = gameObject.AddComponent<MeshFilter>();
    Mesh outlineMesh = new Mesh();
    outlineMeshFilter.mesh = outlineMesh;

    // --------------------------
    // 内部Mesh的顶点、三角形等设置(和你原来的逻辑一致)
    // --------------------------
    Vector3[] innerVertices = new Vector3[4] {
        new Vector3(0, 0, 0),
        new Vector3(0, height, 0),
        new Vector3(width, height, 0),
        new Vector3(width, 0, 0)
    };
    int[] innerTriangles = new int[6] { 0, 1, 3, 1, 2, 3 };
    Vector3[] innerNormals = new Vector3[4];
    Vector2[] innerUVs = new Vector2[4] {
        new Vector2(0, 0),
        new Vector2(0, 1),
        new Vector2(1, 1),
        new Vector2(1, 0)
    };
    for (int i = 0; i < 4; i++) innerNormals[i] = -Vector3.forward;

    innerMesh.vertices = innerVertices;
    innerMesh.triangles = innerTriangles;
    innerMesh.normals = innerNormals;
    innerMesh.uv = innerUVs;

    // --------------------------
    // 轮廓Mesh的顶点、三角形等设置
    // --------------------------
    Vector3[] outlineVertices = new Vector3[4] {
        new Vector3(-OLwidth, -OLwidth, 0),
        new Vector3(-OLwidth, height + OLwidth, 0),
        new Vector3(width + OLwidth, height + OLwidth, 0),
        new Vector3(width + OLwidth, -OLwidth, 0)
    };
    // 注意:这里调整了三角形顺序,避免背面剔除导致轮廓看不到
    int[] outlineTriangles = new int[6] { 0, 3, 1, 1, 3, 2 };
    Vector3[] outlineNormals = new Vector3[4];
    Vector2[] outlineUVs = new Vector2[4] {
        new Vector2(0, 0),
        new Vector2(0, 1),
        new Vector2(1, 1),
        new Vector2(1, 0)
    };
    for (int i = 0; i < 4; i++) outlineNormals[i] = -Vector3.forward;

    outlineMesh.vertices = outlineVertices;
    outlineMesh.triangles = outlineTriangles;
    outlineMesh.normals = outlineNormals;
    outlineMesh.uv = outlineUVs;

    // --------------------------
    // 碰撞体设置(用轮廓的范围)
    // --------------------------
    PolygonCollider2D polyCollider = GetComponent<PolygonCollider2D>();
    polyCollider.pathCount = 1;
    Vector2[] colliderPath = new Vector2[4] {
        new Vector2(-OLwidth, -OLwidth),
        new Vector2(-OLwidth, height + OLwidth),
        new Vector2(width + OLwidth, height + OLwidth),
        new Vector2(width + OLwidth, -OLwidth)
    };
    polyCollider.SetPath(0, colliderPath);

    // --------------------------
    // 手动指定材质顺序(可选,如果你想代码控制)
    // --------------------------
    MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
    // 假设你已经把内部材质和轮廓材质拖到了public变量里
    // meshRenderer.materials = new Material[] { yourInnerMaterial, yourOutlineMaterial };
}

材质分配说明:

打开Inspector面板,找到你的Mesh Renderer组件,确保Materials数组里有两个材质。默认情况下,第一个材质会对应第一个MeshFilter(内部Mesh),第二个材质对应第二个MeshFilter(轮廓Mesh)。如果顺序不对,直接在Inspector里拖拽材质调整顺序就行。


方案二:合并为带SubMesh的单个Mesh(更高效)

如果不想用两个MeshFilter,也可以把内部和轮廓的Mesh合并成一个,用SubMesh来区分,这样一个MeshFilter就够了,性能也更好。

修改后的代码:

void BoxMesh(float width, float height, float OLwidth) {
    MeshFilter meshFilter = GetComponent<MeshFilter>();
    Mesh combinedMesh = new Mesh();
    meshFilter.mesh = combinedMesh;

    // --------------------------
    // 合并所有顶点:内部4个 + 轮廓4个 = 8个顶点
    // --------------------------
    Vector3[] allVertices = new Vector3[8];
    // 内部顶点(索引0-3)
    allVertices[0] = new Vector3(0, 0, 0);
    allVertices[1] = new Vector3(0, height, 0);
    allVertices[2] = new Vector3(width, height, 0);
    allVertices[3] = new Vector3(width, 0, 0);
    // 轮廓顶点(索引4-7)
    allVertices[4] = new Vector3(-OLwidth, -OLwidth, 0);
    allVertices[5] = new Vector3(-OLwidth, height + OLwidth, 0);
    allVertices[6] = new Vector3(width + OLwidth, height + OLwidth, 0);
    allVertices[7] = new Vector3(width + OLwidth, -OLwidth, 0);

    // --------------------------
    // 设置两个SubMesh的三角形
    // --------------------------
    combinedMesh.subMeshCount = 2;
    // SubMesh 0:内部Mesh的三角形
    combinedMesh.SetTriangles(new int[6] { 0, 1, 3, 1, 2, 3 }, 0);
    // SubMesh 1:轮廓Mesh的三角形(调整顺序避免背面剔除)
    combinedMesh.SetTriangles(new int[6] { 4, 7, 5, 5, 7, 6 }, 1);

    // --------------------------
    // 设置法线和UV(这里简化复用,也可以分别自定义)
    // --------------------------
    Vector3[] allNormals = new Vector3[8];
    Vector2[] allUVs = new Vector2[8];
    for (int i = 0; i < 8; i++) {
        allNormals[i] = -Vector3.forward;
        if (i < 4) {
            allUVs[i] = new Vector2(i % 2, i / 2);
        } else {
            allUVs[i] = new Vector2((i - 4) % 2, (i - 4) / 2);
        }
    }
    combinedMesh.normals = allNormals;
    combinedMesh.uv = allUVs;

    // --------------------------
    // 碰撞体设置
    // --------------------------
    PolygonCollider2D polyCollider = GetComponent<PolygonCollider2D>();
    polyCollider.pathCount = 1;
    Vector2[] colliderPath = new Vector2[4] {
        new Vector2(-OLwidth, -OLwidth),
        new Vector2(-OLwidth, height + OLwidth),
        new Vector2(width + OLwidth, height + OLwidth),
        new Vector2(width + OLwidth, -OLwidth)
    };
    polyCollider.SetPath(0, colliderPath);

    // --------------------------
    // 分配材质:SubMesh 0对应第一个材质,SubMesh1对应第二个
    // --------------------------
    MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
    // meshRenderer.materials = new Material[] { yourInnerMaterial, yourOutlineMaterial };
}

注意事项:

  • 方案一的好处是两个Mesh完全独立,后续想单独调整位置、缩放都很方便;方案二更适合性能要求高的场景,因为减少了Draw Call。
  • 轮廓Mesh的三角形顺序一定要注意,Unity默认会剔除背面(逆时针的面),所以我调整了三角形的顶点顺序,确保轮廓Mesh的正面朝向相机,不然可能会看不到轮廓。

内容的提问来源于stack exchange,提问作者Tom Ryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:59:10