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()andcos()functions driven by a globaltimeuniform 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.