using UnityEngine; using System; using System.Collections; using System.Collections.Generic; using UltimateGameTools.MeshSimplifier; public class MeshSimplify : MonoBehaviour { [HideInInspector] public Mesh m_originalMesh = null; [HideInInspector] public Mesh m_simplifiedMesh = null; [HideInInspector] public bool m_bEnablePrefabUsage = false; [HideInInspector] public float m_fVertexAmount = 1.0f; [HideInInspector] public string m_strAssetPath = null; [HideInInspector] public MeshSimplify m_meshSimplifyRoot; [HideInInspector] public List<MeshSimplify> m_listDependentChildren = new List<MeshSimplify>(); [HideInInspector] public bool m_bExpandRelevanceSpheres = true; public RelevanceSphere[] m_aRelevanceSpheres = null; [SerializeField, HideInInspector] private Simplifier m_meshSimplifier = null; [SerializeField, HideInInspector] private bool m_bGenerateIncludeChildren = true; [SerializeField, HideInInspector] private bool m_bOverrideRootSettings = false; [SerializeField, HideInInspector] private bool m_bUseEdgeLength = true, m_bUseCurvature = true, m_bProtectTexture = true, m_bLockBorder = true; [SerializeField, HideInInspector] private bool m_bDataDirty = true; [SerializeField, HideInInspector] private bool m_bExcludedFromTree = false; #if UNITY_EDITOR public void OnDrawGizmos() { if (m_meshSimplifyRoot != null) { if (m_meshSimplifyRoot.m_bExpandRelevanceSpheres == false) { return; } } else { if (m_bExpandRelevanceSpheres == false) { return; } } Gizmos.color = Color.red; RelevanceSphere[] aRelevanceSpheres = m_meshSimplifyRoot != null ? m_meshSimplifyRoot.m_aRelevanceSpheres : m_aRelevanceSpheres; if (aRelevanceSpheres == null) { return; } bool bDrawVertices = false; for (int i = 0; i < UnityEditor.Selection.gameObjects.Length; i++) { if (((UnityEditor.Selection.gameObjects[i] == this.gameObject) && m_meshSimplifyRoot == null) || ((m_meshSimplifyRoot != null) && (UnityEditor.Selection.gameObjects[i] == m_meshSimplifyRoot.gameObject))) { bDrawVertices = true; } } if (bDrawVertices == false) { return; } Vector3[] aVerticesWorld = Simplifier.GetWorldVertices(this.gameObject); if(aVerticesWorld == null) { return; } Matrix4x4[] aSphereMatrices = new Matrix4x4[aRelevanceSpheres.Length]; for (int nSphere = 0; nSphere < aRelevanceSpheres.Length; nSphere++) { aSphereMatrices[nSphere] = Matrix4x4.TRS(aRelevanceSpheres[nSphere].m_v3Position, Quaternion.Euler(aRelevanceSpheres[nSphere].m_v3Rotation), aRelevanceSpheres[nSphere].m_v3Scale).inverse; } for (int nVertex = 0; nVertex < aVerticesWorld.Length; nVertex++) { for (int nSphere = 0; nSphere < aRelevanceSpheres.Length; nSphere++) { if (aRelevanceSpheres[nSphere].m_bExpanded) { Vector3 v3VertexSphereLocal = aSphereMatrices[nSphere].MultiplyPoint(aVerticesWorld[nVertex]); if (v3VertexSphereLocal.magnitude <= 0.5) { Gizmos.DrawCube(aVerticesWorld[nVertex], Vector3.one * UnityEditor.HandleUtility.GetHandleSize(aVerticesWorld[nVertex]) * 0.05f); break; } } } } } #endif public static bool HasValidMeshData(GameObject go) { MeshFilter meshFilter = go.GetComponent<MeshFilter>(); if (meshFilter != null) { return true; } else { SkinnedMeshRenderer skin = go.GetComponent<SkinnedMeshRenderer>(); if (skin != null) { return true; } } return false; } public static bool IsRootOrBelongsToTree(MeshSimplify meshSimplify, MeshSimplify root) { if (meshSimplify == null) { return false; } return (meshSimplify.m_bExcludedFromTree == false) && ((meshSimplify.m_meshSimplifyRoot == null) || (meshSimplify.m_meshSimplifyRoot == root) || (meshSimplify == root) || (meshSimplify.m_meshSimplifyRoot == root.m_meshSimplifyRoot)); } public bool IsGenerateIncludeChildrenActive() { return m_bGenerateIncludeChildren; } public bool HasDependentChildren() { return m_listDependentChildren != null && m_listDependentChildren.Count > 0; } public bool HasDataDirty() { return m_bDataDirty; } public bool SetDataDirty(bool bDirty) { return m_bDataDirty = bDirty; } public bool HasNonMeshSimplifyGameObjectsInTree() { return HasNonMeshSimplifyGameObjectsInTreeRecursive(this, this.gameObject); } private bool HasNonMeshSimplifyGameObjectsInTreeRecursive(MeshSimplify root, GameObject gameObject) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify == null && HasValidMeshData(gameObject)) { return true; } for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { if(HasNonMeshSimplifyGameObjectsInTreeRecursive(root, gameObject.transform.GetChild(nChild).gameObject)) { return true; } } return false; } private void ConfigureSimplifier() { m_meshSimplifier.UseEdgeLength = (m_meshSimplifyRoot != null && m_bOverrideRootSettings == false) ? m_meshSimplifyRoot.m_bUseEdgeLength : m_bUseEdgeLength; m_meshSimplifier.UseCurvature = (m_meshSimplifyRoot != null && m_bOverrideRootSettings == false) ? m_meshSimplifyRoot.m_bUseCurvature : m_bUseCurvature; m_meshSimplifier.ProtectTexture = (m_meshSimplifyRoot != null && m_bOverrideRootSettings == false) ? m_meshSimplifyRoot.m_bProtectTexture : m_bProtectTexture; m_meshSimplifier.LockBorder = (m_meshSimplifyRoot != null && m_bOverrideRootSettings == false) ? m_meshSimplifyRoot.m_bLockBorder : m_bLockBorder; } public Simplifier GetMeshSimplifier() { return m_meshSimplifier; } public void ComputeData(bool bRecurseIntoChildren, Simplifier.ProgressDelegate progress = null) { ComputeDataRecursive(this, this.gameObject, bRecurseIntoChildren, progress); } private static void ComputeDataRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren, Simplifier.ProgressDelegate progress = null) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify == null && root.m_bGenerateIncludeChildren) { if (HasValidMeshData(gameObject)) { meshSimplify = gameObject.AddComponent<MeshSimplify>(); meshSimplify.m_meshSimplifyRoot = root; root.m_listDependentChildren.Add(meshSimplify); } } if(meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { meshSimplify.FreeData(false); MeshFilter meshFilter = meshSimplify.GetComponent<MeshFilter>(); if (meshFilter != null && meshFilter.sharedMesh != null) { if (meshFilter.sharedMesh.vertexCount > 0) { if (meshSimplify.m_originalMesh == null) { meshSimplify.m_originalMesh = meshFilter.sharedMesh; } Simplifier[] simplifiers = meshSimplify.GetComponents<Simplifier>(); for (int c = 0; c < simplifiers.Length; c++) { if (Application.isEditor && Application.isPlaying == false) { DestroyImmediate(simplifiers[c]); } else { Destroy(simplifiers[c]); } } meshSimplify.m_meshSimplifier = meshSimplify.gameObject.AddComponent<Simplifier>(); meshSimplify.m_meshSimplifier.hideFlags = HideFlags.HideInInspector; meshSimplify.ConfigureSimplifier(); IEnumerator enumerator = meshSimplify.m_meshSimplifier.ProgressiveMesh(gameObject, meshSimplify.m_originalMesh, root.m_aRelevanceSpheres, meshSimplify.name, progress); while (enumerator.MoveNext()) { if (Simplifier.Cancelled) { return; } } if (Simplifier.Cancelled) { return; } } } else { SkinnedMeshRenderer skin = meshSimplify.GetComponent<SkinnedMeshRenderer>(); if (skin != null) { if (skin.sharedMesh.vertexCount > 0) { if (meshSimplify.m_originalMesh == null) { meshSimplify.m_originalMesh = skin.sharedMesh; } Simplifier[] simplifiers = meshSimplify.GetComponents<Simplifier>(); for (int c = 0; c < simplifiers.Length; c++) { if (Application.isEditor && Application.isPlaying == false) { DestroyImmediate(simplifiers[c]); } else { Destroy(simplifiers[c]); } } meshSimplify.m_meshSimplifier = meshSimplify.gameObject.AddComponent<Simplifier>(); meshSimplify.m_meshSimplifier.hideFlags = HideFlags.HideInInspector; meshSimplify.ConfigureSimplifier(); IEnumerator enumerator = meshSimplify.m_meshSimplifier.ProgressiveMesh(gameObject, meshSimplify.m_originalMesh, root.m_aRelevanceSpheres, meshSimplify.name, progress); while (enumerator.MoveNext()) { if (Simplifier.Cancelled) { return; } } if (Simplifier.Cancelled) { return; } } } } meshSimplify.m_bDataDirty = false; } } if(bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { ComputeDataRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren, progress); if (Simplifier.Cancelled) { return; } } } } public bool HasData() { return (m_meshSimplifier != null && m_simplifiedMesh != null) || (m_listDependentChildren != null && m_listDependentChildren.Count != 0); } public bool HasSimplifiedMesh() { return m_simplifiedMesh != null && m_simplifiedMesh.vertexCount > 0; } public void ComputeMesh(bool bRecurseIntoChildren, Simplifier.ProgressDelegate progress = null) { ComputeMeshRecursive(this, this.gameObject, bRecurseIntoChildren, progress); } private static void ComputeMeshRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren, Simplifier.ProgressDelegate progress = null) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_meshSimplifier != null) { if (meshSimplify.m_simplifiedMesh) { meshSimplify.m_simplifiedMesh.Clear(); } float fAmount = meshSimplify.m_fVertexAmount; if (meshSimplify.m_bOverrideRootSettings == false && meshSimplify.m_meshSimplifyRoot != null) { fAmount = meshSimplify.m_meshSimplifyRoot.m_fVertexAmount; } if (meshSimplify.m_simplifiedMesh == null) { meshSimplify.m_simplifiedMesh = CreateNewEmptyMesh(meshSimplify); } meshSimplify.ConfigureSimplifier(); IEnumerator enumerator = meshSimplify.m_meshSimplifier.ComputeMeshWithVertexCount(gameObject, meshSimplify.m_simplifiedMesh, Mathf.RoundToInt(fAmount * meshSimplify.m_meshSimplifier.GetOriginalMeshUniqueVertexCount()), meshSimplify.name + " Simplified", progress); while (enumerator.MoveNext()) { if (Simplifier.Cancelled) { return; } } if (Simplifier.Cancelled) { return; } } } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { ComputeMeshRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren, progress); if (Simplifier.Cancelled) { return; } } } } public void AssignSimplifiedMesh(bool bRecurseIntoChildren) { AssignSimplifiedMeshRecursive(this, this.gameObject, bRecurseIntoChildren); } private static void AssignSimplifiedMeshRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_simplifiedMesh != null) { MeshFilter meshFilter = meshSimplify.GetComponent<MeshFilter>(); if (meshFilter != null) { meshFilter.sharedMesh = meshSimplify.m_simplifiedMesh; } else { SkinnedMeshRenderer skin = meshSimplify.GetComponent<SkinnedMeshRenderer>(); if (skin != null) { skin.sharedMesh = meshSimplify.m_simplifiedMesh; } } } } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { AssignSimplifiedMeshRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren); } } } public void RestoreOriginalMesh(bool bDeleteData, bool bRecurseIntoChildren) { RestoreOriginalMeshRecursive(this, this.gameObject, bDeleteData, bRecurseIntoChildren); } private static void RestoreOriginalMeshRecursive(MeshSimplify root, GameObject gameObject, bool bDeleteData, bool bRecurseIntoChildren) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_originalMesh != null) { MeshFilter meshFilter = meshSimplify.GetComponent<MeshFilter>(); if (meshFilter != null) { meshFilter.sharedMesh = meshSimplify.m_originalMesh; } else { SkinnedMeshRenderer skin = meshSimplify.GetComponent<SkinnedMeshRenderer>(); if (skin != null) { skin.sharedMesh = meshSimplify.m_originalMesh; } } } if (bDeleteData) { meshSimplify.FreeData(false); meshSimplify.m_listDependentChildren.Clear(); } } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { RestoreOriginalMeshRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bDeleteData, bRecurseIntoChildren); } } } public bool HasOriginalMeshActive(bool bRecurseIntoChildren) { return HasOriginalMeshActiveRecursive(this, this.gameObject, bRecurseIntoChildren); } private static bool HasOriginalMeshActiveRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); bool bHasOriginalMeshActive = false; if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_originalMesh != null) { MeshFilter meshFilter = meshSimplify.GetComponent<MeshFilter>(); if (meshFilter != null) { if(meshFilter.sharedMesh == meshSimplify.m_originalMesh) { bHasOriginalMeshActive = true; } } else { SkinnedMeshRenderer skin = meshSimplify.GetComponent<SkinnedMeshRenderer>(); if (skin != null) { if(skin.sharedMesh == meshSimplify.m_originalMesh) { bHasOriginalMeshActive = true; } } } } } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { bHasOriginalMeshActive = bHasOriginalMeshActive || HasOriginalMeshActiveRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren); } } return bHasOriginalMeshActive; } public bool HasVertexData(bool bRecurseIntoChildren) { return HasVertexDataRecursive(this, this.gameObject, bRecurseIntoChildren); } private static bool HasVertexDataRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_simplifiedMesh && meshSimplify.m_simplifiedMesh.vertexCount > 0) { return true; } } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { if (HasVertexDataRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren)) { return true; } } } return false; } public int GetOriginalVertexCount(bool bRecurseIntoChildren) { int nVertexCount = 0; GetOriginalVertexCountRecursive(this, this.gameObject, ref nVertexCount, bRecurseIntoChildren); return nVertexCount; } private static void GetOriginalVertexCountRecursive(MeshSimplify root, GameObject gameObject, ref int nVertexCount, bool bRecurseIntoChildren) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_originalMesh != null) { nVertexCount += meshSimplify.m_originalMesh.vertexCount; } } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { GetOriginalVertexCountRecursive(root, gameObject.transform.GetChild(nChild).gameObject, ref nVertexCount, bRecurseIntoChildren); } } } public int GetSimplifiedVertexCount(bool bRecurseIntoChildren) { int nVertexCount = 0; GetSimplifiedVertexCountRecursive(this, this.gameObject, ref nVertexCount, bRecurseIntoChildren); return nVertexCount; } private static void GetSimplifiedVertexCountRecursive(MeshSimplify root, GameObject gameObject, ref int nVertexCount, bool bRecurseIntoChildren) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_simplifiedMesh != null) { nVertexCount += meshSimplify.m_simplifiedMesh.vertexCount; } } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { GetSimplifiedVertexCountRecursive(root, gameObject.transform.GetChild(nChild).gameObject, ref nVertexCount, bRecurseIntoChildren); } } } public void RemoveFromTree() { if (m_meshSimplifyRoot != null) { m_meshSimplifyRoot.m_listDependentChildren.Remove(this); } RestoreOriginalMesh(true, false); m_bExcludedFromTree = true; } public void FreeData(bool bRecurseIntoChildren) { FreeDataRecursive(this, this.gameObject, bRecurseIntoChildren); } private static void FreeDataRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_simplifiedMesh) { meshSimplify.m_simplifiedMesh.Clear(); } Simplifier[] simplifiers = gameObject.GetComponents<Simplifier>(); for (int c = 0; c < simplifiers.Length; c++) { if (Application.isEditor && Application.isPlaying == false) { DestroyImmediate(simplifiers[c]); } else { Destroy(simplifiers[c]); } } meshSimplify.m_bDataDirty = true; } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { FreeDataRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren); } } } private static Mesh CreateNewEmptyMesh(MeshSimplify meshSimplify) { if(meshSimplify.m_originalMesh == null) { return new Mesh(); } Mesh meshOut = Mesh.Instantiate(meshSimplify.m_originalMesh); meshOut.Clear(); return meshOut; } #if UNITY_EDITOR public void DisablePrefabUsage(bool bRecurseIntoChildren) { DisablePrefabUsageRecursive(this, this.gameObject, bRecurseIntoChildren); } private static void DisablePrefabUsageRecursive(MeshSimplify root, GameObject gameObject, bool bRecurseIntoChildren) { MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>(); if (meshSimplify != null) { if (IsRootOrBelongsToTree(meshSimplify, root)) { if (meshSimplify.m_simplifiedMesh) { if (UnityEditor.AssetDatabase.IsMainAsset(meshSimplify.m_simplifiedMesh) || UnityEditor.AssetDatabase.IsSubAsset(meshSimplify.m_simplifiedMesh)) { Mesh newMesh = Instantiate(meshSimplify.m_simplifiedMesh) as Mesh; meshSimplify.m_simplifiedMesh = newMesh; } } meshSimplify.m_strAssetPath = null; } } if (bRecurseIntoChildren) { for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++) { DisablePrefabUsageRecursive(root, gameObject.transform.GetChild(nChild).gameObject, bRecurseIntoChildren); } } } #endif }