Weather system: rain, snow, storms, fog and wind (local + region opt-in) #783

Open
opened 2026-10-15 12:59:57 +00:00 by sky_line · 7 comments
Owner

A viewer-side weather system: rain, snow, storms, fog and wind that react to the environment, rendered GPU-driven, our own design. Closely related to the volumetrics epic (#722): volumetric fog (#718), the volumetric sky cloud layer (#719) and cloud platforms (#720) -- weather should drive those rather than duplicate them.

Weather state

  • A small state vector per region/parcel: precipitation type + intensity (rain / snow / hail), cloud cover, fog density, wind direction + speed, storm (lightning frequency), temperature-ish (rain vs snow), wetness.
  • Smooth transitions between states (minutes, not frames).
  • Where the state comes from (decide; probably layered):
    1. Off by default for regions that say nothing (no surprise rain at someone's wedding).
    2. Local / user choice (a personal "weather" setting, like choosing a personal environment): only you see it.
    3. Region / parcel opt-in convention so everyone using a supporting viewer sees the same weather: e.g. carried alongside the parcel/region environment (EEP) settings, or a documented cross-viewer convention (a scripted weather controller object broadcasting state on a known channel / object description), similar in spirit to #720's marked prims. Deterministic seeds so viewers agree on lightning timing etc.
    4. Optional automatic weather derived from the EEP sky (heavy cloud coverage -> chance of rain) only if the region allows it.

Rendering (GPU-driven, no per-drop CPU work)

  • Precipitation: compute-simulated particles around the camera (rain streaks / snowflakes / hail), motion-blurred streaks for rain, wind-driven, density by intensity; splashes on surfaces.
  • Occlusion: no rain under roofs / indoors -- a top-down depth (or RT visibility toward the sky) occlusion map around the camera.
  • Wet surfaces: darken albedo, lower roughness, ripples on flat upward surfaces, puddles in hollows (from the occlusion/height data), drying over time after rain stops; water bodies get ripple normals.
  • Snow: optional accumulation on upward-facing surfaces (shader-side coverage by normal + occlusion), melting.
  • Storms: lightning flashes (sky + scene light pulse, RT/shadow-aware), thunder audio with distance delay.
  • Fog / clouds: drive the volumetric fog (#718) and cloud layer (#719) density/coverage from the weather state; sky darkening via the environment.
  • Wind: drives precipitation, particles, and (optionally) flexi prims and vegetation sway.
  • Audio: rain/wind ambience by intensity and occlusion (muffled indoors).

Constraints

  • Performance budget per quality level; off = zero cost.
  • Respect the environment the region sets; never override a parcel's chosen look unless the user opts in locally.
  • Our own implementation (design from first principles / published techniques).
A viewer-side weather system: rain, snow, storms, fog and wind that react to the environment, rendered GPU-driven, our own design. Closely related to the volumetrics epic (#722): volumetric fog (#718), the volumetric sky cloud layer (#719) and cloud platforms (#720) -- weather should drive those rather than duplicate them. ## Weather state - A small state vector per region/parcel: precipitation type + intensity (rain / snow / hail), cloud cover, fog density, wind direction + speed, storm (lightning frequency), temperature-ish (rain vs snow), wetness. - Smooth transitions between states (minutes, not frames). - **Where the state comes from** (decide; probably layered): 1. **Off** by default for regions that say nothing (no surprise rain at someone's wedding). 2. **Local / user choice** (a personal "weather" setting, like choosing a personal environment): only you see it. 3. **Region / parcel opt-in convention** so everyone using a supporting viewer sees the same weather: e.g. carried alongside the parcel/region environment (EEP) settings, or a documented cross-viewer convention (a scripted weather controller object broadcasting state on a known channel / object description), similar in spirit to #720's marked prims. Deterministic seeds so viewers agree on lightning timing etc. 4. Optional automatic weather derived from the EEP sky (heavy cloud coverage -> chance of rain) only if the region allows it. ## Rendering (GPU-driven, no per-drop CPU work) - **Precipitation**: compute-simulated particles around the camera (rain streaks / snowflakes / hail), motion-blurred streaks for rain, wind-driven, density by intensity; splashes on surfaces. - **Occlusion**: no rain under roofs / indoors -- a top-down depth (or RT visibility toward the sky) occlusion map around the camera. - **Wet surfaces**: darken albedo, lower roughness, ripples on flat upward surfaces, puddles in hollows (from the occlusion/height data), drying over time after rain stops; water bodies get ripple normals. - **Snow**: optional accumulation on upward-facing surfaces (shader-side coverage by normal + occlusion), melting. - **Storms**: lightning flashes (sky + scene light pulse, RT/shadow-aware), thunder audio with distance delay. - **Fog / clouds**: drive the volumetric fog (#718) and cloud layer (#719) density/coverage from the weather state; sky darkening via the environment. - **Wind**: drives precipitation, particles, and (optionally) flexi prims and vegetation sway. - **Audio**: rain/wind ambience by intensity and occlusion (muffled indoors). ## Constraints - Performance budget per quality level; off = zero cost. - Respect the environment the region sets; never override a parcel's chosen look unless the user opts in locally. - Our own implementation (design from first principles / published techniques).
sky_line added this to the Slipstream project 2026-10-15 12:59:58 +00:00
Author
Owner

Milestones

M1 (done, in testing): local weather state + transitions, GPU rain/snow particles, top-down roof occlusion map, wet surfaces (darkening, gloss, puddles, ripples), Weather floater + toolbar button + World > Weather, drives volumetric fog density.

M1.5 (in progress):

  • Roof map quality: near high-resolution cascade (~3 cm texels around the camera) + the existing coarse map further out, filtered (multi-tap) lookup -- fixes blocky dry patches under objects.
  • Snow coating: shader-side snow cover on upward, sky-open surfaces that accumulates while snowing and melts after (also the long-term fallback for moving and thin objects).
  • Audio: rain / wind ambience by intensity, muffled under cover.

M2: region / parcel opt-in source + EEP-derived weather, cloud layer coverage from weather, GPU splashes, lightning + thunder, puddle reflections, RT sky-visibility (one upward ray per pixel, denoised) for the roof test on RT hardware, precipitation in probes/mirrors.

M3: real snow accumulation (volumetric).

  • Persistent world-space snow depth heightfield clipmap around the camera (~3 cm near texels), fed by the roof map: accumulates where open to the sky, melts over time.
  • Wind drift (advect toward lee sides: piles against walls and in corners), slope slide (thin on steep surfaces / roof edges), settle blur (rounded mounds).
  • Rendered as real geometry: (top surface height + snow depth) as a displaced grid / clipmap mesh, cut at height discontinuities (no curtains off eaves); casts and receives shadows. One compute + one indirect draw (GPU-driven).
  • Footprints / tracks: avatar feet (and optionally vehicles) stamp into the depth field; refill while snowing. Visual only (server physics unchanged).
  • Persistence: a global accumulated-depth counter so newly uncovered texels fill to the current depth instantly; only local edits (tracks, drifts) are lost when you leave.
  • Moving objects and sub-texel thin geometry keep the M1.5 shader coating.
  • RT: snow surface into the TLAS with a slow rebuild cadence (or excluded in the first cut).
  • Budget estimate 0.3-1 ms (mostly the near mesh).
## Milestones **M1 (done, in testing):** local weather state + transitions, GPU rain/snow particles, top-down roof occlusion map, wet surfaces (darkening, gloss, puddles, ripples), Weather floater + toolbar button + World > Weather, drives volumetric fog density. **M1.5 (in progress):** - Roof map quality: near high-resolution cascade (~3 cm texels around the camera) + the existing coarse map further out, filtered (multi-tap) lookup -- fixes blocky dry patches under objects. - Snow coating: shader-side snow cover on upward, sky-open surfaces that accumulates while snowing and melts after (also the long-term fallback for moving and thin objects). - Audio: rain / wind ambience by intensity, muffled under cover. **M2:** region / parcel opt-in source + EEP-derived weather, cloud layer coverage from weather, GPU splashes, lightning + thunder, puddle reflections, RT sky-visibility (one upward ray per pixel, denoised) for the roof test on RT hardware, precipitation in probes/mirrors. **M3: real snow accumulation (volumetric).** - Persistent world-space **snow depth heightfield** clipmap around the camera (~3 cm near texels), fed by the roof map: accumulates where open to the sky, melts over time. - **Wind drift** (advect toward lee sides: piles against walls and in corners), **slope slide** (thin on steep surfaces / roof edges), **settle** blur (rounded mounds). - **Rendered as real geometry**: (top surface height + snow depth) as a displaced grid / clipmap mesh, cut at height discontinuities (no curtains off eaves); casts and receives shadows. One compute + one indirect draw (GPU-driven). - **Footprints / tracks**: avatar feet (and optionally vehicles) stamp into the depth field; refill while snowing. Visual only (server physics unchanged). - **Persistence**: a global accumulated-depth counter so newly uncovered texels fill to the current depth instantly; only local edits (tracks, drifts) are lost when you leave. - Moving objects and sub-texel thin geometry keep the M1.5 shader coating. - RT: snow surface into the TLAS with a slow rebuild cadence (or excluded in the first cut). - Budget estimate 0.3-1 ms (mostly the near mesh).
Author
Owner

M4: run-off -- water streaming off covered surfaces

Rain that lands on roofs, awnings, tables and other covers should run off and fall from their edges, instead of simply vanishing.

  • Flow on the top surfaces (GPU, compute): treat the roof map's top-surface height (near cascade) as a heightfield. Each texel routes its rain to its steepest downhill neighbour (D8-style flow direction), and flow is accumulated over a few iterations per refresh. Flat roofs drain toward their nearest edges. The result is a per-texel flow amount, refreshed with the roof map.
  • Edge discharge: where a covered texel with flow borders a big height drop (the roof edge / eave / table edge), emit a stream whose strength is the discharged flow.
    • Light flow: individual drips (GPU particles from the M1 pool: they fall with gravity and wind, and splash).
    • Heavy flow: continuous streams rendered as thin, velocity-stretched ribbons from the edge to the ground, picked up by the roof map for where they land.
  • Landing: the ground under a drip line gets wetter, sooner (a wetness boost / puddle seed along the drip line), plus splashes (shared with M2 splashes).
  • Rivulets on vertical and steep surfaces: shader-side water trails running down walls, windows and steep roofs: animated streaks in the direction of gravity, projected along the surface, masked by sky-openness and wetness, thicker below run-off sources.
  • Timing: streams start once surfaces are wet, and keep dripping for a while after rain stops (draining), tapering with wetness.
  • Budget: flow is updated only on a roof-map refresh. Stream/drip count is capped per quality level and shares the precipitation particle budget. Off = zero cost.
  • Depends on: M1.5 near cascade (height detail at the edges). It shares splashes with M2 and works with M3 snow (melt water runs off the same way).
## M4: run-off -- water streaming off covered surfaces Rain that lands on roofs, awnings, tables and other covers should **run off and fall from their edges**, instead of simply vanishing. - **Flow on the top surfaces (GPU, compute):** treat the roof map's top-surface height (near cascade) as a heightfield. Each texel routes its rain to its steepest downhill neighbour (D8-style flow direction), and flow is accumulated over a few iterations per refresh. Flat roofs drain toward their nearest edges. The result is a per-texel flow amount, refreshed with the roof map. - **Edge discharge:** where a covered texel with flow borders a big height drop (the roof edge / eave / table edge), emit a **stream** whose strength is the discharged flow. - Light flow: individual drips (GPU particles from the M1 pool: they fall with gravity and wind, and splash). - Heavy flow: continuous streams rendered as thin, velocity-stretched ribbons from the edge to the ground, picked up by the roof map for where they land. - **Landing:** the ground under a drip line gets wetter, sooner (a wetness boost / puddle seed along the drip line), plus splashes (shared with M2 splashes). - **Rivulets on vertical and steep surfaces:** shader-side water trails running down walls, windows and steep roofs: animated streaks in the direction of gravity, projected along the surface, masked by sky-openness and wetness, thicker below run-off sources. - **Timing:** streams start once surfaces are wet, and keep dripping for a while after rain stops (draining), tapering with wetness. - **Budget:** flow is updated only on a roof-map refresh. Stream/drip count is capped per quality level and shares the precipitation particle budget. Off = zero cost. - **Depends on:** M1.5 near cascade (height detail at the edges). It shares splashes with M2 and works with M3 snow (melt water runs off the same way).
Author
Owner

M2 additions (owner, 2026-10-19)

Wind-tilted rain coverage map. Capture the roof / occlusion map along the precipitation direction instead of straight down: d = normalize(horizontal wind velocity + (0, 0, -fall speed)) (rain ~9 m/s, snow ~1-1.5 m/s).

  • Sheared orthographic projection, like a directional shadow map: texels stay on the horizontal snapped grid, the depth axis leans into the wind. Cascades and double-buffering unchanged; centre offset upwind by the slant so the near field stays covered.
  • Lookup / particle cull: project the point back along d onto the map, then the same filtered compare.
  • Walls: a wall is wet when it faces into the rain (N . -d > 0) and is unoccluded along d. This replaces the wall-normal offset heuristic. Rain shadows downwind of buildings; windward edges of covers get wet.
  • Re-render when the rain angle moves more than ~2-3 deg (wind state is already smoothed; gusts only perturb particles, not the map).
  • Cap the map tilt at ~60 deg: snow in strong wind beyond that is drift (M3 transport), not fall; also bounds the depth range.

Wind variation (gusts). New settings:

  • WeatherWindVariation (0..1): how far the wind speed swings around the set speed (e.g. 0.5 = between 50% and 150%); the direction can wander slightly with it.
  • WeatherWindGustiness (0..1): how fast it picks up and dies down, from slow swells over tens of seconds to sharp gusts that rise and fall within a second or two.
  • Smooth deterministic noise (seeded, so the future region source can sync it).
  • Feeds everything the wind feeds: particles, audio wind layers (gusts audible), later flexi / vegetation. The rain-angle map follows only the slow mean.
## M2 additions (owner, 2026-10-19) **Wind-tilted rain coverage map.** Capture the roof / occlusion map along the precipitation direction instead of straight down: d = normalize(horizontal wind velocity + (0, 0, -fall speed)) (rain ~9 m/s, snow ~1-1.5 m/s). - Sheared orthographic projection, like a directional shadow map: texels stay on the horizontal snapped grid, the depth axis leans into the wind. Cascades and double-buffering unchanged; centre offset upwind by the slant so the near field stays covered. - Lookup / particle cull: project the point back along d onto the map, then the same filtered compare. - Walls: a wall is wet when it faces into the rain (N . -d > 0) and is unoccluded along d. This replaces the wall-normal offset heuristic. Rain shadows downwind of buildings; windward edges of covers get wet. - Re-render when the rain angle moves more than ~2-3 deg (wind state is already smoothed; gusts only perturb particles, not the map). - Cap the map tilt at ~60 deg: snow in strong wind beyond that is drift (M3 transport), not fall; also bounds the depth range. **Wind variation (gusts).** New settings: - `WeatherWindVariation` (0..1): how far the wind speed swings around the set speed (e.g. 0.5 = between 50% and 150%); the direction can wander slightly with it. - `WeatherWindGustiness` (0..1): how fast it picks up and dies down, from slow swells over tens of seconds to sharp gusts that rise and fall within a second or two. - Smooth deterministic noise (seeded, so the future region source can sync it). - Feeds everything the wind feeds: particles, audio wind layers (gusts audible), later flexi / vegetation. The rain-angle map follows only the slow mean.
Author
Owner

M2 addition: persistent snow + snow that belongs to moving objects (owner, 2026-10-19)

Observed in M1.5: snow on a physical object shifts when the object moves, and the object casts a moving snow-free "shadow" on the ground. Cause: the coating is computed fresh every frame as global cover x current sky-openness, with world-space noise.

  • Persistent ground cover: an R8 snow-cover texture on the near-cascade grid around the camera, updated each frame by compute: it grows where the texel is sky-open while snowing and decays while melting. Cover is only ever added, never recomputed from current shelter. So a moved object leaves its old spot bare (refilling over time) and does not erase snow where it now stands. This is the coating-level precursor of the M3 snow depth heightfield, and it scrolls with the cascade (newly entered texels initialise to the global cover).
  • Snow on moving / physical / animated instances (the existing moving-caster flag):
    • object-space noise so patches stay attached;
    • a per-instance accumulated snow amount that grows while the instance is still and sky-open, and melts;
    • optionally shaken off above a speed threshold.
  • Moving instances are excluded from the roof map, so they never stamp a moving shelter onto the ground.
## M2 addition: persistent snow + snow that belongs to moving objects (owner, 2026-10-19) Observed in M1.5: snow on a physical object shifts when the object moves, and the object casts a moving snow-free "shadow" on the ground. Cause: the coating is computed fresh every frame as global cover x current sky-openness, with world-space noise. - **Persistent ground cover:** an R8 snow-cover texture on the near-cascade grid around the camera, updated each frame by compute: it grows where the texel is sky-open while snowing and decays while melting. Cover is only ever added, never recomputed from current shelter. So a moved object leaves its old spot bare (refilling over time) and does not erase snow where it now stands. This is the coating-level precursor of the M3 snow depth heightfield, and it scrolls with the cascade (newly entered texels initialise to the global cover). - **Snow on moving / physical / animated instances** (the existing moving-caster flag): - object-space noise so patches stay attached; - a per-instance accumulated snow amount that grows while the instance is still and sky-open, and melts; - optionally shaken off above a speed threshold. - **Moving instances are excluded from the roof map**, so they never stamp a moving shelter onto the ground.
Author
Owner

M3 addition: snow on avatars (owner, 2026-10-19)

Today avatars only collect snow while sitting -- a side effect: rigged draws are excluded from the moving-object snow, fall through to the static grid lookup, and only a sitting avatar becomes part of the static roof map (world-anchored snow that doesn't follow the avatar).

  • Per-avatar snow amount (like M2 movers): builds while the avatar is still and its head is sky-open, melts with the global cover, shed when walking fast / running / flying / jumping (idle animation does not shed).
  • Avatar-anchored pattern: patch noise in bind-pose / skeleton-local coordinates, so snow stays on the shoulders through animation.
  • Upward-facing skinned surfaces only (shoulders, head, hair tops) using the skinned normal.
  • Avatars stay out of the roof map (no moving snow-free patch under a standing avatar); sitting avatars use the per-avatar amount too for consistency.
  • Local only, like all local weather.
## M3 addition: snow on avatars (owner, 2026-10-19) Today avatars only collect snow while sitting -- a side effect: rigged draws are excluded from the moving-object snow, fall through to the static grid lookup, and only a sitting avatar becomes part of the static roof map (world-anchored snow that doesn't follow the avatar). - **Per-avatar snow amount** (like M2 movers): builds while the avatar is still and its head is sky-open, melts with the global cover, shed when walking fast / running / flying / jumping (idle animation does not shed). - **Avatar-anchored pattern:** patch noise in bind-pose / skeleton-local coordinates, so snow stays on the shoulders through animation. - **Upward-facing skinned surfaces only** (shoulders, head, hair tops) using the skinned normal. - Avatars stay out of the roof map (no moving snow-free patch under a standing avatar); sitting avatars use the per-avatar amount too for consistency. - Local only, like all local weather.
Author
Owner

Follow-up (after the M3 edge/seam fixes): outer snow-depth ring

M3's real snow (depth field + mesh) only covers the near cascade's 32 m grid: a square about +-16 m around a 4 m-snapped centre, with stride bands of 6 / 12 / 24 cm inside 10 m / 20 m / the edge. Beyond it, only the flat coating shows.

  • Outer ring: a second, coarser depth grid around the near one, e.g. 128-256 m at about 25-50 cm texels, fed by the coarse roof map. It gets the same accumulate / melt / transport rules, with cheaper transport (settle + slide; drift optional) and a lower update rate (amortised, e.g. every few frames).
  • Mesh from the ring: larger cells, built only outside the near grid. It must be stitched to the near grid's border with no cracks, height steps or seams.
  • Hand-off: where the near grid covers, it wins. Cells moving from the ring into the near grid (and back) take their depth from the other grid (resampled), so walking never resets snow. This is the same "snap must preserve depth" rule as the near grid.
  • Far LOD: beyond the ring the coating stays, faded so there is no visible step at the ring's outer edge. Optionally, add parallax-only depth (no geometry) on the far coating.
  • Budget: the ring adds a 512^2 depth grid (~8 MB rgba32f, or pack to rgba16f), plus a coarse mesh of tens of k triangles, also drawn into the outer sun cascades. Off = zero cost.
  • Setting: RenderVKWeatherSnowOuterRing (Boolean) and its extent.
## Follow-up (after the M3 edge/seam fixes): outer snow-depth ring M3's real snow (depth field + mesh) only covers the near cascade's 32 m grid: a square about +-16 m around a 4 m-snapped centre, with stride bands of 6 / 12 / 24 cm inside 10 m / 20 m / the edge. Beyond it, only the flat coating shows. - **Outer ring:** a second, coarser depth grid around the near one, e.g. 128-256 m at about 25-50 cm texels, fed by the coarse roof map. It gets the same accumulate / melt / transport rules, with cheaper transport (settle + slide; drift optional) and a lower update rate (amortised, e.g. every few frames). - **Mesh from the ring:** larger cells, built only outside the near grid. It must be stitched to the near grid's border with no cracks, height steps or seams. - **Hand-off:** where the near grid covers, it wins. Cells moving from the ring into the near grid (and back) take their depth from the other grid (resampled), so walking never resets snow. This is the same "snap must preserve depth" rule as the near grid. - **Far LOD:** beyond the ring the coating stays, faded so there is no visible step at the ring's outer edge. Optionally, add parallax-only depth (no geometry) on the far coating. - **Budget:** the ring adds a 512^2 depth grid (~8 MB rgba32f, or pack to rgba16f), plus a coarse mesh of tens of k triangles, also drawn into the outer sun cascades. Off = zero cost. - **Setting:** `RenderVKWeatherSnowOuterRing` (Boolean) and its extent.
Author
Owner

Follow-up: snow contact for every limb, not just feet (owner, 2026-10-19)

M3 stamps footprints from the ankle / foot / toe joints only (one 8x8 workgroup per foot, pressed to the sole, >= 20% left).

  • Any contact joint can stamp. Hands (wrist / hand / finger base), the Bento hind-limb chain tips (mHindLimb*, used by many quadruped and creature avatars) and optionally the tail tip. Quadrupeds commonly animate the arms as front legs, so their front paws must print. Rule: a joint stamps when it is within a few cm of (or below) the local snow surface, whatever limb it belongs to. No per-avatar configuration.
  • Limb capsules for deep snow. Lower-limb segments (knee to ankle, elbow to wrist, hind-limb segments) carve their swept capsule wherever they are below the snow top, so wading through drifts leaves a trench instead of only foot spots.
  • Shape. Use the joint's orientation (foot / paw direction) for an elongated print rather than a round blob, once the near grid resolution allows.
  • Cost. One small workgroup per contact this frame, capped per avatar. Only avatars within the depth grid.
## Follow-up: snow contact for every limb, not just feet (owner, 2026-10-19) M3 stamps footprints from the ankle / foot / toe joints only (one 8x8 workgroup per foot, pressed to the sole, >= 20% left). - **Any contact joint can stamp.** Hands (wrist / hand / finger base), the Bento hind-limb chain tips (mHindLimb*, used by many quadruped and creature avatars) and optionally the tail tip. Quadrupeds commonly animate the arms as front legs, so their front paws must print. Rule: a joint stamps when it is within a few cm of (or below) the local snow surface, whatever limb it belongs to. No per-avatar configuration. - **Limb capsules for deep snow.** Lower-limb segments (knee to ankle, elbow to wrist, hind-limb segments) carve their swept capsule wherever they are below the snow top, so wading through drifts leaves a trench instead of only foot spots. - **Shape.** Use the joint's orientation (foot / paw direction) for an elongated print rather than a round blob, once the near grid resolution allows. - **Cost.** One small workgroup per contact this frame, capped per avatar. Only avatars within the depth grid.
sky_line referenced this issue from a commit 2026-10-20 13:44:59 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sky_line/Slipstream#783
No description provided.