From 44480370837c8439cc9e21e180aefa7ff416e2a9 Mon Sep 17 00:00:00 2001 From: Armin Samii Date: Wed, 7 May 2025 14:29:30 -0400 Subject: [PATCH] tile stitching for non-shader terrains, with correct normals --- .../ElevatedTerrainStrategy.cs | 107 ++++++++++++++++++ .../Unity/UnityTileTerrainContainer.cs | 7 +- .../ImageModule/Terrain/TerrainLayerModule.cs | 4 +- .../Unity/TerrainLayerModuleScript.cs | 3 +- 4 files changed, 116 insertions(+), 5 deletions(-) diff --git a/Runtime/Mapbox/BaseModule/Data/TerrainStrategies/ElevatedTerrainStrategy.cs b/Runtime/Mapbox/BaseModule/Data/TerrainStrategies/ElevatedTerrainStrategy.cs index be1a50d58..5888e0718 100644 --- a/Runtime/Mapbox/BaseModule/Data/TerrainStrategies/ElevatedTerrainStrategy.cs +++ b/Runtime/Mapbox/BaseModule/Data/TerrainStrategies/ElevatedTerrainStrategy.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Mapbox.BaseModule.Data.Tiles; using Mapbox.BaseModule.Map; using Mapbox.BaseModule.Unity; using Mapbox.BaseModule.Utilities; @@ -289,6 +290,112 @@ private MeshDataArray CreateBaseMeshSkirts(float size, int sideVertexCount) //mesh.Triangles.Add(_newTriangleList.ToArray()); return mesh; } + + + /// + /// Checkes all neighbours of the given tile and stitches the edges to achieve a smooth mesh surface. + /// + /// UnityMapTile of the tile being processed. + /// All tiles, including this tile, used to find neighbors + /// + public void FixStitches(UnityMapTile tile, Dictionary allTiles) + { + UnwrappedTileId tileId = tile.UnwrappedTileId; + int sampleCount = _useTileSkirts + ? _elevationOptions.modificationOptions.sampleCount + 3 + : _elevationOptions.modificationOptions.sampleCount + 1; + + Vector3[] targetVerts; + Vector3[] verts = tile.MeshFilter.sharedMesh.vertices; + var meshVertCount = verts.Length; + if (allTiles.ContainsKey(tileId.North) && allTiles[tileId.North].TerrainContainer.State == TileContainerState.Final) + { + targetVerts = allTiles[tileId.North].MeshFilter.sharedMesh.vertices; + + for (int i = 0; i < sampleCount; i++) + { + int source_i = meshVertCount - sampleCount + i; + int target_i = i; + verts[source_i] = new Vector3(verts[source_i].x, targetVerts[target_i].y, verts[source_i].z); + } + allTiles[tileId.North].MeshFilter.sharedMesh.vertices = targetVerts; + } + + if (allTiles.ContainsKey(tileId.South) && allTiles[tileId.South].TerrainContainer.State == TileContainerState.Final) + { + targetVerts = allTiles[tileId.South].MeshFilter.sharedMesh.vertices; + + for (int i = 0; i < sampleCount; i++) + { + int source_i = i; + int target_i = meshVertCount - sampleCount + i; + verts[source_i] = new Vector3(verts[source_i].x, targetVerts[target_i].y, verts[source_i].z); + } + } + + if (allTiles.ContainsKey(tileId.West) && allTiles[tileId.West].TerrainContainer.State == TileContainerState.Final) + { + targetVerts = allTiles[tileId.West].MeshFilter.sharedMesh.vertices; + + for (int i = 0; i < sampleCount; i++) + { + int target_i = i * sampleCount + sampleCount - 1; + int source_i = i * sampleCount; + verts[source_i] = new Vector3(verts[source_i].x, targetVerts[target_i].y, verts[source_i].z); + } + } + + if (allTiles.ContainsKey(tileId.East) && allTiles[tileId.East].TerrainContainer.State == TileContainerState.Final) + { + targetVerts = allTiles[tileId.East].MeshFilter.sharedMesh.vertices; + + for (int i = 0; i < sampleCount; i++) + { + int target_i = i * sampleCount; + int source_i = i * sampleCount + sampleCount - 1; + verts[source_i] = new Vector3(verts[source_i].x, targetVerts[target_i].y, verts[source_i].z); + } + } + + if (allTiles.ContainsKey(tileId.NorthWest) && allTiles[tileId.NorthWest].TerrainContainer.State == TileContainerState.Final) + { + targetVerts = allTiles[tileId.NorthWest].MeshFilter.sharedMesh.vertices; + + int source_i = meshVertCount - sampleCount; + int target_i = sampleCount - 1; + verts[source_i] = new Vector3(verts[source_i].x, targetVerts[target_i].y, verts[source_i].z); + } + + if (allTiles.ContainsKey(tileId.NorthEast) && allTiles[tileId.NorthEast].TerrainContainer.State == TileContainerState.Final) + { + targetVerts = allTiles[tileId.NorthEast].MeshFilter.sharedMesh.vertices; + + int source_i = meshVertCount - 1; + int target_i = 0; + verts[source_i] = new Vector3(verts[source_i].x, targetVerts[target_i].y, verts[source_i].z); + } + + if (allTiles.ContainsKey(tileId.SouthWest) && allTiles[tileId.SouthWest].TerrainContainer.State == TileContainerState.Final) + { + targetVerts = allTiles[tileId.SouthWest].MeshFilter.sharedMesh.vertices; + + int source_i = 0; + int target_i = meshVertCount - 1; + verts[source_i] = new Vector3(verts[source_i].x, targetVerts[target_i].y, verts[source_i].z); + } + + if (allTiles.ContainsKey(tileId.SouthEast) && allTiles[tileId.SouthEast].TerrainContainer.State == TileContainerState.Final) + { + targetVerts = allTiles[tileId.SouthEast].MeshFilter.sharedMesh.vertices; + int source_i = sampleCount - 1; + int target_i = meshVertCount - sampleCount; + verts[source_i] = new Vector3(verts[source_i].x, targetVerts[target_i].y, verts[source_i].z); + } + + tile.MeshFilter.sharedMesh.vertices = verts; + tile.MeshFilter.sharedMesh.RecalculateNormals(); + } + #endregion } } diff --git a/Runtime/Mapbox/BaseModule/Unity/UnityTileTerrainContainer.cs b/Runtime/Mapbox/BaseModule/Unity/UnityTileTerrainContainer.cs index b9c5d7ddf..39743a18b 100644 --- a/Runtime/Mapbox/BaseModule/Unity/UnityTileTerrainContainer.cs +++ b/Runtime/Mapbox/BaseModule/Unity/UnityTileTerrainContainer.cs @@ -48,10 +48,13 @@ public void SetTerrainData(TerrainData terrainData, bool useShaderElevation, Til private void FixMeshBounds(bool useShaderElevation) { Mesh mesh = _unityMapTile.MeshFilter.mesh; - if (mesh != null && useShaderElevation) + if (mesh != null) { mesh.RecalculateBounds(); - mesh.bounds = GetBoundsAdjustedForElevation(); + if (useShaderElevation) + { + mesh.bounds = GetBoundsAdjustedForElevation(); + } } } diff --git a/Runtime/Mapbox/ImageModule/Terrain/TerrainLayerModule.cs b/Runtime/Mapbox/ImageModule/Terrain/TerrainLayerModule.cs index 5defbb211..896a08fff 100644 --- a/Runtime/Mapbox/ImageModule/Terrain/TerrainLayerModule.cs +++ b/Runtime/Mapbox/ImageModule/Terrain/TerrainLayerModule.cs @@ -21,12 +21,12 @@ public class TerrainLayerModule : ITerrainLayerModule private TerrainStrategy _terrainStrategy; //Terrain module doesn't support cpu elevation now after TileCreator changes - public TerrainLayerModule(Source source, TerrainLayerModuleSettings settings) : base() + public TerrainLayerModule(Source source, TerrainLayerModuleSettings settings, TerrainStrategy terrainStrategy) : base() { _settings = settings; _retainedTerrainTiles = new HashSet(); _rasterSource = source; - _terrainStrategy = new ElevatedTerrainStrategy(); + _terrainStrategy = terrainStrategy; } public virtual IEnumerator Initialize() diff --git a/Runtime/Mapbox/ImageModule/Unity/TerrainLayerModuleScript.cs b/Runtime/Mapbox/ImageModule/Unity/TerrainLayerModuleScript.cs index a5d8ef6d1..e84c3e0e8 100644 --- a/Runtime/Mapbox/ImageModule/Unity/TerrainLayerModuleScript.cs +++ b/Runtime/Mapbox/ImageModule/Unity/TerrainLayerModuleScript.cs @@ -43,7 +43,8 @@ public override ILayerModule ConstructModule(MapService service, IMapInformation var module = new TerrainLayerModule( service.GetTerrainRasterSource(Settings.DataSettings), - Settings); + Settings, + new ElevatedTerrainStrategy()); mapInformation.QueryElevation = module.QueryElevation; ModuleImplementation = module;