feat(render3d): an aspen quakes, and a tree is no longer bent like a bow
layer_flutter(l, v) gives a scatter layer a per-leaf tremble. The vertex stage offsets each leaf by a phase taken from its own place on the card, so neighbouring leaves are never in step, and writes the result out as a varying the fragment stage uses to flash the leaf's pale underside as it turns - which is the part that reads, since a still frame of a tremble is a still frame of nothing. One uniform, one varying, no extra pass. And the sway itself was measured in METRES: hgt * hgt * 0.35 is right for a 40 cm flower and puts ten metres of sideways into a 14 m trunk, so every tall tree in the valley stood bent over like a fishing rod. It is a fraction of the model's own height now - the tip moves a few per cent of the tree whatever the tree is, and the base does not move at all. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
4975c60ac1
commit
ab6f310013
47 changed files with 99 additions and 19 deletions
|
|
@ -19,6 +19,7 @@ property Layer {
|
|||
imp: Impostor,
|
||||
foliage: bool = false,
|
||||
wind: int = 0, # float bits
|
||||
flutter: int = 0, # float bits; per-leaf tremble (aspen), 0 = none
|
||||
tint: words,
|
||||
inst: words, # INST_FLOATS per instance
|
||||
count: int = 0,
|
||||
|
|
@ -128,6 +129,11 @@ function model_cross_card() -> Model {
|
|||
}
|
||||
|
||||
# A card layer: crossed cards carrying a single-tile atlas baked from `scan`.
|
||||
# An aspen leaf hangs on a flattened stalk and turns in air nothing else feels. Give the
|
||||
# layer a flutter and its leaves tremble and flash their pale undersides; everything else
|
||||
# leaves it at zero. It is per layer rather than per instance because a species quakes or
|
||||
# it does not.
|
||||
function layer_flutter(l: Layer, v: int) -> void { l.flutter = v }
|
||||
function layer_cards(scan: Model, cap: int, wind: int, cull: int) -> Layer {
|
||||
let l = layer_new(model_cross_card(), cap, true, wind, F_ZERO, cull)
|
||||
l.card = true
|
||||
|
|
@ -473,6 +479,7 @@ function impostor_bake(model: Model, tiles: int, tw: int, th: int) -> Impostor {
|
|||
u_mat4(gpu_uniform(bake, "u_view"), view)
|
||||
u_mat4(gpu_uniform(bake, "u_proj"), proj)
|
||||
u_f(gpu_uniform(bake, "u_wind"), F_ZERO)
|
||||
u_f(gpu_uniform(bake, "u_flutter"), F_ZERO)
|
||||
gpu_viewport(t * tw, 0, tw, th)
|
||||
for i in 0 .. len(model.prims) {
|
||||
let pr = model.prims[i]
|
||||
|
|
@ -1032,6 +1039,7 @@ function layer_draw_model(l: Layer, model: Model, vb: int, cnt: int, card: bool,
|
|||
if l.grounded { terrain_bind_height(p) }
|
||||
u_f(gpu_uniform(p, "u_time"), r3d_time)
|
||||
u_f(gpu_uniform(p, "u_wind"), l.wind)
|
||||
u_f(gpu_uniform(p, "u_flutter"), l.flutter)
|
||||
var mh = F_ZERO
|
||||
if not card and l.foliage { mh = model.height }
|
||||
u_f(gpu_uniform(p, "u_model_h"), mh)
|
||||
|
|
@ -1154,6 +1162,7 @@ function layer_draw_depth(l: Layer, model: Model, vb: int, cnt: int) -> void {
|
|||
if l.grounded { terrain_bind_height(p) }
|
||||
u_f(gpu_uniform(p, "u_time"), r3d_time)
|
||||
u_f(gpu_uniform(p, "u_wind"), l.wind)
|
||||
u_f(gpu_uniform(p, "u_flutter"), l.flutter)
|
||||
u_f(gpu_uniform(p, "u_model_h"), model.height)
|
||||
u_mat4(gpu_uniform(p, "u_view"), cam_view)
|
||||
u_mat4(gpu_uniform(p, "u_proj"), cam_proj)
|
||||
|
|
@ -1298,6 +1307,7 @@ function carpet_bake(layers: []Layer, count: int, tile: int, res: int) -> int {
|
|||
u_mat4(gpu_uniform(bake, "u_view"), view)
|
||||
u_mat4(gpu_uniform(bake, "u_proj"), proj)
|
||||
u_f(gpu_uniform(bake, "u_wind"), F_ZERO)
|
||||
u_f(gpu_uniform(bake, "u_flutter"), F_ZERO)
|
||||
u_f(gpu_uniform(bake, "u_time"), F_ZERO)
|
||||
for li in 0 .. len(layers) {
|
||||
let l = layers[li]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue