public void Create(Action finishAction) { MonoBehaviourHelper.maxSharedExecutionTimeMS = 50.0f; //Assets should be saved which changed. AssetDatabase.SaveAssets(); var lodGroups = FindAllGroups(); if (lodGroups.Count == 0) { return; } //find biggest bounds including all groups. var lodGroupList = lodGroups.Values.ToList(); Bounds bounds = CalcBounds(lodGroupList[0]); for (int i = 1; i < lodGroupList.Count; ++i) { bounds.Encapsulate(CalcBounds(lodGroupList[i])); } var rootVolume = LODVolume.Create(); rootVolume.SetLODGroups(lodGroups); rootVolume.Bounds = bounds; m_HLODRootContainer = new GameObject(k_HLODRootContainer); m_HLODRootContainer.AddComponent <SceneLODUpdater>(); m_GroupHLODRootContainer = new Dictionary <string, GameObject>(); StartCustomCoroutine(BuildOctree(rootVolume), CoroutineOrder.BuildTree); StartCustomCoroutine(BuildBatch(), CoroutineOrder.Batch); StartCustomCoroutine(EnqueueAction(finishAction), CoroutineOrder.Finish); StartCustomCoroutine(EnqueueAction(() => { if (rootVolume != null) { rootVolume.ResetLODGroup(); if (m_HLODRootContainer != null) { var updater = m_HLODRootContainer.GetComponent <SceneLODUpdater>(); updater.Build(rootVolume); DestroyImmediate(rootVolume.gameObject); } } }), CoroutineOrder.Finish); currentJobCount = 0; maxJobCount = m_JobContainer.First().Value.Count; currentProgress = 0; maxProgress = (int)CoroutineOrder.Finish + 1; }
IEnumerator UpdateOctree() { if (!m_RootVolume) { yield return(SetRootLODVolume()); if (!m_RootVolume) { if (m_CreateRootVolumeForScene == SceneManager.GetActiveScene().name) { Dbg.Log("Creating root volume"); m_RootVolume = LODVolume.Create(); } else { yield break; } } } var renderers = m_FoundRenderers; renderers.Clear(); yield return(ObjectUtils.FindObjectsOfType(renderers)); // Remove any renderers that should not be there (e.g. HLODs) renderers.RemoveAll(r => m_ExcludedRenderers.Contains(r)); renderers.RemoveAll(r => { if (r) { // Check against previous collection if (m_ExistingRenderers.Contains(r)) { return(false); } if (r.gameObject.layer == LayerMask.NameToLayer(LODVolume.HLODLayer)) { m_ExcludedRenderers.Add(r); return(true); } var mf = r.GetComponent <MeshFilter>(); if (!mf || (mf.sharedMesh && mf.sharedMesh.GetTopology(0) != MeshTopology.Triangles)) { m_ExcludedRenderers.Add(r); return(true); } var lodGroup = r.GetComponentInParent <LODGroup>(); if (lodGroup) { var lods = lodGroup.GetLODs(); // Skip LOD0, so that we keep the original renderers in the list for (int i = 1; i < lods.Length; i++) { if (lods[i].renderers.Contains(r)) { m_ExcludedRenderers.Add(r); return(true); } } } else { // HLODs should come after traditional LODs, so exclude any standalone renderers m_ExcludedRenderers.Add(r); return(true); } } return(false); }); var existingRenderers = m_ExistingRenderers; existingRenderers.Clear(); existingRenderers.UnionWith(m_RootVolume.renderers); var removed = m_RemovedRenderers; removed.Clear(); removed.UnionWith(m_ExistingRenderers); removed.ExceptWith(renderers); var added = m_AddedRenderers; added.Clear(); added.UnionWith(renderers); added.ExceptWith(existingRenderers); foreach (var r in removed) { if (existingRenderers.Contains(r)) { yield return(m_RootVolume.RemoveRenderer(r)); // Check if the BVH shrunk yield return(SetRootLODVolume()); } } foreach (var r in added) { if (!existingRenderers.Contains(r)) { yield return(m_RootVolume.AddRenderer(r)); r.transform.hasChanged = false; // Check if the BVH grew yield return(SetRootLODVolume()); } } }
IEnumerator BuildOctree(LODVolume volume) { var bounds = volume.Bounds; float boundsSize = Mathf.Max(bounds.extents.x, Mathf.Max(bounds.extents.y, bounds.extents.z)); yield return(BuildHLOD(volume)); //reserve logic. //UpdateLODGroup should be run after batch. StartCustomCoroutine(UpdateLODGroup(volume), CoroutineOrder.UpdateLOD); //Make a child if necessary. if (boundsSize < Config.VolumeSize) { yield break; } //Volume doesn't have any group for a split. if (volume.VolumeGroups.Count == 0) { yield break; } ; Vector3 size = bounds.size; size.x /= k_Splits; size.y /= k_Splits; size.z /= k_Splits; for (int i = 0; i < k_Splits; i++) { for (int j = 0; j < k_Splits; j++) { for (int k = 0; k < k_Splits; k++) { var lodVolume = LODVolume.Create(); var lodVolumeTransform = lodVolume.transform; lodVolumeTransform.parent = volume.transform; var center = bounds.min + size * 0.5f + Vector3.Scale(size, new Vector3(i, j, k)); lodVolumeTransform.position = center; lodVolume.Bounds = new Bounds(center, size); foreach (var volumeGroup in volume.VolumeGroups) { List <LODGroup> lodGroups = new List <LODGroup>(volumeGroup.LODGroups.Count); foreach (LODGroup group in volumeGroup.LODGroups) { if (WithinBounds(group, lodVolume.Bounds)) { lodGroups.Add(group); } } if (lodGroups.Count > 0) { lodVolume.SetLODGroups(volumeGroup.GroupName, lodGroups); } } volume.AddChild(lodVolume); yield return(BuildOctree(lodVolume)); } } } }