GrassField¶
from acron.vegetation import GrassField
- class GrassField¶
Bases:
Bases:
TypedReferenceCountThe CPU side of instanced grass: where the blades stand, in square cells round the camera, and which cells draw at which level of detail.
Blades sit on a world-anchored jittered grid of `density` blades per square metre; each grid point keeps its blade with the probability
get_density_at()gives there (the masks: exclusion, water, slope, dry ground, an optional density image, and the light under an Ecosystem’s crowns), so a blade’s existence and shape depend only on its world spot and the seed – cells are seamless and come out byte-identical whenever they are rebuilt. Blades gather in clumps (after Ghost of Tsushima’s grass, Wohllaib, GDC 2021): each belongs to the nearest of a jittered lattice of clump centres, which pulls it in a little and gives it a shared height, facing and tone.A cell’s table is one RGBA32F texel per blade, ROW blades a row: x, y, z of its root (world), and a 24-bit integer as a float: bits 0-7 its height (0..1 of the tallest), 8-15 its facing (0..2 pi), 16-23 its clump’s tone. The table is sorted by a random rank, so drawing its first n blades thins the cell evenly (the far cells draw fewer, the shader shrinks the blades past their rank as they recede).
`update(camera)` picks the cells within the last distance, gives each a level (0, 1, 2: the vertex shader’s 7, 3 or 1 segments per blade) by its nearest distance with hysteresis and a draw count, builds the tables of cells that come into range, frees those far out of it, and reports the cells whose drawing changed.
Threads:
update()releases the GIL; it reads a snapshot of the terrain taken when it starts, and the field’s other methods wait for it (a lock). Limits: cells of 1 to 1024 m, at most MAX_CELL_BLADES blades a cell, and at most MAX_RANGE_CELLS cells a side in range (the last LOD distance is cut to that); a non-finite setting or camera is rejected with an error.Inheritance diagram
digraph inheritance4b28043716 { bgcolor=transparent; rankdir=BT; size="8.0, 12.0"; "DTOOL_SUPER_BASE" [fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style=""]; "GrassField" [URL="acron.vegetation.GrassField.html#acron.vegetation.GrassField",fillcolor=white,fontname="Vera Sans, DejaVu Sans, Liberation Sans, Arial, Helvetica, sans",fontsize=11,height=0.25,shape=box,style="",target="_top",tooltip="/**"]; "TypedReferenceCount" -> "GrassField" [arrowsize=0.75,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__()¶
Grass over `terrain` in cells of `cell_size` metres (1 to 1024).
- build_cell()¶
Builds cell (cx, cy)’s blades now (in range or not); returns its slot.
- clear()¶
Forgets every cell (after a change to the density, the masks or the ecosystem); the next
update()rebuilds what is in range and reports it. Cell slots stay valid (their generation moves on).
- clear_density_image()¶
- clear_ecosystem()¶
- find_cell()¶
The slot of cell (cx, cy), or -1 if it was never in range.
- get_build_seconds()¶
- get_canopy_response()¶
- get_cell_draw_count()¶
- get_cell_generation()¶
Counts the builds of a cell’s table: a renderer re-uploads when it moves.
- get_cell_lod()¶
- get_cell_max()¶
- get_cell_min()¶
- get_cell_num_blades()¶
- get_cell_size()¶
- get_cell_table()¶
The cell’s table, four floats a blade (see the class description).
- get_cell_x()¶
- get_cell_y()¶
- get_changed()¶
- static get_class_type()¶
- get_clump_pull()¶
- get_clump_size()¶
- get_density()¶
- get_density_at()¶
The probability 0..1 that a blade stands at (x, y): the exclusion and water masks clear it, steep slopes thin it, dry ground thins it a little, the density image scales it, and so does the light under an ecosystem’s crowns.
- get_draw_fraction()¶
The share of a cell’s blades drawn at `distance`: 1 up to the thinning start, falling linearly to the far fraction at the last distance.
- get_drawn_blades()¶
- get_far_fraction()¶
- get_hysteresis()¶
- get_lod_cells()¶
- get_lod_distances()¶
- get_num_built()¶
- get_num_cells()¶
- get_num_changed()¶
- get_num_visible()¶
- is_cell_built()¶
- is_cell_visible()¶
- property lod_distances LVecBase4f¶
x: level 0 (7 segments) up to here, y: level 1 (3 segments) up to here, level 2 (one) beyond; z: thinning starts, w: the last blade (metres).
- set_canopy_response()¶
- set_clumping()¶
Clumps `clump_size` metres apart (0: none); `pull` 0..1 draws each blade that far towards its clump’s centre.
- set_density()¶
Blades per square metre where nothing thins them (default 48).
- set_density_image()¶
A density multiplier 0..1 (grey level) over a rectangle of the world (rows north to south, as EcoTerrain’s masks); outside it, 1.
- set_ecosystem()¶
Thins the grass under `ecosystem`’s crowns (its kept tiles’ ground light, to the power of the canopy response). Rebuild (clear()) after simulating new tiles under cells already built.
- set_far_fraction()¶
- set_hysteresis()¶
- set_lod_distances()¶
x: level 0 (7 segments) up to here, y: level 1 (3 segments) up to here, level 2 (one) beyond; z: thinning starts, w: the last blade (metres).
- set_slope_limits()¶
Full grass up to `full_degrees` of slope, none past `none_degrees`.
- update()¶
Chooses the cells in range of `camera` and their levels, builds the tables of the new ones and frees those far behind. Returns how many cells changed (get_changed()).
- write_cell_texture()¶
Writes a cell’s table into `texture` (RGBA32F, ROW texels wide, nearest filtering).