Lighting: directional sun shadows from the day/night sun angle

DayNight.SunShadow returns a cell offset opposite the sun's east-west position, longest near sunrise/sunset (low sun) and zero at noon/night, tilted slightly south so shadows fall in front of occluders. LightmapBuilder gains a directional shadow pass (MaxShadowCells length cap, SunShadowStrength darkening); LightmapSystem feeds it the current sun shadow each rebuild. Tests cover SunShadow's day-arc behaviour and the builder's directional darkening.
This commit is contained in:
Leonid Pershin
2026-06-14 07:04:11 +03:00
parent 38bdfbbb81
commit 96e19c7c61
5 changed files with 136 additions and 4 deletions
@@ -52,6 +52,26 @@ public sealed class DayNight
/// <summary>Light intensity at a world point in <c>[0, 1]</c>. Global today; local (with shadows) later.</summary>
public float SampleAt(Vector2 world) => Daylight;
/// <summary>
/// Offset, in grid cells, of the shadow an occluder casts under the current sun: opposite the
/// sun's eastwest position and longest near sunrise/sunset (low sun), shrinking to zero at noon
/// and at night. Feeds the lightmap's directional shadow pass; <paramref name="maxLength"/> caps
/// the dawn/dusk shadow length. Tilted slightly "south" (down) so shadows fall in front of objects.
/// </summary>
public Vector2 SunShadow(float maxLength)
{
var day = (_calendar.DayProgress - 0.25f) / 0.5f; // daytime fraction over [06:00, 18:00]
if (day <= 0f || day >= 1f)
{
return Vector2.Zero; // night — no sun; the ambient floor handles darkness
}
var altitude = MathF.Sin(day * MathF.PI); // 0 at dawn/dusk, 1 at noon
var direction = new Vector2(2f * day - 1f, 0.4f); // sun east→west ⇒ shadow west→east, tilted south
direction.Normalize();
return direction * (maxLength * (1f - altitude));
}
/// <summary>Ambient tint for the scene: night color at night, day color at noon, eased between.</summary>
public Color Ambient
{