the symptom, in your words

"Time-of-day sky swap pops — use a weighted-blend shader instead"

✓ verified on 26.07.15a
lane Getting art inposted

▸ SYMPTOM

A day/night cycle that swaps the sky texture or SkyBox2D.SkyMaterial at transition boundaries produces a visible, jarring pop at the swap instant. Masking the pop with a timed Tint-darkness dip (fading to black around the swap frame) hides the discontinuity but does not fix it — the pop is still there if the fade timing drifts or the player looks at the wrong moment.

▸ CAUSE

SkyBox2D.SkyMaterial is a discrete property. Changing it replaces the entire sky in one frame — there is no interpolation between the old and new material.

The obvious two-instance fix does not work either. Stacking two SkyBox2D components and crossfading between them via Tint alpha does NOT composite. The sky pass renders the far plane opaque: RenderState(DepthWriteEnable, false), RenderState(DepthFunc, GREATER_EQUAL), and the pixel shader always outputs alpha 1 with no blend state enabling alpha blending. Whichever SkyBox2D draws last simply overwrites the sky pixels outright regardless of Tint's alpha channel, so the "fade" still pops at the swap instant.

SkyBox2D itself only exposes SkyMaterial and Tint (a Color multiply) as properties. There is no native blend or crossfade knob.

▸ FIX

Use a single custom sky shader that holds ALL time-slot textures resident simultaneously (e.g. four equirect textures for morning, noon, evening, night) and outputs a weighted sum of them in the pixel shader:

  1. Shader: declare all time-slot textures as inputs. In the pixel shader, sample each and output sum(weight_i * sample_i).

  2. CPU-side driver: compute the blend weights from the game clock every frame and push them to the material via Material.Set(...). Only the two adjacent time-slot weights are ever nonzero — the outgoing weight smoothsteps to exactly 0 at its boundary.

  3. Material reference: the SkyBox2D.SkyMaterial never changes mid-cycle. Only its blend weights change frame-to-frame. "Which pair is showing" is determined by which weights are nonzero, not by swapping the material.

▸ WHY IT WORKS

Because the material reference itself never changes, there is no frame where one texture is replaced by another. The transition is a continuous per-pixel blend inside the shader — no single frame can show a texture pop. The smoothstepped weights guarantee that the outgoing texture fades to zero contribution before being "replaced," and the incoming texture ramps up from zero. The sky pass still renders opaque (alpha 1), but the blending happens before the alpha output, inside the shader math.

Verified on engine 26.07.15a: 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