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.
 
 
 
 
 

253 lines
13 KiB

using System;
namespace UnityEngine.Rendering.HighDefinition
{
/// <summary>
/// Settings for shadows.
/// </summary>
[Serializable, VolumeComponentMenu("Shadowing/Shadows")]
[SupportedOnRenderPipeline(typeof(HDRenderPipelineAsset))]
[HDRPHelpURL("Override-Shadows")]
public class HDShadowSettings : VolumeComponent, ISerializationCallbackReceiver
{
float[] m_CascadeShadowSplits = new float[3];
float[] m_CascadeShadowBorders = new float[4];
/// <summary>
/// Repartition of shadow cascade splits for directional lights.
/// </summary>
public float[] cascadeShadowSplits
{
get
{
m_CascadeShadowSplits[0] = cascadeShadowSplit0.value;
m_CascadeShadowSplits[1] = cascadeShadowSplit1.value;
m_CascadeShadowSplits[2] = cascadeShadowSplit2.value;
return m_CascadeShadowSplits;
}
}
internal float InterCascadeToSqRangeBorder(float interCascadeBorder, float prevCascadeRelRange, float cascadeRelRange)
{
// Compute the border relative to the cascade range from the inter-cascade range
float rangeBorder = cascadeRelRange >= 0.0f
? (cascadeRelRange - prevCascadeRelRange) * interCascadeBorder / cascadeRelRange
: 0.0f;
// Range will be applied to squared distance, which makes the effective range at b = 1-sqrt(1-b'), so we need to output b'=1-(1-b)^2
return 1.0f - (1.0f - rangeBorder) * (1.0f - rangeBorder);
}
internal float SqRangeBorderToInterCascade(float sqRangeBorder, float prevCascadeRelRange, float cascadeRelRange)
{
// Inverse of InterCascadeToSqRangeBorder
float interCascadeRange = cascadeRelRange - prevCascadeRelRange;
return interCascadeRange > 0.0f
? Mathf.Clamp01((1.0f - Mathf.Sqrt(1.0f - sqRangeBorder)) * cascadeRelRange / interCascadeRange)
: 0.0f;
}
/// <summary>
/// Size of the border between each shadow cascades for directional lights.
/// </summary>
public float[] cascadeShadowBorders
{
get
{
var splitCount = cascadeShadowSplitCount.value;
m_CascadeShadowBorders[0] = InterCascadeToSqRangeBorder(cascadeShadowBorder0.value, 0.0f, splitCount > 1 ? cascadeShadowSplit0.value : 1.0f);
m_CascadeShadowBorders[1] = InterCascadeToSqRangeBorder(cascadeShadowBorder1.value, cascadeShadowSplit0.value, splitCount > 2 ? cascadeShadowSplit1.value : 1.0f);
m_CascadeShadowBorders[2] = InterCascadeToSqRangeBorder(cascadeShadowBorder2.value, cascadeShadowSplit1.value, splitCount > 3 ? cascadeShadowSplit2.value : 1.0f);
m_CascadeShadowBorders[3] = InterCascadeToSqRangeBorder(cascadeShadowBorder3.value, cascadeShadowSplit2.value, 1.0f);
// For now we don't use shadow cascade borders but we still want to have the last split fading out.
if (!HDRenderPipeline.s_UseCascadeBorders)
{
m_CascadeShadowBorders[cascadeShadowSplitCount.value - 1] = 0.2f;
}
return m_CascadeShadowBorders;
}
}
[SerializeField] bool interCascadeBorders = false;
/// <summary>OnBeforeSerialize.</summary>
public void OnBeforeSerialize()
{
// Borders newly serialized are defined against inter-cascade range (as the UI displays)
// Previously serialized borders were sent directly as shader input where they are considered against the full squared range
interCascadeBorders = true;
}
/// <summary>OnAfterDeserialize.</summary>
public void OnAfterDeserialize()
{
if (!interCascadeBorders)
{
// Previously serialized borders were sent directly as shader input where they are considered against the full squared range
// This converts those ranges back to inter-cascade ranges (as the UI displays) so now both UI and shader output match
// Note that if a previously defined border would go out of the inter-cascade range, it will now be clamped to it
var splitCount = cascadeShadowSplitCount.value;
cascadeShadowBorder0.value = SqRangeBorderToInterCascade(cascadeShadowBorder0.value, 0.0f, splitCount > 1 ? cascadeShadowSplit0.value : 1.0f);
cascadeShadowBorder1.value = SqRangeBorderToInterCascade(cascadeShadowBorder1.value, cascadeShadowSplit0.value, splitCount > 2 ? cascadeShadowSplit1.value : 1.0f);
cascadeShadowBorder2.value = SqRangeBorderToInterCascade(cascadeShadowBorder2.value, cascadeShadowSplit1.value, splitCount > 3 ? cascadeShadowSplit2.value : 1.0f);
cascadeShadowBorder3.value = SqRangeBorderToInterCascade(cascadeShadowBorder3.value, cascadeShadowSplit2.value, 1.0f);
}
}
/// <summary>Sets the maximum distance HDRP renders shadows for all Light types.</summary>
[Tooltip("Sets the maximum distance HDRP renders shadows for all Light types.")]
public NoInterpMinFloatParameter maxShadowDistance = new NoInterpMinFloatParameter(500.0f, 0.0f);
/// <summary>Multiplier for thick transmission for directional lights.</summary>
[Tooltip("Multiplier for thick transmission.")]
public ClampedFloatParameter directionalTransmissionMultiplier = new ClampedFloatParameter(1.0f, 0.0f, 1.0f);
/// <summary>Number of cascades HDRP uses for cascaded shadow maps.</summary>
[Tooltip("Controls the number of cascades HDRP uses for cascaded shadow maps.")]
public NoInterpClampedIntParameter cascadeShadowSplitCount = new NoInterpClampedIntParameter(4, 1, 4);
/// <summary>Position of the first cascade split as a percentage of Max Distance if the parameter is normalized or as the distance from the camera if it's not normalized.</summary>
[Tooltip("Sets the position of the first cascade split as a percentage of Max Distance if the parameter is normalized or as the distance from the camera if it's not normalized.")]
public CascadePartitionSplitParameter cascadeShadowSplit0 = new CascadePartitionSplitParameter(0.05f);
/// <summary>Position of the second cascade split as a percentage of Max Distance if the parameter is normalized or as the distance from the camera if it's not normalized.</summary>
[Tooltip("Sets the position of the second cascade split as a percentage of Max Distance if the parameter is normalized or as the distance from the camera if it's not normalized.")]
public CascadePartitionSplitParameter cascadeShadowSplit1 = new CascadePartitionSplitParameter(0.15f);
/// <summary>Sets the position of the third cascade split as a percentage of Max Distance if the parameter is normalized or as the distance from the camera if it's not normalized.</summary>
[Tooltip("Sets the position of the third cascade split as a percentage of Max Distance if the parameter is normalized or as the distance from the camera if it's not normalized.")]
public CascadePartitionSplitParameter cascadeShadowSplit2 = new CascadePartitionSplitParameter(0.3f);
/// <summary>Border size between the first and second cascade split.</summary>
[Tooltip("Sets the border size between the first and second cascade split.")]
public CascadeEndBorderParameter cascadeShadowBorder0 = new CascadeEndBorderParameter(0.0f);
/// <summary>Border size between the second and third cascade split.</summary>
[Tooltip("Sets the border size between the second and third cascade split.")]
public CascadeEndBorderParameter cascadeShadowBorder1 = new CascadeEndBorderParameter(0.0f);
/// <summary>Border size between the third and last cascade split.</summary>
[Tooltip("Sets the border size between the third and last cascade split.")]
public CascadeEndBorderParameter cascadeShadowBorder2 = new CascadeEndBorderParameter(0.0f);
/// <summary>Border size at the end of the last cascade split.</summary>
[Tooltip("Sets the border size at the end of the last cascade split.")]
public CascadeEndBorderParameter cascadeShadowBorder3 = new CascadeEndBorderParameter(0.0f);
HDShadowSettings()
{
displayName = "Shadows";
cascadeShadowSplit0.Init(cascadeShadowSplitCount, 2, maxShadowDistance, null, cascadeShadowSplit1);
cascadeShadowSplit1.Init(cascadeShadowSplitCount, 3, maxShadowDistance, cascadeShadowSplit0, cascadeShadowSplit2);
cascadeShadowSplit2.Init(cascadeShadowSplitCount, 4, maxShadowDistance, cascadeShadowSplit1, null);
cascadeShadowBorder0.Init(cascadeShadowSplitCount, 1, maxShadowDistance, null, cascadeShadowSplit0);
cascadeShadowBorder1.Init(cascadeShadowSplitCount, 2, maxShadowDistance, cascadeShadowSplit0, cascadeShadowSplit1);
cascadeShadowBorder2.Init(cascadeShadowSplitCount, 3, maxShadowDistance, cascadeShadowSplit1, cascadeShadowSplit2);
cascadeShadowBorder3.Init(cascadeShadowSplitCount, 4, maxShadowDistance, cascadeShadowSplit2, null);
}
internal void InitNormalized(bool normalized)
{
cascadeShadowSplit0.normalized = normalized;
cascadeShadowSplit1.normalized = normalized;
cascadeShadowSplit2.normalized = normalized;
cascadeShadowBorder0.normalized = normalized;
cascadeShadowBorder1.normalized = normalized;
cascadeShadowBorder2.normalized = normalized;
cascadeShadowBorder3.normalized = normalized;
}
}
/// <summary>
/// Cascade Partition split parameter.
/// </summary>
[Serializable]
public class CascadePartitionSplitParameter : VolumeParameter<float>
{
[NonSerialized]
NoInterpMinFloatParameter maxDistance;
internal bool normalized;
[NonSerialized]
CascadePartitionSplitParameter previous;
[NonSerialized]
CascadePartitionSplitParameter next;
[NonSerialized]
NoInterpClampedIntParameter cascadeCounts;
int minCascadeToAppears;
internal float min => previous?.value ?? 0f;
internal float max => (cascadeCounts.value > minCascadeToAppears && next != null) ? next.value : 1f;
internal float representationDistance => maxDistance.value;
/// <summary>
/// Size of the split.
/// </summary>
public override float value
{
get => m_Value;
set => m_Value = Mathf.Clamp(value, min, max);
}
/// <summary>
/// Cascade Partition split parameter constructor.
/// </summary>
/// <param name="value">Initial value.</param>
/// <param name="normalized">Partition is normalized.</param>
/// <param name="overrideState">Initial override state.</param>
public CascadePartitionSplitParameter(float value, bool normalized = false, bool overrideState = false)
: base(value, overrideState)
=> this.normalized = normalized;
internal void Init(NoInterpClampedIntParameter cascadeCounts, int minCascadeToAppears, NoInterpMinFloatParameter maxDistance, CascadePartitionSplitParameter previous, CascadePartitionSplitParameter next)
{
this.maxDistance = maxDistance;
this.previous = previous;
this.next = next;
this.cascadeCounts = cascadeCounts;
this.minCascadeToAppears = minCascadeToAppears;
}
}
/// <summary>
/// Cascade End Border parameter.
/// </summary>
[Serializable]
public class CascadeEndBorderParameter : VolumeParameter<float>
{
internal bool normalized;
[NonSerialized]
CascadePartitionSplitParameter min;
[NonSerialized]
CascadePartitionSplitParameter max;
[NonSerialized]
NoInterpMinFloatParameter maxDistance;
[NonSerialized]
NoInterpClampedIntParameter cascadeCounts;
int minCascadeToAppears;
internal float representationDistance => (((cascadeCounts.value > minCascadeToAppears && max != null) ? max.value : 1f) - (min?.value ?? 0f)) * maxDistance.value;
/// <summary>
/// Size of the border.
/// </summary>
public override float value
{
get => m_Value;
set => m_Value = Mathf.Clamp01(value);
}
/// <summary>
/// Cascade End Border parameter constructor.
/// </summary>
/// <param name="value">Initial value.</param>
/// <param name="normalized">Normalized.</param>
/// <param name="overrideState">Initial override state.</param>
public CascadeEndBorderParameter(float value, bool normalized = false, bool overrideState = false)
: base(value, overrideState)
=> this.normalized = normalized;
internal void Init(NoInterpClampedIntParameter cascadeCounts, int minCascadeToAppears, NoInterpMinFloatParameter maxDistance, CascadePartitionSplitParameter min, CascadePartitionSplitParameter max)
{
this.maxDistance = maxDistance;
this.min = min;
this.max = max;
this.cascadeCounts = cascadeCounts;
this.minCascadeToAppears = minCascadeToAppears;
}
}
}