|
|
@@ -1,14 +1,23 @@
|
|
|
using UnityEngine;
|
|
|
using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
+using System.ComponentModel;
|
|
|
|
|
|
public class EndlessTerrain : MonoBehaviour
|
|
|
{
|
|
|
- public const float maxViewDist = 450;
|
|
|
+ const float scale = 5f;
|
|
|
+
|
|
|
+ const float viewerMoveThresholdForChunkUpdate = 25f;
|
|
|
+ const float sqrViewerMoveThresholdForChunkUpdate = viewerMoveThresholdForChunkUpdate * viewerMoveThresholdForChunkUpdate;
|
|
|
+
|
|
|
+ public LODInfo[] detailLevels;
|
|
|
+ public static float maxViewDist;
|
|
|
+
|
|
|
public Transform viewer;
|
|
|
public Material mapMaterial;
|
|
|
|
|
|
public static Vector2 viewerPosition;
|
|
|
+ Vector2 viewerPositionOld;
|
|
|
static MapGenerator mapGenerator;
|
|
|
|
|
|
|
|
|
@@ -16,19 +25,26 @@ public class EndlessTerrain : MonoBehaviour
|
|
|
int chunksVisibleInViewDst;
|
|
|
|
|
|
Dictionary<Vector2, TerrainChunk> terrainChunkDictionary = new Dictionary<Vector2, TerrainChunk>();
|
|
|
- List<TerrainChunk> terrainChunksVisibleLastUpdate = new List<TerrainChunk>();
|
|
|
+ static List<TerrainChunk> terrainChunksVisibleLastUpdate = new List<TerrainChunk>();
|
|
|
|
|
|
private void Start()
|
|
|
{
|
|
|
mapGenerator = FindFirstObjectByType<MapGenerator>();
|
|
|
+ maxViewDist = detailLevels[detailLevels.Length - 1].visibleDstThreshold;
|
|
|
chunkSize = MapGenerator.mapChunkSize - 1;
|
|
|
chunksVisibleInViewDst = Mathf.RoundToInt(maxViewDist / chunkSize);
|
|
|
+
|
|
|
+ UpdateVisibleChunks();
|
|
|
}
|
|
|
|
|
|
private void Update()
|
|
|
{
|
|
|
- viewerPosition = new Vector2(viewer.position.x, viewer.position.z);
|
|
|
- UpdateVisibleChunks();
|
|
|
+ viewerPosition = new Vector2(viewer.position.x, viewer.position.z) / scale;
|
|
|
+ if((viewerPositionOld-viewerPosition).sqrMagnitude > sqrViewerMoveThresholdForChunkUpdate)
|
|
|
+ {
|
|
|
+ viewerPositionOld = viewerPosition;
|
|
|
+ UpdateVisibleChunks();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void UpdateVisibleChunks()
|
|
|
@@ -51,14 +67,10 @@ public class EndlessTerrain : MonoBehaviour
|
|
|
if (terrainChunkDictionary.ContainsKey(viewedChunkCoord))
|
|
|
{
|
|
|
terrainChunkDictionary[viewedChunkCoord].UpdateTerrainChunk();
|
|
|
- if (terrainChunkDictionary[viewedChunkCoord].IsVisible())
|
|
|
- {
|
|
|
- terrainChunksVisibleLastUpdate.Add(terrainChunkDictionary[viewedChunkCoord]);
|
|
|
- }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- terrainChunkDictionary.Add(viewedChunkCoord, new TerrainChunk(viewedChunkCoord, chunkSize, transform, mapMaterial));
|
|
|
+ terrainChunkDictionary.Add(viewedChunkCoord, new TerrainChunk(viewedChunkCoord, chunkSize, detailLevels, transform, mapMaterial));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -70,13 +82,21 @@ public class EndlessTerrain : MonoBehaviour
|
|
|
Vector2 position;
|
|
|
Bounds bounds;
|
|
|
|
|
|
- MapData mapData;
|
|
|
-
|
|
|
MeshRenderer meshRenderer;
|
|
|
MeshFilter meshFilter;
|
|
|
|
|
|
- public TerrainChunk(Vector2 coord, int size, Transform parent, Material material)
|
|
|
+ LODInfo[] detailLevels;
|
|
|
+ LODMesh[] lodMeshes;
|
|
|
+
|
|
|
+ MapData mapData;
|
|
|
+ bool mapDataReceived;
|
|
|
+
|
|
|
+ int previousLODIndex = -1;
|
|
|
+
|
|
|
+ public TerrainChunk(Vector2 coord, int size, LODInfo[] detailLevels, Transform parent, Material material)
|
|
|
{
|
|
|
+ this.detailLevels = detailLevels;
|
|
|
+
|
|
|
position = coord * size;
|
|
|
bounds = new Bounds(position, Vector2.one * size);
|
|
|
Vector3 positionV3 = new Vector3(position.x, 0, position.y);
|
|
|
@@ -86,28 +106,73 @@ public class EndlessTerrain : MonoBehaviour
|
|
|
meshFilter = meshObject.AddComponent<MeshFilter>();
|
|
|
meshRenderer.material = material;
|
|
|
|
|
|
- meshObject.transform.position = positionV3;
|
|
|
+ meshObject.transform.position = positionV3 * scale;
|
|
|
meshObject.transform.parent = parent;
|
|
|
+ meshObject.transform.localScale = Vector3.one * scale;
|
|
|
SetVisible(false);
|
|
|
|
|
|
- mapGenerator.RequestMapData(OnMapDataReceived);
|
|
|
+ lodMeshes = new LODMesh[detailLevels.Length];
|
|
|
+ for (int i = 0; i < detailLevels.Length; i++)
|
|
|
+ {
|
|
|
+ lodMeshes[i] = new LODMesh(detailLevels[i].lod, UpdateTerrainChunk);
|
|
|
+ }
|
|
|
+
|
|
|
+ mapGenerator.RequestMapData(position,OnMapDataReceived);
|
|
|
}
|
|
|
|
|
|
void OnMapDataReceived(MapData mapData)
|
|
|
{
|
|
|
- mapGenerator.RequestMeshData(mapData, OnMeshDataReceived);
|
|
|
- }
|
|
|
+ this.mapData = mapData;
|
|
|
+ mapDataReceived = true;
|
|
|
|
|
|
- void OnMeshDataReceived(MeshData meshData)
|
|
|
- {
|
|
|
- meshFilter.mesh = meshData.CreateMesh();
|
|
|
+ Texture2D texture = TextureGenerator.TextureFromColorMap(mapData.colorMap, MapGenerator.mapChunkSize, MapGenerator.mapChunkSize);
|
|
|
+ meshRenderer.material.mainTexture = texture;
|
|
|
+
|
|
|
+ UpdateTerrainChunk();
|
|
|
}
|
|
|
|
|
|
public void UpdateTerrainChunk()
|
|
|
{
|
|
|
- float viewerDstFromNearestEdge = Mathf.Sqrt(bounds.SqrDistance(viewerPosition));
|
|
|
- bool visible = viewerDstFromNearestEdge <= maxViewDist;
|
|
|
- SetVisible(visible);
|
|
|
+ if (mapDataReceived)
|
|
|
+ {
|
|
|
+ float viewerDstFromNearestEdge = Mathf.Sqrt(bounds.SqrDistance(viewerPosition));
|
|
|
+ bool visible = viewerDstFromNearestEdge <= maxViewDist;
|
|
|
+
|
|
|
+ if (visible)
|
|
|
+ {
|
|
|
+ int lodIndex = 0;
|
|
|
+
|
|
|
+ for (int i = 0; i < detailLevels.Length - 1; i++)
|
|
|
+ {
|
|
|
+ if (viewerDstFromNearestEdge > detailLevels[i].visibleDstThreshold)
|
|
|
+ {
|
|
|
+ lodIndex = i + 1;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (lodIndex != previousLODIndex)
|
|
|
+ {
|
|
|
+ LODMesh lodMesh = lodMeshes[lodIndex];
|
|
|
+ if (lodMesh.hasMesh)
|
|
|
+ {
|
|
|
+ previousLODIndex = lodIndex;
|
|
|
+ meshFilter.mesh = lodMesh.mesh;
|
|
|
+ }
|
|
|
+ else if (!lodMesh.hasRequestedMesh)
|
|
|
+ {
|
|
|
+ lodMesh.RequestMesh(mapData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ terrainChunksVisibleLastUpdate.Add(this);
|
|
|
+ }
|
|
|
+ SetVisible(visible);
|
|
|
+ }
|
|
|
+
|
|
|
}
|
|
|
|
|
|
public void SetVisible(bool visible)
|
|
|
@@ -120,4 +185,40 @@ public class EndlessTerrain : MonoBehaviour
|
|
|
return meshObject.activeSelf;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ class LODMesh
|
|
|
+ {
|
|
|
+ public Mesh mesh;
|
|
|
+ public bool hasRequestedMesh;
|
|
|
+ public bool hasMesh;
|
|
|
+ int lod;
|
|
|
+ System.Action updateCallback;
|
|
|
+
|
|
|
+ public LODMesh(int lod, System.Action updateCallback)
|
|
|
+ {
|
|
|
+ this.lod = lod;
|
|
|
+ this.updateCallback = updateCallback;
|
|
|
+ }
|
|
|
+
|
|
|
+ void OnMeshDataReceived(MeshData meshData)
|
|
|
+ {
|
|
|
+ mesh = meshData.CreateMesh();
|
|
|
+ hasMesh = true;
|
|
|
+
|
|
|
+ updateCallback();
|
|
|
+ }
|
|
|
+ public void RequestMesh(MapData mapData)
|
|
|
+ {
|
|
|
+ hasRequestedMesh = true;
|
|
|
+ mapGenerator.RequestMeshData(mapData, lod, OnMeshDataReceived);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [System.Serializable]
|
|
|
+ public struct LODInfo
|
|
|
+ {
|
|
|
+ public int lod;
|
|
|
+ public float visibleDstThreshold;
|
|
|
+ }
|
|
|
}
|