the symptom, in your words

"A low sun in a street canyon leaves the ground unshadowed"

✓ verified on 26.07.22
lane Getting art inposted

▸ SYMPTOM

  • A frame contains zero visible ground shadows even though every shadow flag is correct.
  • The light is casting, the cascade split ratio is tuned, and the near NPCs all have SceneObject.Flags.CastShadows = true.
  • The cascaded shadow map still costs a large share of the frame while producing nothing on screen.

▸ CAUSE

A golden-hour sun at single-digit elevation puts no direct light on the ground of a street canyon. Nothing standing on that ground casts a visible shadow, and the cascade is billed in full to produce a constant.

Shadow length on flat ground is H / tan(elevation). At 7 degrees that is 8.14 * H, so a 14 m facade throws a 113 m shadow. Only the component across the street blocks the street, which is length * sin(azimuth offset from the street axis).

Worked case: a 25.4 m street with 14 m facades, sun at elevation 7 and azimuth 45 degrees off the street axis, gives an 80 m cross-street shadow against a 12.7 m half-width. That is an overshoot of 6.3x. Every square metre of ground is permanently shaded, all day, everywhere on the map.

This looks exactly like a bug and is not one. On the project that hit this, the cascade measured 65 to 68 per cent of every frame's draws (2.88x at 1600 agents, 3.13x at 2400) while its only on-screen product was the shadow line partway down the facades. Do the arithmetic before touching a renderer flag.

▸ FIX

The fix is the sun angle, and it is a trade, not a free win. For sun to reach the street centreline you need H / tan(elevation) * sin(offset) <= half-width.

  • At a 45-degree offset that case needs elevation 38 to 44, a near-noon sun that is not a golden hour.
  • At a 12-degree offset it needs only elevation 13 to 16, which still reads low and warm and still rakes the cross facades diagonally.

A small azimuth offset buys far more ground light than a big elevation change, because the offset enters as a sine while the elevation enters as a tangent. Rule of thumb for any low-sun street scene: keep the sun within about 15 degrees of the street axis, or accept that the street floor is a shadow.

▸ WHY IT WORKS

Two engine-side companions are silent on a fully shaded ground.

  1. DirectionalLight.ContactShadows earns nothing where there is no direct light to occlude.
  2. An ambient authored as a single flat SkyColor gives shaded ground one constant colour times albedo, which reads as flat and lacking depth. Fix that with an AmbientOcclusion component rather than with any light.
Verified on engine 26.07.22: seen in a real project.
s&box moves fast; an undated fix is a liability. Spot a stale detail?
changelog
  • Published

Want to know when new guides or fixes drop? Join the community to help build this out. Report gotchas, flag outdated fixes, or just lurk.

Join the Discord