You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
162 lines
6.5 KiB
162 lines
6.5 KiB
using System.Collections.Generic;
|
|
using Unity.Collections;
|
|
#if UNITY_EDITOR
|
|
using UnityEditor;
|
|
#endif
|
|
|
|
namespace UnityEngine.Rendering
|
|
{
|
|
#if UNITY_EDITOR
|
|
|
|
/// <summary>
|
|
/// A manager to enqueue extra probe rendering outside of probe volumes.
|
|
/// </summary>
|
|
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();
|
|
/// <summary>
|
|
/// Get the manager that governs the additional light probe rendering requests.
|
|
/// </summary>
|
|
public static AdditionalGIBakeRequestsManager instance { get { return s_Instance; } }
|
|
|
|
const float kInvalidSH = 1f;
|
|
const float kValidSHThresh = 0.33f;
|
|
|
|
private static Dictionary<int, SphericalHarmonicsL2> m_SHCoefficients = new Dictionary<int, SphericalHarmonicsL2>();
|
|
private static Dictionary<int, float> m_SHValidity = new Dictionary<int, float>();
|
|
private static Dictionary<int, Vector3> m_RequestPositions = new Dictionary<int, Vector3>();
|
|
|
|
/// <summary>
|
|
/// Enqueue a request for probe rendering at the specified location.
|
|
/// </summary>
|
|
/// <param name ="capturePosition"> The position at which a probe is baked.</param>
|
|
/// <param name ="probeInstanceID"> The instance ID of the probe doing the request.</param>
|
|
public void EnqueueRequest(Vector3 capturePosition, int probeInstanceID)
|
|
{
|
|
m_SHCoefficients[probeInstanceID] = new SphericalHarmonicsL2();
|
|
m_SHValidity[probeInstanceID] = kInvalidSH;
|
|
m_RequestPositions[probeInstanceID] = capturePosition;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dequeue a request for probe rendering.
|
|
/// </summary>
|
|
/// <param name ="probeInstanceID">The instance ID of the probe for which we want to dequeue a request. </param>
|
|
public void DequeueRequest(int probeInstanceID)
|
|
{
|
|
if (m_SHCoefficients.ContainsKey(probeInstanceID))
|
|
{
|
|
m_SHCoefficients.Remove(probeInstanceID);
|
|
m_SHValidity.Remove(probeInstanceID);
|
|
m_RequestPositions.Remove(probeInstanceID);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name ="probeInstanceID"> The instance ID of the probe doing the request.</param>
|
|
/// <param name ="sh"> The output SH coefficients that have been computed.</param>
|
|
/// <param name ="pos"> The position for which the computed SH coefficients are valid.</param>
|
|
/// <returns>Whether the request for light probe rendering has been fulfilled and sh is valid.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update the capture location for the probe request.
|
|
/// </summary>
|
|
/// <param name ="probeInstanceID"> The instance ID of the probe doing the request and that wants the capture position updated.</param>
|
|
/// <param name ="newPositionnewPosition"> The position at which a probe is baked.</param>
|
|
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<Vector3> GetProbeNormalizationRequests() => new List<Vector3>(m_RequestPositions.Values);
|
|
|
|
static internal void OnAdditionalProbesBakeCompleted(NativeArray<SphericalHarmonicsL2> sh, NativeArray<float> 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<SphericalHarmonicsL2> sh, NativeArray<float> validity)
|
|
{
|
|
Debug.Assert(sh.Length == m_SHCoefficients.Count);
|
|
Debug.Assert(sh.Length == validity.Length);
|
|
|
|
List<int> requestsInstanceIDs = new List<int>(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
|
|
}
|