将此脚本附加到场景中的父GameObject上,该GameObject及其下的所有子GameObject都应该有MeshFilter
和MeshRenderer
组件。
并且所有子GameObject用的都是同一个材质。
父GameObject的坐标要设置成世界坐标原点(0,0,0)
请注意,如果子GameObject使用多个不同的材质,你可能需要合并这些材质或者创建一个支持多个材质的合并后的Mesh。这会更复杂,因为你需要处理子网格材质的合并,同时确保合并后的Mesh使用一个材质数组来保持原有的视觉效果。在这种情况下,你可能需要考虑使用多通道(multi-pass)渲染或者合并材质贴图。
所有子GameObject模型的导入设置都要勾选Read/Write Enabled
直接运行就可以看到效果
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class MeshCombiner : MonoBehaviour
{
public void CombineMeshes()
{
MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>(false);
CombineInstance[] combine = new CombineInstance[meshFilters.Length - 1];
Material[] materials = new Material[meshFilters.Length]; // 用于存储所有材质
int index = 0; // 用于combine数组的索引
for (int i = 0; i < meshFilters.Length; i++)
{
if (meshFilters[i].sharedMesh == null) continue; // 跳过没有Mesh的MeshFilter
if (meshFilters[i] == GetComponent<MeshFilter>()) continue; // 跳过自身的MeshFilter
combine[index].mesh = meshFilters[i].sharedMesh;
combine[index].transform = meshFilters[i].transform.localToWorldMatrix;
materials[index] = meshFilters[i].GetComponent<MeshRenderer>().sharedMaterial;
index++;
meshFilters[i].gameObject.SetActive(false); // 关闭子对象的渲染
}
MeshFilter filter = GetComponent<MeshFilter>();
filter.mesh = new Mesh();
filter.mesh.CombineMeshes(combine, true, true);
GetComponent<MeshRenderer>().materials = new Material[] { /* 你的材质 */ };
MeshRenderer meshRenderer = GetComponent<MeshRenderer>();
if (materials.Length > 0 && materials[0] != null)
{
meshRenderer.material = materials[0]; // 只设置第一个材质
}
else
{
Debug.LogWarning("No materials found on children. Please assign a material.");
}
transform.gameObject.SetActive(true);
transform.transform.position = Vector3.zero;
}
void Start()
{
CombineMeshes();
}
}