ChunkTerrainCullingSystem.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using UnityEngine;
  4. using Sirenix.OdinInspector;
  5. using KairoEngine.Chunks;
  6. namespace KairoEngine.TerrainEngine
  7. {
  8. #if UNITY_EDITOR
  9. [UnityEditor.InitializeOnLoad]
  10. #endif
  11. [HideMonoScript]
  12. public class ChunkTerrainCullingSystem : MonoBehaviour
  13. {
  14. public ChunkTerrainGenerator chunkTerrainGenerator;
  15. public int maxChunks = 512;
  16. public float destroyDistanceModifier = 3f;
  17. public List<CullingTarget> targets;
  18. private void Start()
  19. {
  20. chunkTerrainGenerator.DestroyTerrain();
  21. chunkTerrainGenerator.Initialize();
  22. for (int i = 0; i < targets.Count; i++) targets[i].lastPosition = new Vector3();
  23. }
  24. private void Update()
  25. {
  26. CullChunks();
  27. }
  28. [ShowInInspector] private bool cullObjectsInEditor = false;
  29. [Button("Cull Chunks")]
  30. private void EditorCulling()
  31. {
  32. cullObjectsInEditor = !cullObjectsInEditor;
  33. if(cullObjectsInEditor)
  34. {
  35. chunkTerrainGenerator.DestroyTerrain();
  36. chunkTerrainGenerator.Initialize();
  37. UnityEditor.EditorApplication.update += CullChunks;
  38. for (int i = 0; i < targets.Count; i++) targets[i].lastPosition = new Vector3();
  39. CullChunks();
  40. }
  41. else UnityEditor.EditorApplication.update -= CullChunks;
  42. }
  43. public void CullChunks()
  44. {
  45. if(chunkTerrainGenerator == null) return;
  46. if(!chunkTerrainGenerator.IsInitialized()) return;
  47. for (int i = 0; i < targets.Count; i++)
  48. {
  49. Vector3 chunkPos = chunkTerrainGenerator.chunkSystem.GetChunkGlobalPositionFromGlobalPosition(targets[i].target.position);
  50. if(!chunkPos.Equals(targets[i].lastPosition))
  51. {
  52. chunkTerrainGenerator.ClearChunkDataBuffer();
  53. targets[i].chunkPositions.Clear();
  54. targets[i].chunkPositions.InsertRange(0, GetChunkPositions(targets[i].radius, chunkPos));
  55. for (int a = 0; a < targets[i].chunkPositions.Count; a++)
  56. {
  57. chunkTerrainGenerator.GenerateChunk(targets[i].chunkPositions[a]);
  58. }
  59. }
  60. targets[i].lastPosition = chunkPos;
  61. }
  62. DestroyChunks();
  63. #if UNITY_EDITOR
  64. chunkTerrainGenerator.UpdateEditor ();
  65. #endif
  66. }
  67. private List<Vector3> GetChunkPositions(int radius, Vector3 origin)
  68. {
  69. List<Vector2Int> points = new List<Vector2Int>();
  70. for (int i = 1; i < radius; i++)
  71. {
  72. for (int j = 1; j < radius; j++)
  73. {
  74. if (i * i + j * j < (radius * radius))
  75. {
  76. points.Add(new Vector2Int(i,j));
  77. points.Add(new Vector2Int(-i,j));
  78. points.Add(new Vector2Int(i,-j));
  79. points.Add(new Vector2Int(-i,-j));
  80. points.Add(new Vector2Int(i, 0));
  81. points.Add(new Vector2Int(-i, 0));
  82. points.Add(new Vector2Int(0, j));
  83. points.Add(new Vector2Int(0, -j));
  84. }
  85. }
  86. }
  87. //Debug.Log($"Found {points.Count} points");
  88. List<Vector3> chunkPositions = new List<Vector3>();
  89. chunkPositions.Add(origin);
  90. var voxelSize = chunkTerrainGenerator.voxelSize;
  91. var chunkSize = chunkTerrainGenerator.chunkSize;
  92. for (int i = 0; i < points.Count; i++)
  93. {
  94. for (int j = 0; j < chunkTerrainGenerator.chunkLimit.y; j++)
  95. {
  96. Vector3 pos = new Vector3(points[i].x * chunkSize.x * voxelSize.x, j * chunkSize.y * voxelSize.y, points[i].y * chunkSize.z * voxelSize.z);
  97. pos += origin;
  98. chunkPositions.Add(pos);
  99. }
  100. }
  101. //Debug.Log($"Found {chunkPositions.Count} chunk positions");
  102. return chunkPositions;
  103. }
  104. public void DestroyChunks()
  105. {
  106. int chunkCount = chunkTerrainGenerator.chunkSystem.chunkList.Count;
  107. if(chunkCount < maxChunks) return;
  108. int destroyCount = chunkCount - maxChunks;
  109. Vector3 chunkSize = chunkTerrainGenerator.chunkSize;
  110. Vector3 voxelSize = chunkTerrainGenerator.voxelSize;
  111. Vector3 size = new Vector3(chunkSize.x * voxelSize.x, chunkSize.y * voxelSize.y, chunkSize.z * voxelSize.z);
  112. List<Vector3> destroyList = new List<Vector3>();
  113. for (int i = 0; i < chunkCount; i++)
  114. {
  115. Vector3 chunkPos = chunkTerrainGenerator.chunkSystem.chunkList[i];
  116. List<bool> values = new List<bool>();
  117. for (int a = 0; a < targets.Count; a++)
  118. {
  119. Vector3 targetPos = targets[a].target.position;
  120. Vector3 pos = targetPos + (size * targets[a].radius * destroyDistanceModifier);
  121. pos.y = targetPos.y;
  122. if(Vector3.Distance(targetPos, chunkPos) > Vector3.Distance(targetPos, pos)) values.Add(true);
  123. }
  124. if(values.Count == targets.Count) destroyList.Add(chunkPos);
  125. if(destroyList.Count >= destroyCount) break;
  126. }
  127. for (int i = 0; i < destroyList.Count; i++)
  128. {
  129. chunkTerrainGenerator.DestroyChunk(destroyList[i]);
  130. }
  131. }
  132. [System.Serializable]
  133. public class CullingTarget
  134. {
  135. [HorizontalGroup("Target", 0.8f), HideLabel] public Transform target;
  136. [HorizontalGroup("Target"), HideLabel, Range(0, 16)] public int radius;
  137. public Vector3 lastPosition;
  138. public List<Vector3> chunkPositions;
  139. }
  140. }
  141. }