CloudVolume¶
from acron.atmosphere import CloudVolume
- class CloudVolume¶
Bases:
Bases:
TypedReferenceCountA voxel cloud: a hero or local cloud volume after Schneider’s Nubis^3 (Guerrilla, SIGGRAPH 2023), drawn by acron.clouds where the 2.5-D layer is not enough (a towering cumulonimbus up close, a camera flying through a cloud).
A box of nx x ny x nz voxels (get_size() metres) placed in the frame that drifts with the wind (set_origin(): the box’s lowest corner, x y air metres, z metres above the sea). Per voxel it holds
a signed distance (metres) to the cloud’s envelope, negative inside: the march skips empty space by it, and nothing outside the envelope (plus a voxel) can hold cloud;
a dimensional profile 0..1: how far inside the envelope (0 at its edge, 1 from
get_edge()metres in), which erodes the clouds’ base noise the way the layer’s height profile does (wisps at the edges, a dense core);a type 0..1 (0 cumulus, 1 cumulonimbus: billows and anvils);
after
update_light(), the depth of cloud between the voxel and the key light (density x metres of the expected density): the volume’s self-shadow.
The envelope comes from primitives (spheres and ellipsoids as metaballs,
add_sphere()/add_ellipsoid(), voxelised byvoxelize()), from a storm cell (make_cumulonimbus()) or from the weather map (build_from_field(): a large-scale volume of the layer).fill_shape()/fill_light()write it into a slot of a 3-D texture atlas (RGBA8 r distance, g profile, b type; R16 light depth). AWeatherFieldthat holds the volume (WeatherField::add_volume, or its hero volumes) counts it in density_at() and the sun’s column.Inheritance diagram
digraph inheritance89fb22f423 { bgcolor=transparent; rankdir=BT; size="8.0, 12.0"; "CloudVolume" [URL="acron.atmosphere.CloudVolume.html#acron.atmosphere.CloudVolume",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top",tooltip="/**"]; "TypedReferenceCount" -> "CloudVolume" [arrowsize=0.75,style=""]; "DTOOL_SUPER_BASE" [fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style=""]; "ReferenceCount" [URL="acron.core.ReferenceCount.html#acron.core.ReferenceCount",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top",tooltip="/**"]; "DTOOL_SUPER_BASE" -> "ReferenceCount" [arrowsize=0.75,style=""]; "TypedObject" [URL="acron.core.TypedObject.html#acron.core.TypedObject",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top",tooltip="/**"]; "DTOOL_SUPER_BASE" -> "TypedObject" [arrowsize=0.75,style=""]; "TypedReferenceCount" [URL="acron.core.TypedReferenceCount.html#acron.core.TypedReferenceCount",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top",tooltip="/**"]; "TypedObject" -> "TypedReferenceCount" [arrowsize=0.75,style=""]; "ReferenceCount" -> "TypedReferenceCount" [arrowsize=0.75,style=""]; }- __init__()¶
An empty volume of size (metres) and nx x ny x nz voxels (2..512 each).
- add_ellipsoid()¶
A metaball stretched to the given radii along x, y and z (see
add_sphere()).
- add_sphere()¶
A metaball of the given radius (where it alone reaches the threshold), centred at a local point (metres from the box’s lowest corner). Weight scales its field (overlapping primitives merge smoothly); cloud_type 0 cumulus .. 1 cumulonimbus. Returns its index.
- property anchor LPoint3f¶
A point of the box (local metres from its lowest corner) that
set_center()places: a storm cell’s centre at its base.
- build_from_field()¶
A large-scale volume from the field’s weather map: the box at air_min (its size and resolution as set) filled with the envelope the map’s columns give (cover, base, top, as the shader’s base profile without the noise), its distances and profile. It keeps the far layer’s shape: a near-field voxel copy of it.
- property center LPoint3f¶
- Getter
Where the anchor is in the air frame.
- Setter
Places the box so that its anchor is at this air-frame point.
- clear_primitives()¶
Removes the primitives (the voxels stay until the next
voxelize()).
- property edge float¶
How far inside the envelope the profile reaches 1 (metres; 0: an eighth of the box’s smallest side, 150 to 600 m).
- static expected_density()¶
The expected density (0..1, before extinction) of a voxel of this profile, over the base noise: the shader’s remap(n, 1 - p, 1, 0, 1) with the profile’s softening and the filled core, averaged over a uniform n. The self-shadow is integrated from it.
- fill_light()¶
Writes the light depth into slot
slotof an R16 atlas (like fill_shape()): log2(1 + D / 8) / log2(1 +get_light_range()/ 8), D the depth in metres of expected density.
- fill_shape()¶
Writes the shape into slot
slotof an atlas ofslotsvolumes stacked along z (set up as nx x ny x nz*slots RGBA8, clamped, linear, if it isn’t already; the other slots are kept): r the signed distance packed as 0.5 + d / (2get_distance_range()), g the profile, b the type, a 1 inside the envelope.
- property floor float¶
The flat base: no cloud below this local height (metres from the box’s floor).
- get_anchor()¶
- get_center()¶
Where the anchor is in the air frame.
- static get_class_type()¶
- get_cloud_base()¶
The lowest point of the envelope (metres above the sea).
- get_cloud_top()¶
The highest point of the envelope (metres above the sea).
- get_cloud_type()¶
The type 0..1 (0 cumulus, 1 cumulonimbus) at the air-frame point.
- get_distance()¶
The signed distance (metres) from the air-frame point to the envelope: negative inside, trilinear between voxel centres, at least the distance to the box outside it.
- get_distance_range()¶
- get_edge()¶
- get_floor()¶
- get_light_depth()¶
The depth of cloud (expected density x metres) between the air-frame point and the key light, as the last finished
update_light()swept it (0 outside the box).
- get_light_dir()¶
- static get_light_range()¶
- get_light_version()¶
- get_num_primitives()¶
- get_occupied()¶
- get_origin()¶
- get_profile()¶
The dimensional profile 0..1 at the air-frame point (0 outside).
- get_resolution()¶
- get_shape_version()¶
- get_size()¶
- get_threshold()¶
- get_voxel_size()¶
One voxel’s size (metres).
- is_empty()¶
- is_inside()¶
Whether the air-frame point is inside the envelope (signed distance < 0).
- static make_cumulonimbus()¶
A cumulonimbus (or, shallower, a cumulus congestus) as metaballs, after a storm cell’s shape: a tower of
depthmetres on a flat base, body_radius wide, stacked from jittered balls with cauliflower turrets round its upper half and leaning with the shear (m/s, the upper wind relative to the cloud); with anvil 0..1 an anvil of anvil_radius spreads at the top, blown downwind, with an overshooting top. The box fits it; the anchor is the tower’s centre at its base. seed picks the jitter.
- property origin LPoint3f¶
Places the box: its lowest corner (x, y in the frame that drifts with the wind, metres; z metres above the sea).
- property resolution LVecBase3i¶
- set_anchor()¶
A point of the box (local metres from its lowest corner) that
set_center()places: a storm cell’s centre at its base.
- set_center()¶
Places the box so that its anchor is at this air-frame point.
- set_edge()¶
How far inside the envelope the profile reaches 1 (metres; 0: an eighth of the box’s smallest side, 150 to 600 m).
- set_floor()¶
The flat base: no cloud below this local height (metres from the box’s floor).
- set_origin()¶
Places the box: its lowest corner (x, y in the frame that drifts with the wind, metres; z metres above the sea).
- set_size()¶
Changes the box’s size (metres); the voxels are cleared (voxelize again).
- set_threshold()¶
The metaball field’s iso level (default 0.25).
- property size LVecBase3f¶
Changes the box’s size (metres); the voxels are cleared (voxelize again).
- update_light()¶
The self-shadow towards the key light (to_light, any length): for each voxel the expected density integrated to where the light enters the box. One slice of voxels at a time across the light’s main axis, each from the slice before (bilinear): the whole volume costs about as much as reading it once. A new shape is swept at once; after that a light that has moved more than half a degree is swept again, max_slices slices a call when max_slices > 0 (the last finished sweep stays in use meanwhile; a light that moves on by more than two degrees starts it over). Returns true when a sweep has finished (the light depth and its version changed).
- property voxel_size LVecBase3f¶
One voxel’s size (metres).
- voxelize()¶
Voxelises the primitives: the metaball field at every voxel, the envelope where it passes the threshold above the floor, the signed distance to it (an exact Euclidean distance transform), the profile and the type.
voxelize() with the caller’s working buffers (kept between builds: their capacity is reused, nothing large is allocated).