Skip to content

Commit

Permalink
Probe Volumes: Reflection Probe Normalization by Probe Volumes added.…
Browse files Browse the repository at this point in the history
… In order to enable, NormalizeReflectionProbeWithProbeVolume needs to be enabled in the Frame Settings for the Camera, and scenes need to be rebaked. Options exist on the ProbeVolumeController volume override. (#27)

Co-authored-by: pastasfuture <nickb@bonfirestudios.com>
  • Loading branch information
pastasfuture and pastasfuture committed Sep 14, 2021
1 parent d91cada commit 60fb5ba
Show file tree
Hide file tree
Showing 18 changed files with 793 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using UnityEngine.Profiling;
using UnityEngine.SceneManagement;
using Unity.Collections;
using UnityEditor;

namespace UnityEngine.Rendering.HighDefinition
{
/// <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; } }

private AdditionalGIBakeRequestsManager()
{
SubscribeOnBakeStarted();
}

~AdditionalGIBakeRequestsManager()
{
UnsubscribeOnBakeStarted();
}

private static List<SphericalHarmonicsL2> m_SHCoefficients = new List<SphericalHarmonicsL2>();
private static List<Vector3> m_RequestPositions = new List<Vector3>();
private static int m_FreelistHead = -1;

private static readonly Vector2 s_FreelistSentinel = new Vector2(float.MaxValue, float.MaxValue);

/// <summary>
/// Enqueue a request for probe rendering at the specified location.
/// </summary>
/// <param name ="capturePosition"> The position at which a probe is baked.</param>
/// <returns>An ID that can be used to retrieve the data once it has been computed</returns>
public int EnqueueRequest(Vector3 capturePosition)
{
Debug.Assert(ComputeCapturePositionIsValid(capturePosition));

if (m_FreelistHead >= 0)
{
int requestID = m_FreelistHead;
Debug.Assert(requestID < m_RequestPositions.Count);
m_FreelistHead = ComputeFreelistNext(m_RequestPositions[requestID]);
m_RequestPositions[requestID] = capturePosition;
m_SHCoefficients[requestID] = new SphericalHarmonicsL2();
return requestID;
}
else
{
int requestID = m_RequestPositions.Count;
m_RequestPositions.Add(capturePosition);
m_SHCoefficients.Add(new SphericalHarmonicsL2());
return requestID;
}
}

/// <summary>
/// Enqueue a request for probe rendering at the specified location.
/// </summary>
/// <param name ="requestID"> An ID that can be used to retrieve the data once it has been computed</param>
/// <returns>An ID that can be used to retrieve the data once it has been computed</returns>
public void DequeueRequest(int requestID)
{
Debug.Assert(requestID >= 0 && requestID < m_RequestPositions.Count);

m_RequestPositions[requestID] = new Vector3(s_FreelistSentinel.x, s_FreelistSentinel.y, m_FreelistHead);
m_SHCoefficients[requestID] = new SphericalHarmonicsL2();
m_FreelistHead = requestID;
}

private bool ComputeCapturePositionIsValid(Vector3 capturePosition)
{
return !((capturePosition.x == s_FreelistSentinel.x) && (capturePosition.y == s_FreelistSentinel.y));
}

private int ComputeFreelistNext(Vector3 capturePosition)
{
Debug.Assert(ComputeRequestIsFree(capturePosition));

int freelistNext = (int)capturePosition.z;
Debug.Assert(freelistNext >= -1 && freelistNext < m_RequestPositions.Count);
return freelistNext;
}

private bool ComputeRequestIsFree(int requestID)
{
Debug.Assert(requestID >= 0 && requestID < m_RequestPositions.Count);
Vector3 requestPosition = m_RequestPositions[requestID];
return ComputeRequestIsFree(requestPosition);
}

private bool ComputeRequestIsFree(Vector3 capturePosition)
{
return (capturePosition.x == s_FreelistSentinel.x) && (capturePosition.y == s_FreelistSentinel.y);
}

/// <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 ="requestID"> The request ID that has been given by the manager through a previous EnqueueRequest.</param>
/// <param name ="sh"> The output SH coefficients that have been computed.</param>
/// <returns>Whether the request for light probe rendering has been fulfilled and sh is valid.</returns>
public bool RetrieveProbeSH(int requestID, out SphericalHarmonicsL2 sh)
{
if (requestID >= 0 && requestID < m_SHCoefficients.Count
&& ComputeCapturePositionIsValid(m_RequestPositions[requestID]))
{
sh = m_SHCoefficients[requestID];
return true;
}
else
{
sh = new SphericalHarmonicsL2();
return false;
}
}

/// <summary>
/// Update the capture location for the probe request.
/// </summary>
/// <param name ="requestID"> The request ID that has been given by the manager through a previous EnqueueRequest.</param>
/// <param name ="newPositionnewPosition"> The position at which a probe is baked.</param>
public int UpdatePositionForRequest(int requestID, Vector3 newPosition)
{
if (requestID >= 0 && requestID < m_RequestPositions.Count)
{
Debug.Assert(ComputeCapturePositionIsValid(m_RequestPositions[requestID]));
m_RequestPositions[requestID] = newPosition;
m_SHCoefficients[requestID] = new SphericalHarmonicsL2();
return requestID;
}
else
{
return EnqueueRequest(newPosition);
}
}

private void SubscribeOnBakeStarted()
{
UnsubscribeOnBakeStarted();
Lightmapping.bakeStarted += AddRequestsToLightmapper;
}

private void UnsubscribeOnBakeStarted()
{
Lightmapping.bakeStarted -= AddRequestsToLightmapper;
RemoveRequestsFromLightmapper();
}

internal void AddRequestsToLightmapper()
{
UnityEditor.Experimental.Lightmapping.SetAdditionalBakedProbes(s_BakingID, m_RequestPositions.ToArray());

Lightmapping.bakeCompleted -= OnAdditionalProbesBakeCompleted;
Lightmapping.bakeCompleted += OnAdditionalProbesBakeCompleted;
}

private void RemoveRequestsFromLightmapper()
{
UnityEditor.Experimental.Lightmapping.SetAdditionalBakedProbes(s_BakingID, null);
}

private void OnAdditionalProbesBakeCompleted()
{
Lightmapping.bakeCompleted -= OnAdditionalProbesBakeCompleted;

var sh = new NativeArray<SphericalHarmonicsL2>(m_RequestPositions.Count, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var validity = new NativeArray<float>(m_RequestPositions.Count, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
var bakedProbeOctahedralDepth = new NativeArray<float>(m_RequestPositions.Count * 64, Allocator.Temp, NativeArrayOptions.UninitializedMemory);

UnityEditor.Experimental.Lightmapping.GetAdditionalBakedProbes(s_BakingID, sh, validity, bakedProbeOctahedralDepth);

SetSHCoefficients(sh);
PushSHCoefficientsToReflectionProbes();

sh.Dispose();
validity.Dispose();
bakedProbeOctahedralDepth.Dispose();
}

private void SetSHCoefficients(NativeArray<SphericalHarmonicsL2> sh)
{
Debug.Assert(sh.Length == m_SHCoefficients.Count);
for (int i = 0; i < sh.Length; ++i)
{
m_SHCoefficients[i] = sh[i];
}
}

private void PushSHCoefficientsToReflectionProbes()
{
List<HDProbe> hdProbes = HDProbe.GetInstances();
foreach (var hdProbe in hdProbes)
{
hdProbe.TryUpdateLuminanceSHL2ForNormalization();
}
}
}
}
#endif

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,14 @@ struct EnvLightData
public float distanceBasedRoughness;
// Sampling properties
public int envIndex;

// The luma SH for irradiance at probe location.
public Vector4 L0L1;
public Vector4 L2_1; // First 4 coeffs of L2 {-2, -1, 0, 1}
public float L2_2; // Last L2 coeff {2}
// Whether the probe is normalized by probe volume content.
public int normalizeWithProbeVolumes;
public Vector2 padding;
};

[GenerateHLSL]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ struct EnvLightData
float roughReflections;
float distanceBasedRoughness;
int envIndex;
float4 L0L1;
float4 L2_1;
float L2_2;
int normalizeWithProbeVolumes;
float2 padding;
};


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2082,6 +2082,16 @@ internal bool GetEnvLightData(CommandBuffer cmd, HDCamera hdCamera, in Processed

envLightData.envIndex = envIndex;

envLightData.normalizeWithProbeVolumes = hdCamera.frameSettings.IsEnabled(FrameSettingsField.NormalizeReflectionProbeWithProbeVolume) ? 1 : 0;
if (envLightData.normalizeWithProbeVolumes > 0)
{
if (!probe.GetLuminanceSHL2ForNormalization(out envLightData.L0L1, out envLightData.L2_1, out envLightData.L2_2))
{
// We don't have valid data, hence we disable the feature.
envLightData.normalizeWithProbeVolumes = 0;
}
}

// Proxy data
var proxyToWorld = probe.proxyToWorld;
envLightData.proxyExtents = probe.proxyExtents;
Expand Down

0 comments on commit 60fb5ba

Please sign in to comment.