using System.Collections.Generic; using Unity.Collections; #if UNITY_EDITOR using UnityEditor; #endif namespace UnityEngine.Rendering { #if UNITY_EDITOR /// /// A manager to enqueue extra probe rendering outside of probe volumes. /// public class AdditionalGIBakeRequestsManager { // The baking ID for the extra requests // TODO: Need to ensure this never conflicts with bake IDs from others interacting with the API. // In our project, this is ProbeVolumes. internal static readonly int s_BakingID = 912345678; private static AdditionalGIBakeRequestsManager s_Instance = new AdditionalGIBakeRequestsManager(); /// /// Get the manager that governs the additional light probe rendering requests. /// public static AdditionalGIBakeRequestsManager instance { get { return s_Instance; } } const float kInvalidSH = 1f; const float kValidSHThresh = 0.33f; private static Dictionary m_SHCoefficients = new Dictionary(); private static Dictionary m_SHValidity = new Dictionary(); private static Dictionary m_RequestPositions = new Dictionary(); /// /// Enqueue a request for probe rendering at the specified location. /// /// The position at which a probe is baked. /// The instance ID of the probe doing the request. public void EnqueueRequest(Vector3 capturePosition, int probeInstanceID) { m_SHCoefficients[probeInstanceID] = new SphericalHarmonicsL2(); m_SHValidity[probeInstanceID] = kInvalidSH; m_RequestPositions[probeInstanceID] = capturePosition; } /// /// Dequeue a request for probe rendering. /// /// The instance ID of the probe for which we want to dequeue a request. public void DequeueRequest(int probeInstanceID) { if (m_SHCoefficients.ContainsKey(probeInstanceID)) { m_SHCoefficients.Remove(probeInstanceID); m_SHValidity.Remove(probeInstanceID); m_RequestPositions.Remove(probeInstanceID); } } /// /// Retrieve the result of a capture request, it will return false if the request has not been fulfilled yet or the request ID is invalid. /// /// The instance ID of the probe doing the request. /// The output SH coefficients that have been computed. /// The position for which the computed SH coefficients are valid. /// Whether the request for light probe rendering has been fulfilled and sh is valid. public bool RetrieveProbeSH(int probeInstanceID, out SphericalHarmonicsL2 sh, out Vector3 pos) { if (m_SHCoefficients.ContainsKey(probeInstanceID)) { sh = m_SHCoefficients[probeInstanceID]; pos = m_RequestPositions[probeInstanceID]; return m_SHValidity[probeInstanceID] < kValidSHThresh; } sh = new SphericalHarmonicsL2(); pos = Vector3.negativeInfinity; return false; } static internal bool GetPositionForRequest(int probeInstanceID, out Vector3 pos) { if (m_SHCoefficients.ContainsKey(probeInstanceID)) { pos = m_RequestPositions[probeInstanceID]; return true; } pos = Vector3.negativeInfinity; return false; } /// /// Update the capture location for the probe request. /// /// The instance ID of the probe doing the request and that wants the capture position updated. /// The position at which a probe is baked. public void UpdatePositionForRequest(int probeInstanceID, Vector3 newPosition) { if (m_SHCoefficients.ContainsKey(probeInstanceID)) { m_RequestPositions[probeInstanceID] = newPosition; m_SHCoefficients[probeInstanceID] = new SphericalHarmonicsL2(); m_SHValidity[probeInstanceID] = kInvalidSH; } else { EnqueueRequest(newPosition, probeInstanceID); } } static internal List GetProbeNormalizationRequests() => new List(m_RequestPositions.Values); static internal void OnAdditionalProbesBakeCompleted(NativeArray sh, NativeArray validity) { SetSHCoefficients(sh, validity); ProbeReferenceVolume.instance.retrieveExtraDataAction?.Invoke(new ProbeReferenceVolume.ExtraDataActionInput()); } static bool IsZero(in SphericalHarmonicsL2 s) { for (var r = 0; r < 3; ++r) { for (var c = 0; c < 9; ++c) { if (s[r, c] != 0f) return false; } } return true; } static void SetSHCoefficients(NativeArray sh, NativeArray validity) { Debug.Assert(sh.Length == m_SHCoefficients.Count); Debug.Assert(sh.Length == validity.Length); List requestsInstanceIDs = new List(m_SHCoefficients.Keys); for (int i = 0; i < sh.Length; ++i) SetSHCoefficients(requestsInstanceIDs[i], sh[i], validity[i]); } static internal void SetSHCoefficients(int instanceID, SphericalHarmonicsL2 sh, float validity) { if (validity < kValidSHThresh) { if (IsZero(in sh)) { // Use max value as a sentinel to explicitly pass coefficients to light loop that cancel out reflection probe contribution const float k = float.MaxValue; sh.AddAmbientLight(new Color(k, k, k)); } } m_SHCoefficients[instanceID] = sh; m_SHValidity[instanceID] = validity; } } #endif }