using System; using System.Collections.Generic; using ProceduralWorlds.WaterSystem; using UnityEngine; using UnityEditor; namespace Gaia { public static class LightProbeUtils { #region Variables //Probe locaions private static Quadtree m_probeLocations = new Quadtree(new Rect(0, 0, 10f, 10f)); //Stored list of reflection probes public static int m_storedProbes; //Current created count public static int m_currentProbeCount; #endregion #region Light Probe Creation Button Functions /// /// Setup for the automatically probe spawning /// /// public static void CreateAutomaticProbes(ReflectionProbeData profile) { int numberTerrains = Terrain.activeTerrains.Length; if (numberTerrains == 0) { Debug.LogError("Unable to initiate probe spawning systen. No terrain found"); } else { if (profile.lightProbesPerRow < 2) { Debug.LogError("Please set Light Probes Per Row to a value of 2 or higher"); } else { LoadProbesFromScene(); m_probeLocations = null; ClearCreatedLightProbes(); float seaLevel = 0f; PWS_WaterSystem gaiawater = GameObject.FindObjectOfType(); if (gaiawater != null) { seaLevel = gaiawater.SeaLevel; } if (GaiaUtils.HasDynamicLoadedTerrains()) { Action terrAction = (t) => GenerateProbesOnTerrain(t, profile, seaLevel); GaiaUtils.CallFunctionOnDynamicLoadedTerrains(terrAction, true, null, "Generating Light Probes"); } else { foreach (var activeTerrain in Terrain.activeTerrains) { GenerateProbesOnTerrain(activeTerrain, profile, seaLevel); } } } } } #endregion #region Light Probe Utils private static void GenerateProbesOnTerrain(Terrain terrain, ReflectionProbeData profile, float seaLevel) { GameObject lightProbeObject = GameObject.Find(terrain.name + " Light Probes Group Data"); if (lightProbeObject == null) { lightProbeObject = new GameObject(terrain.name + " Light Probes Group Data"); } LightProbeGroup lightProbeData = lightProbeObject.GetComponent(); if (lightProbeData == null) { lightProbeData = lightProbeObject.AddComponent(); lightProbeData.probePositions = new Vector3[0]; } GameObject lightParentObject = LightProbeParenting(terrain); Vector3 terrainSize = terrain.terrainData.size; m_storedProbes = profile.lightProbesPerRow * profile.lightProbesPerRow; for (int row = 0; row < profile.lightProbesPerRow; ++row) { for (int columns = 0; columns < profile.lightProbesPerRow; ++columns) { Vector3 newPosition = lightProbeObject.transform.position - lightProbeData.transform.position; newPosition.x = ((columns + 1) * terrainSize.x / profile.lightProbesPerRow) - terrainSize.x / profile.lightProbesPerRow / 2f + terrain.transform.position.x; newPosition.z = ((row + 1) * terrainSize.z / profile.lightProbesPerRow) - terrainSize.z / profile.lightProbesPerRow / 2f + terrain.transform.position.z; float sampledHeight = terrain.SampleHeight(newPosition); newPosition.y = sampledHeight + 2.5f; List probePositions = new List(lightProbeData.probePositions); if (sampledHeight > seaLevel) { probePositions.Add(newPosition); newPosition += new Vector3(0f, 2.5f, 0f); probePositions.Add(newPosition); newPosition += new Vector3(0f, 10f, 0f); probePositions.Add(newPosition); lightProbeData.probePositions = probePositions.ToArray(); m_currentProbeCount++; } } } lightProbeObject.transform.SetParent(lightParentObject.transform); EditorGUIUtility.PingObject(lightParentObject); } /// /// Creates the reflection prrobe parent object /// /// /// private static GameObject LightProbeParenting(Terrain parentTerrain) { if (parentTerrain == null) { Debug.LogWarning("Terrain provided in ReflectionProbeParenting() is null"); return null; } GameObject reflectionProbeParent = GameObject.Find(parentTerrain.name + " Light Probes"); if (reflectionProbeParent == null) { reflectionProbeParent = new GameObject(parentTerrain.name + " Light Probes"); } reflectionProbeParent.transform.SetParent(parentTerrain.transform); return reflectionProbeParent; } /// /// Load the probes in from the scene /// private static void LoadProbesFromScene() { //Start time //DateTime startTime = DateTime.Now; //Destroy previous contents m_probeLocations = null; //Work out the bounds of the environment float minY = float.NaN; float minX = float.NaN; float maxX = float.NaN; float minZ = float.NaN; float maxZ = float.NaN; Terrain sampleTerrain = null; foreach (Terrain terrain in Terrain.activeTerrains) { if (float.IsNaN(minY)) { sampleTerrain = terrain; minY = terrain.transform.position.y; minX = terrain.transform.position.x; minZ = terrain.transform.position.z; maxX = minX + terrain.terrainData.size.x; maxZ = minZ + terrain.terrainData.size.z; } else { if (terrain.transform.position.x < minX) { minX = terrain.transform.position.x; } if (terrain.transform.position.z < minZ) { minZ = terrain.transform.position.z; } if ((terrain.transform.position.x + terrain.terrainData.size.x) > maxX) { maxX = terrain.transform.position.x + terrain.terrainData.size.x; } if ((terrain.transform.position.z + terrain.terrainData.size.z) > maxZ) { maxZ = terrain.transform.position.z + terrain.terrainData.size.z; } } } if (sampleTerrain != null) { Rect terrainBounds = new Rect(minX, minZ, maxX - minX, maxZ - minZ); m_probeLocations = new Quadtree(terrainBounds); } else { Rect bigSpace = new Rect(-10000f, -10000f, 20000f, 20000f); m_probeLocations = new Quadtree(bigSpace); } //Now grab all the light probes in the scene LightProbeGroup probeGroup; LightProbeGroup[] probeGroups = UnityEngine.Object.FindObjectsOfType(); for (int probeGroupIdx = 0; probeGroupIdx < probeGroups.Length; probeGroupIdx++) { probeGroup = probeGroups[probeGroupIdx]; for (int probePosition = 0; probePosition < probeGroup.probePositions.Length; probePosition++) { m_probeLocations.Insert(probeGroup.transform.position.x + probeGroup.probePositions[probePosition].x, probeGroup.transform.position.z + probeGroup.probePositions[probePosition].z, probeGroup); } } } /// /// Add a probe instance into storage - must be called after the initial load call /// /// Position it is being located at /// Probe group being managed public static void AddProbe(Vector3 position, LightProbeGroup probeGroup) { if (m_probeLocations == null) { return; } m_probeLocations.Insert(position.x, position.z, probeGroup); } /// /// Add a probe instance into storage - must be called after the initial load call /// /// Position it is being located at /// Probe group being managed public static void RemoveProbe(Vector3 position, LightProbeGroup probeGroup) { if (m_probeLocations == null) { return; } m_probeLocations.Remove(position.x, position.z, probeGroup); } /// /// Clears reflection probes created /// public static void ClearCreatedLightProbes() { if (GaiaUtils.HasDynamicLoadedTerrains()) { Action terrAction = (t) => DeleteProbeGroup(t); GaiaUtils.CallFunctionOnDynamicLoadedTerrains(terrAction, true, null, "Clearing Light Probes"); } else { if (Terrain.activeTerrains.Length < 1) { Debug.LogError("No terrains we're found, unable to clear light probes."); } else { foreach (var activeTerrain in Terrain.activeTerrains) { DeleteProbeGroup(activeTerrain); } } } } private static void DeleteProbeGroup(Terrain terrain) { GameObject lightProbeParent = GameObject.Find(terrain.name + " Light Probes"); if (lightProbeParent != null) { GameObject.DestroyImmediate(lightProbeParent); m_currentProbeCount = 0; } } #endregion } }