diff options
Diffstat (limited to 'Runtime/Export/StaticBatching')
-rw-r--r-- | Runtime/Export/StaticBatching/CombineForStaticBatching.cs | 230 | ||||
-rw-r--r-- | Runtime/Export/StaticBatching/MeshSubsetCombineUtility.cs | 30 |
2 files changed, 260 insertions, 0 deletions
diff --git a/Runtime/Export/StaticBatching/CombineForStaticBatching.cs b/Runtime/Export/StaticBatching/CombineForStaticBatching.cs new file mode 100644 index 0000000..ffe5477 --- /dev/null +++ b/Runtime/Export/StaticBatching/CombineForStaticBatching.cs @@ -0,0 +1,230 @@ +//using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + +#if !UNITY_FLASH// no static batching in flash + +namespace UnityEngine +{ +internal class InternalStaticBatchingUtility { + // assume 16bit indices + const int MaxVerticesInBatch = 64000; // a little bit less than 64K - just in case + const string CombinedMeshPrefix = "Combined Mesh"; + + static public void Combine (UnityEngine.GameObject staticBatchRoot) + { + Combine(staticBatchRoot, false); + } + + static public void Combine (UnityEngine.GameObject staticBatchRoot, bool combineOnlyStatic) + { + GameObject[] gos = (GameObject[])UnityEngine.Object.FindObjectsOfType(typeof(GameObject)); + + List<GameObject> filteredGos = new List<GameObject>(); + foreach (GameObject go in gos) + { + if (staticBatchRoot != null) + if (!go.transform.IsChildOf(staticBatchRoot.transform)) + continue; + + if (combineOnlyStatic && !go.isStaticBatchable ) + continue; + + filteredGos.Add(go); + } + + gos = filteredGos.ToArray(); + + // Inform user about Advanced license only feature + // real license guard is baked into the native code. + bool hasProOrAdvancedLicense = Application.HasProLicense() || Application.HasAdvancedLicense(); + if (!hasProOrAdvancedLicense) + { + // Display error only if invoked from the user script + if (staticBatchRoot != null && gos.Length > 0) + Debug.LogError("Your Unity license is not sufficient for Static Batching."); + } + + Combine(gos, staticBatchRoot); + } + + static public void Combine(GameObject[] gos, UnityEngine.GameObject staticBatchRoot) + { + Matrix4x4 staticBatchInverseMatrix = Matrix4x4.identity; + Transform staticBatchRootTransform = null; + if (staticBatchRoot) + { + staticBatchInverseMatrix = staticBatchRoot.transform.worldToLocalMatrix; + staticBatchRootTransform = staticBatchRoot.transform; + } + + int batchIndex = 0; + int verticesInBatch = 0; + List<MeshSubsetCombineUtility.MeshInstance> meshes = new List<MeshSubsetCombineUtility.MeshInstance>(); + List<MeshSubsetCombineUtility.SubMeshInstance> subsets = new List<MeshSubsetCombineUtility.SubMeshInstance>(); + List<GameObject> subsetGOs = new List<GameObject> (); + + Array.Sort(gos, new SortGO()); + + foreach (GameObject go in gos) + { + MeshFilter filter = go.GetComponent(typeof(MeshFilter)) as MeshFilter; + if (filter == null) + continue; + + // reject if has no mesh + if (filter.sharedMesh == null) + continue; + + // reject if mesh not readable + if (!filter.sharedMesh.canAccess) + continue; + + // reject if has not renderer or renderer is disabled + if (filter.renderer == null || !filter.renderer.enabled) + continue; + + // reject if already combined for static batching + if (filter.renderer.staticBatchIndex != 0) + continue; + + // check if we have enough space inside the current batch + if (verticesInBatch + filter.sharedMesh.vertexCount > MaxVerticesInBatch) + { + MakeBatch (meshes, subsets, subsetGOs, staticBatchRootTransform, batchIndex++); + meshes.Clear(); + subsets.Clear(); + subsetGOs.Clear(); + verticesInBatch = 0; + } + + MeshSubsetCombineUtility.MeshInstance instance = new MeshSubsetCombineUtility.MeshInstance (); + Mesh instanceMesh = filter.sharedMesh; + instance.meshInstanceID = instanceMesh.GetInstanceID(); + instance.transform = staticBatchInverseMatrix * filter.transform.localToWorldMatrix; + instance.lightmapTilingOffset = filter.renderer.lightmapTilingOffset; + + //;;Debug.Log("New static mesh (" + go.name + ")verts: " + instance.mesh.vertexCount + + // ", tris: " + instance.mesh.triangles.Length + + // ", materials: " + filter.renderer.sharedMaterials.Length + + // ", subs: " + instance.mesh.subMeshCount + // ); + + meshes.Add(instance); + + Material[] materials = filter.renderer.sharedMaterials; + if (materials.Length > instanceMesh.subMeshCount) + { + Debug.LogWarning("Mesh has more materials (" + materials.Length + ") than subsets (" + instanceMesh.subMeshCount + ")"); + // extra materials don't have a meaning and it screws the rendering as Unity + // tries to render with those extra materials. + Material[] newMats = new Material[instanceMesh.subMeshCount]; + for (int i = 0; i < instanceMesh.subMeshCount; ++i) + newMats[i] = filter.renderer.sharedMaterials[i]; + filter.renderer.sharedMaterials = newMats; + materials = newMats; + } + + for (int m = 0; m < System.Math.Min(materials.Length, instanceMesh.subMeshCount); ++m) + { + //;;Debug.Log(" new subset : " + m + ", tris " + instance.mesh.GetTriangles(m).Length); + MeshSubsetCombineUtility.SubMeshInstance subsetInstance = new MeshSubsetCombineUtility.SubMeshInstance(); + subsetInstance.meshInstanceID = filter.sharedMesh.GetInstanceID(); + subsetInstance.vertexOffset = verticesInBatch; + subsetInstance.subMeshIndex = m; + subsetInstance.gameObjectInstanceID = go.GetInstanceID(); + subsetInstance.transform = instance.transform; + subsets.Add(subsetInstance); + subsetGOs.Add(go); + } + verticesInBatch += instanceMesh.vertexCount; + } + + MakeBatch(meshes, subsets, subsetGOs, staticBatchRootTransform, batchIndex); + } + + static private void MakeBatch(List<MeshSubsetCombineUtility.MeshInstance> meshes, List<MeshSubsetCombineUtility.SubMeshInstance> subsets, List<GameObject> subsetGOs, Transform staticBatchRootTransform, int batchIndex) + { + if (meshes.Count < 2) + return; + + MeshSubsetCombineUtility.MeshInstance[] aMeshes = meshes.ToArray(); + MeshSubsetCombineUtility.SubMeshInstance[] aSubsets = subsets.ToArray(); + + string combinedMeshName = CombinedMeshPrefix; + combinedMeshName += " (root: " + ((staticBatchRootTransform != null)? staticBatchRootTransform.name: "scene") + ")"; + if (batchIndex > 0) + combinedMeshName += " " + (batchIndex + 1); + + Mesh combinedMesh = StaticBatchingUtility.InternalCombineVertices (aMeshes, combinedMeshName); + StaticBatchingUtility.InternalCombineIndices(aSubsets, combinedMesh); + + int subsetIndex = 0; + for (int item = 0; item < aSubsets.Length; item++) + { + MeshSubsetCombineUtility.SubMeshInstance i = aSubsets[item]; + GameObject go = subsetGOs[item]; + Mesh m = combinedMesh; + + MeshFilter filter = (MeshFilter)go.GetComponent(typeof(MeshFilter)); + filter.sharedMesh = m; + + go.renderer.SetSubsetIndex(i.subMeshIndex, subsetIndex); + go.renderer.staticBatchRootTransform = staticBatchRootTransform; + + // for some reason if GOs were created dynamically + // then we need to toggle renderer to avoid caching old geometry + go.renderer.enabled = false; + go.renderer.enabled = true; + + subsetIndex++; + } + } + + internal class SortGO : IComparer + { + int IComparer.Compare( object a, object b ) + { + if (a == b) + return 0; + + Renderer aRenderer = GetRenderer(a as GameObject); + Renderer bRenderer = GetRenderer(b as GameObject); + + int compare = GetMaterialId(aRenderer).CompareTo(GetMaterialId(bRenderer)); + if (compare == 0) + compare = GetLightmapIndex(aRenderer).CompareTo(GetLightmapIndex(bRenderer)); + return compare; + } + + static private int GetMaterialId(Renderer renderer) + { + if (renderer == null || renderer.sharedMaterial == null) + return 0; + return renderer.sharedMaterial.GetInstanceID(); + } + + static private int GetLightmapIndex(Renderer renderer) + { + if (renderer == null) + return -1; + return renderer.lightmapIndex; + } + + static private Renderer GetRenderer(GameObject go) + { + if (go == null) + return null; + MeshFilter filter = go.GetComponent(typeof(MeshFilter)) as MeshFilter; + if (filter == null) + return null; + + return filter.renderer; + } + } +} + +} // namespace UnityEngine + +#endif diff --git a/Runtime/Export/StaticBatching/MeshSubsetCombineUtility.cs b/Runtime/Export/StaticBatching/MeshSubsetCombineUtility.cs new file mode 100644 index 0000000..0c76f14 --- /dev/null +++ b/Runtime/Export/StaticBatching/MeshSubsetCombineUtility.cs @@ -0,0 +1,30 @@ +using UnityEngine; +using System.Collections; + +#if !UNITY_FLASH// no static batching in flash + +namespace UnityEngine +{ + +internal class MeshSubsetCombineUtility { + + public struct MeshInstance + { + public int meshInstanceID; + public Matrix4x4 transform; + public Vector4 lightmapTilingOffset; + } + + public struct SubMeshInstance + { + public int meshInstanceID; + public int vertexOffset; + public int gameObjectInstanceID; + public int subMeshIndex; + public Matrix4x4 transform; + } +} + +} // namespace UnityEngine + +#endif |