Files
VR-WuKong/Assets/ThirdParty/Tools/MeshCombineStudio/Scripts/Mesh/MeshCombiner.cs
2025-11-14 18:44:06 +08:00

1047 lines
38 KiB
C#

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine.Rendering;
namespace MeshCombineStudio
{
[ExecuteInEditMode]
public class MeshCombiner : MonoBehaviour
{
static public List<MeshCombiner> instances = new List<MeshCombiner>();
public enum ObjectType { Normal, LodGroup, LodRenderer }
public enum HandleComponent { Disable, Destroy };
public enum ObjectCenter { BoundsCenter, TransformPosition };
public enum BackFaceTriangleMode { Box, Direction }
public delegate void DefaultMethod();
public event DefaultMethod OnCombiningReady;
public MeshCombineJobManager.JobSettings jobSettings = new MeshCombineJobManager.JobSettings();
public LODGroupSettings[] lodGroupsSettings;
public ComputeShader computeDepthToArray;
public GameObject instantiatePrefab;
public const int maxLodCount = 8;
public string saveMeshesFolder;
public ObjectOctree.Cell octree;
public List<ObjectOctree.MaxCell> changedCells;
[NonSerialized] public bool octreeContainsObjects;
// Output Settings
public bool useCells = true;
public int cellSize = 32;
public Vector3 cellOffset;
public bool useVertexOutputLimit;
public int vertexOutputLimit = 65534;
public enum RebakeLightingMode { CopyLightmapUvs, RegenarateLightmapUvs };
public RebakeLightingMode rebakeLightingMode;
public bool copyBakedLighting, validCopyBakedLighting;
public bool rebakeLighting, validRebakeLighting;
#if UNITY_5 || UNITY_2017
public bool useLightProbes = true;
#else
public LightProbeUsage lightProbeUsage = LightProbeUsage.BlendProbes;
public ReflectionProbeUsage reflectionProbeUsage = ReflectionProbeUsage.BlendProbes;
public MotionVectorGenerationMode motionVectorGenerationMode = MotionVectorGenerationMode.Object;
#endif
public bool receiveShadows = true;
public ShadowCastingMode shadowCastingMode = ShadowCastingMode.On;
public int outputLayer = 0;
public int outputStatic = 0;
public float scaleInLightmap = 1;
public bool addMeshColliders = false;
public bool addMeshCollidersInRange = false;
public Bounds addMeshCollidersBounds;
public bool makeMeshesUnreadable = true;
public bool removeTrianglesBelowSurface;
public bool noColliders;
public LayerMask surfaceLayerMask;
public float maxSurfaceHeight = 1000;
public bool removeOverlappingTriangles;
public GameObject overlappingCollidersGO;
public LayerMask overlapLayerMask;
public int voxelizeLayer;
public int lodGroupLayer;
public bool removeBackFaceTriangles;
public BackFaceTriangleMode backFaceTriangleMode;
public Vector3 backFaceDirection;
public Bounds backFaceBounds;
public bool twoSidedShadows = true;
// Runtime Settings
public bool combineInRuntime;
public bool combineOnStart = true;
public bool useCombineSwapKey;
public KeyCode combineSwapKey = KeyCode.Tab;
public HandleComponent originalMeshRenderers = HandleComponent.Disable;
public HandleComponent originalLODGroups = HandleComponent.Disable;
public SearchOptions searchOptions;
public Vector3 oldPosition, oldScale;
public LodParentHolder[] lodParentHolders = new LodParentHolder[maxLodCount];
public List<CachedGameObject> foundObjects = new List<CachedGameObject>();
public List<CachedLodGameObject> foundLodObjects = new List<CachedLodGameObject>();
public List<LODGroup> foundLodGroups = new List<LODGroup>();
public List<Collider> foundColliders = new List<Collider>();
public HashSet<LODGroup> uniqueFoundLodGroups = new HashSet<LODGroup>();
public List<Mesh> unreadableMeshes = new List<Mesh>();
public HashSet<Mesh> selectImportSettingsMeshes = new HashSet<Mesh>();
public HashSet<MeshCombineJobManager.MeshCombineJob> meshCombineJobs = new HashSet<MeshCombineJobManager.MeshCombineJob>();
public int totalMeshCombineJobs;
public int mrDisabledCount = 0;
public bool combined = false;
public bool activeOriginal = true;
public bool combinedActive;
public bool drawGizmos = true;
public bool drawMeshBounds = true;
public int originalTotalVertices, originalTotalTriangles;
public int totalVertices, totalTriangles;
public int originalDrawCalls, newDrawCalls;
public int foundMaterialsCount;
public float combineTime;
public FastList<MeshColliderAdd> addMeshCollidersList = new FastList<MeshColliderAdd>();
HashSet<Transform> uniqueLodObjects = new HashSet<Transform>();
HashSet<Material> foundMaterials = new HashSet<Material>();
[NonSerialized] MeshCombiner thisInstance;
bool hasFoundFirstObject;
Bounds bounds;
[Serializable]
public class SearchOptions
{
public enum ComponentCondition { And, Or, Not };
public enum LODGroupSearchMode { LodGroup, LodRenderers };
public GameObject parent;
public ObjectCenter objectCenter;
public LODGroupSearchMode lodGroupSearchMode;
public bool useSearchBox = false;
public Bounds searchBoxBounds;
public bool searchBoxSquare;
public Vector3 searchBoxPivot;
public Vector3 searchBoxSize = new Vector3(25, 25, 25);
public bool useMaxBoundsFactor = true;
public float maxBoundsFactor = 1.5f;
public bool useVertexInputLimit = true;
public int vertexInputLimit = 5000;
public bool useLayerMask;
public LayerMask layerMask = ~0;
public bool useTag;
public string tag;
public bool useNameContains;
public List<string> nameContainList = new List<string>();
public bool onlyActive = true;
public bool onlyStatic = true;
public bool useComponentsFilter;
public ComponentCondition componentCondition;
public List<string> componentNameList = new List<string>();
public SearchOptions(GameObject parent)
{
this.parent = parent;
}
public void GetSearchBoxBounds()
{
searchBoxBounds = new Bounds(searchBoxPivot + new Vector3(0, searchBoxSize.y * 0.5f, 0), searchBoxSize);
}
}
public void AddMeshColliders()
{
for (int i = 0; i < addMeshCollidersList.Count; i++)
{
MeshColliderAdd mca = addMeshCollidersList.items[i];
mca.go.AddComponent<MeshCollider>().sharedMesh = mca.mesh;
}
addMeshCollidersList.Clear();
}
public void ExecuteOnCombiningReady()
{
if (OnCombiningReady != null) OnCombiningReady();
totalMeshCombineJobs = 0;
#if MCSCaves
if (removeOverlappingTriangles) CreateOverlapColliders.DestroyOverlapColliders(overlappingCollidersGO);
#endif
stopwatch.Stop();
combineTime = (float)stopwatch.ElapsedMilliseconds / 1000;
}
void Awake()
{
instances.Add(this);
thisInstance = this;
}
void OnEnable()
{
if (thisInstance == null)
{
instances.Add(this);
thisInstance = this;
}
}
void Start()
{
if (Application.isPlaying && !combineInRuntime) return;
InitMeshCombineJobManager();
if (instances[0] == this)
MeshCombineJobManager.instance.SetJobMode(jobSettings);
if (!Application.isPlaying && Application.isEditor) return;
// Debug.Log("Start");
StartRuntime();
}
// ==========================================================================================================================
void OnDestroy()
{
RestoreOriginalRenderersAndLODGroups();
thisInstance = null;
instances.Remove(this);
// if (!Application.isPlaying && Application.isEditor) return;
if (instances.Count == 0 && MeshCombineJobManager.instance != null)
{
Methods.Destroy(MeshCombineJobManager.instance.gameObject);
MeshCombineJobManager.instance = null;
}
}
static public MeshCombiner GetInstance(string name)
{
for (int i = 0; i < instances.Count; i++)
{
if (instances[i].gameObject.name == name) return instances[i];
}
return null;
}
public void CopyJobSettingsToAllInstances()
{
for (int i = 0; i < instances.Count; i++) instances[i].jobSettings.CopySettings(jobSettings);
}
public void InitMeshCombineJobManager()
{
if (MeshCombineJobManager.instance == null)
{
MeshCombineJobManager.CreateInstance(this, instantiatePrefab);
}
}
public void CreateLodGroupsSettings()
{
lodGroupsSettings = new LODGroupSettings[maxLodCount];
for (int i = 0; i < lodGroupsSettings.Length; i++) lodGroupsSettings[i] = new LODGroupSettings(i);
}
private void StartRuntime()
{
if (combineInRuntime)
{
if (combineOnStart) CombineAll();
if (useCombineSwapKey && originalMeshRenderers == HandleComponent.Disable && originalLODGroups == HandleComponent.Disable)
{
if (SwapCombineKey.instance == null) gameObject.AddComponent<SwapCombineKey>(); else SwapCombineKey.instance.meshCombinerList.Add(this);
}
}
}
// ==========================================================================================================================
public void DestroyCombinedObjects()
{
AbortAndClearMeshCombineJobs();
RestoreOriginalRenderersAndLODGroups();
Methods.DestroyChildren(transform);
combined = false;
}
void Reset()
{
DestroyCombinedObjects();
foundColliders.Clear();
foundObjects.Clear();
foundLodGroups.Clear();
uniqueLodObjects.Clear();
uniqueFoundLodGroups.Clear();
foundLodObjects.Clear();
unreadableMeshes.Clear();
ResetOctree();
hasFoundFirstObject = false;
bounds.center = bounds.size = Vector3.zero;
if (searchOptions.useSearchBox) searchOptions.GetSearchBoxBounds();
InitAndResetLodParentsCount();
}
public void AbortAndClearMeshCombineJobs()
{
foreach (var meshCombineJob in meshCombineJobs)
{
meshCombineJob.abort = true;
}
ClearMeshCombineJobs();
}
public void ClearMeshCombineJobs()
{
#if MCSCaves
if (removeOverlappingTriangles) CreateOverlapColliders.DestroyOverlapColliders(overlappingCollidersGO);
#endif
meshCombineJobs.Clear();
totalMeshCombineJobs = 0;
}
public void AddObjects(List<Transform> transforms, bool useSearchOptions, bool checkForLODGroups = true)
{
List<LODGroup> lodGroups = new List<LODGroup>();
if (checkForLODGroups)
{
for (int i = 0; i < transforms.Count; i++)
{
LODGroup lodGroup = transforms[i].GetComponent<LODGroup>();
if (lodGroup != null) lodGroups.Add(lodGroup);
}
if (lodGroups.Count > 0) AddLodGroups(lodGroups.ToArray(), useSearchOptions);
}
AddTransforms(transforms.ToArray(), useSearchOptions);
}
public void AddObjectsAutomatically()
{
Reset();
AddObjectsFromSearchParent();
AddFoundObjectsToOctree();
if (octreeContainsObjects) octree.SortObjects(this);
if (Console.instance != null) LogOctreeInfo();
}
public void AddFoundObjectsToOctree()
{
if (foundObjects.Count > 0 || foundLodObjects.Count > 0) octreeContainsObjects = true;
else
{
Debug.Log("No matching GameObjects with chosen search options are found for combining.");
return;
}
foundMaterials.Clear();
CalcOctreeSize(bounds);
ObjectOctree.MaxCell.maxCellCount = 0;
for (int i = 0; i < foundObjects.Count; i++)
{
CachedGameObject foundObject = foundObjects[i];
AddFoundMaterials(foundObject.mr);
Vector3 position = (searchOptions.objectCenter == ObjectCenter.TransformPosition ? foundObject.t.position : foundObject.mr.bounds.center);
octree.AddObject(position, this, foundObject, 0, 0);
}
for (int i = 0; i < foundLodObjects.Count; i++)
{
CachedLodGameObject cachedLodGO = foundLodObjects[i];
AddFoundMaterials(cachedLodGO.mr);
octree.AddObject(cachedLodGO.center, this, cachedLodGO, cachedLodGO.lodCount, cachedLodGO.lodLevel);
}
foundMaterialsCount = foundMaterials.Count;
}
// ==========================================================================================================================
void AddFoundMaterials(MeshRenderer mr)
{
Material[] mats = mr.sharedMaterials;
for (int i = 0; i < mats.Length; i++)
{
if (mats[i]) foundMaterials.Add(mats[i]);
}
}
public void ResetOctree()
{
// Debug.Log("ResetOctree");
octreeContainsObjects = false;
if (octree == null) { octree = new ObjectOctree.Cell(); return; }
BaseOctree.Cell[] cells = octree.cells;
octree.Reset(ref cells);
}
// ==========================================================================================================================
public void CalcOctreeSize(Bounds bounds)
{
float size;
int levels;
Methods.SnapBoundsAndPreserveArea(ref bounds, cellSize, useCells ? cellOffset : Vector3.zero);
if (useCells)
{
float areaSize = Mathf.Max(Mathw.GetMax(bounds.size), cellSize);
levels = Mathf.CeilToInt(Mathf.Log(areaSize / cellSize, 2));
size = (int)Mathf.Pow(2, levels) * cellSize;
}
else
{
size = Mathw.GetMax(bounds.size);
levels = 0;
}
if (levels == 0 && octree is ObjectOctree.Cell) octree = new ObjectOctree.MaxCell();
else if (levels > 0 && octree is ObjectOctree.MaxCell) octree = new ObjectOctree.Cell();
octree.maxLevels = levels;
octree.bounds = new Bounds(bounds.center, new Vector3(size, size, size));
// Debug.Log("size " + size + " levels " + levels);
}
// ==========================================================================================================================
public void ApplyChanges()
{
validRebakeLighting = rebakeLighting && !validCopyBakedLighting && !Application.isPlaying && Application.isEditor;
for (int i = 0; i < changedCells.Count; i++)
{
ObjectOctree.MaxCell maxCell = changedCells[i];
maxCell.hasChanged = false;
maxCell.ApplyChanges(this);
}
changedCells.Clear();
}
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
public void CombineAll()
{
stopwatch.Reset();
stopwatch.Start();
#if MCSCaves
RemoveOverlappingTris.triangles.Clear();
#endif
addMeshCollidersList.Clear();
unreadableMeshes.Clear();
selectImportSettingsMeshes.Clear();
AddObjectsAutomatically();
if (!octreeContainsObjects) return;
SetOriginalCollidersActive(false);
#if MCSCaves
if (removeOverlappingTriangles)
{
if (CreateOverlapColliders.IsAnythingOnFreeLayers(voxelizeLayer, lodGroupLayer)) return;
CreateOverlapColliders.Create(transform, overlapLayerMask, lodGroupLayer, ref overlappingCollidersGO);
}
#endif
validRebakeLighting = rebakeLighting && !validCopyBakedLighting && !Application.isPlaying && Application.isEditor;
totalVertices = totalTriangles = originalTotalVertices = originalTotalTriangles = originalDrawCalls = newDrawCalls = 0;
for (int i = 0; i < lodParentHolders.Length; i++)
{
LodParentHolder lodParentHolder = lodParentHolders[i];
if (!lodParentHolder.found) continue;
if (lodParentHolder.go == null) lodParentHolder.Create(this, i);
octree.CombineMeshes(this, i);
}
if (MeshCombineJobManager.instance.jobSettings.combineJobMode == MeshCombineJobManager.CombineJobMode.CombineAtOnce) MeshCombineJobManager.instance.ExecuteJobs();
combinedActive = true;
combined = true;
activeOriginal = false;
ExecuteHandleObjects(activeOriginal, HandleComponent.Disable, HandleComponent.Disable, false);
#if UNITY_EDITOR
UnityEditor.EditorUtility.SetDirty(this);
#endif
}
// ==========================================================================================================================
void InitAndResetLodParentsCount()
{
for (int i = 0; i < lodParentHolders.Length; i++)
{
if (lodParentHolders[i] == null) lodParentHolders[i] = new LodParentHolder(i + 1);
else lodParentHolders[i].Reset();
}
}
public void AddObjectsFromSearchParent()
{
if (searchOptions.parent == null)
{
Debug.Log("You need to assign a 'Parent' GameObject in which meshes will be searched");
return;
}
LODGroup[] lodGroups = searchOptions.parent.GetComponentsInChildren<LODGroup>(true);
AddLodGroups(lodGroups);
Transform[] transforms = searchOptions.parent.GetComponentsInChildren<Transform>(true);
AddTransforms(transforms);
if (addMeshColliders)
{
for (int i = 0; i < foundObjects.Count; i++)
{
foundColliders.AddRange(foundObjects[i].go.GetComponentsInChildren<Collider>(false));
}
for (int i = 0; i < foundLodGroups.Count; i++)
{
foundColliders.AddRange(foundLodGroups[i].gameObject.GetComponentsInChildren<Collider>(false));
}
}
}
// ==========================================================================================================================
void AddLodGroups(LODGroup[] lodGroups, bool useSearchOptions = true)
{
List<CachedLodGameObject> cachedLodRenderers = new List<CachedLodGameObject>();
CachedGameObject cachedGODummy = null;
for (int i = 0; i < lodGroups.Length; i++)
{
LODGroup lodGroup = lodGroups[i];
bool validLodGroup;
if (searchOptions.lodGroupSearchMode == SearchOptions.LODGroupSearchMode.LodGroup) validLodGroup = (ValidObject(lodGroup.transform, ObjectType.LodGroup, useSearchOptions, ref cachedGODummy) == 1);
else
{
if (searchOptions.onlyActive && !lodGroup.gameObject.activeInHierarchy) continue;
validLodGroup = true;
}
LOD[] lods = lodGroup.GetLODs();
int lodParentIndex = lods.Length - 1;
if (lodParentIndex <= 0) continue;
// Debug.Log(lods.Length);
Vector3 center = Vector3.zero;
int rendererCount = 0;
for (int j = 0; j < lods.Length; j++)
{
LOD lod = lods[j];
for (int k = 0; k < lod.renderers.Length; k++)
{
Renderer r = lod.renderers[k];
if (!r) continue;
if (validLodGroup)
{
CachedGameObject cachedGO = null;
int result = ValidObject(r.transform, ObjectType.LodRenderer, useSearchOptions, ref cachedGO);
if (result == -1) continue;
else if (result == -2)
{
cachedLodRenderers.Clear();
goto breakLoop;
}
cachedLodRenderers.Add(new CachedLodGameObject(cachedGO, lodParentIndex, j));
if (searchOptions.objectCenter == ObjectCenter.BoundsCenter)
{
center += cachedGO.mr.bounds.center;
rendererCount++;
}
}
uniqueLodObjects.Add(r.transform);
}
}
breakLoop:
if (cachedLodRenderers.Count > 0)
{
if (searchOptions.objectCenter == ObjectCenter.BoundsCenter) center /= rendererCount;
else center = lodGroup.transform.position;
for (int j = 0; j < cachedLodRenderers.Count; j++)
{
CachedLodGameObject cachedLodGO = cachedLodRenderers[j];
cachedLodGO.center = center;
if (!hasFoundFirstObject) { bounds.center = cachedLodGO.mr.bounds.center; hasFoundFirstObject = true; }
bounds.Encapsulate(cachedLodGO.mr.bounds);
foundLodObjects.Add(cachedLodGO);
lodParentHolders[lodParentIndex].found = true;
lodParentHolders[lodParentIndex].lods[cachedLodGO.lodLevel]++;
}
uniqueFoundLodGroups.Add(lodGroup);
cachedLodRenderers.Clear();
}
}
foundLodGroups = new List<LODGroup>(uniqueFoundLodGroups);
}
void AddTransforms(Transform[] transforms, bool useSearchOptions = true)
{
int uniqueLodObjectsCount = uniqueLodObjects.Count;
for (int i = 0; i < transforms.Length; i++)
{
Transform t = transforms[i];
if (uniqueLodObjectsCount > 0 && uniqueLodObjects.Contains(t)) continue;
CachedGameObject cachedGO = null;
if (ValidObject(t, ObjectType.Normal, useSearchOptions, ref cachedGO) == 1)
{
if (!hasFoundFirstObject) { bounds.center = cachedGO.mr.bounds.center; hasFoundFirstObject = true; }
bounds.Encapsulate(cachedGO.mr.bounds);
foundObjects.Add(cachedGO);
lodParentHolders[0].lods[0]++;
}
}
if (foundObjects.Count > 0) lodParentHolders[0].found = true;
// Debug.Log("Count " + count);
// Debug.Log(foundObjects.Count);
}
// ==========================================================================================================================
int ValidObject(Transform t, ObjectType objectType, bool useSearchOptions, ref CachedGameObject cachedGameObject)
{
GameObject go = t.gameObject;
MeshRenderer mr = null;
MeshFilter mf = null;
Mesh mesh = null;
if (objectType != ObjectType.LodGroup || searchOptions.lodGroupSearchMode == SearchOptions.LODGroupSearchMode.LodRenderers)
{
mr = t.GetComponent<MeshRenderer>();
if (mr == null || !mr.enabled) return -1;
mf = t.GetComponent<MeshFilter>();
if (mf == null) return -1;
mesh = mf.sharedMesh;
if (mesh == null) return -1;
if (!mesh.isReadable)
{
Debug.LogError("Mesh Combine Studio -> Read/Write is disabled on the mesh on GameObject " + go.name + " and can't be combined. Click the 'Make Meshes Readable' in the MCS Inspector to make it automatically readable in the mesh import settings.");
unreadableMeshes.Add(mesh);
return -1;
}
}
if (useSearchOptions)
{
if (searchOptions.onlyActive && !go.activeInHierarchy) return -1;
if (objectType != ObjectType.LodRenderer || searchOptions.lodGroupSearchMode == SearchOptions.LODGroupSearchMode.LodRenderers)
{
if (searchOptions.useLayerMask)
{
int layer = 1 << t.gameObject.layer;
if ((searchOptions.layerMask.value & layer) != layer) return -1;
}
if (searchOptions.onlyStatic && !go.isStatic) return -1;
if (searchOptions.useTag)
{
if (!t.CompareTag(searchOptions.tag)) return -1;
}
if (searchOptions.useComponentsFilter)
{
if (searchOptions.componentCondition == SearchOptions.ComponentCondition.And)
{
bool pass = true;
for (int j = 0; j < searchOptions.componentNameList.Count; j++)
{
if (t.GetComponent(searchOptions.componentNameList[j]) == null) { pass = false; break; }
}
if (!pass) return -1;
}
else if (searchOptions.componentCondition == SearchOptions.ComponentCondition.Or)
{
bool pass = false;
for (int j = 0; j < searchOptions.componentNameList.Count; j++)
{
if (t.GetComponent(searchOptions.componentNameList[j]) != null) { pass = true; break; }
}
if (!pass) return -1;
}
else
{
bool pass = true;
for (int j = 0; j < searchOptions.componentNameList.Count; j++)
{
if (t.GetComponent(searchOptions.componentNameList[j]) != null) { pass = false; break; }
}
if (!pass) return -1;
}
}
if (searchOptions.useNameContains)
{
bool found = false;
for (int k = 0; k < searchOptions.nameContainList.Count; k++)
{
if (Methods.Contains(t.name, searchOptions.nameContainList[k])) { found = true; break; }
}
if (!found) return -1;
}
if (searchOptions.useSearchBox)
{
if (searchOptions.objectCenter == ObjectCenter.BoundsCenter)
{
if (!searchOptions.searchBoxBounds.Contains(mr.bounds.center)) return -2;
}
else if (!searchOptions.searchBoxBounds.Contains(t.position)) return -2;
}
}
if (objectType != ObjectType.LodGroup)
{
if (searchOptions.useVertexInputLimit && mesh.vertexCount > searchOptions.vertexInputLimit) return -2;
if (useVertexOutputLimit && mesh.vertexCount > vertexOutputLimit) return -2;
if (searchOptions.useMaxBoundsFactor && useCells)
{
if (Mathw.GetMax(mr.bounds.size) > cellSize * searchOptions.maxBoundsFactor) return -2;
}
}
}
if (objectType != ObjectType.LodGroup)
{
cachedGameObject = new CachedGameObject(go, t, mr, mf, mesh);
}
return 1;
}
public void RestoreOriginalRenderersAndLODGroups()
{
if (activeOriginal) return;
activeOriginal = true;
ExecuteHandleObjects(activeOriginal, HandleComponent.Disable, HandleComponent.Disable);
}
public void SwapCombine()
{
if (!combined) { CombineAll(); }
combinedActive = !combinedActive;
ExecuteHandleObjects(!combinedActive, originalMeshRenderers, originalLODGroups);
}
void SetOriginalCollidersActive(bool active)
{
for (int i = 0; i < foundColliders.Count; i++)
{
Collider collider = foundColliders[i];
if (collider) collider.enabled = active;
else Methods.ListRemoveAt(foundColliders, i--);
}
}
public void ExecuteHandleObjects(bool active, HandleComponent handleOriginalObjects, HandleComponent handleOriginalLodGroups, bool includeColliders = true)
{
Methods.SetChildrenActive(transform, !active);
if (handleOriginalObjects == HandleComponent.Disable)
{
if (includeColliders) SetOriginalCollidersActive(active);
for (int i = 0; i < foundObjects.Count; i++)
{
CachedGameObject cachedGO = foundObjects[i];
if (cachedGO.mr) cachedGO.mr.enabled = active;
else Methods.ListRemoveAt(foundObjects, i--);
}
for (int i = 0; i < foundLodObjects.Count; i++)
{
CachedLodGameObject cachedLodGO = foundLodObjects[i];
if (cachedLodGO.mr) cachedLodGO.mr.enabled = active;
else Methods.ListRemoveAt(foundLodObjects, i--);
}
}
if (handleOriginalObjects == HandleComponent.Destroy)
{
for (int i = 0; i < foundColliders.Count; i++)
{
Collider collider = foundColliders[i];
if (collider) Destroy(collider);
else Methods.ListRemoveAt(foundColliders, i--);
}
for (int i = 0; i < foundObjects.Count; i++)
{
bool remove = false;
CachedGameObject cachedGO = foundObjects[i];
if (cachedGO.mf) Destroy(cachedGO.mf);
else remove = true;
if (cachedGO.mr) Destroy(cachedGO.mr);
else remove = true;
if (remove) Methods.ListRemoveAt(foundObjects, i--);
}
for (int i = 0; i < foundLodObjects.Count; i++)
{
bool remove = false;
CachedGameObject cachedGO = foundLodObjects[i];
if (cachedGO.mf) Destroy(cachedGO.mf);
else remove = true;
if (cachedGO.mr) Destroy(cachedGO.mr);
else remove = true;
if (remove) Methods.ListRemoveAt(foundLodObjects, i--);
}
}
if (handleOriginalLodGroups == HandleComponent.Disable)
{
for (int i = 0; i < foundLodGroups.Count; i++)
{
LODGroup lodGroup = foundLodGroups[i];
if (lodGroup) lodGroup.enabled = active;
}
}
else if (handleOriginalLodGroups == HandleComponent.Destroy)
{
for (int i = 0; i < foundLodGroups.Count; i++)
{
LODGroup lodGroup = foundLodGroups[i];
if (lodGroup != null) Destroy(lodGroup);
}
}
}
void DrawGizmosCube(Bounds bounds, Color color)
{
Gizmos.color = color;
Gizmos.DrawWireCube(bounds.center, bounds.size);
Gizmos.color = new Color(color.r, color.g, color.b, 0.5f);
Gizmos.DrawCube(bounds.center, bounds.size);
Gizmos.color = Color.white;
}
void OnDrawGizmosSelected()
{
if (addMeshColliders && addMeshCollidersInRange)
{
DrawGizmosCube(addMeshCollidersBounds, Color.green);
}
if (removeBackFaceTriangles)
{
if (backFaceTriangleMode == BackFaceTriangleMode.Box)
{
DrawGizmosCube(backFaceBounds, Color.blue);
}
}
if (!drawGizmos) return;
if (octree != null && octreeContainsObjects)
{
octree.Draw(this, true, !searchOptions.useSearchBox);
}
if (searchOptions.useSearchBox)
{
searchOptions.GetSearchBoxBounds();
Gizmos.color = Color.green;
Gizmos.DrawWireCube(searchOptions.searchBoxBounds.center, searchOptions.searchBoxBounds.size);
Gizmos.color = Color.white;
}
}
// ==========================================================================================================================
void LogOctreeInfo()
{
Console.Log("Cells " + ObjectOctree.MaxCell.maxCellCount + " -> Found Objects: ");
LodParentHolder[] lodParentsCount = lodParentHolders;
if (lodParentsCount == null || lodParentsCount.Length == 0) return;
for (int i = 0; i < lodParentsCount.Length; i++)
{
LodParentHolder lodParentCount = lodParentsCount[i];
if (!lodParentCount.found) continue;
string text = "";
text = "LOD Group " + (i + 1) + " |";
int[] lods = lodParentCount.lods;
for (int j = 0; j < lods.Length; j++)
{
text += " " + lods[j].ToString() + " |";
}
Console.Log(text);
}
}
[Serializable]
public class LODGroupSettings
{
public LODSettings[] lodSettings;
public LODGroupSettings(int lodParentIndex)
{
int lodCount = lodParentIndex + 1;
lodSettings = new LODSettings[lodCount];
float percentage = 1.0f / lodCount;
for (int i = 0; i < lodSettings.Length; i++)
{
lodSettings[i] = new LODSettings(1 - (percentage * (i + 1)));
}
}
}
[Serializable]
public class LODSettings
{
public float screenRelativeTransitionHeight;
public float fadeTransitionWidth;
public LODSettings(float screenRelativeTransitionHeight)
{
this.screenRelativeTransitionHeight = screenRelativeTransitionHeight;
}
}
public class LodParentHolder
{
public GameObject go;
public Transform t;
public bool found;
public int[] lods;
public LodParentHolder(int lodCount)
{
lods = new int[lodCount];
}
public void Create(MeshCombiner meshCombiner, int lodParentIndex)
{
if (meshCombiner.foundLodGroups.Count == 0)
{
go = new GameObject("Cells");
}
else
{
go = new GameObject("LODGroup " + (lodParentIndex + 1));
var lodGroupSetup = go.AddComponent<LODGroupSetup>();
lodGroupSetup.Init(meshCombiner, lodParentIndex);
}
t = go.transform;
Transform parentT = t.transform;
parentT.parent = meshCombiner.transform;
}
public void Reset()
{
found = false;
Array.Clear(lods, 0, lods.Length);
}
}
}
public struct MeshColliderAdd
{
public GameObject go;
public Mesh mesh;
public MeshColliderAdd(GameObject go, Mesh mesh)
{
this.go = go;
this.mesh = mesh;
}
}
}