using UnityEngine; using System.Collections.Generic; using System.Linq; namespace SimpleLightProbePlacer { [RequireComponent(typeof(LightProbeGroup))] [AddComponentMenu("Rendering/Light Probe Group Control")] public class LightProbeGroupControl : MonoBehaviour { [SerializeField] private float m_mergeDistance = 0.5f; [SerializeField] private bool m_usePointLights = true; [SerializeField] private float m_pointLightRange = 1; public float MergeDistance { get { return m_mergeDistance; } set { m_mergeDistance = value; } } public int MergedProbes { get { return m_mergedProbes; } } public bool UsePointLights { get { return m_usePointLights; } set { m_usePointLights = value; } } public float PointLightRange { get { return m_pointLightRange; } set { m_pointLightRange = value; } } public LightProbeGroup LightProbeGroup { get { if (m_lightProbeGroup != null) return m_lightProbeGroup; return m_lightProbeGroup = GetComponent(); } } private int m_mergedProbes; private LightProbeGroup m_lightProbeGroup; public void DeleteAll() { LightProbeGroup.probePositions = null; m_mergedProbes = 0; } public void Create() { DeleteAll(); List positions = CreatePositions(); positions.AddRange(CreateAroundPointLights(m_pointLightRange)); positions = MergeClosestPositions(positions, m_mergeDistance, out m_mergedProbes); ApplyPositions(positions); } public void Merge() { if (LightProbeGroup.probePositions == null) return; List positions = MergeClosestPositions(LightProbeGroup.probePositions.ToList(), m_mergeDistance, out m_mergedProbes); positions = positions.Select(x => transform.TransformPoint(x)).ToList(); ApplyPositions(positions); } private void ApplyPositions(List positions) { LightProbeGroup.probePositions = positions.Select(x => transform.InverseTransformPoint(x)).ToArray(); } private static List CreatePositions() { var lightProbeVolumes = FindObjectsOfType(); if (lightProbeVolumes.Length == 0) return new List(); List probes = new List(); for (int i = 0; i < lightProbeVolumes.Length; i++) { probes.AddRange(lightProbeVolumes[i].CreatePositions()); } return probes; } private static List CreateAroundPointLights(float range) { var lights = FindObjectsOfType().Where(x => x.type == LightType.Point).ToList(); if (lights.Count == 0) return new List(); List probes = new List(); for (int i = 0; i < lights.Count; i++) { probes.AddRange(CreatePositionsAround(lights[i].transform, range)); } return probes; } private static List MergeClosestPositions(List positions, float distance, out int mergedCount) { if (positions == null) { mergedCount = 0; return new List(); } int exist = positions.Count; bool done = false; while (!done) { Dictionary> closest = new Dictionary>(); for (int i = 0; i < positions.Count; i++) { List points = positions.Where(x => (x - positions[i]).magnitude < distance).ToList(); if (points.Count > 0 && !closest.ContainsKey(positions[i])) { closest.Add(positions[i], points); } } positions.Clear(); List keys = closest.Keys.ToList(); for (int i = 0; i < keys.Count; i++) { var center = closest[keys[i]].Aggregate(Vector3.zero, (result, target) => result + target) / closest[keys[i]].Count; if (!positions.Exists(x => x == center)) positions.Add(center); } done = positions.Select(x => positions.Where(y => y != x && (y - x).magnitude < distance)).All(x => !x.Any()); } mergedCount = exist - positions.Count; return positions; } public static List CreatePositionsAround(Transform transform, float range) { Vector3[] corners = { new Vector3(-0.5f, 0.5f, -0.5f), new Vector3(-0.5f, 0.5f, 0.5f), new Vector3(0.5f, 0.5f, 0.5f), new Vector3(0.5f, 0.5f, -0.5f), new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(-0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, 0.5f), new Vector3(0.5f, -0.5f, -0.5f) }; return corners.Select(x => transform.TransformPoint(x * range)).ToList(); } } }