summaryrefslogtreecommitdiff
path: root/Runtime/Export/StaticBatching/CombineForStaticBatching.cs
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2019-08-14 22:50:43 +0800
committerchai <chaifix@163.com>2019-08-14 22:50:43 +0800
commit15740faf9fe9fe4be08965098bbf2947e096aeeb (patch)
treea730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Export/StaticBatching/CombineForStaticBatching.cs
+Unity Runtime codeHEADmaster
Diffstat (limited to 'Runtime/Export/StaticBatching/CombineForStaticBatching.cs')
-rw-r--r--Runtime/Export/StaticBatching/CombineForStaticBatching.cs230
1 files changed, 230 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