Fix ambient flyer cadence and rotating shadows

This commit is contained in:
Erik 2026-08-22 17:39:38 +02:00
parent 9cd429dd73
commit 8b7b601b32
5 changed files with 239 additions and 3 deletions

View file

@ -438,6 +438,41 @@ internal sealed class DirectionalSunShadowRenderer : IDirectionalShadowReceiverS
};
}
/// <summary>
/// The fitted frustum slice bounds receivers, not the casters that project
/// onto them. At low celestial elevations a modest tree can be many metres
/// farther along the light ray than its visible ground shadow. Padding by
/// less than the effective receiver reach therefore clips a caster as the
/// camera-relative slice turns, producing partial or disappearing shadows.
/// This expands depth only; cascade XY density, draw count, and caster
/// membership are unchanged.
/// </summary>
internal static float ResolveCasterDepthPaddingMeters(
float configuredPaddingMeters,
float qualityReachMeters,
float residentMaximumReachMeters)
{
if (!float.IsFinite(configuredPaddingMeters)
|| configuredPaddingMeters <= 0f)
{
throw new ArgumentOutOfRangeException(
nameof(configuredPaddingMeters));
}
if (!float.IsFinite(qualityReachMeters) || qualityReachMeters <= 0f)
throw new ArgumentOutOfRangeException(nameof(qualityReachMeters));
if (float.IsNaN(residentMaximumReachMeters)
|| residentMaximumReachMeters <= 0f)
{
throw new ArgumentOutOfRangeException(
nameof(residentMaximumReachMeters));
}
float effectiveReceiverReach = MathF.Min(
qualityReachMeters,
residentMaximumReachMeters);
return MathF.Max(configuredPaddingMeters, effectiveReceiverReach);
}
internal DirectionalSunShadowDiagnostics RenderPrepared(
IGpuFrame frame,
in DirectionalShadowEnvironmentState environment,
@ -473,6 +508,11 @@ internal sealed class DirectionalSunShadowRenderer : IDirectionalShadowReceiverS
nameof(worldTransforms));
long started = Stopwatch.GetTimestamp();
float effectiveCasterDepthPaddingMeters =
ResolveCasterDepthPaddingMeters(
casterDepthPaddingMeters,
_quality.MaximumReachMeters,
residentMaximumReachMeters);
var fit = new DirectionalShadowCascadeFitInput(
cameraView,
cameraProjection,
@ -480,7 +520,7 @@ internal sealed class DirectionalSunShadowRenderer : IDirectionalShadowReceiverS
_quality,
cameraNearMeters,
PracticalSplitLambda: 0.65f,
casterDepthPaddingMeters,
effectiveCasterDepthPaddingMeters,
residentMaximumReachMeters);
int cascadeCount = DirectionalShadowCascadeFitter.Fit(
fit,