This commit is contained in:
2025-11-14 18:44:06 +08:00
parent 10156da245
commit 22e867d077
7013 changed files with 2572882 additions and 1804 deletions

View File

@@ -0,0 +1,862 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using UltimateGameTools.MeshSimplifier;
public class MeshSimplify : MonoBehaviour
{
public bool RecurseIntoChildren
{
get
{
return m_bGenerateIncludeChildren;
}
}
public Simplifier MeshSimplifier
{
get
{
return m_meshSimplifier;
}
set
{
m_meshSimplifier = value;
}
}
[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;
}
public 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 GetOriginalTriangleCount(bool bRecurseIntoChildren)
{
int nTriangleCount = 0;
GetOriginalTriangleCountRecursive(this, this.gameObject, ref nTriangleCount, bRecurseIntoChildren);
return nTriangleCount;
}
private static void GetOriginalTriangleCountRecursive(MeshSimplify root, GameObject gameObject, ref int nTriangleCount, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_originalMesh != null)
{
nTriangleCount += meshSimplify.m_originalMesh.triangles.Length / 3;
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
GetOriginalTriangleCountRecursive(root, gameObject.transform.GetChild(nChild).gameObject, ref nTriangleCount, 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 int GetSimplifiedTriangleCount(bool bRecurseIntoChildren)
{
int nTriangleCount = 0;
GetSimplifiedTriangleCountRecursive(this, this.gameObject, ref nTriangleCount, bRecurseIntoChildren);
return nTriangleCount;
}
private static void GetSimplifiedTriangleCountRecursive(MeshSimplify root, GameObject gameObject, ref int nTriangleCount, bool bRecurseIntoChildren)
{
MeshSimplify meshSimplify = gameObject.GetComponent<MeshSimplify>();
if (meshSimplify != null)
{
if (IsRootOrBelongsToTree(meshSimplify, root))
{
if (meshSimplify.m_simplifiedMesh != null)
{
nTriangleCount += meshSimplify.m_simplifiedMesh.triangles.Length / 3;
}
}
}
if (bRecurseIntoChildren)
{
for (int nChild = 0; nChild < gameObject.transform.childCount; nChild++)
{
GetSimplifiedTriangleCountRecursive(root, gameObject.transform.GetChild(nChild).gameObject, ref nTriangleCount, 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
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 100bcc9db4f7fc64e95ecc1abca8c97d
timeCreated: 1438106980
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,378 @@
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace UltimateGameTools
{
namespace MeshSimplifier
{
/// <summary>
/// Class that will take a Mesh as input and will build internal data to identify which vertices are repeated due to
/// different vertex data (UV, vertex colors etc).
/// </summary>
[Serializable]
public class MeshUniqueVertices
{
#region Public types
/////////////////////////////////////////////////////////////////////////////////////////////////
// Public types
/////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// A list of vertex indices. We use this in order to be able to serialize a list of lists.
/// </summary>
[Serializable]
public class ListIndices
{
public ListIndices()
{
m_listIndices = new List<int>();
}
public List<int> m_listIndices;
}
/// <summary>
/// Our serializable version of Unity's BoneWeight
/// </summary>
[Serializable]
public class SerializableBoneWeight
{
public SerializableBoneWeight(BoneWeight boneWeight)
{
_boneIndex0 = boneWeight.boneIndex0;
_boneIndex1 = boneWeight.boneIndex1;
_boneIndex2 = boneWeight.boneIndex2;
_boneIndex3 = boneWeight.boneIndex3;
_boneWeight0 = boneWeight.weight0;
_boneWeight1 = boneWeight.weight1;
_boneWeight2 = boneWeight.weight2;
_boneWeight3 = boneWeight.weight3;
}
public BoneWeight ToBoneWeight()
{
BoneWeight boneWeight = new BoneWeight();
boneWeight.boneIndex0 = _boneIndex0;
boneWeight.boneIndex1 = _boneIndex1;
boneWeight.boneIndex2 = _boneIndex2;
boneWeight.boneIndex3 = _boneIndex3;
boneWeight.weight0 = _boneWeight0;
boneWeight.weight1 = _boneWeight1;
boneWeight.weight2 = _boneWeight2;
boneWeight.weight3 = _boneWeight3;
return boneWeight;
}
public int _boneIndex0;
public int _boneIndex1;
public int _boneIndex2;
public int _boneIndex3;
public float _boneWeight0;
public float _boneWeight1;
public float _boneWeight2;
public float _boneWeight3;
}
/// <summary>
/// Vertex that is has a unique position in space.
/// </summary>
public class UniqueVertex
{
// Overrides from Object
public override bool Equals(object obj)
{
UniqueVertex uniqueVertex = obj as UniqueVertex;
return (uniqueVertex.m_nFixedX == m_nFixedX) && (uniqueVertex.m_nFixedY == m_nFixedY) && (uniqueVertex.m_nFixedZ == m_nFixedZ);
}
public override int GetHashCode()
{
return m_nFixedX + (m_nFixedY << 2) + (m_nFixedZ << 4);
}
// Constructor
public UniqueVertex(Vector3 v3Vertex)
{
FromVertex(v3Vertex);
}
// Public methods
public Vector3 ToVertex()
{
return new Vector3(FixedToCoord(m_nFixedX), FixedToCoord(m_nFixedY), FixedToCoord(m_nFixedZ));
}
// Comparison operators
public static bool operator ==(UniqueVertex a, UniqueVertex b)
{
return a.Equals(b);
}
public static bool operator !=(UniqueVertex a, UniqueVertex b)
{
return !a.Equals(b);
}
// Private methods/vars
private void FromVertex(Vector3 vertex)
{
m_nFixedX = CoordToFixed(vertex.x);
m_nFixedY = CoordToFixed(vertex.y);
m_nFixedZ = CoordToFixed(vertex.z);
}
private int CoordToFixed(float fCoord)
{
int nInteger = Mathf.FloorToInt(fCoord);
int nRemainder = Mathf.FloorToInt((fCoord - nInteger) * fDecimalMultiplier);
return nInteger << 16 | nRemainder;
}
private float FixedToCoord(int nFixed)
{
float fRemainder = (nFixed & 0xFFFF) / fDecimalMultiplier;
float fInteger = nFixed >> 16;
return fInteger + fRemainder;
}
// Private vars
private int m_nFixedX, m_nFixedY, m_nFixedZ;
private const float fDecimalMultiplier = 100000.0f;
}
#endregion
#region Public properties
/////////////////////////////////////////////////////////////////////////////////////////////////
// Public properties
/////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// For each submesh, a list of faces. ListIndices has 3 indices for each face.
/// Each index is a vertex in ListVertices.
/// </summary>
public ListIndices[] SubmeshesFaceList
{
get
{
return m_aFaceList;
}
}
/// <summary>
/// Our list of vertices. Vertices are unique, so no vertex shares the same position in space.
/// </summary>
public List<Vector3> ListVertices
{
get
{
return m_listVertices;
}
}
/// <summary>
/// Our list of vertices in world space.
/// Vertices are unique, so no vertex shares the same position in space.
/// </summary>
public List<Vector3> ListVerticesWorld
{
get
{
return m_listVerticesWorld;
}
}
/// <summary>
/// Our list of vertex bone weights
/// </summary>
public List<SerializableBoneWeight> ListBoneWeights
{
get
{
return m_listBoneWeights;
}
}
#endregion // Public properties
#region Public methods
/////////////////////////////////////////////////////////////////////////////////////////////////
// Public methods
/////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Takes a Mesh as input and will build a new list of faces and vertices. The vertex list will
/// have no vertices sharing position in 3D space. The input mesh may have them, since often
/// a vertex will have different mapping coordinates for each of the faces that share it.
/// </summary>
/// <param name="sourceMesh"></param>
/// <param name="av3VerticesWorld"</param>
public void BuildData(Mesh sourceMesh, Vector3[] av3VerticesWorld)
{
Vector3[] av3Vertices = sourceMesh.vertices;
BoneWeight[] aBoneWeights = sourceMesh.boneWeights;
Dictionary<UniqueVertex, RepeatedVertexList> dicUniqueVertex2RepeatedVertexList = new Dictionary<UniqueVertex, RepeatedVertexList>();
m_listVertices = new List<Vector3>();
m_listVerticesWorld = new List<Vector3>();
m_listBoneWeights = new List<SerializableBoneWeight>();
m_aFaceList = new ListIndices[sourceMesh.subMeshCount];
for (int nSubMesh = 0; nSubMesh < sourceMesh.subMeshCount; nSubMesh++)
{
m_aFaceList[nSubMesh] = new ListIndices();
int[] anFaces = sourceMesh.GetTriangles(nSubMesh);
for (int i = 0; i < anFaces.Length; i++)
{
UniqueVertex vertex = new UniqueVertex(av3Vertices[anFaces[i]]);
if (dicUniqueVertex2RepeatedVertexList.ContainsKey(vertex))
{
dicUniqueVertex2RepeatedVertexList[vertex].Add(new RepeatedVertex(i / 3, anFaces[i]));
m_aFaceList[nSubMesh].m_listIndices.Add(dicUniqueVertex2RepeatedVertexList[vertex].UniqueIndex);
}
else
{
int nNewUniqueIndex = m_listVertices.Count;
dicUniqueVertex2RepeatedVertexList.Add(vertex, new RepeatedVertexList(nNewUniqueIndex, new RepeatedVertex(i / 3, anFaces[i])));
m_listVertices.Add(av3Vertices[anFaces[i]]);
m_listVerticesWorld.Add(av3VerticesWorld[anFaces[i]]);
m_aFaceList[nSubMesh].m_listIndices.Add(nNewUniqueIndex);
if(aBoneWeights != null && aBoneWeights.Length > 0)
{
m_listBoneWeights.Add(new SerializableBoneWeight(aBoneWeights[anFaces[i]]));
}
}
}
}
//Debug.Log("In: " + av3Vertices.Length + " vertices. Out: " + m_listVertices.Count + " vertices.");
}
#endregion // Public methods
#region Private types
/////////////////////////////////////////////////////////////////////////////////////////////////
// Private types
/////////////////////////////////////////////////////////////////////////////////////////////////
/// <summary>
/// Vertex that has the same position in space as another one, but different vertex data (UV, color...).
/// </summary>
private class RepeatedVertex
{
// Public properties
/// <summary>
/// Face it belongs to. This will be the same index in the source mesh as in the internal created face list.
/// </summary>
public int FaceIndex
{
get
{
return _nFaceIndex;
}
}
/// <summary>
/// Position in the original vertex array.
/// </summary>
public int OriginalVertexIndex
{
get
{
return _nOriginalVertexIndex;
}
}
// Constructor
public RepeatedVertex(int nFaceIndex, int nOriginalVertexIndex)
{
_nFaceIndex = nFaceIndex;
_nOriginalVertexIndex = nOriginalVertexIndex;
}
// Private vars
private int _nFaceIndex;
private int _nOriginalVertexIndex;
}
/// <summary>
/// List of vertices that have the same position in space but different vertex data (UV, color...).
/// </summary>
private class RepeatedVertexList
{
// Public properties
/// <summary>
/// Unique vertex index in our array for this list.
/// </summary>
public int UniqueIndex
{
get
{
return m_nUniqueIndex;
}
}
// Public methods
public RepeatedVertexList(int nUniqueIndex, RepeatedVertex repeatedVertex)
{
m_nUniqueIndex = nUniqueIndex;
m_listRepeatedVertices = new List<RepeatedVertex>();
m_listRepeatedVertices.Add(repeatedVertex);
}
public void Add(RepeatedVertex repeatedVertex)
{
m_listRepeatedVertices.Add(repeatedVertex);
}
// Private vars
private int m_nUniqueIndex;
private List<RepeatedVertex> m_listRepeatedVertices;
}
#endregion // Private types
#region Private vars
/////////////////////////////////////////////////////////////////////////////////////////////////
// Private vars
/////////////////////////////////////////////////////////////////////////////////////////////////
[SerializeField]
private List<Vector3> m_listVertices;
[SerializeField]
private List<Vector3> m_listVerticesWorld;
[SerializeField]
private List<SerializableBoneWeight> m_listBoneWeights;
[SerializeField]
private ListIndices[] m_aFaceList;
#endregion // Private vars
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c9aa0aceed4b66242b713cf6b09e6a9f
timeCreated: 1434653219
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,176 @@
using System.Collections;
using System.Collections.Generic;
using UltimateGameTools.MeshSimplifier;
using UnityEngine;
[RequireComponent(typeof(MeshSimplify))]
public class RuntimeMeshSimplifier : MonoBehaviour
{
public string ProgressTitle
{
get
{
return m_strLastTitle;
}
}
public string ProgressMessage
{
get
{
return m_strLastMessage;
}
}
public int ProgressPercent
{
get
{
return m_nLastProgress;
}
}
public bool Finished
{
get
{
return m_bFinished;
}
}
public void Simplify(float percent)
{
if (m_bFinished == false)
{
StartCoroutine(ComputeMeshWithVertices(Mathf.Clamp01(percent / 100.0f)));
}
}
private void Awake()
{
m_selectedMeshSimplify = GetComponent<MeshSimplify>();
m_objectMaterials = new Dictionary<GameObject, Material[]>();
AddMaterials(m_selectedMeshSimplify.gameObject, m_objectMaterials);
m_bFinished = false;
}
private void AddMaterials(GameObject theGameObject, Dictionary<GameObject, Material[]> dicMaterials)
{
Renderer theRenderer = theGameObject.GetComponent<Renderer>();
if (theRenderer != null && theRenderer.sharedMaterials != null && (MeshSimplify.HasValidMeshData(theGameObject) || theGameObject.GetComponent<MeshSimplify>() != null))
{
dicMaterials.Add(theGameObject, theRenderer.sharedMaterials);
}
if (m_selectedMeshSimplify.RecurseIntoChildren)
{
for (int i = 0; i < theGameObject.transform.childCount; i++)
{
AddMaterials(theGameObject.transform.GetChild(i).gameObject, dicMaterials);
}
}
}
private void Progress(string strTitle, string strMessage, float fT)
{
int nPercent = Mathf.RoundToInt(fT * 100.0f);
if (nPercent != m_nLastProgress || m_strLastTitle != strTitle || m_strLastMessage != strMessage)
{
m_strLastTitle = strTitle;
m_strLastMessage = strMessage;
m_nLastProgress = nPercent;
//Debug.Log(strTitle + " " + strMessage + " " + nPercent);
}
}
private IEnumerator ComputeMeshWithVertices(float fAmount)
{
Simplifier.CoroutineFrameMiliseconds = 20;
foreach (KeyValuePair<GameObject, Material[]> pair in m_objectMaterials)
{
MeshSimplify meshSimplify = pair.Key.GetComponent<MeshSimplify>();
MeshFilter meshFilter = pair.Key.GetComponent<MeshFilter>();
SkinnedMeshRenderer skin = pair.Key.GetComponent<SkinnedMeshRenderer>();
if(meshSimplify == null)
{
meshSimplify = pair.Key.AddComponent<MeshSimplify>();
meshSimplify.m_meshSimplifyRoot = m_selectedMeshSimplify;
m_selectedMeshSimplify.m_listDependentChildren.Add(meshSimplify);
}
if(meshSimplify.MeshSimplifier == null)
{
meshSimplify.MeshSimplifier = meshSimplify.gameObject.AddComponent<Simplifier>();
meshSimplify.MeshSimplifier.hideFlags = HideFlags.HideInInspector;
meshSimplify.ConfigureSimplifier();
}
if (meshSimplify && MeshSimplify.HasValidMeshData(pair.Key))
{
Mesh newMesh = null;
if (meshFilter != null)
{
newMesh = Mesh.Instantiate(meshFilter.sharedMesh);
}
else if (skin != null)
{
newMesh = Mesh.Instantiate(skin.sharedMesh);
}
if (meshSimplify.HasData() == false)
{
meshSimplify.GetMeshSimplifier().CoroutineEnded = false;
StartCoroutine(meshSimplify.GetMeshSimplifier().ProgressiveMesh(pair.Key, meshFilter != null ? meshFilter.sharedMesh : skin.sharedMesh, null, meshSimplify.name, Progress));
while (meshSimplify.GetMeshSimplifier().CoroutineEnded == false)
{
yield return null;
}
}
if (meshSimplify.GetMeshSimplifier() != null)
{
meshSimplify.GetMeshSimplifier().CoroutineEnded = false;
StartCoroutine(meshSimplify.GetMeshSimplifier().ComputeMeshWithVertexCount(pair.Key, newMesh, Mathf.RoundToInt(fAmount * meshSimplify.GetMeshSimplifier().GetOriginalMeshUniqueVertexCount()), meshSimplify.name, Progress));
while (meshSimplify.GetMeshSimplifier().CoroutineEnded == false)
{
yield return null;
}
if (meshFilter != null)
{
meshFilter.mesh = newMesh;
}
else if (skin != null)
{
skin.sharedMesh = newMesh;
}
meshSimplify.m_simplifiedMesh = newMesh;
}
}
}
m_bFinished = true;
}
private Dictionary<GameObject, Material[]> m_objectMaterials;
private MeshSimplify m_selectedMeshSimplify;
private bool m_bFinished = false;
private Mesh m_newMesh;
private int m_nLastProgress = -1;
private string m_strLastTitle = "";
private string m_strLastMessage = "";
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 10b6bfc6d6d946449bd6178082a26d5e
timeCreated: 1496044654
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 90d922b6196aab34697b544f28239ee2
timeCreated: 1434653219
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: