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,128 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace MeshCombineStudio
{
public class BaseOctree
{
public class Cell
{
public Cell mainParent;
public Cell parent;
// public Cell[] cells;
public bool[] cellsUsed;
public Bounds bounds;
public int cellIndex;
public int cellCount;
public int level = 0;
public int maxLevels;
public Cell() { }
public Cell(Vector3 position, Vector3 size, int maxLevels)
{
bounds = new Bounds(position, size);
this.maxLevels = maxLevels;
}
public Cell(Cell parent, int cellIndex, Bounds bounds)
{
if (parent != null)
{
maxLevels = parent.maxLevels;
mainParent = parent.mainParent;
level = parent.level + 1;
}
this.parent = parent;
this.cellIndex = cellIndex;
this.bounds = bounds;
}
public void SetCell(Cell parent, int cellIndex, Bounds bounds)
{
if (parent != null)
{
maxLevels = parent.maxLevels;
mainParent = parent.mainParent;
level = parent.level + 1;
}
this.parent = parent;
this.cellIndex = cellIndex;
this.bounds = bounds;
}
protected int AddCell<T, U>(ref T[] cells, Vector3 position, out bool maxCellCreated) where T : Cell, new() where U : Cell, new()
{
Vector3 localPos = position - bounds.min;
int x = (int)(localPos.x / bounds.extents.x);
int y = (int)(localPos.y / bounds.extents.y);
int z = (int)(localPos.z / bounds.extents.z);
int index = x + (y * 4) + (z * 2);
AddCell<T, U>(ref cells, index, x, y, z, out maxCellCreated);
return index;
}
protected void AddCell<T, U>(ref T[] cells, int index, int x, int y, int z, out bool maxCellCreated) where T : Cell, new() where U : Cell, new()
{
if (cells == null) { cells = new T[8]; }
if (cellsUsed == null) { cellsUsed = new bool[8]; }
// Reporter.Log("index "+index+" position "+localPos+" x: "+x+" y: "+y+" z: "+z+" extents "+bounds.extents);
if (!cellsUsed[index])
{
Bounds subBounds = new Bounds(new Vector3(bounds.min.x + (bounds.extents.x * (x + 0.5f)), bounds.min.y + (bounds.extents.y * (y + 0.5f)), bounds.min.z + (bounds.extents.z * (z + 0.5f))), bounds.extents);
if (level == maxLevels - 1)
{
cells[index] = new U() as T;
cells[index].SetCell(this, index, subBounds);
maxCellCreated = true;
}
else
{
maxCellCreated = false;
cells[index] = new T();
cells[index].SetCell(this, index, subBounds);
}
cellsUsed[index] = true;
++cellCount;
}
else maxCellCreated = false;
}
//public void RemoveCell(int index)
//{
// cells[index] = null;
// cellsUsed[index] = false;
// --cellCount;
// if (cellCount == 0)
// {
// if (parent != null) parent.RemoveCell(cellIndex);
// }
//}
public bool InsideBounds(Vector3 position)
{
position -= bounds.min;
if (position.x >= bounds.size.x || position.y >= bounds.size.y || position.z >= bounds.size.z || position.x <= 0 || position.y <= 0 || position.z <= 0) { return false; }
return true;
} //===============================================================================================================================
public void Reset(ref Cell[] cells)
{
cells = null;
cellsUsed = null;
}
}
}
}

View File

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

View File

@@ -0,0 +1,435 @@
using UnityEngine;
using System;
using System.Collections.Generic;
namespace MeshCombineStudio
{
public class ObjectOctree
{
public class LODParent
{
public GameObject cellGO;
public Transform cellT;
public LODGroup lodGroup;
public LODLevel[] lodLevels;
public bool hasChanged;
public int jobsPending;
public LODParent(int lodCount)
{
lodLevels = new LODLevel[lodCount];
for (int i = 0; i < lodLevels.Length; i++) lodLevels[i] = new LODLevel();
}
public void AssignLODGroup(MeshCombiner meshCombiner)
{
LOD[] lods = new LOD[lodLevels.Length];
int lodGroupParentIndex = lods.Length - 1;
for (int i = 0; i < lodLevels.Length; i++)
{
LODLevel lodLevel = lodLevels[i];
// Debug.Log(i + " " + lodLevel.newMeshRenderers.Count);
lods[i] = new LOD(meshCombiner.lodGroupsSettings[lodGroupParentIndex].lodSettings[i].screenRelativeTransitionHeight, lodLevel.newMeshRenderers.ToArray());
}
lodGroup.SetLODs(lods);
lodGroup.size = meshCombiner.cellSize;
}
public void ApplyChanges(MeshCombiner meshCombiner)
{
for (int i = 0; i < lodLevels.Length; i++) lodLevels[i].ApplyChanges(meshCombiner);
hasChanged = false;
}
}
public class LODLevel
{
public List<CachedGameObject> cachedGOs = new List<CachedGameObject>();
public List<MeshObjectsHolder> meshObjectsHolders;
public List<MeshObjectsHolder> changedMeshObjectsHolders;
public List<MeshRenderer> newMeshRenderers = new List<MeshRenderer>();
public int vertCount, objectCount = 0;
public int GetSortMeshIndex(Material mat, bool shadowCastingModeTwoSided, int lightmapIndex)
{
int matInstanceID = mat.GetInstanceID();
for (int i = 0; i < meshObjectsHolders.Count; i++)
{
MeshObjectsHolder meshObjectHolder = meshObjectsHolders[i];
// if (mat == null) Debug.Log("Material null");
if (meshObjectHolder.mat == null) { continue; }// Debug.Log("Sorted mat null");
if (meshObjectHolder.mat.GetInstanceID() == matInstanceID && meshObjectHolder.shadowCastingModeTwoSided == shadowCastingModeTwoSided && meshObjectHolder.lightmapIndex == lightmapIndex) return i;
// if (meshObjectHolder.mat.name == mat.name && meshObjectHolder.mat.shader == mat.shader && meshObjectHolder.shadowCastingModeTwoSided == shadowCastingModeTwoSided && meshObjectHolder.lightmapIndex == lightmapIndex &&
// (!mat.HasProperty("_MainTex") || (mat.HasProperty("_MainTex") && meshObjectHolder.mat.GetTexture("_MainTex") == mat.GetTexture("_MainTex")))) return i;
}
return -1;
}
public void ApplyChanges(MeshCombiner meshCombiner)
{
for (int i = 0; i < changedMeshObjectsHolders.Count; i++)
{
MeshObjectsHolder meshObjectHolder = changedMeshObjectsHolders[i];
meshObjectHolder.hasChanged = false;
}
changedMeshObjectsHolders.Clear();
}
}
public class MaxCell : Cell
{
static public int maxCellCount;
public LODParent[] lodParents;
public List<LODParent> changedLodParents;
public bool hasChanged;
public void ApplyChanges(MeshCombiner meshCombiner)
{
for (int i = 0; i < changedLodParents.Count; i++) changedLodParents[i].ApplyChanges(meshCombiner);
changedLodParents.Clear();
hasChanged = false;
}
}
public class Cell : BaseOctree.Cell
{
public Cell[] cells;
public Cell() { }
public Cell(Vector3 position, Vector3 size, int maxLevels) : base(position, size, maxLevels) { }
public CachedGameObject AddObject(Vector3 position, MeshCombiner meshCombiner, CachedGameObject cachedGO, int lodParentIndex, int lodLevel, bool isChangeMode = false)
{
if (InsideBounds(position))
{
AddObjectInternal(meshCombiner, cachedGO, position, lodParentIndex, lodLevel, isChangeMode);
return cachedGO;
}
return null;
}
void AddObjectInternal(MeshCombiner meshCombiner, CachedGameObject cachedGO, Vector3 position, int lodParentIndex, int lodLevel, bool isChangeMode)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
if (thisCell.lodParents == null) thisCell.lodParents = new LODParent[10];
if (thisCell.lodParents[lodParentIndex] == null) thisCell.lodParents[lodParentIndex] = new LODParent(lodParentIndex + 1);
LODParent lodParent = thisCell.lodParents[lodParentIndex];
LODLevel lod = lodParent.lodLevels[lodLevel];
lod.cachedGOs.Add(cachedGO);
if (isChangeMode)
{
if (SortObject(meshCombiner, lod, cachedGO))
{
if (!thisCell.hasChanged)
{
thisCell.hasChanged = true;
if (meshCombiner.changedCells == null) meshCombiner.changedCells = new List<MaxCell>();
meshCombiner.changedCells.Add(thisCell);
}
if (!lodParent.hasChanged)
{
lodParent.hasChanged = true;
thisCell.changedLodParents.Add(lodParent);
}
}
}
lod.objectCount++;
lod.vertCount += cachedGO.mesh.vertexCount;
return;
}
else
{
bool maxCellCreated;
int index = AddCell<Cell, MaxCell>(ref cells, position, out maxCellCreated);
if (maxCellCreated) MaxCell.maxCellCount++;
cells[index].AddObjectInternal(meshCombiner, cachedGO, position, lodParentIndex, lodLevel, isChangeMode);
}
}
public void SortObjects(MeshCombiner meshCombiner)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
LODParent[] lodParents = thisCell.lodParents;
for (int i = 0; i < lodParents.Length; i++)
{
LODParent lodParent = lodParents[i];
if (lodParent == null) continue;
for (int j = 0; j < lodParent.lodLevels.Length; j++)
{
LODLevel lod = lodParent.lodLevels[j];
if (lod == null || lod.cachedGOs.Count == 0) return;
for (int k = 0; k < lod.cachedGOs.Count; ++k)
{
CachedGameObject cachedGO = lod.cachedGOs[k];
if (!SortObject(meshCombiner, lod, cachedGO))
{
Methods.ListRemoveAt(lod.cachedGOs, k--);
}
}
}
}
}
else
{
for (int i = 0; i < 8; ++i)
{
if (cellsUsed[i]) cells[i].SortObjects(meshCombiner);
}
}
}
public bool SortObject(MeshCombiner meshCombiner, LODLevel lod, CachedGameObject cachedGO, bool isChangeMode = false)
{
if (cachedGO.mr == null) return false;
if (lod.meshObjectsHolders == null) lod.meshObjectsHolders = new List<MeshObjectsHolder>();
Material[] mats = cachedGO.mr.sharedMaterials;
// TODO check submeshes and material
int length = Mathf.Min(cachedGO.mesh.subMeshCount, mats.Length);
for (int l = 0; l < length; l++)
{
Material mat = mats[l];
if (mat == null) continue;
bool shadowCastingModeTwoSided = (cachedGO.mr.shadowCastingMode == UnityEngine.Rendering.ShadowCastingMode.TwoSided);
int lightmapIndex = meshCombiner.validCopyBakedLighting ? cachedGO.mr.lightmapIndex : -1;
int index = lod.GetSortMeshIndex(mat, shadowCastingModeTwoSided, lightmapIndex);
MeshObjectsHolder meshObjectHolder;
if (index == -1)
{
meshObjectHolder = new MeshObjectsHolder(cachedGO, mat, l, shadowCastingModeTwoSided, lightmapIndex);
lod.meshObjectsHolders.Add(meshObjectHolder);
}
else
{
meshObjectHolder = lod.meshObjectsHolders[index];
meshObjectHolder.meshObjects.Add(new MeshObject(cachedGO, l));
}
if (isChangeMode && !meshObjectHolder.hasChanged)
{
meshObjectHolder.hasChanged = true;
lod.changedMeshObjectsHolders.Add(meshObjectHolder);
}
}
return true;
}
public void CombineMeshes(MeshCombiner meshCombiner, int lodParentIndex)
{
if (level == maxLevels)
{
MaxCell thisCell = (MaxCell)this;
LODParent lodParent = thisCell.lodParents[lodParentIndex];
if (lodParent == null) return;
lodParent.cellGO = new GameObject(meshCombiner.useCells ? "Cell " + bounds.center : "Combined Objects");
lodParent.cellT = lodParent.cellGO.transform;
lodParent.cellT.position = bounds.center;
lodParent.cellT.parent = meshCombiner.lodParentHolders[lodParentIndex].t;
if (lodParentIndex > 0)
{
lodParent.lodGroup = lodParent.cellGO.AddComponent<LODGroup>();
lodParent.lodGroup.localReferencePoint = lodParent.cellT.position = bounds.center;
}
LODLevel[] lods = lodParent.lodLevels;
for (int i = 0; i < lods.Length; i++)
{
LODLevel lod = lodParent.lodLevels[i];
if (lod == null || lod.meshObjectsHolders == null) return;
GameObject lodGO;
Transform lodT = null;
if (lodParentIndex > 0)
{
lodGO = new GameObject("LOD" + i);
lodT = lodGO.transform;
lodT.parent = lodParent.cellT;
}
for (int k = 0; k < lod.meshObjectsHolders.Count; ++k)
{
MeshObjectsHolder sortedMeshes = lod.meshObjectsHolders[k];
sortedMeshes.lodParent = lodParent;
sortedMeshes.lodLevel = i;
MeshCombineJobManager.instance.AddJob(meshCombiner, sortedMeshes, lodParentIndex > 0 ? lodT : lodParent.cellT, bounds.center);
}
}
}
else
{
for (int i = 0; i < 8; ++i)
{
if (cellsUsed[i]) cells[i].CombineMeshes(meshCombiner, lodParentIndex);
}
}
}
public void Draw(MeshCombiner meshCombiner, bool onlyMaxLevel, bool drawLevel0)
{
if (!onlyMaxLevel || level == maxLevels || (drawLevel0 && level == 0))
{
Gizmos.DrawWireCube(bounds.center, bounds.size);
if (level == maxLevels)
{
if (meshCombiner.drawMeshBounds)
{
MaxCell thisCell = (MaxCell)this;
LODParent[] lodParents = thisCell.lodParents;
for (int i = 0; i < lodParents.Length; i++)
{
if (lodParents[i] == null) continue;
LODLevel[] lods = lodParents[i].lodLevels;
Gizmos.color = meshCombiner.activeOriginal ? Color.blue : Color.green;
for (int j = 0; j < lods.Length; j++)
{
for (int k = 0; k < lods[j].cachedGOs.Count; k++)
{
if (lods[j].cachedGOs[k].mr == null) continue;
Bounds meshBounds = lods[j].cachedGOs[k].mr.bounds;
Gizmos.DrawWireCube(meshBounds.center, meshBounds.size);
}
}
Gizmos.color = Color.white;
}
return;
}
}
}
if (cells == null || cellsUsed == null) { return; }
for (int i = 0; i < 8; i++)
{
if (cellsUsed[i]) cells[i].Draw(meshCombiner, onlyMaxLevel, drawLevel0);
}
}
}
}
[Serializable]
public class MeshObjectsHolder
{
public Material mat;
public List<MeshObject> meshObjects = new List<MeshObject>();
public ObjectOctree.LODParent lodParent;
public List<CachedGameObject> newCachedGOs;
public int lodLevel;
public int lightmapIndex;
public bool shadowCastingModeTwoSided;
public bool hasChanged;
public MeshObjectsHolder(CachedGameObject cachedGO, Material mat, int subMeshIndex, bool shadowCastingModeTwoSided, int lightmapIndex)
{
// Debug.Log(useForLightmapping);
this.mat = mat;
this.shadowCastingModeTwoSided = shadowCastingModeTwoSided;
this.lightmapIndex = lightmapIndex;
meshObjects.Add(new MeshObject(cachedGO, subMeshIndex));
}
}
[Serializable]
public class MeshObject
{
public CachedGameObject cachedGO;
public MeshCache meshCache;
public int subMeshIndex;
public Vector3 position, scale;
public Quaternion rotation;
public Vector4 lightmapScaleOffset;
public bool intersectsSurface;
public int startNewTriangleIndex, newTriangleCount;
public bool skip;
public MeshObject(CachedGameObject cachedGO, int subMeshIndex)
{
this.cachedGO = cachedGO;
this.subMeshIndex = subMeshIndex;
Transform t = cachedGO.t;
position = t.position;
rotation = t.rotation;
scale = t.lossyScale;
lightmapScaleOffset = cachedGO.mr.lightmapScaleOffset;
}
}
[Serializable]
public class CachedGameObject
{
public GameObject go;
public Transform t;
public MeshRenderer mr;
public MeshFilter mf;
public Mesh mesh;
public CachedGameObject(GameObject go, Transform t, MeshRenderer mr, MeshFilter mf, Mesh mesh)
{
this.go = go;
this.t = t;
this.mr = mr;
this.mf = mf;
this.mesh = mesh;
}
public CachedGameObject(CachedComponents cachedComponent)
{
go = cachedComponent.go;
t = cachedComponent.t;
mr = cachedComponent.mr;
mf = cachedComponent.mf;
mesh = cachedComponent.mf.sharedMesh;
}
}
[Serializable]
public class CachedLodGameObject : CachedGameObject
{
public Vector3 center;
public int lodCount, lodLevel;
public CachedLodGameObject(CachedGameObject cachedGO, int lodCount, int lodLevel) : base(cachedGO.go, cachedGO.t, cachedGO.mr, cachedGO.mf, cachedGO.mesh)
{
this.lodCount = lodCount;
this.lodLevel = lodLevel;
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 95bb6d48e5a70ec4bb2e73afcccda6c5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: