ProjectsExperiments

Falling Leaves

An interactive WebGPU tree: shake it with the pointer and leaves come loose, fall with the wind and grow back on the branches. The whole simulation runs on the GPU.

Status
In progress
Period
2026.10 — present
Type
Experiment
Role
Solo project, 3D development, Shaders, Technical art
Technologies
  • Three.js
  • WebGPU
  • TSL
  • Vite
  • Blender
Development log
2 entries

Context and goal

A technical demo to validate the leaf particle system before modelling the final tree: leaves born anchored to the branches, a tree that reacts to the pointer, movement that shakes some of them loose, a believable fall and leaves that grow back in place.

Interactive demo

Move the pointer over the branches to shake the tree and drag to orbit the camera. The panel sets the number of leaves, turns falling and regrowth on or off, resets and shakes the whole tree. Add #debug to the URL to see every setting and the counters. It needs a browser with WebGPU.

A leaf's life cycle

There is one particle per anchor for the whole life of the page: nothing is created or destroyed. Each one goes through three states:

  • Attached: it follows its branch. It comes loose when its bone's shake exceeds its grip, which is different for every leaf and changes every cycle, after a draw made 20 times a second so it does not depend on the frame rate.
  • Falling: it leaves with the branch's velocity and falls with gravity, air drag, wind with 3D-noise gusts and a spin of its own. When it touches the ground it lies flat, rests for a few seconds and shrinks away.
  • Growing: it goes back to its anchor at scale 0, waits a moment and grows to full size, already following the branch while it grows.

Technical description

  • CPU: only the pointer raycast and the tree rig, a few dozen bones moved by damped springs at a fixed step. Nothing loops over the leaves in JavaScript.
  • GPU: the whole state and motion of the leaves, in a single TSL compute shader per frame, with six fixed-size buffers created once.
  • Anchors: each leaf is a point in the local space of one bone. The compute and the render read the same matrices in the same frame, so an attached leaf never lags behind its branch.
  • Reproducible randomness: derived on the GPU from a hash of the leaf index, the seed and the cycle. It takes no memory and the same seed gives the same result.
  • Rendering: the leaves are a single instanced mesh, with one material and a single draw call. Each one picks one of five conifer-sprig textures from a configurable split.

From the Blender tree to the demo

The tree is built in Blender with Sapling Tree Gen and exported as GLB: an Armature with trunk and branch bones, and the skinned mesh. For that I wrote a spec of the format, a script that converts a Sapling tree to it and a validator that checks the scene before exporting. The GLB can be meshopt-compressed. To keep the pointer raycast cheap, the tree carries a simplified collider mesh.

Tests

  • Attached leaves follow their branches within 0.39 µm of the CPU reference, and 0.48 µm with 100,000 leaves.
  • Two runs with the same seed give bit-identical buffers.
  • Twenty full cycles leave no memory behind.
  • The rig gives the same rotations at 30, 60, 75 and 240 fps.
  • With 1,000, 20,000 and 100,000 leaves it held about 64 fps, the display's refresh limit at the time: the real ceiling is not measured yet.

Results and limitations

  • Each leaf follows a single bone, not the deformed surface, so the tree needs almost rigid weights along each branch segment.
  • The pointer raycast runs on the CPU against the deformed mesh; dense meshes need the collider.
  • Leaves do not collide with the tree or with each other, and the wind only moves the falling ones.
  • Only tested on Chromium with WebGPU. Performance and stress tests with more trees in the scene are still to do.

Credits

  • Based on lessons from Three.js Journey's WebGPU & TSL course (Anvil, Clair Obscur Title and Sphere Particles Physics).
  • Tree generated with Sapling Tree Gen, the Blender add-on.
  • Leaf textures cut out of an AI-generated reference image.
LOG

Development log

  1. From the Blender tree to the demo

    A GLB format for the tree, a converter from Sapling Tree Gen and a validator.

  2. Leaves that fall and grow back

    The published demo: shake the tree, watch the leaves fall and watch them grow again.