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
}