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
相关产品推荐
相关产品推荐

