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

Unity脚本生成网格光照异常问题求助

解决程序化生成三角棱柱的光照异常问题

嘿,我看了你的代码和遇到的问题,光照异常的核心原因是三角形顶点的缠绕顺序(winding order)不对!Unity默认要求正面三角形的顶点是顺时针排列(从面的外部视角观察),而你代码里的很多三角形顶点顺序是逆时针的,这就导致RecalculateNormals()算出的法线指向了网格内部,自然光照就会出现异常(比如表面发黑、没有正确的高光效果)。

下面是具体的分析和修正方案:

问题根源:三角形顶点顺序错误

先看你定义的顶点数组:

FragMesh.vertices = new Vector3[] {
    point1 + Vector3.forward * 0.5f, // 0: 前左下角
    point2 + Vector3.forward * 0.5f, // 1: 前右下角
    new Vector3(0f, 0f, 0.5f),       // 2: 前中心
    new Vector3(0f, 0f, -0.5f),      // 3: 后中心
    point2 - Vector3.forward * 0.5f, // 4: 后右下角
    point1 - Vector3.forward * 0.5f  // 5: 后左下角
};

再看你设置的triangles数组,比如第一个三角形1,0,2:从正面视角看,顶点顺序是「前右下角→前左下角→前中心」,这是逆时针方向,Unity会把这个面判定为背面,法线就会指向内部,导致光照错误。

修正方案

1. 调整三角形顶点的缠绕顺序

把每个面的三角形顶点顺序改成顺时针(从该面的外部视角看)。调整后的triangles数组如下:

FragMesh.triangles = new int[] {
    // 前面:前左→前右→前中心(顺时针)
    0, 1, 2,
    // 后面:后右→后左→后中心(顺时针)
    4, 5, 3,
    // 左面(两个三角形)
    0, 5, 3, 
    3, 2, 0,
    // 右面(两个三角形)
    4, 1, 2, 
    2, 3, 4,
    // 底面(两个三角形)
    5, 4, 1, 
    1, 0, 5,
    // 顶面(两个三角形)
    1, 4, 3, 
    3, 2, 1
};

2. 可选但推荐:设置Mesh的索引格式

如果后续你的网格顶点数可能超过65535,记得设置indexFormat为UInt32,避免索引溢出。即使现在只有6个顶点,养成好习惯也没坏处:

FragMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;

3. 重新计算法线和切线

在设置完顶点和三角形后,调用以下方法确保法线和切线正确:

FragMesh.RecalculateNormals();
FragMesh.RecalculateTangents(); // 如果你用的是带法线贴图的材质,这个很有必要

4. 补充物理组件(你提到后续要加力)

如果要让碎片有物理效果,记得给每个Fragment添加Rigidbody组件:

Rigidbody rb = Fragment.AddComponent<Rigidbody>();
rb.mass = 0.25f; // 可以根据原立方体的总质量调整每个碎片的质量

完整修正后的代码

// 2D Points which will connect to the center to form triangles
List<Vector2> shatterPoints = new List<Vector2> {
    new Vector2(-0.5f, -0.5f), 
    new Vector2(-0.5f, 0.5f), 
    new Vector2(0.5f, 0.5f), 
    new Vector2(0.5f, -0.5f)
}; 

// Generate each fragment
for (int i = 0; i < shatterPoints.Count; i++) { 
    GameObject Fragment = new GameObject("Empty"); 
    Fragment.AddComponent<MeshFilter>(); 
    Fragment.AddComponent<MeshRenderer>();
    // 添加物理组件
    Rigidbody rb = Fragment.AddComponent<Rigidbody>();
    rb.mass = 0.25f;

    Vector3 point1 = shatterPoints[i]; 
    Vector3 point2; 
    if (i + 1 == shatterPoints.Count) { 
        point2 = shatterPoints[0]; 
    } else { 
        point2 = shatterPoints[i + 1]; 
    } 

    Mesh FragMesh = new Mesh(); 
    // 设置索引格式
    FragMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;

    FragMesh.vertices = new Vector3[] {
        point1 + Vector3.forward * 0.5f, // 0: 前左下角
        point2 + Vector3.forward * 0.5f, // 1: 前右下角
        new Vector3(0f, 0f, 0.5f),       // 2: 前中心
        new Vector3(0f, 0f, -0.5f),      // 3: 后中心
        point2 - Vector3.forward * 0.5f, // 4: 后右下角
        point1 - Vector3.forward * 0.5f  // 5: 后左下角
    }; 

    // 修正后的三角形顺序
    FragMesh.triangles = new int[] {
        0, 1, 2,
        4, 5, 3,
        0, 5, 3, 
        3, 2, 0,
        4, 1, 2, 
        2, 3, 4,
        5, 4, 1, 
        1, 0, 5,
        1, 4, 3, 
        3, 2, 1
    }; 

    Fragment.GetComponent<MeshFilter>().mesh = FragMesh; 
    Fragment.transform.position = Panel.transform.position; 
    Fragment.transform.rotation = Panel.transform.rotation; 
    Fragment.transform.localScale = Panel.transform.localScale; 
    Fragment.GetComponent<Renderer>().material = Panel.GetComponent<Renderer>().material; 

    FragMesh.RecalculateNormals();
    FragMesh.RecalculateTangents();
} 
Destroy(Panel);

这样调整后,每个面的法线都会正确指向外部,光照就能正常显示啦!

内容的提问来源于stack exchange,提问作者Isaac Thompson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:35:46