using System;
namespace UnityEngine.Rendering.HighDefinition
{
///
/// A volume component that holds a list of Diffusion Profile.
///
[Serializable, VolumeComponentMenu("Material/Diffusion Profile List")]
[SupportedOnRenderPipeline(typeof(HDRenderPipelineAsset))]
[HDRPHelpURL("Override-Diffusion-Profile")]
public class DiffusionProfileList : VolumeComponent
{
///
/// List of diffusion profiles used inside the volume.
///
[Tooltip("List of diffusion profiles used inside the volume.")]
[SerializeField]
public DiffusionProfileSettingsParameter diffusionProfiles = new DiffusionProfileSettingsParameter(default(DiffusionProfileSettings[]));
internal int Length => diffusionProfiles.value == null ? 0 : diffusionProfiles.value.Length;
internal DiffusionProfileSettings[] ToArray()
{
return diffusionProfiles.value ?? Array.Empty();
}
internal void ReplaceWithArray(DiffusionProfileSettings[] profileSettingsArray)
{
profileSettingsArray ??= Array.Empty();
if (profileSettingsArray.Length >= DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT)
throw new IndexOutOfRangeException($"The length {profileSettingsArray.Length} of {nameof(profileSettingsArray)} exceeds the limit {DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT}");
diffusionProfiles.value = profileSettingsArray;
}
}
///
/// A that holds a value.
///
[Serializable]
public sealed class DiffusionProfileSettingsParameter : VolumeParameter
{
static System.Buffers.ArrayPool s_ArrayPool =
System.Buffers.ArrayPool.Create(DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT, 5);
// To accumulate diffusion profiles when resolving stack and not make a new allocation everytime,
// We allocate once an array with max size, and store the ammount of slots used here.
internal DiffusionProfileSettings[] accumulatedArray = null;
internal int accumulatedCount = 0;
private DiffusionProfileSettings m_DefaultDiffusionProfileSettings = null;
///
/// Creates a new instance.
///
/// The initial value to store in the parameter.
/// The initial override state for the parameter.
public DiffusionProfileSettingsParameter(DiffusionProfileSettings[] value, bool overrideState = true)
: base(value, overrideState) { }
// Perform custom interpolation: We want to accumulate profiles instead of replacing them
void AddProfile(DiffusionProfileSettings profile)
{
if (profile == null)
return;
for (int i = 0; i < accumulatedCount; i++)
{
if (profile == m_Value[i])
return;
}
m_Value[accumulatedCount++] = profile;
}
///
/// Sets the value of this parameter to the value in .
/// Implemented explicitly for DiffusionProfileList because we have internal state to copy.
///
/// The to copy the value from.
public override void SetValue(VolumeParameter parameter)
{
base.SetValue(parameter);
var param = parameter as DiffusionProfileSettingsParameter;
accumulatedCount = param.accumulatedCount;
}
///
/// Interpolates two values using a factor .
///
///
/// By default, this method does a "snap" interpolation, meaning it returns the value
/// if is higher than 0, and
/// otherwise.
///
/// The start value.
/// The end value.
/// The interpolation factor in range [0,1].
public override void Interp(DiffusionProfileSettings[] from, DiffusionProfileSettings[] to, float t)
{
m_Value = s_ArrayPool.Rent(DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT);
accumulatedCount = 0;
if (m_DefaultDiffusionProfileSettings == null)
{
m_DefaultDiffusionProfileSettings = GraphicsSettings.TryGetRenderPipelineSettings(out var assets) ?
assets.defaultDiffusionProfile : null;
}
m_Value[accumulatedCount++] = m_DefaultDiffusionProfileSettings;
if (to != null)
{
foreach (var profile in to)
{
AddProfile(profile);
if (accumulatedCount >= DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT)
break;
}
}
if (from != null)
{
foreach (var profile in from)
{
AddProfile(profile);
if (accumulatedCount >= DiffusionProfileConstants.DIFFUSION_PROFILE_COUNT)
break;
}
}
for (int i = accumulatedCount; i < m_Value.Length; i++)
m_Value[i] = null;
if (accumulatedArray != null)
s_ArrayPool.Return(accumulatedArray);
accumulatedArray = m_Value;
}
///
/// Override this method to free all allocated resources
///
public override void Release()
{
if (accumulatedArray != null)
s_ArrayPool.Return(accumulatedArray);
accumulatedArray = null;
}
}
}