You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

416 lines
13 KiB

using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
using Mapbox.Unity.MeshGeneration.Data;
using Mapbox.Unity.Map;
using Mapbox.Map;
using Mapbox.Utils;
using Debug = UnityEngine.Debug;
namespace Mapbox.Unity.MeshGeneration.Factories.TerrainStrategies
{
public class MeshDataArray
{
public Vector3[] Vertices;
public Vector3[] Normals;
public int[] Triangles;
public Vector2[] Uvs;
}
public class ElevatedTerrainStrategy : TerrainStrategy, IElevationBasedTerrainStrategy
{
private Dictionary<UnwrappedTileId, Mesh> _meshData;
private MeshData _currentTileMeshData;
private Dictionary<UnityTile, MeshDataArray> _cachedMeshDataArrays;
private Dictionary<UnwrappedTileId, MeshDataArray> _dataArrays;
private Dictionary<int, MeshDataArray> _meshSamples;
private List<Vector3> _newVertexList;
private List<Vector3> _newNormalList;
private List<Vector2> _newUvList;
private List<int> _newTriangleList;
private Vector3 _newDir;
private int _vertA, _vertB, _vertC;
private int _counter;
public override int RequiredVertexCount
{
get { return _elevationOptions.modificationOptions.sampleCount * _elevationOptions.modificationOptions.sampleCount; }
}
public override void Initialize(ElevationLayerProperties elOptions)
{
base.Initialize(elOptions);
_meshSamples = new Dictionary<int, MeshDataArray>();
_dataArrays = new Dictionary<UnwrappedTileId, MeshDataArray>();
_cachedMeshDataArrays = new Dictionary<UnityTile, MeshDataArray>();
_meshData = new Dictionary<UnwrappedTileId, Mesh>();
_currentTileMeshData = new MeshData();
var sampleCountSquare = _elevationOptions.modificationOptions.sampleCount * _elevationOptions.modificationOptions.sampleCount;
_newVertexList = new List<Vector3>(sampleCountSquare);
_newNormalList = new List<Vector3>(sampleCountSquare);
_newUvList = new List<Vector2>(sampleCountSquare);
_newTriangleList = new List<int>();
}
public override void RegisterTile(UnityTile tile)
{
if (_elevationOptions.unityLayerOptions.addToLayer && tile.gameObject.layer != _elevationOptions.unityLayerOptions.layerId)
{
tile.gameObject.layer = _elevationOptions.unityLayerOptions.layerId;
}
if (tile.MeshFilter.sharedMesh.vertexCount != RequiredVertexCount || !_cachedMeshDataArrays.ContainsKey(tile))
{
tile.MeshFilter.sharedMesh.Clear();
if (_meshSamples.ContainsKey(_elevationOptions.modificationOptions.sampleCount))
{
var newMesh = _meshSamples[_elevationOptions.modificationOptions.sampleCount];
tile.MeshFilter.sharedMesh.vertices = newMesh.Vertices;
tile.MeshFilter.sharedMesh.normals = newMesh.Normals;
tile.MeshFilter.sharedMesh.triangles = newMesh.Triangles;
tile.MeshFilter.sharedMesh.uv = newMesh.Uvs;
}
else
{
//TODO remoev tile dependency from CreateBaseMesh method
var newMesh = CreateBaseMesh(tile, _elevationOptions.modificationOptions.sampleCount);
_meshSamples.Add(_elevationOptions.modificationOptions.sampleCount, newMesh);
tile.MeshFilter.sharedMesh.vertices = newMesh.Vertices;
tile.MeshFilter.sharedMesh.normals = newMesh.Normals;
tile.MeshFilter.sharedMesh.triangles = newMesh.Triangles;
tile.MeshFilter.sharedMesh.uv = newMesh.Uvs;
}
if (!_dataArrays.ContainsKey(tile.UnwrappedTileId))
{
_dataArrays.Add(tile.UnwrappedTileId, new MeshDataArray()
{
Normals = tile.MeshFilter.sharedMesh.normals,
Vertices = tile.MeshFilter.sharedMesh.vertices,
Triangles = tile.MeshFilter.sharedMesh.triangles
});
}
}
else
{
_dataArrays.Add(tile.UnwrappedTileId, _cachedMeshDataArrays[tile]);
_cachedMeshDataArrays.Remove(tile);
}
tile.ElevationType = TileTerrainType.Elevated;
GenerateTerrainMesh(tile);
}
public override void UnregisterTile(UnityTile tile)
{
_meshData.Remove(tile.UnwrappedTileId);
if (_dataArrays.ContainsKey(tile.UnwrappedTileId))
{
_cachedMeshDataArrays.Add(tile, _dataArrays[tile.UnwrappedTileId]);
_dataArrays.Remove(tile.UnwrappedTileId);
}
}
public override void DataErrorOccurred(UnityTile t, TileErrorEventArgs e)
{
ResetToFlatMesh(t);
}
public override void PostProcessTile(UnityTile tile)
{
}
#region mesh gen
private MeshDataArray CreateBaseMesh(UnityTile tile, int sampleCount)
{
//TODO use arrays instead of lists
_newVertexList.Clear();
_newNormalList.Clear();
_newUvList.Clear();
_newTriangleList.Clear();
for (float y = 0; y < sampleCount; y++)
{
var yrat = y / (sampleCount - 1);
for (float x = 0; x < sampleCount; x++)
{
var xrat = x / (sampleCount - 1);
var xx = Mathd.Lerp(tile.Rect.Min.x, tile.Rect.Max.x, xrat);
var yy = Mathd.Lerp(tile.Rect.Min.y, tile.Rect.Max.y, yrat);
_newVertexList.Add(new Vector3(
(float) (xx - tile.Rect.Center.x) * tile.TileScale,
0,
(float) (yy - tile.Rect.Center.y) * tile.TileScale));
_newNormalList.Add(Mapbox.Unity.Constants.Math.Vector3Up);
_newUvList.Add(new Vector2(x * 1f / (sampleCount - 1), 1 - (y * 1f / (sampleCount - 1))));
}
}
int vertA, vertB, vertC;
for (int y = 0; y < sampleCount - 1; y++)
{
for (int x = 0; x < sampleCount - 1; x++)
{
vertA = (y * sampleCount) + x;
vertB = (y * sampleCount) + x + sampleCount + 1;
vertC = (y * sampleCount) + x + sampleCount;
_newTriangleList.Add(vertA);
_newTriangleList.Add(vertB);
_newTriangleList.Add(vertC);
vertA = (y * sampleCount) + x;
vertB = (y * sampleCount) + x + 1;
vertC = (y * sampleCount) + x + sampleCount + 1;
_newTriangleList.Add(vertA);
_newTriangleList.Add(vertB);
_newTriangleList.Add(vertC);
}
}
var mesh = new MeshDataArray();
mesh.Vertices = _newVertexList.ToArray();
mesh.Normals = _newNormalList.ToArray();
mesh.Uvs = _newUvList.ToArray();
mesh.Triangles = _newTriangleList.ToArray();
return mesh;
}
private Vector3[] _verts;
private Vector3[] _normals;
private Vector3[] _targetVerts;
private Vector3[] _targetNormals;
private void GenerateTerrainMesh(UnityTile tile)
{
_verts = _dataArrays[tile.UnwrappedTileId].Vertices;
_normals = _dataArrays[tile.UnwrappedTileId].Normals;
var _sampleCount = _elevationOptions.modificationOptions.sampleCount;
var hd = tile.HeightData;
var ts = tile.TileScale;
for (float y = 0; y < _sampleCount; y++)
{
for (float x = 0; x < _sampleCount; x++)
{
_verts[(int) (y * _sampleCount + x)] = new Vector3(
_verts[(int) (y * _sampleCount + x)].x,
hd[((int)((1 - y / (_sampleCount - 1)) * 255) * 256) + ((int)(x / (_sampleCount - 1) * 255))] * ts,
_verts[(int) (y * _sampleCount + x)].z);
_normals[(int) (y * _sampleCount + x)] = Mapbox.Unity.Constants.Math.Vector3Zero;
}
}
FixStitches(tile.UnwrappedTileId, _verts, _normals);
tile.MeshFilter.sharedMesh.vertices = _verts;
tile.MeshFilter.sharedMesh.RecalculateNormals();
tile.MeshFilter.sharedMesh.RecalculateBounds();
if (!_meshData.ContainsKey(tile.UnwrappedTileId))
{
_meshData.Add(tile.UnwrappedTileId, tile.MeshFilter.sharedMesh);
}
if (_elevationOptions.colliderOptions.addCollider)
{
var meshCollider = tile.Collider as MeshCollider;
if (meshCollider)
{
meshCollider.sharedMesh = tile.MeshFilter.sharedMesh;
}
}
}
private void ResetToFlatMesh(UnityTile tile)
{
if (tile.MeshFilter.sharedMesh.vertexCount == 0)
{
CreateBaseMesh(tile, _elevationOptions.modificationOptions.sampleCount);
}
else
{
tile.MeshFilter.sharedMesh.GetVertices(_currentTileMeshData.Vertices);
tile.MeshFilter.sharedMesh.GetNormals(_currentTileMeshData.Normals);
_counter = _currentTileMeshData.Vertices.Count;
for (int i = 0; i < _counter; i++)
{
_currentTileMeshData.Vertices[i] = new Vector3(
_currentTileMeshData.Vertices[i].x,
0,
_currentTileMeshData.Vertices[i].z);
_currentTileMeshData.Normals[i] = Mapbox.Unity.Constants.Math.Vector3Up;
}
tile.MeshFilter.sharedMesh.SetVertices(_currentTileMeshData.Vertices);
tile.MeshFilter.sharedMesh.SetNormals(_currentTileMeshData.Normals);
tile.MeshFilter.sharedMesh.RecalculateBounds();
}
}
/// <summary>
/// Checkes all neighbours of the given tile and stitches the edges to achieve a smooth mesh surface.
/// </summary>
/// <param name="tileId">UnwrappedTileId of the tile being processed.</param>
/// <param name="mesh"></param>
private void FixStitches(UnwrappedTileId tileId, Vector3[] verts, Vector3[] normals)
{
var _sampleCount = _elevationOptions.modificationOptions.sampleCount;
var meshVertCount = verts.Length;
if (_dataArrays.ContainsKey(tileId.North))
{
_targetVerts = _dataArrays[tileId.North].Vertices;
_targetNormals = _dataArrays[tileId.North].Normals;
for (int i = 0; i < _sampleCount; i++)
{
//just snapping the y because vertex pos is relative and we'll have to do tile pos + vertex pos for x&z otherwise
verts[i] = new Vector3(
verts[i].x,
_targetVerts[meshVertCount - _sampleCount + i].y,
verts[i].z);
normals[i] = new Vector3(_targetNormals[meshVertCount - _sampleCount + i].x,
_targetNormals[meshVertCount - _sampleCount + i].y,
_targetNormals[meshVertCount - _sampleCount + i].z);
}
}
if (_dataArrays.ContainsKey(tileId.South))
{
_targetVerts = _dataArrays[tileId.South].Vertices;
_targetNormals = _dataArrays[tileId.South].Normals;
for (int i = 0; i < _sampleCount; i++)
{
verts[meshVertCount - _sampleCount + i] = new Vector3(
verts[meshVertCount - _sampleCount + i].x,
_targetVerts[i].y,
verts[meshVertCount - _sampleCount + i].z);
normals[meshVertCount - _sampleCount + i] = new Vector3(
_targetNormals[i].x,
_targetNormals[i].y,
_targetNormals[i].z);
}
}
if (_dataArrays.ContainsKey(tileId.West))
{
_targetVerts = _dataArrays[tileId.West].Vertices;
_targetNormals = _dataArrays[tileId.West].Normals;
for (int i = 0; i < _sampleCount; i++)
{
verts[i * _sampleCount] = new Vector3(
verts[i * _sampleCount].x,
_targetVerts[i * _sampleCount + _sampleCount - 1].y,
verts[i * _sampleCount].z);
normals[i * _sampleCount] = new Vector3(
_targetNormals[i * _sampleCount + _sampleCount - 1].x,
_targetNormals[i * _sampleCount + _sampleCount - 1].y,
_targetNormals[i * _sampleCount + _sampleCount - 1].z);
}
}
if (_dataArrays.ContainsKey(tileId.East))
{
_targetVerts = _dataArrays[tileId.East].Vertices;
_targetNormals = _dataArrays[tileId.East].Normals;
for (int i = 0; i < _sampleCount; i++)
{
verts[i * _sampleCount + _sampleCount - 1] = new Vector3(
verts[i * _sampleCount + _sampleCount - 1].x,
_targetVerts[i * _sampleCount].y,
verts[i * _sampleCount + _sampleCount - 1].z);
normals[i * _sampleCount + _sampleCount - 1] = new Vector3(
_targetNormals[i * _sampleCount].x,
_targetNormals[i * _sampleCount].y,
_targetNormals[i * _sampleCount].z);
}
}
if (_dataArrays.ContainsKey(tileId.NorthWest))
{
_targetVerts = _dataArrays[tileId.NorthWest].Vertices;
_targetNormals = _dataArrays[tileId.NorthWest].Normals;
verts[0] = new Vector3(
verts[0].x,
_targetVerts[meshVertCount - 1].y,
verts[0].z);
normals[0] = new Vector3(
_targetNormals[meshVertCount - 1].x,
_targetNormals[meshVertCount - 1].y,
_targetNormals[meshVertCount - 1].z);
}
if (_dataArrays.ContainsKey(tileId.NorthEast))
{
_targetVerts = _dataArrays[tileId.NorthEast].Vertices;
_targetNormals = _dataArrays[tileId.NorthEast].Normals;
verts[_sampleCount - 1] = new Vector3(
verts[_sampleCount - 1].x,
_targetVerts[meshVertCount - _sampleCount].y,
verts[_sampleCount - 1].z);
normals[_sampleCount - 1] = new Vector3(
_targetNormals[meshVertCount - _sampleCount].x,
_targetNormals[meshVertCount - _sampleCount].y,
_targetNormals[meshVertCount - _sampleCount].z);
}
if (_dataArrays.ContainsKey(tileId.SouthWest))
{
_targetVerts = _dataArrays[tileId.SouthWest].Vertices;
_targetNormals = _dataArrays[tileId.SouthWest].Normals;
verts[meshVertCount - _sampleCount] = new Vector3(
verts[meshVertCount - _sampleCount].x,
_targetVerts[_sampleCount - 1].y,
verts[meshVertCount - _sampleCount].z);
normals[meshVertCount - _sampleCount] = new Vector3(
_targetNormals[_sampleCount - 1].x,
_targetNormals[_sampleCount - 1].y,
_targetNormals[_sampleCount - 1].z);
}
if (_dataArrays.ContainsKey(tileId.SouthEast))
{
_targetVerts = _dataArrays[tileId.SouthEast].Vertices;
_targetNormals = _dataArrays[tileId.SouthEast].Normals;
verts[meshVertCount - 1] = new Vector3(
verts[meshVertCount - 1].x,
_targetVerts[0].y,
verts[meshVertCount - 1].z);
normals[meshVertCount - 1] = new Vector3(
_targetNormals[0].x,
_targetNormals[0].y,
_targetNormals[0].z);
}
}
#endregion
}
}