183 lines
6.7 KiB
C#
183 lines
6.7 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.ProBuilder;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace Unity.FPS.Game
|
|
{
|
|
public static class MeshCombineUtility
|
|
{
|
|
public class RenderBatchData
|
|
{
|
|
public class MeshAndTrs
|
|
{
|
|
public Mesh Mesh;
|
|
public Matrix4x4 Trs;
|
|
|
|
public MeshAndTrs(Mesh m, Matrix4x4 t)
|
|
{
|
|
Mesh = m;
|
|
Trs = t;
|
|
}
|
|
}
|
|
|
|
public Material Material;
|
|
public int SubmeshIndex = 0;
|
|
public ShadowCastingMode ShadowMode;
|
|
public bool ReceiveShadows;
|
|
public MotionVectorGenerationMode MotionVectors;
|
|
public List<MeshAndTrs> MeshesWithTrs = new List<MeshAndTrs>();
|
|
}
|
|
|
|
public enum RendererDisposeMethod
|
|
{
|
|
DestroyGameObject,
|
|
DestroyRendererAndFilter,
|
|
DisableGameObject,
|
|
DisableRenderer,
|
|
}
|
|
|
|
public static void Combine(List<MeshRenderer> renderers, RendererDisposeMethod disposeMethod,
|
|
string newObjectName)
|
|
{
|
|
int renderersCount = renderers.Count;
|
|
|
|
List<RenderBatchData> renderBatches = new List<RenderBatchData>();
|
|
|
|
// Build render batches for all unique material + submeshIndex combinations
|
|
for (int i = 0; i < renderersCount; i++)
|
|
{
|
|
MeshRenderer meshRenderer = renderers[i];
|
|
|
|
if (meshRenderer == null)
|
|
continue;
|
|
|
|
MeshFilter meshFilter = meshRenderer.GetComponent<MeshFilter>();
|
|
|
|
if (meshFilter == null)
|
|
continue;
|
|
|
|
Mesh mesh = meshFilter.sharedMesh;
|
|
|
|
if (mesh == null)
|
|
continue;
|
|
|
|
Transform t = meshRenderer.GetComponent<Transform>();
|
|
Material[] materials = meshRenderer.sharedMaterials;
|
|
|
|
for (int s = 0; s < mesh.subMeshCount; s++)
|
|
{
|
|
if (materials[s] == null)
|
|
continue;
|
|
|
|
int batchIndex = GetExistingRenderBatch(renderBatches, materials[s], meshRenderer, s);
|
|
if (batchIndex >= 0)
|
|
{
|
|
renderBatches[batchIndex].MeshesWithTrs
|
|
.Add(new RenderBatchData.MeshAndTrs(mesh,
|
|
Matrix4x4.TRS(t.position, t.rotation, t.lossyScale)));
|
|
}
|
|
else
|
|
{
|
|
RenderBatchData newBatchData = new RenderBatchData();
|
|
newBatchData.Material = materials[s];
|
|
newBatchData.SubmeshIndex = s;
|
|
newBatchData.ShadowMode = meshRenderer.shadowCastingMode;
|
|
newBatchData.ReceiveShadows = meshRenderer.receiveShadows;
|
|
newBatchData.MeshesWithTrs.Add(new RenderBatchData.MeshAndTrs(mesh,
|
|
Matrix4x4.TRS(t.position, t.rotation, t.lossyScale)));
|
|
|
|
renderBatches.Add(newBatchData);
|
|
}
|
|
}
|
|
|
|
// Destroy probuilder component if present
|
|
ProBuilderMesh pbm = meshRenderer.GetComponent<ProBuilderMesh>();
|
|
if (pbm)
|
|
{
|
|
GameObject.Destroy(pbm);
|
|
}
|
|
|
|
switch (disposeMethod)
|
|
{
|
|
case RendererDisposeMethod.DestroyGameObject:
|
|
if (Application.isPlaying)
|
|
{
|
|
GameObject.Destroy(meshRenderer.gameObject);
|
|
}
|
|
else
|
|
{
|
|
GameObject.DestroyImmediate(meshRenderer.gameObject);
|
|
}
|
|
|
|
break;
|
|
case RendererDisposeMethod.DestroyRendererAndFilter:
|
|
if (Application.isPlaying)
|
|
{
|
|
GameObject.Destroy(meshRenderer);
|
|
GameObject.Destroy(meshFilter);
|
|
}
|
|
else
|
|
{
|
|
GameObject.DestroyImmediate(meshRenderer);
|
|
GameObject.DestroyImmediate(meshFilter);
|
|
}
|
|
|
|
break;
|
|
case RendererDisposeMethod.DisableGameObject:
|
|
meshRenderer.gameObject.SetActive(false);
|
|
break;
|
|
case RendererDisposeMethod.DisableRenderer:
|
|
meshRenderer.enabled = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Combine each unique render batch
|
|
for (int i = 0; i < renderBatches.Count; i++)
|
|
{
|
|
RenderBatchData rbd = renderBatches[i];
|
|
|
|
Mesh newMesh = new Mesh();
|
|
newMesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
|
|
CombineInstance[] combineInstances = new CombineInstance[rbd.MeshesWithTrs.Count];
|
|
|
|
for (int j = 0; j < rbd.MeshesWithTrs.Count; j++)
|
|
{
|
|
combineInstances[j].subMeshIndex = rbd.SubmeshIndex;
|
|
combineInstances[j].mesh = rbd.MeshesWithTrs[j].Mesh;
|
|
combineInstances[j].transform = rbd.MeshesWithTrs[j].Trs;
|
|
}
|
|
|
|
// Create mesh
|
|
newMesh.CombineMeshes(combineInstances);
|
|
newMesh.RecalculateBounds();
|
|
|
|
// Create the gameObject
|
|
GameObject combinedObject = new GameObject(newObjectName);
|
|
MeshFilter mf = combinedObject.AddComponent<MeshFilter>();
|
|
mf.sharedMesh = newMesh;
|
|
MeshRenderer mr = combinedObject.AddComponent<MeshRenderer>();
|
|
mr.sharedMaterial = rbd.Material;
|
|
mr.shadowCastingMode = rbd.ShadowMode;
|
|
}
|
|
}
|
|
|
|
static int GetExistingRenderBatch(List<RenderBatchData> renderBatches, Material mat, MeshRenderer ren, int submeshIndex)
|
|
{
|
|
for (int i = 0; i < renderBatches.Count; i++)
|
|
{
|
|
RenderBatchData data = renderBatches[i];
|
|
if (data.Material == mat &&
|
|
data.SubmeshIndex == submeshIndex &&
|
|
data.ShadowMode == ren.shadowCastingMode &&
|
|
data.ReceiveShadows == ren.receiveShadows)
|
|
{
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
} |