noradninja

LODManager

Aug 10th, 2025
376
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 5.88 KB | None | 0 0
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. using Unity.Jobs;
  4. using Unity.Collections;
  5.  
  6. public class LODManager : MonoBehaviour
  7. {
  8.     public static LODManager Instance { get; private set; }
  9.  
  10.     [Header("Global LOD Settings")]
  11.     public int tickInterval = 10;
  12.     public int batchSize = 50; // Number of items to process per frame
  13.  
  14.     private List<Shader_LOD_Enumerator> enumerators = new List<Shader_LOD_Enumerator>();
  15.     private Transform playerTransform;
  16.     private Camera mainCam;
  17.     private float farClipSqr;
  18.  
  19.     // NativeArrays to store only necessary data
  20.     private NativeArray<Vector2> enumeratorPositions;
  21.     private NativeArray<float> distSqrArray;
  22.  
  23.     private int currentBatchIndex = 0;
  24.  
  25.     private void Awake()
  26.     {
  27.         if (Instance != null && Instance != this)
  28.         {
  29.             Destroy(gameObject);
  30.             return;
  31.         }
  32.         Instance = this;
  33.         mainCam = Camera.main;
  34.     }
  35.  
  36.     private void Start()
  37.     {
  38.         if (enumerators.Count > 0)
  39.             playerTransform = enumerators[0].player.transform;
  40.  
  41.         farClipSqr = (mainCam.farClipPlane + 2f) * (mainCam.farClipPlane + 2f);
  42.     }
  43.  
  44.     private int unloadCycleCount = 0; // Count how many frames have passed
  45.  
  46.     private void Update()
  47.     {
  48.         if (Time.frameCount % tickInterval != 0) return;
  49.         if (playerTransform == null) return;
  50.  
  51.         // Resize NativeArrays to match the current enumerators list if needed
  52.         if (enumeratorPositions.Length != enumerators.Count)
  53.         {
  54.             if (enumeratorPositions.IsCreated)
  55.                 enumeratorPositions.Dispose();
  56.  
  57.             enumeratorPositions = new NativeArray<Vector2>(enumerators.Count, Allocator.Persistent);
  58.  
  59.             if (distSqrArray.IsCreated)
  60.                 distSqrArray.Dispose();
  61.  
  62.             distSqrArray = new NativeArray<float>(enumerators.Count, Allocator.Persistent);
  63.  
  64.             // Populate the NativeArrays with the relevant data
  65.             for (int i = 0; i < enumerators.Count; i++)
  66.             {
  67.                 enumeratorPositions[i] = new Vector2(enumerators[i].transform.position.x, enumerators[i].transform.position.z);
  68.             }
  69.         }
  70.  
  71.         Vector2 playerPos2D = new Vector2(
  72.             playerTransform.position.x,
  73.             playerTransform.position.z
  74.         );
  75.  
  76.         // Calculate the range of enumerators to process in this frame
  77.         int startIndex = currentBatchIndex * batchSize;
  78.         int endIndex = Mathf.Min((currentBatchIndex + 1) * batchSize, enumerators.Count);
  79.  
  80.         if (startIndex >= enumerators.Count)
  81.             return;  // No more enumerators to process, we are done
  82.  
  83.         // Create NativeSlice for positions and distSqrArray for this batch
  84.         NativeSlice<Vector2> batchPositions = enumeratorPositions.Slice(startIndex, endIndex - startIndex);
  85.         NativeSlice<float> batchDistSqrArray = distSqrArray.Slice(startIndex, endIndex - startIndex);
  86.  
  87.         // Create and schedule job for distance and LOD update for this batch
  88.         LODJob lodJob = new LODJob
  89.         {
  90.             playerPos = playerPos2D,
  91.             farClipSqr = farClipSqr,
  92.             positions = batchPositions,
  93.             distSqrArray = batchDistSqrArray
  94.         };
  95.  
  96.         JobHandle jobHandle = lodJob.Schedule(batchPositions.Length, 1);
  97.         jobHandle.Complete();
  98.  
  99.         // After the job completes, update the actual Shader_LOD_Enumerator objects for this batch
  100.         for (int i = startIndex; i < endIndex; i++)
  101.         {
  102.             enumerators[i].UpdateLOD(distSqrArray[i], farClipSqr);
  103.         }
  104.  
  105.         // Increment the batch index for the next frame
  106.         currentBatchIndex++;
  107.  
  108.         // Reset batch index if we've processed all enumerators
  109.         if (currentBatchIndex * batchSize >= enumerators.Count)
  110.         {
  111.             currentBatchIndex = 0; // Start over or adjust based on logic
  112.  
  113.             // Trigger unloading only for objects with disabled renderers every 5 cycles
  114.             unloadCycleCount++;
  115.             if (unloadCycleCount >= 5)
  116.             {
  117.                 StartCoroutine(UnloadUnusedAssetsCoroutine());
  118.                 unloadCycleCount = 0; // Reset cycle count after unloading
  119.             }
  120.         }
  121.     }
  122.  
  123.     private IEnumerator UnloadUnusedAssetsCoroutine()
  124.     {
  125.         // Optionally, you can add a small delay to ensure all frame work is done before unloading.
  126.         yield return null; // This simply waits for the next frame.
  127.  
  128.         // Unload unused assets only for objects with disabled renderers
  129.         foreach (var enumerator in enumerators)
  130.         {
  131.             if (!enumerator.GetComponent<Renderer>().enabled)
  132.             {
  133.                 Resources.UnloadUnusedAssets();
  134.                 Debug.Log("Unused assets unloaded for disabled renderers.");
  135.                 break; // Exit after unloading unused assets for the first disabled renderer
  136.             }
  137.         }
  138.     }
  139.  
  140.     public void Register(Shader_LOD_Enumerator e)
  141.     {
  142.         if (!enumerators.Contains(e))
  143.             enumerators.Add(e);
  144.     }
  145.  
  146.     public void Unregister(Shader_LOD_Enumerator e)
  147.     {
  148.         enumerators.Remove(e);
  149.     }
  150.  
  151.     private void OnDestroy()
  152.     {
  153.         if (enumeratorPositions.IsCreated)
  154.             enumeratorPositions.Dispose();
  155.  
  156.         if (distSqrArray.IsCreated)
  157.             distSqrArray.Dispose();
  158.     }
  159.  
  160.     // Define the job struct to handle LOD updates
  161.     struct LODJob : IJobParallelFor
  162.     {
  163.         public Vector2 playerPos;
  164.         public float farClipSqr;
  165.         public NativeSlice<Vector2> positions;
  166.         public NativeSlice<float> distSqrArray;
  167.  
  168.         public void Execute(int index)
  169.         {
  170.             Vector2 thisPos2D = positions[index];
  171.             float distSqr = (playerPos - thisPos2D).sqrMagnitude;
  172.             distSqrArray[index] = distSqr;  // Store the calculated distance in the NativeArray
  173.         }
  174.     }
  175. }
Advertisement
Add Comment
Please, Sign In to add comment