Weather, sky and light
Time of day
1. Run a day cycle with set_time
set_time with freeze=false and a daylength (seconds) runs the sun; with freeze=true (the default) and a
fraction it pins the time (0.25 morning, 0.5 midday, 0.75 dusk). This build ran a 7200 s day. Scripts read the
same day through llGetRegionDayLength() and llGetRegionDayOffset() (scripts.md).
Weather in the sky belongs to the region environment
2. Drive the viewer's own sky; do not build clouds out of prims or particles
The viewer draws its own clouds from the region ENVIRONMENT, so that is where a storm belongs. WorldBridge's sky
tick (once a minute) blends every sky frame from its fair baseline by the storm value: cloud_shadow (cover) up to
0.95, cloud_pos_density1.z, cloud_color darker, cloud_scroll_rate faster, haze_density up; then
StoreOnRegion and WindlightRefresh(transition).
- The day cycle sits in a PRIVATE field of
ViewerEnvironment(Cycle);DayCycle.skyframesis public. One reflection read. - Capture the fair baseline ONCE to a file (
worldbridge-sky.json): a restart after a storm must not mistake the stormy sky for the fair one. skycommand:{"storm": 0.9}to look at a storm,{"storm": -1}back to the clock. Seen in Firestorm: 0.9 is a bruised overcast, 0 a blue sky with scattered cloud.osReplaceRegionEnvironmentswaps whole day-cycle assets; editing the live environment from the module needs no assets at all.- See:
worldbridge/WorldBridgeModule.cs(SkyTick,ApplySky,ApplyWater,StormNow).
3. Particle and prim clouds failed
PSYS_SRC_BURST_RADIUSis ignored with FOLLOW_SRC (all puffs sat at the emitter).- Non-emissive particles take the viewer's light (orange under its low sun).
- At 100-170 m particle clouds are grey smudges.
- Earlier prim clouds (clusters of white spheres) drifted in lockstep and bunched into one corner of the sky over the region's uptime until each cloud got its own drift multiplier.
4. The water is in the same environment
DayCycle.waterframes (normScale, wave1Dir and wave2Dir as direction times speed, fresnelScale and fresnelOffset,
blurMultiplier, scaleAbove, waterFogDensity and waterFogColor). WorldBridge blends it from a captured baseline with
the storm and the region's wind: calm water goes glassy (the normal map barely stirring, more fresnel, a crisp
reflection); storm water runs fast downwind, rough, darker and murkier. The [calm, storm] pairs are tunable live
from worldbridge-sky.json ("waterTune"), so the look is tuned without a rebuild.
- How much of the shore a viewer sees reflected in the water is that viewer's own reflection setting.
5. The weather is one formula every script shares
One organic storm value (a sum of incommensurate periods, scaled by a seasonal storminess) is computed identically by every script from the wall clock and by the module in C#, so sky, clouds, mist, stream, rain and memory never desynchronise.
- See:
tools/weather_common.py(STORM_LSL,WIND_LSL) andStormNow/WindNowin the module.
Particles: fire, mist, rain
6. Fire is particles, not glowing spheres
A grown flame sprite, FOLLOW_VELOCITY plus WIND, emissive. ADDITIVE blending blooms at night but washes to pink
against a bright sky; by day draw it with ONE_MINUS_SOURCE_ALPHA in a deeper orange. People look UP at a beacon:
size the plume for being seen from below (2-3 m of flame over the basket).
- See:
tools/build_fire.py.
7. Atmosphere is particles, not translucent prims
Mist made of translucent prims catches the camera's focus (alt-click, object view) and confuses movement. Particles cannot be clicked.
- See:
tools/mist_particles.py.
8. Rain follows the visitor
Rain is local: a phantom, invisible emitter follows the nearest avatar (llGetAgentList plus OBJECT_POS,
llSetRegionPos once a second), emitting WITHOUT FOLLOW_SRC so streaks already falling stay in the world as it
moves.
- Shape:
PSYS_SRC_PATTERN_EXPLODEwith a burst radius (an 11 m sphere, 10 m overhead), near-zero speed, acceleration<wind * 0.6, -13>,FOLLOW_VELOCITYso each streak leans along its fall, age 2.1 s (the sphere's top to the ground). - A FULL-sphere
ANGLE_CONE(begin 0, end PI) COLLAPSES to a point in the viewer: every streak fell in one column. A BAND ofANGLE_CONE(PI/2 +- 0.3) works as a curtain at the radius (used under a roof, so none falls through). - A 4-6 cm particle is visible only if its TEXTURE FILLS the quad (a gaussian across most of the width); a thin line drawn in a wide texture is sub-pixel. Start alpha low and interpolate to the end alpha so no streak is seen to begin.
- Shelter:
llCastRaystraight up from the head (RC_REJECT_AGENTS | LAND); a hit is a roof. Tree meshes with tiny physics do not count, which is right. - Particles fall into the region water and vanish under it; over land they die underground. Pops at death are hidden if the age is only just long enough.
- See:
tools/build_rain.py.
9. Rings on water are squashed billboards
Particles are billboards, so squash them (scale x = 3 y) and they read as rings lying on the water from standing
height. Interpolate scale small to large and alpha to 0 over 0.9 s. Emit one ring of emitters per
llParticleSystem call (a horizontal ANGLE_CONE band at a radius) with a new area-uniform radius (R * sqrt(u))
four times a second: already emitted particles outlive the call that made them. Sit the emitter 7 cm ABOVE the
water, or the ring's lower half is under it.
Flashes, bolts and lights
10. A sky flash cannot come from the environment; flash a mesh dome
osReplaceAgentEnvironment and WindlightRefreshForced take a transition, but for a modern viewer the refresh only
re-sends region info; the viewer re-fetches the environment and eases into it on its own schedule, so a "flash"
arrives as a slow swell. Prims update at once: flash a mesh DOME over the whole region (236 m, fullbright, alpha
blend, alpha 0 at rest, phantom, tiny physics).
- A broad patch of cloud base lit on the horizon reads as lightning; a narrow column with a hot foot reads as a SEARCHLIGHT.
- Turn the prim (
PRIM_ROTATIONabout z) to put the glow's azimuth on the strike. Flicker it withllRegionSayfrom the controller per stroke,llSleep(0.04-0.1)between. PRIM_GLOWshows even at alpha 0: zero the glow with the alpha.- A point light (radius 20, the maximum) on a controller over the visitor lights the ground in the same flicker.
- By day the horizon glow and sky wash are mostly lost to daylight; scale them with the sun's height.
- See:
tools/build_thunder.py,tools/thunder_physics.py.
11. Put a distant bolt on a shell where the eye would see it
Carry every point of the channel along its line of sight from the listener onto a shell inside the dome (ribbons facing the centre, joints overlapped). It then has the exact look of that channel from where you stand, stands on the horizon, and turns with the glow. Extra faces of the dome (a mesh prim has up to 8) hold several bolts, lit one at a time.
12. Aim from the camera, not from the dome's centre
WorldBridge avatars gives the camera position and lookAt; intersect that ray with the dome sphere to get the
bearing to show dead ahead.
- Learned: 40 m off the dome's centre, "bearing = look direction" put the glow 18 degrees aside, behind the minimap overlay.
- Hold an effect with a debug "show" command to screenshot it.
13. Light that must read at night is fullbright and casts light
Without fullbright or a light a prim goes dark at night, exactly when a beacon matters. spawn takes fullbright,
glow, shiny and a point light (radius up to 20).
14. Carry every change in size and colour; glow is only the flourish
Glow is a bloom the viewer dims or drops at modest graphics settings. Glow and light are also not readable through WorldBridge; colour and size are.
- Learned: blossoms that changed almost wholly in glow read as "pretty static".
15. A flickering lamp: make the glowing part its own object
A flicker script that sets ALL_SIDES lights everything in its object. Make the glowing panes one object and the
iron frame another, or the flicker lights the iron too. Give the panes a tiny physics box.
16. Indoor light
Torches as a mesh (strap, ring, shaft, charred head) with a small emitter prim at the head, placed where no one brushes past (half a turn from a stair at that height).
Weather on surfaces
17. Wet is darker plus a gloss
Multiply PRIM_COLOR by about 0.68 for stone and 0.8 for timber, and add PRIM_SPECULAR (TEXTURE_BLANK,
glossiness about 120, environment about 35 for stone) scaled by the wetness. 170 / 60 read brassy at a low sun.
- Bake each face's DRY colour into the script from the world (
inspectrgba) at lay time; never read it atstate_entry, or a script restarted in the rain takes the wet tone as its base and darkens it again. - Where another script already owns a face's colour (a weathering memory), give wetness only the gloss.
- See:
tools/build_wet.py.
18. Snow on things is a cap grown from the thing's own mesh
Upward triangles (n.z > 0.55) whose centroid ray straight up meets none of the mesh's own triangles, lifted along VERTEX normals (no cracks), UV from above, one texture whose alpha is a per-texel ladder; the mask cutoff follows a broadcast depth. Check the saved mesh file's extents equal the object's size before mapping file vertices to the world.
- See:
tools/build_snowcaps.py,tools/build_icicles.py.
19. An object centred on the eye (a rainbow)
A 242 m ring 70 m ahead plus a mirrored speck of invisible geometry puts the object's centre at the viewer's eye;
the script moves it there and turns +X to the antisolar point (llRotBetween(<1,0,0>, -llGetSunDirection())). Put
vertex rings fine where the colour changes fast and coarse elsewhere, within 65,535 vertices per face.
- See:
tools/build_rainbow.py.