From bdbd0eb99b99054185a4b42254c7b09006d4ee94 Mon Sep 17 00:00:00 2001 From: "s0wlz (Matthias Puchstein)" Date: Fri, 23 Jan 2026 16:42:17 +0100 Subject: [PATCH] add per-tile min/max elevation support --- .../Editor/GeoTileAddressablesBuilder.cs | 28 +++++++- Assets/Scripts/Editor/GeoTileImporter.cs | 70 ++++++++++++------- .../Scripts/Editor/GeoTilePrefabImporter.cs | 48 +++++++++---- .../Scripts/GeoDataUtils/GeoTileMetadata.cs | 5 +- Assets/Scripts/GeoDataUtils/TileManifest.cs | 2 + 5 files changed, 111 insertions(+), 42 deletions(-) diff --git a/Assets/Scripts/Editor/GeoTileAddressablesBuilder.cs b/Assets/Scripts/Editor/GeoTileAddressablesBuilder.cs index 92d4c64..4ad42a9 100644 --- a/Assets/Scripts/Editor/GeoTileAddressablesBuilder.cs +++ b/Assets/Scripts/Editor/GeoTileAddressablesBuilder.cs @@ -53,6 +53,8 @@ public static class GeoTileAddressablesBuilder public double Ymin; public double GlobalMin; public double GlobalMax; + public double TileMin; + public double TileMax; } internal struct BuildRequest @@ -348,7 +350,9 @@ public static class GeoTileAddressablesBuilder tileId = tile.TileId, offsetX = (float)(tile.Xmin - minX), offsetZ = (float)(tile.Ymin - minY), - baseY = (float)tile.GlobalMin + baseY = (float)tile.TileMin, + tileMin = (float)tile.TileMin, + tileMax = (float)tile.TileMax }; } @@ -405,6 +409,8 @@ public static class GeoTileAddressablesBuilder int IDX_YMIN = headerMap["ymin"]; int IDX_GMIN = headerMap["global_min"]; int IDX_GMAX = headerMap["global_max"]; + int IDX_TMIN = headerMap.TryGetValue("tile_min", out var idxTileMin) ? idxTileMin : -1; + int IDX_TMAX = headerMap.TryGetValue("tile_max", out var idxTileMax) ? idxTileMax : -1; int IDX_TILE_KEY = headerMap.TryGetValue("tile_key", out var idxTileKey) ? idxTileKey : -1; for (int i = 1; i < lines.Length; i++) @@ -417,6 +423,10 @@ public static class GeoTileAddressablesBuilder int maxIdx = Math.Max(IDX_TILE, Math.Max(IDX_XMIN, Math.Max(IDX_YMIN, Math.Max(IDX_GMIN, IDX_GMAX)))); if (IDX_TILE_KEY >= 0) maxIdx = Math.Max(maxIdx, IDX_TILE_KEY); + if (IDX_TMIN >= 0) + maxIdx = Math.Max(maxIdx, IDX_TMIN); + if (IDX_TMAX >= 0) + maxIdx = Math.Max(maxIdx, IDX_TMAX); if (parts.Length <= maxIdx) continue; @@ -426,6 +436,16 @@ public static class GeoTileAddressablesBuilder var ymin = double.Parse(parts[IDX_YMIN], ci); var tileKeyRaw = IDX_TILE_KEY >= 0 ? parts[IDX_TILE_KEY].Trim() : ""; var tileKey = ResolveTileKey(tileKeyRaw, xmin, ymin, tileKeyConfig, out var xKey, out var yKey); + var globalMin = double.Parse(parts[IDX_GMIN], ci); + var globalMax = double.Parse(parts[IDX_GMAX], ci); + double tileMin = globalMin; + double tileMax = globalMax; + if (IDX_TMIN >= 0 && IDX_TMIN < parts.Length && + double.TryParse(parts[IDX_TMIN], NumberStyles.Float, ci, out var parsedTileMin)) + tileMin = parsedTileMin; + if (IDX_TMAX >= 0 && IDX_TMAX < parts.Length && + double.TryParse(parts[IDX_TMAX], NumberStyles.Float, ci, out var parsedTileMax)) + tileMax = parsedTileMax; tiles.Add(new TileRecord { @@ -435,8 +455,10 @@ public static class GeoTileAddressablesBuilder YKey = yKey, Xmin = xmin, Ymin = ymin, - GlobalMin = double.Parse(parts[IDX_GMIN], ci), - GlobalMax = double.Parse(parts[IDX_GMAX], ci) + GlobalMin = globalMin, + GlobalMax = globalMax, + TileMin = tileMin, + TileMax = tileMax }); } catch (Exception e) diff --git a/Assets/Scripts/Editor/GeoTileImporter.cs b/Assets/Scripts/Editor/GeoTileImporter.cs index 66dbfbd..46fcefe 100644 --- a/Assets/Scripts/Editor/GeoTileImporter.cs +++ b/Assets/Scripts/Editor/GeoTileImporter.cs @@ -149,7 +149,7 @@ public class GeoTileImporter : EditorWindow EditorGUILayout.HelpBox( "Creates one Unity Terrain per CSV row and positions tiles on a meter grid.\n" + - "Absolute elevation mapping: Terrain Y = global_min, Terrain height = (global_max - global_min).\n" + + "Absolute elevation mapping: Terrain Y = tile_min (fallback global_min), Terrain height = (tile_max - tile_min).\n" + "CSV is header-driven (order-independent). Optionally applies ortho JPGs and instantiates buildings/trees GLBs.", MessageType.Info); @@ -336,7 +336,7 @@ public class GeoTileImporter : EditorWindow int imported = 0, skipped = 0; int importedTextures = 0; - var placements = new List<(string tileId, float ux, float uz, float gmin)>(); + var placements = new List<(string tileId, float ux, float uz, float baseY)>(); for (int i = 0; i < selectedTiles.Count; i++) { @@ -344,17 +344,17 @@ public class GeoTileImporter : EditorWindow var tileId = tile.TileId; double xmin = tile.Xmin; double ymin = tile.Ymin; - double gmin = tile.GlobalMin; - double gmax = tile.GlobalMax; + double baseMin = tile.TileMin; + double baseMax = tile.TileMax; if (tile.OutRes != heightmapResolution) Debug.LogWarning($"[GeoTileImporter] Tile {tileId}: out_res={tile.OutRes} but importer expects {heightmapResolution}."); - float heightRange = (float)(gmax - gmin); + float heightRange = (float)(baseMax - baseMin); if (heightRange <= 0.0001f) { skipped++; - Debug.LogWarning($"[GeoTileImporter] Tile {tileId}: invalid height range (global_max <= global_min). Skipping."); + Debug.LogWarning($"[GeoTileImporter] Tile {tileId}: invalid height range (tile_max <= tile_min). Skipping."); continue; } @@ -422,7 +422,7 @@ public class GeoTileImporter : EditorWindow float ux = (float)(xmin - originX); float uz = (float)(ymin - originY); - go.transform.position = new Vector3(ux, (float)gmin, uz); + go.transform.position = new Vector3(ux, (float)baseMin, uz); var terrain = go.GetComponent(); terrain.drawInstanced = true; @@ -463,9 +463,9 @@ public class GeoTileImporter : EditorWindow } } - Debug.Log($"[GeoTileImporter] Imported {tileId} ({tile.TileKey}) @ XZ=({ux},{uz}) Y={gmin} heightRange={heightRange} usedU16={usedU16}"); + Debug.Log($"[GeoTileImporter] Imported {tileId} ({tile.TileKey}) @ XZ=({ux},{uz}) Y={baseMin} heightRange={heightRange} usedU16={usedU16}"); imported++; - placements.Add((tileId, ux, uz, (float)gmin)); + placements.Add((tileId, ux, uz, (float)baseMin)); } Debug.Log($"[GeoTileImporter] DONE. Imported={imported}, Skipped={skipped}, OrthoApplied={importedTextures} under '{parentName}'."); @@ -672,6 +672,8 @@ public class GeoTileImporter : EditorWindow int IDX_GMIN = headerMap["global_min"]; int IDX_GMAX = headerMap["global_max"]; int IDX_RES = headerMap["out_res"]; + int IDX_TMIN = headerMap.ContainsKey("tile_min") ? headerMap["tile_min"] : -1; + int IDX_TMAX = headerMap.ContainsKey("tile_max") ? headerMap["tile_max"] : -1; int IDX_TILE_KEY = headerMap.ContainsKey("tile_key") ? headerMap["tile_key"] : -1; for (int i = 1; i < lines.Length; i++) @@ -684,6 +686,10 @@ public class GeoTileImporter : EditorWindow int needMaxIndex = Math.Max(Math.Max(Math.Max(Math.Max(IDX_TILE, IDX_XMIN), IDX_YMIN), IDX_GMIN), Math.Max(IDX_GMAX, IDX_RES)); if (IDX_TILE_KEY >= 0) needMaxIndex = Math.Max(needMaxIndex, IDX_TILE_KEY); + if (IDX_TMIN >= 0) + needMaxIndex = Math.Max(needMaxIndex, IDX_TMIN); + if (IDX_TMAX >= 0) + needMaxIndex = Math.Max(needMaxIndex, IDX_TMAX); if (parts.Length <= needMaxIndex) { @@ -697,6 +703,16 @@ public class GeoTileImporter : EditorWindow var ymin = double.Parse(parts[IDX_YMIN], ci); var tileKeyRaw = IDX_TILE_KEY >= 0 ? parts[IDX_TILE_KEY].Trim() : ""; var tileKey = ResolveTileKey(tileKeyRaw, xmin, ymin, out var xKey, out var yKey); + var globalMin = double.Parse(parts[IDX_GMIN], ci); + var globalMax = double.Parse(parts[IDX_GMAX], ci); + double tileMin = globalMin; + double tileMax = globalMax; + if (IDX_TMIN >= 0 && IDX_TMIN < parts.Length && + double.TryParse(parts[IDX_TMIN], NumberStyles.Float, ci, out var parsedTileMin)) + tileMin = parsedTileMin; + if (IDX_TMAX >= 0 && IDX_TMAX < parts.Length && + double.TryParse(parts[IDX_TMAX], NumberStyles.Float, ci, out var parsedTileMax)) + tileMax = parsedTileMax; tiles.Add(new TileRecord { @@ -706,8 +722,10 @@ public class GeoTileImporter : EditorWindow YKey = yKey, Xmin = xmin, Ymin = ymin, - GlobalMin = double.Parse(parts[IDX_GMIN], ci), - GlobalMax = double.Parse(parts[IDX_GMAX], ci), + GlobalMin = globalMin, + GlobalMax = globalMax, + TileMin = tileMin, + TileMax = tileMax, OutRes = int.Parse(parts[IDX_RES], ci) }); } @@ -775,6 +793,8 @@ public class GeoTileImporter : EditorWindow public double Ymin; public double GlobalMin; public double GlobalMax; + public double TileMin; + public double TileMax; public int OutRes; } @@ -786,7 +806,7 @@ public class GeoTileImporter : EditorWindow } - private void ImportBuildings(List<(string tileId, float ux, float uz, float gmin)> placements) + private void ImportBuildings(List<(string tileId, float ux, float uz, float baseY)> placements) { if (!importBuildings) return; @@ -810,7 +830,7 @@ public class GeoTileImporter : EditorWindow } int imported = 0, missing = 0; - foreach (var (tileId, ux, uz, gmin) in placements) + foreach (var (tileId, ux, uz, baseY) in placements) { string glbPath = Path.Combine(activeDir, $"{tileId}.glb").Replace("\\", "/"); if (!File.Exists(glbPath)) @@ -831,7 +851,7 @@ public class GeoTileImporter : EditorWindow var inst = PrefabUtility.InstantiatePrefab(prefab) as GameObject ?? Instantiate(prefab); inst.name = tileId; inst.transform.SetParent(parent.transform, false); - inst.transform.position = new Vector3(ux, gmin, uz); + inst.transform.position = new Vector3(ux, baseY, uz); inst.transform.localRotation = Quaternion.Euler(0f, 180f, 0f); inst.isStatic = true; imported++; @@ -840,7 +860,7 @@ public class GeoTileImporter : EditorWindow Debug.Log($"[GeoTileImporter] Buildings ({sourceLabel}) imported={imported}, missing/failed={missing} under '{buildingsParentName}'."); } - private void ImportTrees(List<(string tileId, float ux, float uz, float gmin)> placements) + private void ImportTrees(List<(string tileId, float ux, float uz, float baseY)> placements) { if (!importTrees) return; @@ -865,7 +885,7 @@ public class GeoTileImporter : EditorWindow } int importedTiles = 0, importedChunks = 0, missingTiles = 0; - foreach (var (tileId, ux, uz, gmin) in placements) + foreach (var (tileId, ux, uz, baseY) in placements) { // Look for chunk files: {tileId}_0_0.glb, {tileId}_0_1.glb, etc. // Standard tree export creates 4x4 chunks per tile @@ -889,7 +909,7 @@ public class GeoTileImporter : EditorWindow // Create container for this tile's tree chunks var tileContainer = new GameObject($"Trees_{tileId}"); tileContainer.transform.SetParent(parent.transform, false); - tileContainer.transform.position = new Vector3(ux, gmin, uz); + tileContainer.transform.position = new Vector3(ux, baseY, uz); tileContainer.transform.localRotation = Quaternion.Euler(0f, 180f, 0f); tileContainer.isStatic = true; @@ -917,7 +937,7 @@ public class GeoTileImporter : EditorWindow Debug.Log($"[GeoTileImporter] Trees imported: {importedTiles} tiles, {importedChunks} chunks, {missingTiles} missing under '{treesParentName}'."); } - private void ImportFurniture(List<(string tileId, float ux, float uz, float gmin)> placements) + private void ImportFurniture(List<(string tileId, float ux, float uz, float baseY)> placements) { if (!importFurniture) return; @@ -939,7 +959,7 @@ public class GeoTileImporter : EditorWindow int imported = 0, skipped = 0; var ci = CultureInfo.InvariantCulture; - foreach (var (tileId, ux, uz, gmin) in placements) + foreach (var (tileId, ux, uz, baseY) in placements) { string csvPath = Path.Combine(furnitureDir, $"{tileId}.csv").Replace("\\", "/"); if (!File.Exists(csvPath)) @@ -973,7 +993,7 @@ public class GeoTileImporter : EditorWindow // Create tile container var tileContainer = new GameObject($"Furniture_{tileId}"); tileContainer.transform.SetParent(parent.transform, false); - tileContainer.transform.position = new Vector3(ux, gmin, uz); + tileContainer.transform.position = new Vector3(ux, baseY, uz); tileContainer.isStatic = true; for (int i = 1; i < lines.Length; i++) @@ -1044,7 +1064,7 @@ public class GeoTileImporter : EditorWindow } obj.transform.SetParent(tileContainer.transform, false); - obj.transform.localPosition = new Vector3(xLocal, zGround - gmin, yLocal); + obj.transform.localPosition = new Vector3(xLocal, zGround - baseY, yLocal); obj.isStatic = true; imported++; } @@ -1059,7 +1079,7 @@ public class GeoTileImporter : EditorWindow Debug.Log($"[GeoTileImporter] Furniture imported={imported}, skipped={skipped} under '{furnitureParentName}'."); } - private void ImportEnhancedTrees(List<(string tileId, float ux, float uz, float gmin)> placements) + private void ImportEnhancedTrees(List<(string tileId, float ux, float uz, float baseY)> placements) { if (!importEnhancedTrees) return; @@ -1081,7 +1101,7 @@ public class GeoTileImporter : EditorWindow int imported = 0, skipped = 0; var ci = CultureInfo.InvariantCulture; - foreach (var (tileId, ux, uz, gmin) in placements) + foreach (var (tileId, ux, uz, baseY) in placements) { string csvPath = Path.Combine(enhancedTreesDir, $"{tileId}.csv").Replace("\\", "/"); if (!File.Exists(csvPath)) @@ -1119,7 +1139,7 @@ public class GeoTileImporter : EditorWindow // Create tile container var tileContainer = new GameObject($"Trees_{tileId}"); tileContainer.transform.SetParent(parent.transform, false); - tileContainer.transform.position = new Vector3(ux, gmin, uz); + tileContainer.transform.position = new Vector3(ux, baseY, uz); tileContainer.isStatic = true; for (int i = 1; i < lines.Length; i++) @@ -1217,7 +1237,7 @@ public class GeoTileImporter : EditorWindow } treeObj.transform.SetParent(tileContainer.transform, false); - treeObj.transform.localPosition = new Vector3(xLocal, zGround - gmin, yLocal); + treeObj.transform.localPosition = new Vector3(xLocal, zGround - baseY, yLocal); treeObj.isStatic = true; imported++; } diff --git a/Assets/Scripts/Editor/GeoTilePrefabImporter.cs b/Assets/Scripts/Editor/GeoTilePrefabImporter.cs index 6860e94..26fea74 100644 --- a/Assets/Scripts/Editor/GeoTilePrefabImporter.cs +++ b/Assets/Scripts/Editor/GeoTilePrefabImporter.cs @@ -69,6 +69,7 @@ public class GeoTilePrefabImporter : EditorWindow public int YKey; public double Xmin, Ymin, Xmax, Ymax; public double GlobalMin, GlobalMax; + public double TileMin, TileMax; public int OutRes; } @@ -144,6 +145,7 @@ public class GeoTilePrefabImporter : EditorWindow "Creates one .prefab asset per tile in the manifest.\n" + "Each prefab contains: Terrain (with TerrainData), Buildings, Trees, Furniture.\n" + "TerrainData and TerrainLayers are saved as separate .asset files.\n" + + "Per-tile elevation: uses tile_min/tile_max when present (falls back to global_min/global_max).\n" + "IMPORTANT: Use 'Place All Prefabs in Scene' to position tiles correctly.", MessageType.Info); @@ -495,6 +497,8 @@ public class GeoTilePrefabImporter : EditorWindow int IDX_YMAX = headerMap["ymax"]; int IDX_GMIN = headerMap["global_min"]; int IDX_GMAX = headerMap["global_max"]; + int IDX_TMIN = headerMap.ContainsKey("tile_min") ? headerMap["tile_min"] : -1; + int IDX_TMAX = headerMap.ContainsKey("tile_max") ? headerMap["tile_max"] : -1; int IDX_RES = headerMap["out_res"]; int IDX_TILE_KEY = headerMap.ContainsKey("tile_key") ? headerMap["tile_key"] : -1; @@ -509,6 +513,10 @@ public class GeoTilePrefabImporter : EditorWindow Math.Max(Math.Max(IDX_YMAX, IDX_GMIN), Math.Max(IDX_GMAX, IDX_RES))); if (IDX_TILE_KEY >= 0) maxIdx = Math.Max(maxIdx, IDX_TILE_KEY); + if (IDX_TMIN >= 0) + maxIdx = Math.Max(maxIdx, IDX_TMIN); + if (IDX_TMAX >= 0) + maxIdx = Math.Max(maxIdx, IDX_TMAX); if (parts.Length <= maxIdx) { Debug.LogWarning($"[GeoTilePrefabImporter] Skipping line {i + 1}: too few columns."); @@ -521,6 +529,16 @@ public class GeoTilePrefabImporter : EditorWindow var ymin = double.Parse(parts[IDX_YMIN], ci); var tileKeyRaw = IDX_TILE_KEY >= 0 ? parts[IDX_TILE_KEY].Trim() : ""; var tileKey = ResolveTileKey(tileKeyRaw, xmin, ymin, out var xKey, out var yKey); + var globalMin = double.Parse(parts[IDX_GMIN], ci); + var globalMax = double.Parse(parts[IDX_GMAX], ci); + double tileMin = globalMin; + double tileMax = globalMax; + if (IDX_TMIN >= 0 && IDX_TMIN < parts.Length && + double.TryParse(parts[IDX_TMIN], NumberStyles.Float, ci, out var parsedTileMin)) + tileMin = parsedTileMin; + if (IDX_TMAX >= 0 && IDX_TMAX < parts.Length && + double.TryParse(parts[IDX_TMAX], NumberStyles.Float, ci, out var parsedTileMax)) + tileMax = parsedTileMax; tiles.Add(new TileMetadata { @@ -532,8 +550,10 @@ public class GeoTilePrefabImporter : EditorWindow Ymin = ymin, Xmax = double.Parse(parts[IDX_XMAX], ci), Ymax = double.Parse(parts[IDX_YMAX], ci), - GlobalMin = double.Parse(parts[IDX_GMIN], ci), - GlobalMax = double.Parse(parts[IDX_GMAX], ci), + GlobalMin = globalMin, + GlobalMax = globalMax, + TileMin = tileMin, + TileMax = tileMax, OutRes = int.Parse(parts[IDX_RES], ci) }); } @@ -601,7 +621,7 @@ public class GeoTilePrefabImporter : EditorWindow private bool CreateTilePrefab(TileMetadata tile) { // Validate height range - float heightRange = (float)(tile.GlobalMax - tile.GlobalMin); + float heightRange = (float)(tile.TileMax - tile.TileMin); if (heightRange <= 0.0001f) { Debug.LogWarning($"[GeoTilePrefabImporter] Tile {tile.TileId}: invalid height range. Skipping."); @@ -686,6 +706,8 @@ public class GeoTilePrefabImporter : EditorWindow metadata.ymin = tile.Ymin; metadata.globalMin = tile.GlobalMin; metadata.globalMax = tile.GlobalMax; + metadata.tileMin = tile.TileMin; + metadata.tileMax = tile.TileMax; // Add child components if (includeBuildings) @@ -769,15 +791,15 @@ public class GeoTilePrefabImporter : EditorWindow } // Building GLB vertices have absolute Z (elevation) from CityGML. - // Since prefab root will be at Y=gmin when placed, offset buildings by -gmin - // so building world Y = gmin + (-gmin) + GLB_Y = GLB_Y (correct absolute elevation) + // Since prefab root will be at Y=tile_min when placed, offset buildings by -tile_min + // so building world Y = tile_min + (-tile_min) + GLB_Y = GLB_Y (correct absolute elevation) var instance = PrefabUtility.InstantiatePrefab(buildingPrefab) as GameObject; if (instance == null) instance = Instantiate(buildingPrefab); instance.name = "Buildings"; instance.transform.SetParent(root.transform, false); - instance.transform.localPosition = new Vector3(0f, -(float)tile.GlobalMin, 0f); + instance.transform.localPosition = new Vector3(0f, -(float)tile.TileMin, 0f); instance.transform.localRotation = Quaternion.Euler(0f, 180f, 0f); instance.isStatic = true; } @@ -799,11 +821,11 @@ public class GeoTilePrefabImporter : EditorWindow } // Tree GLB vertices use absolute elevation (z_ground from DGM). - // Since prefab root will be at Y=gmin when placed, offset trees by -gmin - // so tree world Y = gmin + (-gmin) + GLB_Y = GLB_Y (correct absolute elevation) + // Since prefab root will be at Y=tile_min when placed, offset trees by -tile_min + // so tree world Y = tile_min + (-tile_min) + GLB_Y = GLB_Y (correct absolute elevation) var treesContainer = new GameObject("Trees"); treesContainer.transform.SetParent(root.transform, false); - treesContainer.transform.localPosition = new Vector3(0f, -(float)tile.GlobalMin, 0f); + treesContainer.transform.localPosition = new Vector3(0f, -(float)tile.TileMin, 0f); treesContainer.transform.localRotation = Quaternion.Euler(0f, 180f, 0f); treesContainer.isStatic = true; @@ -863,7 +885,7 @@ public class GeoTilePrefabImporter : EditorWindow furnitureContainer.transform.localPosition = Vector3.zero; furnitureContainer.isStatic = true; - float gmin = (float)tile.GlobalMin; + float baseY = (float)tile.TileMin; for (int i = 1; i < lines.Length; i++) { @@ -883,7 +905,7 @@ public class GeoTilePrefabImporter : EditorWindow GameObject obj = CreateFurnitureObject(furnitureType, height, i); obj.transform.SetParent(furnitureContainer.transform, false); - obj.transform.localPosition = new Vector3(xLocal, zGround - gmin, yLocal); + obj.transform.localPosition = new Vector3(xLocal, zGround - baseY, yLocal); obj.isStatic = true; } catch (Exception e) @@ -978,7 +1000,7 @@ public class GeoTilePrefabImporter : EditorWindow treesContainer.transform.localPosition = Vector3.zero; treesContainer.isStatic = true; - float gmin = (float)tile.GlobalMin; + float baseY = (float)tile.TileMin; for (int i = 1; i < lines.Length; i++) { @@ -1008,7 +1030,7 @@ public class GeoTilePrefabImporter : EditorWindow GameObject treeObj = CreateEnhancedTree(height, radius, canopyColor, i); treeObj.transform.SetParent(treesContainer.transform, false); - treeObj.transform.localPosition = new Vector3(xLocal, zGround - gmin, yLocal); + treeObj.transform.localPosition = new Vector3(xLocal, zGround - baseY, yLocal); treeObj.isStatic = true; } catch (Exception e) diff --git a/Assets/Scripts/GeoDataUtils/GeoTileMetadata.cs b/Assets/Scripts/GeoDataUtils/GeoTileMetadata.cs index b871bf2..5eb8d6e 100644 --- a/Assets/Scripts/GeoDataUtils/GeoTileMetadata.cs +++ b/Assets/Scripts/GeoDataUtils/GeoTileMetadata.cs @@ -12,15 +12,18 @@ public class GeoTileMetadata : MonoBehaviour public double ymin; public double globalMin; public double globalMax; + public double tileMin; + public double tileMax; /// /// Returns the world position this tile should be placed at, given a global origin. /// public Vector3 GetWorldPosition(double originX, double originY) { + double baseY = tileMax > tileMin ? tileMin : globalMin; return new Vector3( (float)(xmin - originX), - (float)globalMin, + (float)baseY, (float)(ymin - originY) ); } diff --git a/Assets/Scripts/GeoDataUtils/TileManifest.cs b/Assets/Scripts/GeoDataUtils/TileManifest.cs index 9551ed9..bd44329 100644 --- a/Assets/Scripts/GeoDataUtils/TileManifest.cs +++ b/Assets/Scripts/GeoDataUtils/TileManifest.cs @@ -18,4 +18,6 @@ public class TileEntry public float offsetX; public float offsetZ; public float baseY; + public float tileMin; + public float tileMax; }