Author a deterministic weather regime with Weather Lab
verifiedAgainst e50826a · verifiedOn 2026-09-10.
What you will build
Section titled “What you will build”In Voxamine, weather is not a dice roll or an arbitrary timer. It is governed by a continuous, deterministic atmospheric barometric pressure field that drifts across the world terrain along prevailing wind vectors (MASTERPLAN.md §13.2 / §23). A high-pressure system brings clear, sunny skies with sparse fair-weather clouds; a low-pressure trough brings overcast gloom, rainstorms, and mountain blizzards.
You will author and tune a biome weather regime by defining its precipitation susceptibility in BiomeWeatherProfile, evaluating barometric thresholds in WeatherModel.Classify, observing lapse-rate snow line elevation transitions ($Y \ge 72$), and inspecting barometric stability across biomes using the Weather Lab module in the Voxel Workshop (WeatherLabModule.cs) without entering Play Mode or dirtying world saves.
// Pure deterministic weather evaluation:WeatherSnapshot snapshot = WeatherModel.Classify(pressureNormalized, elevation, snowLine, biome);// snapshot.Type -> WeatherType.Clear, WeatherType.Rain, or WeatherType.Snow// snapshot.CloudCover -> [0.12, 1.0]// snapshot.LightingDimFactor -> [0.48, 1.0]Where this sits
Section titled “Where this sits”The weather subsystem connects procedural math, biome classification, physical presentation runtimes, and editor validation tools:
- Atmospheric Pressure Field (
World.Environment) samples 2D continuous noise drifting with the world’s weather clock and wind vector. - Weather Model (
World.Environment) deterministically evaluates barometric lowness, biome susceptibility, and elevation lapse rates to produce an immutableWeatherSnapshot. - Biome Weather Profile (
World.Environment) defines the precipitation threshold ($[0, 1]$) and freezing characteristics of each biome archetype. - Weather Lab (
VoxelWorkshop.Modules.WeatherLab) provides an editor-only analysis tool to audit precipitation thresholds and wind-drifted pressures across biomes. - Presentation Layer (
HdrpStormPresentationRuntime,VoxelCloudRuntime,RainAmbienceRuntime) consumes the resulting snapshot to modulate volumetric clouds, rain particle density, sky dimming, and thunder delays.
flowchart TD
subgraph INPUTS["Simulation Inputs"]
SEED["WorldSeed & WeatherClock\n(elapsed seconds)"]
WIND["Prevailing Wind Field\n(drift direction & velocity)"]
COL["World Column (X, Z)\nSurface elevation & BiomeType"]
end
subgraph SOLVER["VoxelSandbox.World.Environment"]
FIELD["AtmosphericPressureField\n(2D drifting noise -> [-1, 1] normalized)"]
PROFILE["BiomeWeatherProfile\n(PrecipitationSusceptibility & Freezes)"]
MODEL["WeatherModel.Classify\n(Lowness, onset, lapse rate snow line)"]
SNAP["WeatherSnapshot\n(WeatherType, Intensity, CloudCover, LightingDim)"]
end
subgraph WORKSHOP["Voxel Workshop"]
LAB["WeatherLabModule\n(Interactive pressure field & biome audit)"]
end
subgraph RUNTIME["Presentation & Audio"]
SKY["SkyCycleBlend & Sunlight\n(lightingDimFactor)"]
CLOUDS["VoxelCloudRuntime\n(cloudCover density)"]
STORM["HdrpStormPresentationRuntime\n(Rain / snow particles & lightning)"]
AUDIO["RainAmbienceRuntime\n(Crossfaded rain & wind beds)"]
end
SEED --> FIELD
WIND --> FIELD
FIELD --> MODEL
COL --> MODEL
PROFILE --> MODEL
MODEL --> SNAP
FIELD --> LAB
MODEL --> LAB
SNAP --> SKY
SNAP --> CLOUDS
SNAP --> STORM
SNAP --> AUDIO
Crucially, no random state is stored or mutated during weather evaluation. Given the same seed and weather clock, any column in the world yields the exact same weather snapshot across multiple clients or after reloading a save.
Before you start
Section titled “Before you start”Read Docs/MASTERPLAN.md §13.2 (“Environmental systems”) and review:
AtmosphericPressureField, continuous 2D noise generation with wind drift.WeatherModel, the pure classification rules.BiomeWeatherProfile, the per-biome precipitation character table.WeatherLabModule, the Workshop inspection UI.WeatherModelTests, test suite validating weather invariants.
Review these physical and mathematical constants:
| Metric | Value | Meaning |
|---|---|---|
| Settled High ($P_{\text{high}}$) | +0.15 normalized ($1018.5\text{ hPa}$) |
Clear skies, minimal clouds ($< 0.20$), maximum sunlight ($> 0.95$). |
| Deep Low ($P_{\text{low}}$) | -0.78 normalized ($971.0\text{ hPa}$) |
Extreme cyclonic trough; precipitates across every biome. |
| Global Snow Line | $Y = 72$ blocks | Elevation threshold above which precipitation falls as snow regardless of ambient biome warmth. |
| Mean Sea Level Pressure | $1013.25\text{ hPa}$ | Atmospheric baseline. |
| Pressure Half-Range | $50.0\text{ hPa}$ | Total dynamic range spans $963.25\text{ hPa}$ to $1063.25\text{ hPa}$. |
The build, step by step
Section titled “The build, step by step”1. Sampling the Continuous Pressure Field
Section titled “1. Sampling the Continuous Pressure Field”The barometric field is evaluated via AtmosphericPressureField.SampleNormalized:
// Drifts continuously with elapsed weather clock along prevailing wind vectorfloat pressureNormalized = AtmosphericPressureField.SampleNormalized( worldX, worldZ, worldSeed, weatherClockSeconds);The output is bounded in $[-1.0, 1.0]$. A value of $+1.0$ represents maximum anticyclonic high pressure; $-1.0$ represents a violent cyclonic low.
2. Biome Precipitation Susceptibility
Section titled “2. Biome Precipitation Susceptibility”Open BiomeWeatherProfile.cs to tune how a biome responds to barometric dips:
public static BiomeWeatherProfile For(BiomeType biome){ return biome switch { BiomeType.Desert => new BiomeWeatherProfile(0.05f, false), BiomeType.Badlands => new BiomeWeatherProfile(0.08f, false), BiomeType.Savanna => new BiomeWeatherProfile(0.30f, false), BiomeType.Plains => new BiomeWeatherProfile(0.62f, false), BiomeType.Forest => new BiomeWeatherProfile(0.82f, false), BiomeType.Jungle => new BiomeWeatherProfile(1.00f, false), BiomeType.Mountains => new BiomeWeatherProfile(0.92f, true), BiomeType.Taiga => new BiomeWeatherProfile(0.90f, true), BiomeType.Tundra => new BiomeWeatherProfile(0.86f, true), _ => new BiomeWeatherProfile(0.50f, false) };}- Arid Biomes (
Desert,Badlands): Have near-zero susceptibility ($0.05$). They remain dry under ordinary troughs and only precipitate when a record-breaking low ($P \le -0.95$) passes through. - Humid Biomes (
Jungle,Forest): Have high susceptibility ($1.0$). Even a mild barometric depression triggers cloud buildup and showers. - Freezing Biomes (
Tundra,Taiga,Mountains): MarkFreezes: true. Any precipitation in these regions always falls as snow, regardless of elevation.
3. Classification and Elevation Lapse Rates
Section titled “3. Classification and Elevation Lapse Rates”Inspect WeatherModel.Classify:
// 0 at a settled high (+0.15), 1 at a deep low (-0.78)float lowness = Mathf.InverseLerp(SettledHighNormalized, DeepLowNormalized, pressureNormalized);float cloudCover = Mathf.Clamp01(0.12f + 0.9f * lowness);
BiomeWeatherProfile profile = BiomeWeatherProfile.For(biome);
// Onset threshold: susceptible biomes start precipitating early (0.30)float onset = Mathf.Clamp01(Mathf.Lerp(0.98f, 0.30f, profile.PrecipitationSusceptibility));float intensity = Mathf.Clamp01(Mathf.InverseLerp(onset, 1f, lowness));
if (intensity <= 0f){ float dryDim = Mathf.Lerp(1f, 0.88f, cloudCover); return WeatherSnapshot.ClearSky(pressureHectopascals, cloudCover, dryDim);}
// Check freezing conditions: biome character OR high-altitude lapse ratebool freezing = profile.Freezes || columnSurfaceHeight >= snowLineHeight;WeatherType type = freezing ? WeatherType.Snow : WeatherType.Rain;
float precipitationDim = type == WeatherType.Snow ? Mathf.Lerp(0.90f, 0.72f, intensity) : Mathf.Lerp(0.82f, 0.48f, intensity);
return new WeatherSnapshot(type, pressureHectopascals, intensity, cloudCover, precipitationDim);When elevation reaches or exceeds snowLineHeight ($72$), precipitation converts to snow even in warm biomes (e.g. Plains or Forest), accurately modeling mountainous altitude cooling.
4. Interactive Inspection via Weather Lab
Section titled “4. Interactive Inspection via Weather Lab”Open WeatherLabModule.cs. The module renders a live analysis table showing:
- Prevailing wind vector and drift distance for the chosen weather clock.
- Current barometric reading at mid-elevation ($Y=48$) in normalized units and hectopascals.
- A complete breakdown of every biome’s precipitation threshold, active state, intensity, and sunlight dim factor.
This allows designers to drag the Weather Clock slider and watch weather fronts sweep across biomes without launching the game.
Verify
Section titled “Verify”1. Execute Headless Weather Unit Tests
Section titled “1. Execute Headless Weather Unit Tests”Run the EditMode test suite to confirm the classification invariants hold:
/opt/unity/Editor/Unity -batchmode -nographics \ -projectPath /home/soulwax/workspace/engines/unity/minecraft/Minecraft-HD \ -runTests -testPlatform EditMode \ -testFilter VoxelSandbox.Tests.WeatherModelTestsConfirm that:
- Settled highs yield clear skies with high light factors.
- Deep lows cause heavy rain in jungles.
- Moderate lows rain in jungles but remain clear in deserts.
- Cold biomes (Tundra, Taiga, Mountains) precipitate as snow at all elevations.
- Elevations above the snow line ($Y \ge 72$) precipitate as snow in temperate biomes.
2. Inspect in Voxel Workshop
Section titled “2. Inspect in Voxel Workshop”- Open Tools → Voxel Sandbox → Voxel Workshop → Weather Lab.
- Drag the Weather Clock slider between $0$ and $120\text{ minutes}$.
- Observe the barometric pressure fluctuate smoothly.
- Verify that when pressure drops below $980\text{ hPa}$, the Plains and Forest rows switch from
CleartoRain. - Confirm the Desert row remains
Clearuntil extreme lows below $970\text{ hPa}$.
Now do your own
Section titled “Now do your own”To author weather for a newly created biome (e.g. Volcanic Caldera or Salt Flat):
- Decide susceptibility and freezing: Choose how readily the environment precipitates ($0.05$ for ultra-arid to $1.0$ for monsoon) and whether it freezes.
- Add case to
BiomeWeatherProfile.For: Register the newBiomeTypein the switch expression. - Verify in Weather Lab: Open the Weather Lab module and verify the new biome row displays the expected onset threshold.
- Add EditMode test: Add test assertions in
BiomeWeatherProfileTests.csandWeatherModelTests.csverifying classification under both high and low pressure.
Pitfalls
Section titled “Pitfalls”| Symptom | Cause | Fix |
|---|---|---|
| Weather desynchronizes or changes randomly upon loading a save. | Weather code called UnityEngine.Random instead of sampling the deterministic pressure field. |
Only read AtmosphericPressureField.SampleNormalized using the persisted weather clock and world seed. |
| Mountain peaks rain instead of snowing. | The column surface height was not passed to WeatherModel.Classify. |
Pass the column surface height and compare against snowLineHeight ($72$). |
| Deserts experience continuous, frequent rain. | Precipitation susceptibility was set too high ($> 0.15$). | Keep arid susceptibility low ($0.05$ to $0.08$) so only deep cyclonic lows trigger precipitation. |
| Sunlight dims instantly when a cloud appears. | The presentation layer snapped the light dim factor instead of lerping. | Let SkyCycleBlend smoothly interpolate light dim factors across frames using Time.deltaTime. |
| Excessive memory allocations during weather updates. | WeatherSnapshot was implemented as a managed class. |
Keep WeatherSnapshot as an immutable, allocation-free readonly struct. |
User-contributed notes
Corrections, clarifications, and practical tips for this page. Anonymous is fine — a name is optional. Basic Markdown works:
**bold**,*italic*,`code`, and links.Notes policy
Notes are lightly filtered for spam and may be edited or removed. Keep them about this page — no support requests, no personal data, nothing you would not publish. Links are limited and marked
nofollow.