Skip to content

Rework the volumetric cloud deck into a modelled water cloud - #76

Open
arena-ai-coding-agent[bot] wants to merge 7 commits into
mainfrom
arena/01a0625d-testingcasutica
Open

Rework the volumetric cloud deck into a modelled water cloud#76
arena-ai-coding-agent[bot] wants to merge 7 commits into
mainfrom
arena/01a0625d-testingcasutica

Conversation

@arena-ai-coding-agent

@arena-ai-coding-agent arena-ai-coding-agent Bot commented Sep 2, 2026

Copy link
Copy Markdown

What

The volumetric cloud style is rebuilt as a physically-modelled water-cloud deck: 3D-eroded geometry, a weather-driven cloud-genus model, multi-scattered light through three optical-depth probes, and a marching scheme that is dithered, energy-conserving and early-exiting. The classic style (vanilla's boxes) is deliberately untouched apart from borrowing the new sun probe.

Full write-up — the model, the reference material, where every constant comes from, the cost budget and a tuning guide — is in docs/realistic-volumetric-clouds.md.

Why

Three measurable defects, not taste:

  1. A 2D picture extruded through a height profile. Coverage and erosion were both 2D, so lobes lined up vertically through the whole depth and the crown never broke into individual heads.
  2. Single scattering in a medium that is not single-scattering. Measured optical depth of low water cloud is 12–92, so a photon scatters tens of times before escaping; single scattering renders that as a silhouette with a black underside.
  3. ~8× too dim, in the wrong places. Calibrated against the real sky (an optically thick conservative deck reflects ~0.75 of the irradiance reaching it over the hemisphere → 0.75/π ≈ 0.24·E), the old interior produced ~0.03·E.

Plus one missing input: the deck had a single shape regardless of weather, so rain darkened it but never made it a different kind of cloud.

Geometry

  • Coverage stays 2D (a cloud layer really is one condensing air mass) at CLOUD_SHAPE_DIV = 2.0 → one cell = 48 blocks, so a cloud is a few hundred blocks across, matched to the deck's depth because real cumulus are about as wide as they are tall. It is now one function with three callers (visible density, cloud shadow, flat sheet) — the density and the shadow used to merge the weather fill differently, so in rain the deck stayed at the slider's coverage while its shadow closed the sky.
  • Genus (CloudWeather, resolved once per march): sheet from coverage (smoothstep(0.55, 0.92)), convection from 4c(1−c)·(1−sheet) and thunder, absorbing from rain/thunder. Reads push.weather gated on FEATURE_WEATHER_LIGHTING, so the deck only changes shape where the rest of the renderer agrees weather exists. No new slider: it is the same state that dims the sun and thickens the fog.
  • Height profile: flat base at the lifting condensation level (sharp for a heap, fraying for a sheet), crown rounding off at 0.70 of the slab for heaps / 0.94 for towers / 0.48 for a sheet, dense cores lifting their own crown, belly bulge for heaps only. Asymmetric because measured liquid-water profiles are.
  • Erosion: two octaves of 3D billow noise on their own lattice, sampled in blocks above the deck's base and never in camera-relative Y (otherwise the cloud's internal structure swims as the camera climbs). Bites hardest at thin edges and slab extremes, leaving the interior solid; then an edge-sharpening exponent from 1.55 (wispy base) to 0.90 (crisp crown).
  • Wind shear: sample position displaced by an amplitude growing to 2.2× at the crown, 55% of it leaning the tower over. Scalar-field shear rather than a curl-noise texture, because a deck that must survive the anchor wrap may only sample fields periodic with it.

Light

  • Three optical-depth probes returning raw ∫density·dl: sun/moon on 6 exponentially growing strides over a span that divides by the light's elevation (so sunrise shadowing stretches sideways instead of lighting the whole bank from within); zenith in 2 steps; ground bounce analytic. Probes sample a shape-level density whose erosion is replaced by its expected value (a billow octave averages 0.5) — unbiased, and free.
  • Six-order multi-scattering expansion: each bounce order re-evaluates the same three light terms with scatter *= 0.5, extinct *= 0.4, phase_g *= 0.8, powder → √powder halfway. Converging series, no extra march, and it is what produces a bright soft interior, a lit crown and a dark-but-not-black base.
  • Phase: normalised three-lobe mixture (broad g = 0.60 / silver 0.88 / back −0.22, weights 0.50/0.30/0.20 summing to 1) so the mixture stays 4π-normalised at every order and cannot invent energy. The tight lobe is the silver lining.
  • Powder relaxes toward the light (0.8·max(cosT, 0)) or it eats the silver lining it exists to frame.
  • Aerial perspective blends the deck toward skyBehind · (1 − transmittance) with distance, so the view-limit cutoff is hidden by cloud dissolving into the sky.
  • CLOUD_SCATTER_GAIN = 0.85 is calibrated, not eyeballed — see §5.6 of the doc.

Marching

Energy-conserving step integral (S · (σ_s/σ_t) · (1 − e^{−τ}), independent of stride length, so step count refines the silhouette instead of brightening the deck) · dithered march start from DispatchRaysIndex().xy + push.frameIndex (pixel-only dither freezes into static, frame-only bands across the screen) · early exit at T < 0.02 · fine-octave LOD between 320 and 1400 blocks · two quality tiers (diffuse bounces get 3 orders, 2 sun strides, an analytic sky probe and coarse-only erosion, keeping the energy identical).

Preserved because they fix reported bugs: crossing exclusion, CLOUD_MAX_SLAB_CROSSINGS horizon cap, horizon fade, step-count scaling, and opacity applied once to the finished march as a genuine ceiling.

Controls

Thickness is the deck's bulk; height is where it sits — two independent properties a flat clouds.png plane could not express. Extinction is normalised by slab depth (CLOUD_REFERENCE_THICKNESS), so raising thickness adds volume without adding opacity; see-through stays Cloud Opacity. Within whatever depth the player sets, the weather picks the genus: storm towers fill the slab, fair-weather heaps round off below the top, an overcast sheet hugs the bottom. Config javadoc and the en_us/pt_br tooltips now say this explicitly.

Cost

Roughly 2× the previous volumetric model per pixel (~40 hash lookups per full density, plus probes), which is the price of the look — texture-based cloud passes are heavier still, and buy that budget back by sampling precomputed 3D noise instead of hashing it, which this module cannot do (it may not import world_core, so it declares no bindings). Mitigations, in order of what they save: the cheap tier on every diffuse bounce, the density <= 0 skip that avoids all three probes in empty air (most of a scattered deck), the transmittance early exit, the distance LOD, and shape-level probes.

Follow-up: calibrated against UE5's published height gradients

The structure above was right but initially mis-calibrated: with the convection parabola peaking at 1.0, the default coverage made nearly every cloud a slab-filling tower, so the sky read as one thick layer whose top sat at the slab ceiling — a straight top that follows the thickness slider, from the inside.

UE5's Volumetric Cloud shape stage publishes the clearest numeric statement of what cumulus vs congestus means — a fair-weather cumulus closes its dome at roughly (0.0, 0.2, 0.42, 0.6) of the layer, a developing tower at (0.0, 0.08, 0.75, 0.98) — so the genus profiles are now tuned against those two gradients (commit e55e2ab):

  • heap crown 0.70 → 0.55, rounding 0.30 → 0.26: an ordinary cumulus domes at ~55–75% of the layer;
  • the crown fade is clamped to close at the slab top at the latest (crownEnd = min(start + rounding, 1)), otherwise a tall crown's fade ends above the slab and the deck is sliced flat by its own ceiling;
  • the tower lift is a smoothstep(0.35, 0.90, coverage) over local coverage instead of a linear ramp, so one sky holds low fringes, mid heaps and tall towers at once (a linear lift gives every cloud the same height);
  • clear-sky convection scaled to 0.45 of the parabola — thunderstorms still carry the full range;
  • base ramp 0.07 → 0.06 for a crisper condensation-level floor;
  • the coverage field is pushed toward its own extremes before thresholding (individual clouds with clean air and crisp edges, not a connected wash). That commit also pushed the erosion field toward its own extremes to fake ridge-and-cell scoops; the section below replaces that approximation with the real thing.

Practical note for trying it in game: vertical development is the Espessura slider (that is the "grossura" requirement), so UE5-style towers are what thickness near 100% looks like, while 30–50% gives the scattered fair-weather cumulus of the second reference image.

Follow-up: the erosion detail is now real 3D Worley (cellular) noise

The one field this module still approximated was the detail. Every implementation the technique is known for — Horizon Zero Dawn, Frostbite, UE5, and the Minecraft packs that followed them — erodes with the Perlin-Worley pair: value/billow noise for the soft rounded lobes, cellular (Worley) noise for the crisp scoops between them. The usual answer is a precomputed 3D texture, and this shader has no texture binding at all, so the previous revision faked the cellular character by pushing the billow toward its own extremes. It got the idea, not the silhouette: billow's boundaries stay soft everywhere, which is the "aerated cotton wool" read.

Commit 8b468d9 generates the real field instead:

  • cloudWorley3 is a true F1 — the distance to the nearest feature point of a jittered lattice — over the 3x3x3 neighbourhood, replacing the fine octave (the coarse one stays billow, so the pair is a genuine FBM);
  • because the jitter is held to +-0.4 cells per axis (CLOUD_WORLEY_JITTER = 0.8), the nearest feature point is provably inside that neighbourhood, so 27 taps is an exact F1 rather than an approximation;
  • the new cloudHash3Bits unpacks all three jitter components as 8-bit slices of one 24-bit hash per neighbour, so the octave costs 27 hashes rather than 81 — and it still lives only at CLOUD_DETAIL_FULL, behind the existing distance LOD, since it is the most expensive thing in the density;
  • the remap is fitted, not guessed: raw F1 averages 0.511 on this lattice, and 2.55x - 0.81 lands the mean on exactly 0.500 with ~25% of the range on the clamps (that clipping is the crispness). The mean is load-bearing — the SHAPE tier substitutes this octave's expected value for it when probing optical depth, so an unfitted remap would silently bias every light probe.

Periodicity is untouched: the Worley lattice uses the same divisor and the same hash masks as the fine billow it replaces, so RtCloudPeriodMirrorTest's anchor-wrap identity still holds for the cellular field.

Follow-up: fluffy, opaque, and free of the thickness slider

Played in game against real cumulus and shader-pack references, the deck still read as translucent cotton wool stuck to a ceiling, and its depth was a rectangle the thickness slider drew. Commit b6d18e8 attacks both at the root:

  • Opacity. A real cumulus is opaque because it is hundreds of metres deep (optical depth 30-100 straight up); this deck is a compressed sky a few tens of blocks deep, so it buys that opacity per block. CLOUD_EXTINCTION 0.115 -> 0.42 puts a developed core at tau ~7-15 - opaque body, dark shadowed base, silver lining at the rim - while a low-density fringe still transmits: the core/wisp split real clouds show. The core density curve saturates at 1 and powder went up to frame the rim.
  • Depth belongs to the cloud, not to a knob. The volumetric march now takes its slab from cloudDeckDepth - 64 blocks of sheet, 165 of heap, 210 of tower, one reading of the same coverage/weather state that picks the profile - and a zero thickness can no longer collapse it to the flat sheet. The thickness option shapes only the classic boxes; the volumetric clouds screen swaps that row for a greyed-out explanation (the mirror of what coverage already does in classic).
  • Every cloud its own size and height. A per-cloud vigour stretch of the height coordinate gives shallow humilis puddles next to towering mediocris at identical local coverage, and a wandering coverage threshold (CLOUD_COVERAGE_CLUSTER) merges neighbours into big masses in one region and shrinks them to fragments with clean air in the next.
  • Proportions. First playtests read as vertically stretched pillars: the crown lift ran to 1.0 and a cumulus core is dense by nature, so essentially every core closed its dome at the slab top - 150-block columns on a 200-block base. The lift is now capped at CLOUD_CROWN_LIFT_MAX = 0.78 (window 0.45-0.95), heap crown 0.55 -> 0.48, convection peak 0.45 -> 0.30, deck headroom 165 -> 128 blocks (tower 210 -> 192) and the vigour band narrowed to 1.25-0.85: height lands at ~0.2-0.7 of a cloud's width, the cumulus ratio, with only convection carrying a crown past the cap.
  • Fluffiness. Coarse billow lobes 24 -> 48 blocks (a fifth of a cloud's width - the scale real cauliflower shows), crown erosion and edge sharpening up for a crisper silhouette, base fray up for the misty underside, belly bulge and crown rounding up for rounder masses.

The option screen, both language files, the regression tests (genus depth override, segment gate, classic keeping the slider, vigour, clustering) and the design doc follow the same decision.

One follow-up bug fix rode along (f6cb989): the genus slab was being centred on the pushed slab centre, so once the march stopped reading the pushed thickness, the deck's FLOOR drifted with that ignored slider - a saved high thickness floated the base tens of blocks above the altitude the height option promises ("the clouds are too high", reported from game). The base is now recovered from the pushed centre and the pushed depth - exactly the Y the screen shows - and the genus slab grows upward from it; the shipped default height also drops 320 -> 224, since with the base exact there is no drift left to compensate.

Provenance and licensing

No part of this PR is derived from another shader pack's source. Photon was read as a working example of a shipping real-time cloud pass — which its license explicitly permits ("examine and learn from Photon Shaders's source code") — and what was taken from it is technique, not code: no file, function, expression, identifier, constant set or asset of it appears in this repository, and the two implementations differ mechanically at every level.

Photon this PR
language / loader GLSL, Iris/OptiFine Slang, Caustica's Vulkan RT pipeline
inputs uniforms + precomputed 3D noise and coverage textures WorldPush lanes, no texture or sampler of any kind in the module
noise sampled atlases (3D Perlin-Worley base + Worley detail) the same two noise families, generated from a periodic integer hash written here (cloudHash3Bits / cloudNoise3 / cloudBillow3 / cloudWorley3), because the deck must survive the anchor wrap
constants its own per-cloud-type parameter structs derived here from cloud optics (§5.6 calibrates the deck against the real sky, not against another shader)

A follow-up commit also re-attributes the techniques in the comments to where they were published — Wrenninge's multi-scattering octave model, the Frostbite and Horizon Zero Dawn (Nubis) implementations, Mie/HG practice, Kokhanovsky and the CALIPSO/MODIS optical-depth climatologies — instead of naming a redistributable implementation for methods that predate it. docs/realistic-volumetric-clouds.md §3 carries the full reference list and the provenance statement.

Tests

  • RtCloudShaderRegressionTest — 11 new tests, each naming the artefact that returns if it fails: one shared coverage field, 3D erosion anchored to the deck base (asserts posRel.y is absent from the density function), three probes through the octave expansion, thickness→bulk normalisation, both halves of the dither seed, the energy-conserving integral, aerial perspective, genus from the already-pushed lanes, the cellular detail octave being Worley with its jitter bound and fitted remap, and classic keeping its flat vanilla shading and staying out of the storm absorption. The three existing pinned assertions are unchanged.
  • RtCloudPeriodMirrorTest (new) — re-derives the anchor wrap identity from both sides: every octave divisor must be a power of two, CLOUD_FIELD_PERIOD_BLOCKS must equal 512 · 12 · maxDivisor / scale, every octave's own repeat must divide it exactly (24576/24576/12288/3072), and the vertical lattice (1536 blocks) must not repeat inside the deepest deck RtComposite can push. This has broken twice before, both times on a non-power-of-two divisor.

No Java code changes — RtComposite and CausticaConfig are documentation-only in this PR, since the thickness/height split was already correct on the CPU side.

All 8 shader stages compile to SPIR-V locally (Slang 2026.14); CI runs the full gradlew build with -warnings-as-errors.

xysgottaken2 and others added 7 commits September 2, 2026 15:10
The volumetric style was a 2D noise field extruded through a height profile
and lit by single scattering. Three measurable consequences: lobes lined up
vertically through the whole depth (a picture, not a cloud), an optically
thick medium rendered as a silhouette with a black underside, and the
interior was about eight times dimmer than a sunlit cloud top should be.

Geometry: coverage stays 2D (a cloud layer is one condensing air mass) and is
now one function shared by the deck and its shadow, which used to merge the
weather fill differently and so disagreed in rain. Erosion moves to a 3D
billow lattice sampled in blocks above the deck's own base, so the crown
breaks into individual cauliflower heads and the structure stays pinned to
the world instead of swimming past the camera. A weather-driven genus model
picks the height profile from lanes the frame already pushes: a closed sky is
a stratocumulus sheet, a scattered one is fair-weather cumulus heaps,
thunderstorms are convective towers, and precipitating cloud adds absorption.
Wind shear displaces the sample position by an amplitude that grows with
altitude, so towers lean and crowns curl.

Light: three optical-depth probes (sun on exponentially growing strides,
zenith, analytic ground bounce) feed a six-order multi-scattering expansion
that relaxes scattering, extinction and phase per bounce order, through a
normalised three-lobe Mie-approximating phase and a powder term that lets go
toward the light. Distant cloud fades into the sky rather than being deleted
at the view limit. The overall gain is calibrated against the real sky
(0.75/PI of the incident irradiance for an optically thick conservative deck)
instead of tuned by eye.

March: energy-conserving step integral, per-pixel per-frame dithered start,
transmittance early exit, distance LOD on the fine erosion octave.

Thickness stays the deck's BULK and height stays its base: extinction is
normalised by the slab depth, so raising thickness adds volume without adding
opacity. The classic style is unchanged apart from borrowing the new sun
probe, and stays out of the storm absorption and aerial perspective terms.

docs/realistic-volumetric-clouds.md records the model, the reference material
and where every number comes from. Two test classes guard it: nine new
assertions on the transport model, and RtCloudPeriodMirrorTest re-deriving the
anchor wrap identity from both the shader's octave divisors and RtComposite's
pushed period.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
The previous commit's comments cited another shader pack by name and quoted
three of its expressions and two of its parameter names while doing so. That
was sloppy in both directions: it credited a redistributable implementation
for techniques that were published in the literature years earlier, and it put
fragments of someone else's code — however trivial — into this repository's
comments under a license that reserves all rights not explicitly granted.

Nothing here was ever derived from that source: no file, function, expression,
identifier, constant set or asset of it exists in this repo, and the two
implementations differ mechanically at every level (GLSL sampling precomputed
3D textures through uniforms, versus Slang reading WorldPush lanes and
generating every field from a periodic integer hash written here, with no
texture or sampler in the module at all). The sources were read, which its
license explicitly permits, and the ideas are what was taken.

So: the octave relaxation schedule, the powder term, the growing-stride light
march, the early exit and the edge-sharpening exponent are now attributed to
where they were published (Wrenninge's multi-scattering model, the Frostbite
and Nubis implementations, Mie/HG practice), and the reference section of
docs/realistic-volumetric-clouds.md states the provenance and licensing
position explicitly instead of leaving a reader to infer it.

Comment and documentation changes only — no code, no constants, no behaviour.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
The deck had the right structure for a real sky but the wrong calibration:
with the convection parabola peaking at 1.0, the DEFAULT coverage (0.55) made
almost every cloud a slab-filling tower, so the sky read as one thick layer
with a top at the slab ceiling — the "straight top that follows the thickness
slider" look, from the inside.

UE5's Volumetric Cloud shape stage publishes the clearest numeric statement of
what cumulus and congestus mean: a fair-weather cumulus closes its dome at
roughly (0.0, 0.2, 0.42, 0.6) of the layer, a developing tower at
(0.0, 0.08, 0.75, 0.98). Tuned against those two gradients:

* heap crown 0.70 -> 0.55 with rounding 0.30 -> 0.26, so an ordinary cumulus
  domes at ~55-75% of the layer instead of hugging the ceiling;
* the crown fade is clamped to close AT the slab top at the latest
  (crownEnd = min(start + rounding, 1)). Without it a tall crown's fade ends
  above the slab and the deck is sliced flat by its own ceiling;
* the tower lift is now a smoothstep over local coverage (0.35..0.90) instead
  of a linear ramp, so one sky holds low fringes, mid heaps and tall towers at
  once — a linear lift gives every cloud in the sky the same height;
* clear-sky convection is scaled to 0.45 of the parabola (thunderstorms still
  carry the full range), so scattered fair weather develops to about half its
  layer the way the published cumulus gradient does;
* base ramp 0.07 -> 0.06: a crisper condensation-level floor.

Two shaping passes, both free of extra hash lookups:

* the coverage field is pushed toward its own extremes before the threshold,
  which separates individual clouds with clean air and crisp edges instead of
  a sky of connected blobs;
* the billow field gets the same treatment before eroding, giving the erosion
  Worley-like ridge-and-cell character (defined scoops with crisp boundaries)
  rather than a smooth wash.

docs/realistic-volumetric-clouds.md records the UE5 presets in the reference
list and the new numbers in the genus and erosion sections.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
The volumetric deck's erosion was a billow-only FBM: rounded lobes with soft
boundaries everywhere, then a smoothstep push toward the field's extremes to
fake cellular character. Every write-up of the technique — Horizon Zero Dawn,
Frostbite, UE5, and the Minecraft packs that followed them — erodes with the
Perlin-Worley pair instead, and the cellular half is what carves the aerated,
scooped silhouette a cumulus crown actually has. It was the one field this
module approximated rather than computed, because the usual answer is a
precomputed 3D texture and this shader has no texture binding at all.

So generate it: cloudWorley3 walks the 3x3x3 neighbourhood of the sample's
cell and returns the distance to the nearest feature point, each feature being
its cell's centre plus a jitter of +-0.4 cells. Keeping the jitter under half a
cell per axis is what makes 27 taps an EXACT F1 rather than an approximation,
and unpacking all three components from one 24-bit hash per neighbour (the new
cloudHash3Bits) keeps it at 27 hashes rather than 81. It stays the most
expensive thing in the density, so it replaces the fine octave only, behind the
existing detail LOD and tier.

The remap is fitted, not guessed. Raw F1 averages 0.511 on this lattice; 2.55x
- 0.81 lands the mean on exactly 0.500 with ~25% of the range on the clamps,
and that clipping is the crispness. The mean matters because the SHAPE tier
substitutes this octave's expected value for it when probing optical depth, so
an unfitted remap would silently bias every light probe. A regression test now
pins the cellular octave, the jitter bound and the remap.

Periodicity is unchanged: the Worley lattice uses the same divisor and the same
hash masks as the fine billow it replaces, so the anchor wrap the mirror test
proves still holds for the cellular field.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Two complaints from playing it, both fair: the deck read as translucent
cotton wool stuck to a ceiling, and its depth was a rectangle the thickness
slider drew. Real cumulus are opaque because they are hundreds of metres
deep, and how deep one is belongs to the parcel, not to a knob.

Opacity first. The deck is a compressed sky a few tens of blocks deep, so it
cannot buy a real cloud's optical depth (30-100 straight up) with depth; at
the physical per-metre extinction a core here reached tau 1-3, which renders
as see-through fluff with no shadowed underside. CLOUD_EXTINCTION 0.115 ->
0.42 puts a developed core at tau 7-15 (opaque body, dark base, silver lining
at the rim) while a low-density fringe still transmits - the core/wisp split
real clouds show. The core density curve now saturates at 1 instead of
topping out below it, and powder went up to frame the rim.

Depth second. The volumetric march now takes its slab from cloudDeckDepth -
64 blocks of sheet, 165 of heap, 210 of tower, one reading of the same
coverage/weather state that picks the profile - instead of from the pushed
thickness, and a zero thickness can no longer collapse it to the flat sheet.
The thickness option shapes only the classic boxes, whose extrusion genuinely
is it; the volumetric clouds screen swaps that row for a greyed-out
explanation, mirroring what the coverage row already does in classic. Inside
the slab, each parcel draws its own vertical development (a per-cloud vigour
stretch of the height coordinate) and the coverage threshold wanders across
the sky (CLOUD_COVERAGE_CLUSTER), so one sky holds shallow puddles, mid heaps
and merging masses with clean air between them instead of one population of
identical puffs.

Fluffiness last: coarse billow lobes 24 -> 48 blocks (a fifth of a cloud's
width, the scale real cauliflower shows), crown erosion and edge sharpening
up for a crisper silhouette, base fray up for the misty underside, belly
bulge and crown rounding up for rounder masses.

Also commits the lang rework that had stayed uncommitted since the deck
rework (style/coverage/thickness tooltips), now with the thickness tooltip
restated as classic-only, in en_us and pt_br. Regression tests pin the genus
depth override, the segment gate, the classic boxes keeping the slider, the
vigour stretch and the clustering mask; docs follow in §1, §4 and §5.1.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
The genus-depth slab was centred on the pushed slab centre, which Java
computes as configured base + pushedDepth/2. Once the volumetric march
stopped reading the pushed thickness, that centre stopped matching the
genus slab, and the deck's FLOOR drifted with a slider the style no longer
reads: with a saved high thickness the base floated tens of blocks above
the altitude the height option promises - reported from game as "the
clouds are too high". The march now recovers the base from the pushed
centre and the PUSHED depth (exactly the Y the options screen shows), and
grows the genus slab upward from it; the crossing-exclusion zone follows
the new slab's own mid-plane. Classic bounds are algebraically unchanged.

The shipped default height also drops 320 -> 224: with the base now exact,
a little above vanilla's 192 is where a modelled deck reads right, and the
old number carried an offset that was compensating for the drift.

Config javadoc follows the decision: thickness is documented as the
classic-only knob it became, height as the deck's exact floor.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Played from game, the deck read as vertically stretched pillars. The cause
was the crown lift: it runs to 1.0, and a cumulus core is dense by nature, so
smoothstep(0.35, 0.90, coverage) read essentially every core as "tower" and
closed its dome at the slab top - 150-block columns on a 200-block base, with
the convection term (0.45 of the parabola at default coverage) pushing the
same direction and a 165-block slab giving the columns room to grow.

Rebalanced to real cumulus proportions (height ~0.2-0.7 of width):
  * crown lift capped at CLOUD_CROWN_LIFT_MAX = 0.78, window 0.45-0.95 - only
    convection (storm, or a sunny day building) carries a crown past that;
  * CLOUD_CROWN_START_HEAP 0.55 -> 0.48, the published gradient's mid-layer;
  * CLOUD_CONVECTION_PEAK 0.45 -> 0.30, so fair weather builds instead of
    erupting;
  * deck headroom 165 -> 128 blocks of heap (tower 210 -> 192), so even a
    full tower stays a cloud shape;
  * vigour band narrowed to 1.25-0.85, biased shallower.
Fringes still stay low, cores still rise above them, storms still fill the
sky - the spread is just the sky's, not the slab's.

Co-authored-by: arena-agent <297053741+arena-agent@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant