render3d/foliage: a small plant is occluded by the sward it stands in, so it no longer glows at night

The user saw kit grass, ferns and flowers lit up at night. Nothing was
emissive and every layer draw binds the scene's lighting; what differed was
occlusion. At night the sky's light is nearly all the light, and it is
scaled by ambient occlusion: the meadow's blades are heavily occluded near
the ground, while a kit plant's own AO map knows nothing of the grass around
it, so it took the full sky. By day the sun hides the difference.

model.vert hands on each vertex's height above the model's base (v_lh), and
a non-blade FOLIAGE plant under 2 m scales its AO from 0.35 at the ground to
1 at 0.9 m. Crowns and the blades are untouched.

Measured in the lab (R3D_AT=tree, same binary, old and new SPIR-V): the fern
against the meadow beside it was 2.05x at 23:00 and 1.66x at 13:00; now 1.58x
and 1.60x - the same relation by night as by day. The flowers' brightest
tenth at night 78 -> 52. The noon frame moves 8.4% of pixels past 8 (the fern
and flower bases a little darker; run-to-run noise is part of that).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-29 12:19:10 +03:00
parent 3a2d594626
commit 6a82b4928b
27 changed files with 11 additions and 0 deletions

View file

@ -6,6 +6,9 @@ in vec2 v_rot;
in float v_hull;
in float v_quake; // an aspen leaf turning its pale side up
in float v_near; // 0 in the camera's face, 1 past arm's length (NEAR_FADE)
#if defined(FOLIAGE) && !defined(BLADE)
in float v_lh; // height above the model's base (model.vert)
#endif
uniform float u_model_h;
out vec4 o_color;
uniform sampler2D u_diff;
@ -208,6 +211,12 @@ void main() {
if (u_model_h > 2.0) arm.r *= mix(0.5, 1.0, v_hull);
#endif
alb *= u_tint * (0.85 + 0.3 * fract(v_seed * 7.13));
#if defined(FOLIAGE) && !defined(BLADE)
// A fern or a clump stands IN the sward, and its low leaves see the sky through it no more than the
// blades beside them do. Its own occlusion map knows nothing of the grass around it, so by night -
// when the sky's light is nearly all the light there is - it stood out lit against the meadow.
if (u_model_h <= 2.0) arm.r *= mix(0.35, 1.0, smoothstep(0.0, 0.9, v_lh));
#endif
// The quake made visible. A turning aspen leaf shows its pale, almost white underside, so
// the crown does not merely move - it GLITTERS, leaf by leaf, and that is what reads at a
// distance and in a still frame. Toward the viewer is the pale side; away is the face.

View file

@ -61,6 +61,7 @@ out float v_hull; // 0 at the crown's axis .. 1 at its rim
uniform float u_flutter;
out float v_near; // 0 in the camera's face, 1 past arm's length (NEAR_FADE)
out float v_quake;
out float v_lh; // height above the model's base (m): a small plant's ground occlusion
void main() {
float s = i_rot.x, c = i_rot.y;
v_quake = 0.0;
@ -68,6 +69,7 @@ void main() {
#ifdef CARD
p = vec3(p.x * u_card_w, p.y * u_card_h, p.z * u_card_w);
#endif
v_lh = max(p.y, 0.0);
vec3 n = a_nrm;
#ifdef BLADE
// distant blades: wider so a thinner field keeps its coverage, lit like the ground