Unity场景Mesh网格合并
今天突然被美术问傻了,就是在游戏场景中Mesh找不到了源文件,就是这个
查了一下,原来是之前项目在做场景的时候把一些mesh合并了。到底怎么实现的呢?
为什么要合并Mesh
unity引擎中渲染代价的指标是场景中网格(Mesh)的数量,对显卡来说渲染一个100面的物体和渲染一个1500面的物体几乎是等价的,于是当多个物体的材质(Shader)相同时,可以把他们的网格合并起来,然后共用一个材料(Material)来降低渲染的成本,达成优化游戏体验的效果。ps(不是所有的Mesh都可以合并的)
1.shader相同的物体才可以合并、
2.要合并的物体需要处于一定范围内(具体什么范围看自己的需求)
3.物体的光照贴图需要相同(lightmapindex属性相同)
代码实现
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
public class ChangeMesh
{
[MenuItem("Custom /ChangeMesh")]
static void BuildPCChangeIconName()
{
List<GameObject> listGo = GetAllSceneObjectsWithInactive();
GameObject mountscripts = null;
for (int i = 0; i < listGo.Count; i++)
{
Debug.LogError(listGo[i].name);
if (listGo[i].name == "scenes_Mesh")
{
mountscripts = listGo[i];
break;
}
}
//合并Mount Scripts的所有网格
MergeMesh(mountscripts);
}
/// <summary>
/// 合并网格
/// </summary>
static void MergeMesh(GameObject go)
{
//获取 所有子物体的网格
MeshFilter[] meshFilters = go.GetComponentsInChildren<MeshFilter>();
//新建一个合并组,长度与 meshfilters一致
CombineInstance[] combineInstances = new CombineInstance[meshFilters.Length];
for (int i = 0; i < meshFilters.Length; i++)
{
combineInstances[i].mesh = meshFilters[i].sharedMesh; //将共享mesh,赋值
combineInstances[i].transform = meshFilters[i].transform.localToWorldMatrix; //本地坐标转矩阵,赋值
}
//新网格对象
Mesh newMesh = new Mesh();
//将combineInstances数组传入函数
newMesh.CombineMeshes(combineInstances);
//给当前空物体,添加网格组件;将合并后的网格,给到自身网格
go.gameObject.AddComponent<MeshFilter>().sharedMesh = newMesh;
//给当前空物体添加渲染组件,给新模型网格上色;
go.gameObject.AddComponent<MeshRenderer>().material = Resources.Load<Material>("Materials/Koala");
}
/// <summary>
/// 获取当前的场景所有预设
/// </summary>
/// <returns></returns>
static List<GameObject> GetAllSceneObjectsWithInactive()
{
var allTransforms = Resources.FindObjectsOfTypeAll(typeof(Transform));
var previousSelection = Selection.objects;
Selection.objects = allTransforms.Cast<Transform>()
.Where(x => x != null)
.Select(x => x.gameObject)
//如果你只想获取所有在Hierarchy中被禁用的物体,反注释下面代码
//.Where(x => x != null && !x.activeInHierarchy)
.Cast<UnityEngine.Object>().ToArray();
var selectedTransforms = Selection.GetTransforms(SelectionMode.Editable | SelectionMode.ExcludePrefab);
Selection.objects = previousSelection;
return selectedTransforms.Select(tr => tr.gameObject).ToList();
}
}
运行看看效果吧
- 运行
- 运行之前,Sense_mesh是没有挂任何组建的,3. 运行之后,在scenes_Mesh对象上就会自动挂上Mesh_Filter 和 MeshRenderer,说明我们合并成功了。我们就可以把 scenes_Mesh对象的子物体删除掉。