From e8c982b646a431555f17b960cb652c4ed760cada Mon Sep 17 00:00:00 2001 From: Mike van Riel Date: Thu, 29 Feb 2024 16:59:12 +0100 Subject: [PATCH] Delete left-over Game Objects when changing LOD levels and when tiles are destroyed before the Game Object was spawned --- CHANGELOG.md | 8 ++ .../Layers/BinaryMeshLayer/BinaryMeshLayer.cs | 118 +++++++-------- Runtime/Scripts/TileHandler.cs | 135 ++++++------------ package.json | 2 +- 4 files changed, 108 insertions(+), 155 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 35b13f1..7a5e4cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this package will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [1.1.1] - 2024-02-29 + +### Fixed + +- GameObjects that were created after a tile had been removed are now properly destroyed +- When changing LOD levels, prior game objects are now destroyed +- Code readability improvements +- A performance improvement in determining whether a Tile needs to be destroyed when out of view ## [1.1.0] - 2024-02-24 diff --git a/Runtime/Scripts/Layers/BinaryMeshLayer/BinaryMeshLayer.cs b/Runtime/Scripts/Layers/BinaryMeshLayer/BinaryMeshLayer.cs index 1613331..0088073 100644 --- a/Runtime/Scripts/Layers/BinaryMeshLayer/BinaryMeshLayer.cs +++ b/Runtime/Scripts/Layers/BinaryMeshLayer/BinaryMeshLayer.cs @@ -1,6 +1,4 @@ - - -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine; @@ -10,7 +8,6 @@ #if SUBOBJECT using Netherlands3D.SubObjects; #endif -using System.Diagnostics; namespace Netherlands3D.CartesianTiles { @@ -41,8 +38,7 @@ public override void HandleTile(TileChange tileChange, System.Action switch (action) { case TileAction.Create: - Tile newTile = CreateNewTile(tileKey); - tiles.Add(tileKey, newTile); + tiles.Add(tileKey, CreateNewTile(tileKey)); break; case TileAction.Upgrade: tiles[tileKey].unityLOD++; @@ -54,51 +50,46 @@ public override void HandleTile(TileChange tileChange, System.Action InteruptRunningProcesses(tileKey); RemoveGameObjectFromTile(tileKey); tiles.Remove(tileKey); - callback(tileChange); + callback?.Invoke(tileChange); return; - default: - break; } tiles[tileKey].runningCoroutine = StartCoroutine(DownloadBinaryMesh(tileChange, callback)); } private Tile CreateNewTile(Vector2Int tileKey) { - Tile tile = new Tile(); - tile.unityLOD = 0; - tile.tileKey = tileKey; - tile.layer = transform.gameObject.GetComponent(); + return new Tile + { + unityLOD = 0, + tileKey = tileKey, + layer = this + }; + } + private void RemoveGameObjectFromTile(Vector2Int tileKey) + { + if (!tiles.TryGetValue(tileKey, out var tile)) return; - return tile; + var tileGameObject = tile.gameObject; + if (!tileGameObject) return; + + RemoveGameObject(tileGameObject); } - private void RemoveGameObjectFromTile(Vector2Int tileKey) + + private static void RemoveGameObject(GameObject tileGameObject) { - if (tiles.ContainsKey(tileKey)) - { - Tile tile = tiles[tileKey]; - if (tile == null) - { - return; - } - if (tile.gameObject == null) - { - return; - } - string meshname = tile.gameObject.GetComponent().sharedMesh.name; - MeshFilter mf = tile.gameObject.GetComponent(); - if (mf != null) - { - Destroy(tile.gameObject.GetComponent().sharedMesh); - } - Destroy(tiles[tileKey].gameObject); + MeshFilter mf = tileGameObject.GetComponent(); + if (mf) { + Destroy(mf.sharedMesh); } + Destroy(tileGameObject); } - + private IEnumerator DownloadBinaryMesh(TileChange tileChange, System.Action callback = null) { var tileKey = new Vector2Int(tileChange.X, tileChange.Y); - int index = tiles[tileKey].unityLOD; + var tile = tiles[tileKey]; + int index = tile.unityLOD; string url = Datasets[index].path; if (Datasets[index].path.StartsWith("https://") || Datasets[index].path.StartsWith("file://")) { @@ -116,46 +107,52 @@ private IEnumerator DownloadBinaryMesh(TileChange tileChange, System.Action pauseLoading == false); - GameObject newGameobject = CreateNewGameObject(url, results, tileChange); - if (newGameobject != null) - { -#if SUBOBJECT - if (hasMetaData) - { - yield return StartCoroutine(LoadMetaData(newGameobject, url)); - } -#endif + byte[] results = webRequest.downloadHandler.data; - tiles[tileKey].gameObject = newGameobject; + yield return new WaitUntil(() => pauseLoading == false); + GameObject newGameobject = CreateNewGameObject(url, results, tileChange); + + if (!newGameobject) + { + callback?.Invoke(tileChange); + yield break; + } - callback(tileChange); - - } - else + if (tiles.TryGetValue(tileKey, out tile)) + { + if (tile.gameObject) RemoveGameObject(tile.gameObject); + + tile.gameObject = newGameobject; + +#if SUBOBJECT + if (hasMetaData) { - callback(tileChange); + yield return StartCoroutine(LoadMetaData(newGameobject, url)); } +#endif + } + else + { + // Tile was destroyed in the mean time.. destroy this game object too then. + RemoveGameObject(newGameobject); } - } - + callback?.Invoke(tileChange); + } #if SUBOBJECT private IEnumerator LoadMetaData(GameObject gameObject, string geometryUrl) @@ -185,6 +182,9 @@ private IEnumerator LoadMetaData(GameObject gameObject, string geometryUrl) private void ReadMetaDataFile(byte[] results, GameObject gameobject) { + // The gameobject could be destroyed in the mean time + if (!gameobject) return; + ObjectMapping objectMapping = gameobject.AddComponent(); objectMapping.items = new List(); using (var stream = new MemoryStream(results)) diff --git a/Runtime/Scripts/TileHandler.cs b/Runtime/Scripts/TileHandler.cs index 687cac6..766e412 100644 --- a/Runtime/Scripts/TileHandler.cs +++ b/Runtime/Scripts/TileHandler.cs @@ -112,16 +112,6 @@ public bool pauseLoading private float groundLevelClipRange = 1000; - //[Header("Optional events")] - //[SerializeField] - //private Vector2IntEvent tileCreatedEvent; - //[SerializeField] - //private Vector2IntEvent tileUpgradeEvent; - //[SerializeField] - //private Vector2IntEvent tileDowngradeEvent; - //[SerializeField] - //private Vector2IntEvent tileDestroyedEvent; - void Start() { layers = GetComponentsInChildren(false).ToList(); @@ -150,12 +140,11 @@ public void AddLayer(Layer layer) layers.Add(layer); GetTilesizes(); } + public void RemoveLayer(Layer layer) { - int layerIndex = layers.IndexOf(layer); - // add all existing tiles to pending destroy int tilesizeIndex = tileSizes.IndexOf(layer.tileSize); foreach (Vector3Int tileDistance in tileDistances[tilesizeIndex]) @@ -176,8 +165,6 @@ public void RemoveLayer(Layer layer) } InstantlyStartRemoveChanges(); layers.Remove(layer); - - } private void CacheCameraFrustum() @@ -218,13 +205,8 @@ void Update() { TileChange highestPriorityTileChange = GetHighestPriorityTileChange(); Vector3Int tilekey = new Vector3Int(highestPriorityTileChange.X, highestPriorityTileChange.Y, highestPriorityTileChange.layerIndex); - if (activeTileChanges.ContainsKey(tilekey) == false) - { - activeTileChanges.Add(tilekey, highestPriorityTileChange); - pendingTileChanges.Remove(highestPriorityTileChange); - layers[highestPriorityTileChange.layerIndex].HandleTile(highestPriorityTileChange, TileHandled); - } - else if (activeTileChanges.TryGetValue(tilekey, out TileChange existingTileChange)) + + if (activeTileChanges.TryGetValue(tilekey, out TileChange existingTileChange)) { //Change running tile changes to more important ones Debug.Log("Upgrading existing"); @@ -234,6 +216,12 @@ void Update() pendingTileChanges.Remove(highestPriorityTileChange); } } + else + { + activeTileChanges.Add(tilekey, highestPriorityTileChange); + pendingTileChanges.Remove(highestPriorityTileChange); + layers[highestPriorityTileChange.layerIndex].HandleTile(highestPriorityTileChange, TileHandled); + } } } @@ -243,7 +231,7 @@ private void InstantlyStartRemoveChanges() for (int i = removeChanges.Length - 1; i >= 0; i--) { var removeChange = removeChanges[i]; - layers[removeChange.layerIndex].HandleTile(removeChange, TileRemoved); + layers[removeChange.layerIndex].HandleTile(removeChange); pendingTileChanges.Remove(removeChange); //Abort all tilechanges with the same key @@ -259,7 +247,7 @@ private void AbortSimilarTileChanges(TileChange removeChange) { var runningChange = changes[i]; layers[removeChange.layerIndex].InteruptRunningProcesses(new Vector2Int(removeChange.X, removeChange.Y)); - layers[removeChange.layerIndex].HandleTile(removeChange, TileRemoved); + layers[removeChange.layerIndex].HandleTile(removeChange); activeTileChanges.Remove(runningChange.Key); } } @@ -271,47 +259,16 @@ private void AbortPendingSimilarTileChanges(TileChange removeChange) { var runningChange = changes[i]; layers[removeChange.layerIndex].InteruptRunningProcesses(new Vector2Int(removeChange.X, removeChange.Y)); - layers[removeChange.layerIndex].HandleTile(removeChange, TileRemoved); + layers[removeChange.layerIndex].HandleTile(removeChange); pendingTileChanges.Remove(runningChange); } } public void TileHandled(TileChange handledTileChange) { - InvokeTileChangeEvent(handledTileChange); - activeTileChanges.Remove(new Vector3Int(handledTileChange.X, handledTileChange.Y, handledTileChange.layerIndex)); } - private void InvokeTileChangeEvent(TileChange handledTileChange) - { - //switch (handledTileChange.action) - //{ - // case TileAction.Create: - // if (tileCreatedEvent) - // tileCreatedEvent.InvokeStarted(new Vector2Int(handledTileChange.X, handledTileChange.Y)); - // break; - // case TileAction.Downgrade: - // if (tileDowngradeEvent) - // tileDowngradeEvent.InvokeStarted(new Vector2Int(handledTileChange.X, handledTileChange.Y)); - // break; - // case TileAction.Upgrade: - // if (tileUpgradeEvent) - // tileUpgradeEvent.InvokeStarted(new Vector2Int(handledTileChange.X, handledTileChange.Y)); - // break; - // case TileAction.Remove: - // if (tileDestroyedEvent) - // tileDestroyedEvent.InvokeStarted(new Vector2Int(handledTileChange.X, handledTileChange.Y)); - // break; - //} - } - - public void TileRemoved(TileChange handledTileChange) - { - //if (tileDestroyedEvent) - // tileDestroyedEvent.InvokeStarted(new Vector2Int(handledTileChange.X, handledTileChange.Y)); - } - /// /// uses CameraExtent /// updates the variable viewrange @@ -529,9 +486,7 @@ private void GetTileChanges() private void AddTileChange(TileChange tileChange, int layerIndex) { - //don't add a tilechange if the tile has an active tilechange already - Vector3Int activekey = new Vector3Int(tileChange.X, tileChange.Y, tileChange.layerIndex); if (activeTileChanges.ContainsKey(activekey) && tileChange.action != TileAction.Remove) { @@ -622,13 +577,10 @@ private int CalculatePriorityScore(int layerPriority, int lod, int distanceSquar return priority; } - Layer layer; - List neededTiles; - List neededTileKeys = new List(); - TileChange tileChange; - private void RemoveOutOfViewTiles() { + Layer layer = null; + for (int layerIndex = 0; layerIndex < layers.Count; layerIndex++) { // create a list of tilekeys for the tiles that are within the viewrange @@ -637,40 +589,39 @@ private void RemoveOutOfViewTiles() { continue; } - if (layer.gameObject.activeSelf == false) { continue; } - if (layer.isEnabled == false) - { - continue; - } + + if (layer.gameObject.activeSelf == false) continue; + if (layer.isEnabled == false) continue; + int tilesizeIndex = tileSizes.IndexOf(layer.tileSize); - neededTiles = tileDistances[tilesizeIndex]; - neededTileKeys.Clear(); - neededTileKeys.Capacity = neededTiles.Count; - foreach (var neededTile in neededTiles) - { - //tileKey.x = neededTile.x; - //tileKey.y = neededTile.y; - neededTileKeys.Add(new Vector2Int(neededTile.x, neededTile.y)); - } - //activeTiles = layer.tiles.Keys.ToArray(); - //activeTiles = new List(layer.tiles.Keys); + var neededTiles = tileDistances[tilesizeIndex]; + + var neededTileKeys = new HashSet( + neededTiles.Select(neededTile => new Vector2Int(neededTile.x, neededTile.y)) + ); + // check for each active tile if the key is in the list of tilekeys within the viewrange foreach (var kvp in layer.tiles) { - if (neededTileKeys.Contains(kvp.Key) == false) // if the tile is not within the viewrange, set it up for removal - { - tileChange = new TileChange(); - tileChange.action = TileAction.Remove; - tileChange.X = kvp.Key.x; - tileChange.Y = kvp.Key.y; - tileChange.layerIndex = layerIndex; - tileChange.priorityScore = int.MaxValue; // set the priorityscore to maximum - AddTileChange(tileChange, layerIndex); - } + if (neededTileKeys.Contains(kvp.Key)) continue; + + // if the tile is not within the viewrange, set it up for removal + AddTileChange( + new TileChange + { + action = TileAction.Remove, + X = kvp.Key.x, + Y = kvp.Key.y, + layerIndex = layerIndex, + priorityScore = int.MaxValue // set the priorityscore to maximum + }, + layerIndex + ); } } } + private TileChange GetHighestPriorityTileChange() { TileChange highestPriorityTileChange = pendingTileChanges[0]; @@ -687,14 +638,8 @@ private TileChange GetHighestPriorityTileChange() return highestPriorityTileChange; } } - [Serializable] - - - - - - + [Serializable] public enum LODCalculationMethod { Auto, diff --git a/package.json b/package.json index b7d335d..f92b8b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eu.netherlands3d.cartesiantiles", - "version": "1.1.0", + "version": "1.1.1", "displayName": "Netherlands3D - Cartesian Tiles", "description": "Loads and unloads datasets in a cartesian coordinateSystem", "unity": "2022.2",