Files
Alex38Lyon 878ea46cac update
2025-06-03 12:00:47 +02:00

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;
}
}
}