Real-Time Procedural Wind Animation in glTF Foliage

This article explores the technical methods used to simulate real-time procedural wind deformation on glTF foliage models without relying on pre-baked skeletal rigs. By leveraging custom vertex shaders, vertex attribute masking, trigonometric waves, and procedural noise, graphics engines can displace 3D plant vertices dynamically while maintaining high frame rates.

1. Vertex Attribute Encoding in glTF

The standard glTF 2.0 format stores geometry using standard attributes such as POSITION, NORMAL, and TEXCOORD_n. Because procedural wind requires different parts of a plant to react with varying intensity, developers embed deformation weight data directly into the glTF model before export:

  • Vertex Colors (COLOR_0): The primary method to store flexibility data. For instance, the red channel can represent branch flexibility, the green channel leaf fluttering, and the blue channel absolute height or distance from the root.
  • Secondary UV Channels (TEXCOORD_1): Can be used to store local object-space pivot origins, allowing sub-branches or leaves to rotate around an anchor rather than stretching uncontrollably.

2. Custom Vertex Shader Displacement

Standard PBR pipelines render glTF assets statically unless modified. Real-time deformation is achieved by intercepting the vertex shader stage (using custom shaders or shader-chunk injection in engines like Three.js or Babylon.js) before applying the model-view-projection matrix.

The basic implementation applies mathematical transformations to the local vertex position:

  • Trigonometric Functions: Combining sin() and cos() functions driven by a global time uniform and the vertex's world coordinates creates traveling wave patterns across a field of foliage.
  • Wind Direction Vectors: Displacements are projected along a global wind direction vector, tilting the mesh in the direction of the gust.

3. Layered Multi-Frequency Deformation

To avoid unnatural, uniform swaying, procedural wind algorithms separate motion into distinct hierarchical frequencies:

  • Low-Frequency Motion (Main Trunk): Bends the entire mesh along the wind vector, scaled by vertex height or root distance.
  • Mid-Frequency Motion (Branches): Applies localized swaying to secondary branches using intermediate vertex weights.
  • High-Frequency Motion (Leaves): Implements rapid, low-amplitude vibration or fluttering on leaf vertices, often utilizing high-speed sinusoidal oscillation or cross-product rotations perpendicular to the surface normals.

4. GPU-Based Procedural Noise

While trigonometric functions simulate calm, rhythmic breezes, realistic turbulent gusts require continuous procedural noise. Vertex shaders can compute:

  • Simplex or Perlin Noise: Evaluated directly in the shader using world-space coordinates combined with time, producing continuous, non-repeating gusts of wind that sweep across the terrain.
  • Flow Maps and Wind Textures: For lower-end hardware, a looping, pre-computed 2D noise texture can be sampled inside the vertex shader to drive wind speed and angle across thousands of instanced glTF foliage meshes simultaneously.

5. Instanced Mesh Transformation

When dealing with large forests or dense grass fields, individual glTF meshes are rendered via hardware instancing (such as the EXT_mesh_gpu_instancing glTF extension). Procedural wind equations incorporate the instance matrix or instance-specific attributes into the noise calculation. This ensures that adjacent plants do not sway in identical synchronization, maintaining visual variety across the scene with minimal draw call overhead.