My agent insisted that volumetric clouds would be too expensive and shouldn't be included in my Godot flight sim. It drew terrible solid clouds instead. They were so bad I didn't even want to take a screen grab.

我的代理人坚持认为体积云太昂贵,不能在我的 Godot 飞行模拟中加入。它绘制了糟糕的实体云。它们太差劲,我甚至不想拍摄屏幕截图。

So I started a new, separate project in Codex instead of Cursor, model set Sol 6.1, just to experiment with volumetric clouds. Explained that the goal was to create a cloud system which would be owned by the sim, not a plugin. Then fed it a few papers on the subject of volumetric clouds and an hour later I could merge the files in the main project.

所以我另起一个项目在 Codex 而不是 Cursor,模型设置为 Sol 6.1,仅为了实验体积云。说明目标是创建一个由模拟器拥有的云系统,而不是插件。然后我给它提供了一些关于体积云的论文,一小时后就可以将文件合并到主项目中。

Clouds use seeded, connected lobes with procedural detail, a flat base, and controllable growth, drift, wind shear and dissipation. Lighting combines Beer–Lambert transmission, self-shadowing and an approximate multiple-scattering model. A GPU-generated 3D optical-depth cache avoids repeated shadow raymarches and blends between updates.

云采用有种子的、相连的凹陷(lobes)以及可控的增长、漂移、风切变和消散。光照结合了 Beer–Lambert 传输、自阴影和近似的多散射模型。一个由 GPU 生成的 3D 光深度缓存避免了重复的阴影射线跟踪,并在更新之间进行混合。

The simulator supplies cloud state and illumination through a small input API. The current prototype renders one cumulus. Multi-cloud scalability and further realism improvements are still the next step.

模拟器通过小型输入接口提供云状态和光照。当前原型渲染了一朵积云。多云可扩展性和更多真实感改进仍是下一步。

(Not sure which flair to add, hope I picked the right one)

(不确定该加哪个标签,希望我选对了)

Procedural Cumulus Shape: Formulas

程序化积云形状:公式

The current shape model combines eight connected ellipsoidal lobes using a smooth union, then adds procedural noise, erosion and a flat base. It produces a dimensionless density field for volumetric raymarching.

当前形状模型结合了八个相连的椭圆体,使用平滑联合,然后加入程序化噪声、侵蚀和平坦底部。它生成无量纲的密度场用于体积光线跟踪。

Smooth transitions

平滑过渡

All smooth transitions use:

S(a,b,x) = u²(3 - 2u)
u = clamp((x-a)/(b-a), 0, 1)

所有平滑过渡使用:

S(a,b,x) = u²(3 - 2u)
u = clamp((x-a)/(b-a), 0, 1)

1. Local coordinates, wind shear and growth

1. 局部坐标、风切变与增长

Let x be the world-space sample position, b the centre of the cloud base, R the horizontal scale and H the full vertical envelope height. World Y points upward.

让 x 为世界空间采样位置,b 为云底中心,R 为水平尺度,H 为完整的垂直包络高度。世界 Y 轴向上。

p = (x - b) / (R, H, R)

在包络顶部应用指定的水平位移 s = (sₓ, sᵤ)(第二分量代表 Z):

p.xz ← p.xz - (s/R) · p.y

For development g ∈ [0,1], horizontal and vertical growth scales are:

W = 0.35 + 0.65√g
V = 0.16 + 0.84g

u = p / (W, V, W)

2. Connected ellipsoidal lobes

2. 相连的椭圆体

The macro shape consists of a broad flattened base and seven overlapping shoulder/turret lobes. Their initial centres cᵢ⁽⁰⁾ and radii rᵢ⁽⁰⁾ receive small, reproducible seed-dependent perturbations.

宏观形状由宽阔的平坦底部和七个相互重叠的肩部/塔楼体组成。它们的初始中心 cᵢ⁽⁰⁾ 和半径 rᵢ⁽⁰⁾ 会受到小且可复制的种子依赖扰动。

Upper lobes activate progressively, for i = 1, ..., 7:

Aᵢ = S(0.08 + 0.035i, 0.50 + 0.035i, g)

cᵢ,y = 0.12 + (cᵢ,y⁽⁰⁾ - 0.12)Aᵢ
rᵢ = rᵢ⁽⁰⁾(0.12 + 0.88Aᵢ)

Their horizontal centres remain unchanged. The base lobe, i = 0, does not use this activation rule. These lobe parameters are calculated on the CPU and supplied to both the rendering and light-cache shaders.

上层体逐步激活,对于 i = 1, ..., 7:

Aᵢ = S(0.08 + 0.035i, 0.50 + 0.035i, g)

cᵢ,y = 0.12 + (cᵢ,y⁽⁰⁾ - 0.12)Aᵢ
rᵢ = rᵢ⁽⁰⁾(0.12 + 0.88Aᵢ)

它们的水平中心保持不变。基底体,i = 0,不使用此激活规则。这些体参数在 CPU 上计算并同时供给渲染和光缓存着色器。

For each lobe, define its ellipsoid axes:

aᵢ = rᵢ(1, λᵢ, 1)

λᵢ = 0.43  if i = 0 (flattened base)
     0.95  if i > 0 (shoulders and turrets)

The approximate distance field is:

dᵢ(u) = rᵢ(‖(u - cᵢ)/aᵢ‖ - 1)

Negative values indicate the interior. This expression has the desired ellipsoidal zero surface, but is not an exact Euclidean signed-distance function for an ellipsoid.

3. Smooth union

3. 平滑联合

Combine the lobe fields by repeatedly applying:

h = max(k - |a-b|, 0) / k

smin(a,b) = min(a,b) - (k/4)h²

k = 0.09

The resulting field D joins overlapping lobes without hard seams.

通过重复应用以下公式结合体场:

h = max(k - |a-b|, 0) / k

smin(a,b) = min(a,b) - (k/4)h²

k = 0.09

得到的字段 D 将重叠的体块在没有硬边的情况下合并。

4. Billowing, fine erosion and dissipation

4. 起伏、细微侵蚀与消散

Let N(q) be smooth, trilinearly interpolated 3D value noise in [0,1], σ a fixed seed offset, and φ a continuous detail phase:

q = 5u + σ + 0.25φ

Large-scale structure and fine detail are:

n = 0.65N(q) + 0.35N(2.03q)
m = N(4.1q + φ)

For billow strength B, erosion strength E, and dissipation f, all in [0,1]:

F = D + 0.16B(n - 0.5)
      + 0.10E(m - 0.35)
      + f(0.10 + 0.15n)

The first noise term perturbs the silhouette. The second adds finer erosion. Increasing dissipation erodes the body nonuniformly before it disappears.

5. Final density

5. 最终密度

Convert the perturbed field into a soft volume mask:

M = 1 - S(-0.08, 0.04, F)

A shared vertical profile flattens the underside and fades the envelope top:

P = S(0, 0.035, p.y) · [1 - S(0.96, 1, p.y)]

The final dimensionless density is:

ρ = M · P · (0.65 + 0.35n)
    · S(0, 0.08, g) · (1-f)^1.3

Density is explicitly zero outside the supported envelope, when development is zero, or when dissipation reaches one. The implementation also rejects samples outside 0 < p.y < 1 or with |p.xz| > 1.15 after shear removal.

该密度乘以从液态水含量和有效 droplet radius 计算出的消亡幅度。它不经过归一化,以保持指定的总水质量。

Example temporal controls

示例时间控制

The optional laboratory animation prescribes, for age t in seconds:

g(t) = S(0, 280, t)
f(t) = S(620, 900, t)

φ(t) = (0.0006, -0.0025, 0.0003)t
b(t) = b₀ + vt

It additionally uses:

s(t) = (130, 35)g(t) metres
E(t) = 0.18 + 0.57f(t)
B = 0.75

Sampling the same age and seed reproduces the same shape, independently of previous sampling history. The renderer has no lifecycle clock: the host supplies development, dissipation, phase, position and shear. The sim can replace the laboratory lifecycle entirely with values from its own atmospheric and thermal logic.

Temporal lighting

时间光照

Slow morphology updates are rendered immediately, while optical-depth caches refresh at up to four updates per real second by default. Two GPU textures allow the old and new cached fields to blend smoothly. Large changes discard stale lighting.

慢速形态更新会立即渲染,而光深度缓存默认每秒最多刷新四次。两块 GPU 纹理允许旧缓存和新缓存字段平滑混合。大的变化会丢弃过时的光照。

This is temporal light-cache blending, not screen-space temporal reconstruction or accumulation of stochastic samples.

编辑:公式难以显示正确