背景
unity的静态合批在特定的情况下不能有效地合批,但是在scene的场景中缺有大量的静态物体!
技术原理
通过代码手动合批,生成一个个合并后的mesh和纹理材质,然后替换场景中原有的物体!
具体
unity本身也提供了相应的api给我们处理,在说到实现前,需要先说明一下合批的一些前提条件:
前提
- 材质(Material):材质球要相同,如果材质球不同,unity则无法进行静态合批!
- 静态(static): 必须是静态的对象!
CombineInstance
Struct used to describe meshes to be combined using Mesh.CombineMeshes.
用来描绘网格合并的结构,主要是为了使用
Mesh.CombineMeshes
name | des |
---|---|
mesh | 合并的网格 |
subMeshIndex | 子网格索引 |
transform | 合并之前,网格变换的矩阵 |
CombineMeshes
这里就不细说了,代码里有注释了!
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
public class CombineDemo
{
[MenuItem("Tools/Combine Scene Static Mesh")]
static void CombineInstance()
{
List<GameObject> rootGameObjects = new List<GameObject>();
if (Selection.gameObjects != null && Selection.gameObjects.Length!=0)
{
foreach (var gameObject in Selection.gameObjects)
{
rootGameObjects.Add(gameObject);
}
}
else
{
var editorScene = SceneManager.GetActiveScene();
editorScene.GetRootGameObjects(rootGameObjects);
}
// 递归查找可以合并的mesh
Dictionary<Material,CombineInstance[]> combineInstanceses = new Dictionary<Material, CombineInstance[]>();
Recurrence(rootGameObjects, combineInstanceses);
foreach (var combineInstances in combineInstanceses)
{
Mesh instance = new Mesh();
instance.CombineMeshes(combineInstances.Value);
// 如果是直接使用
var testObj = new GameObject();
var meshFilter = testObj.AddComponent<MeshFilter>();
var meshRender = testObj.AddComponent<MeshRenderer>();
meshFilter.mesh = instance;
meshRender.material = combineInstances.Key;
// 如果是需要保存下来作为运行时使用!
// AssetDatabase.CreateAsset(instance, "path/name.assets");
}
}
private static void Recurrence(List<GameObject> objs, Dictionary<Material,CombineInstance[]> list)
{
Dictionary<Material, List<MeshFilter>> dictionary = new Dictionary<Material, List<MeshFilter>>();
foreach (var o in objs)
{
ResearchGameObject(o, dictionary);
}
foreach (var staticObjs in dictionary)
{
CombineInstance[] combineInstances = new CombineInstance[staticObjs.Value.Count];
for (int i = 0; i < staticObjs.Value.Count; i++)
{
combineInstances[i] = new CombineInstance();
combineInstances[i].mesh = staticObjs.Value[i].sharedMesh;
combineInstances[i].transform = staticObjs.Value[i].transform.localToWorldMatrix;
// 有需要的可以看着官方文档去添加一些属性的记录
// combineInstances[i].realtimeLightmapScaleOffset
}
list.Add(staticObjs.Key, combineInstances);
}
}
private static void ResearchGameObject(GameObject gameObject, Dictionary<Material,List<MeshFilter>> dictionary)
{
var flag = GameObjectUtility.GetStaticEditorFlags(gameObject);
if (flag == StaticEditorFlags.BatchingStatic)
{
var meshFilter = gameObject.GetComponent<MeshFilter>();
var meshRenderer = gameObject.GetComponent<MeshRenderer>();
List<MeshFilter> meshFilters;
if (!dictionary.TryGetValue(meshRenderer.sharedMaterial, out meshFilters))
{
meshFilters = new List<MeshFilter>();
dictionary.Add(meshRenderer.sharedMaterial, meshFilters);
}
meshFilters.Add(meshFilter);
}
int childCount = gameObject.transform.childCount;
for (int i = 0; i < childCount; i++)
{
ResearchGameObject(gameObject.transform.GetChild(i).gameObject, dictionary);
}
}
}
PREVIOUSunity的断点续传
NEXTUnity的性能优化之路