Advertisement

Interactive 3D Falling Leaves Shader

| by Vladimir | 2 min read | code by CeramicSoda
Advanced

Tech & Dependencies

JavaScript HTML CSS
Three.js ES Modules

Features

  • Instanced Rendering
  • Custom GLSL Shaders
  • Raycasted Interaction
  • Dynamic Matrix Updates

Browser Support

Chrome 84+ Edge 84+ Firefox 63+ Safari 14.1+

Core

This Interactive 3D Falling Leaves Shader is a sophisticated WebGL demonstration built with Three.js that showcases efficient rendering of thousands of unique objects. By utilizing InstancedMesh and custom GLSL shaders, it creates a stylized autumn tree where leaves respond to wind, sway realistically, and “die” (fall off) either randomly or through user interaction via raycasting.

Core Technique: Instancing & Shader Logic

The project achieves high performance by offloading calculations to the GPU and using efficient data structures for thousands of leaf instances.

1. GPU-Accelerated Displacement

The vertex shader handles both the organic wind sway (via triplanar noise) and the physical interaction. When the mouse moves, the uRaycast uniform is updated. The shader calculates the distance between each leaf instance and the cursor, applying a displacement force if they are close.

// Offset calculation based on mouse position
float offset = clamp(0.8 - distance(uRaycast, instanceMatrix[3].xyz), 0., 999.); 
offset = (pow(offset, 0.8) / 2.0) * vCloseToGround;
mouseDisplace[3].xyz = vec3(offset);

// Triplanar noise for wind effect
vec4 noiseOffset = getTriplanar(uNoiseMap) * vCloseToGround; 

2. Instanced Mesh Management (Логика JavaScript)

Instead of creating thousands of individual Mesh objects, the code uses one THREE.InstancedMesh. The falling physics are handled in the animate loop by decomposing the transformation matrix of “dead” leaves, updating their position and rotation, and then recomposing them.

tree.deadID = tree.deadID.map(i => {
  tree.leaves.getMatrixAt(i, matrix);
  matrix.decompose(dummy.position, dummy.rotation, dummy.scale);
  if (dummy.position.y > 0) {
    dummy.position.y -= 0.04; // Gravity
    dummy.position.x += Math.random()/5 - 0.11; // Flutter
    dummy.updateMatrix();
    tree.leaves.setMatrixAt(i, dummy.matrix);
    return(i);
  }
});
tree.leaves.instanceMatrix.needsUpdate = true; 

Browser Support

This snippet requires modern browser support for WebGL and ES Modules. Only legacy browsers without WebGL or ES Module support (like IE11) will fail to render this scene.

Advertisement