Ejemplo n.º 1
0
            static void PersistHLODs(LODVolume lodVolume, string scenePath)
            {
                var hlodRoot = lodVolume.hlodRoot;

                if (hlodRoot)
                {
                    var mf = hlodRoot.GetComponent <MeshFilter>();
                    if (mf)
                    {
                        var sharedMesh = mf.sharedMesh;
                        if (string.IsNullOrEmpty(AssetDatabase.GetAssetPath(sharedMesh)))
                        {
                            SaveUniqueHLODAsset(sharedMesh, scenePath);
                        }
                    }
                }

                foreach (Transform child in lodVolume.transform)
                {
                    var childLODVolume = child.GetComponent <LODVolume>();
                    if (childLODVolume)
                    {
                        PersistHLODs(childLODVolume, scenePath);
                    }
                }
            }
Ejemplo n.º 2
0
        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;
        }
Ejemplo n.º 3
0
    public static LODVolume Create()
    {
        GameObject go = new GameObject(k_DefaultName + s_VolumesCreated++, typeof(LODVolume));

        go.layer = LayerMask.NameToLayer(HLODLayer);
        LODVolume volume = go.GetComponent <LODVolume>();

        return(volume);
    }
Ejemplo n.º 4
0
        IEnumerator BuildHLOD(LODVolume volume)
        {
            foreach (var volumeGroup in volume.VolumeGroups)
            {
                string groupName = volumeGroup.GroupName;
                if (m_GroupHLODRootContainer.ContainsKey(groupName) == false)
                {
                    var groupRoot = new GameObject(groupName);
                    groupRoot.layer            = LayerMask.NameToLayer(LODVolume.HLODLayer);
                    groupRoot.transform.parent = m_HLODRootContainer.transform;
                    m_GroupHLODRootContainer.Add(groupName, groupRoot);
                }

                yield return(CreateHLODObject(volumeGroup.LODGroups, volume.Bounds, volumeGroup, volume.gameObject.name));
            }
        }
Ejemplo n.º 5
0
        IEnumerator SetRootLODVolume()
        {
            if (m_RootVolume)
            {
                var rootVolumeTransform = m_RootVolume.transform;
                var transformRoot       = rootVolumeTransform.root;

                // Handle the case where the BVH has grown
                if (rootVolumeTransform != transformRoot)
                {
                    m_RootVolume = transformRoot.GetComponent <LODVolume>();
                }

                yield break;
            }

            // Handle initialization or the case where the BVH has shrunk
            LODVolume lodVolume       = null;
            var       scene           = SceneManager.GetActiveScene();
            var       rootGameObjects = scene.GetRootGameObjects();

            foreach (var go in rootGameObjects)
            {
                if (!go)
                {
                    continue;
                }

                lodVolume = go.GetComponent <LODVolume>();
                if (lodVolume)
                {
                    break;
                }

                yield return(null);
            }

            if (lodVolume)
            {
                m_RootVolume = lodVolume;
            }

            m_ExcludedRenderers.Clear();
        }
Ejemplo n.º 6
0
    IEnumerator Shrink()
    {
        var populatedChildrenNodes = 0;

        foreach (Transform child in transform)
        {
            var lodVolume = child.GetComponent <LODVolume>();
            var renderers = lodVolume.renderers;
            if (renderers != null && renderers.Count > 0 && renderers.Count(r => r != null) > 0)
            {
                populatedChildrenNodes++;
            }

            yield return(null);
        }

        if (populatedChildrenNodes <= 1)
        {
            var       lodVolumes    = GetComponentsInChildren <LODVolume>();
            LODVolume newRootVolume = null;
            if (lodVolumes.Length > 0)
            {
                newRootVolume = lodVolumes[lodVolumes.Length - 1];
                newRootVolume.transform.parent = null;
            }

            // Clean up child HLODs before destroying the GameObject; Otherwise, we'd leak into the scene
            foreach (var lodVolume in lodVolumes)
            {
                if (lodVolume != newRootVolume)
                {
                    lodVolume.CleanupHLOD();
                }
            }
            DestroyImmediate(gameObject);

            if (newRootVolume)
            {
                yield return(newRootVolume.Shrink());
            }
        }
    }
Ejemplo n.º 7
0
        IEnumerator UpdateLODGroup(LODVolume volume)
        {
            List <Renderer> lodRenderers = new List <Renderer>();

            foreach (var volumeGroup in volume.VolumeGroups)
            {
                if (volumeGroup.HLODObject == null)
                {
                    continue;
                }

                lodRenderers.AddRange(volumeGroup.HLODObject.GetComponentsInChildren <Renderer>(false));
            }

            LOD lod       = new LOD();
            LOD detailLOD = new LOD();

            detailLOD.screenRelativeTransitionHeight = Config.LODRange;
            lod.screenRelativeTransitionHeight       = 0.0f;

            var lodGroup = volume.GetComponent <LODGroup>();

            if (!lodGroup)
            {
                lodGroup = volume.gameObject.AddComponent <LODGroup>();
            }

            volume.LodGroup = lodGroup;

            lod.renderers = lodRenderers.ToArray();
            lodGroup.SetLODs(new LOD[] { detailLOD, lod });

            //bounds is cuboid.
            //it has the same size each axis.
            lodGroup.size = volume.Bounds.size.x;
            yield break;
        }
Ejemplo n.º 8
0
        bool UpdateLODGroup(LODVolume lodVolume, Camera camera, Vector3 cameraPosition, bool fastPath)
        {
            var lodGroupEnabled = s_HLODEnabled;

            var lodGroup       = lodVolume.lodGroup;
            var lodGroupExists = lodGroup != null && lodGroup.lodGroup;

            // Start with leaf nodes first
            var lodVolumeTransform = lodVolume.transform;
            var childVolumes       = lodVolume.childVolumes;

            foreach (var childVolume in childVolumes)
            {
                if (childVolume)
                {
                    if (!fastPath || !lodGroupExists || !lodGroup.lodGroup.enabled)
                    {
                        lodGroupEnabled &= UpdateLODGroup(childVolume, camera, cameraPosition, fastPath);
                    }
                }
            }

            if (lodGroupEnabled)
            {
                var allChildrenUsingCoarsestLOD = true;
                if (lodVolumeTransform.childCount == 0) // Leaf node
                {
                    var cached = lodVolume.cached;

                    // Disable all children LODGroups if an HLOD LODGroup could replace it
                    foreach (var r in cached)
                    {
                        var childLODGroup = r as LODVolume.LODGroupHelper;

                        if (childLODGroup != null && childLODGroup.GetCurrentLOD(camera, cameraPosition) != childLODGroup.GetMaxLOD())
                        {
                            allChildrenUsingCoarsestLOD = false;
                            break;
                        }
                    }

                    foreach (var r in cached)
                    {
                        var childLODGroup = r as LODVolume.LODGroupHelper;

                        if (childLODGroup != null)
                        {
                            childLODGroup.SetEnabled(!allChildrenUsingCoarsestLOD);
                        }
                        else if (r != null)
                        {
                            ((Renderer)r).enabled = !allChildrenUsingCoarsestLOD;
                        }
                    }
                }
                else
                {
                    foreach (var childVolume in childVolumes)
                    {
                        var childLODGroup = childVolume.lodGroup;
                        if (childLODGroup != null && childLODGroup.lodGroup)
                        {
                            var maxLOD = childLODGroup.GetMaxLOD();
                            if (maxLOD > 0 && childLODGroup.GetCurrentLOD(camera, cameraPosition) != maxLOD)
                            {
                                allChildrenUsingCoarsestLOD = false;
                                break;
                            }
                        }
                    }

                    foreach (var childVolume in childVolumes)
                    {
                        var childLODGroup = childVolume.lodGroup;
                        if (childLODGroup != null && childLODGroup.lodGroup)
                        {
                            childLODGroup.SetEnabled(!allChildrenUsingCoarsestLOD);
                        }
                    }
                }

                lodGroupEnabled &= allChildrenUsingCoarsestLOD;
            }
            else if (!s_HLODEnabled && lodVolumeTransform.childCount == 0) // Re-enable default renderers
            {
                foreach (var r in lodVolume.renderers)
                {
                    if (!r)
                    {
                        continue;
                    }

                    var childLODGroup = r.GetComponentInParent <LODGroup>();
                    if (childLODGroup)
                    {
                        childLODGroup.SetEnabled(true);
                    }
                    else
                    {
                        r.enabled = true;
                    }
                }
            }

            if (lodGroupExists)
            {
                lodGroup.SetEnabled(lodGroupEnabled);
            }

            return(lodGroupEnabled);
        }
Ejemplo n.º 9
0
        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());
                }
            }
        }
Ejemplo n.º 10
0
 public void AddChild(LODVolume volume)
 {
     childVolumes.Add(volume);
 }
Ejemplo n.º 11
0
        public void Build(LODVolume rootLODVolume)
        {
            if (rootLODVolume == null)
            {
                Debug.LogError("SceneLODUpdate build failed. RootLODVolume is null.");
                return;
            }

            //it build by BFS.
            List <VolumeBounds>   boundsList   = new List <VolumeBounds>();
            List <VolumeRenderer> rendererList = new List <VolumeRenderer>();

            Queue <LODVolume> treeTrevelQueue  = new Queue <LODVolume>();
            Queue <int>       parentIndexQueue = new Queue <int>();

            treeTrevelQueue.Enqueue(rootLODVolume);
            parentIndexQueue.Enqueue(-1);

            while (treeTrevelQueue.Count > 0)
            {
                var          current = treeTrevelQueue.Dequeue();
                VolumeBounds bounds;

                int currentIndex = boundsList.Count;
                int parentIndex  = parentIndexQueue.Dequeue();

                if (current.VolumeGroups.Count == 0)
                {
                    continue;
                }

                bounds.Center = current.Bounds.center;
                bounds.Size   = current.Bounds.size.x;
                bounds.Radius = current.Bounds.extents.magnitude;

                boundsList.Add(bounds);

                VolumeRenderer renderer;
                renderer.LODMeshes = new List <Renderer>();
                renderer.LODGroups = new List <LODGroupRendererProxy>();
                renderer.Volumes   = new List <VolumeRendererProxy>();


                LODGroup lodGroup = current.GetComponent <LODGroup>();
                if (lodGroup != null)
                {
                    LOD[] lods = lodGroup.GetLODs();

                    if (lods.Length >= 2)
                    {
                        for (int ri = 0; ri < lods[1].renderers.Length; ++ri)
                        {
                            renderer.LODMeshes.Add(lods[1].renderers[ri]);
                        }
                    }
                }

                if (current.ChildVolumes.Count == 0)
                {
                    for (int vi = 0; vi < current.VolumeGroups.Count; ++vi)
                    {
                        var volumeGroup = current.VolumeGroups[vi];
                        for (int gi = 0; gi < volumeGroup.LODGroups.Count; ++gi)
                        {
                            renderer.LODGroups.Add(new LODGroupRendererProxy(volumeGroup.LODGroups[gi]));
                        }
                    }
                }

                rendererList.Add(renderer);

                //If FirstChildIndex of the parent is empty, this is the first node.
                if (parentIndex != -1)
                {
                    var parentRenderer = rendererList[parentIndex];
                    parentRenderer.Volumes.Add(new VolumeRendererProxy(currentIndex));
                }

                for (int i = 0; i < current.ChildVolumes.Count; ++i)
                {
                    treeTrevelQueue.Enqueue(current.ChildVolumes[i]);
                    parentIndexQueue.Enqueue(currentIndex);
                }
            }

            m_Bounds    = boundsList;
            m_Renderers = rendererList;

            if (m_Bounds.Count > 0)
            {
                m_ActiveVolumes.AddLast(0);
            }
        }
Ejemplo n.º 12
0
        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));
                    }
                }
            }
        }