Skip to content

Using the wind in your own shaders

Any shader can sway with the same wind as the grass. Include the wind file:

#include "Packages/com.theycallmealfred.fable/Shaders/Shared/FableWind.hlsl"

The Wind module sets its values as global shader properties every frame, so there is nothing to wire up. The file provides:

Function Returns
float2 FableWindSway(float2 rootXZ, float time) Combined breeze and gust push for a plant rooted at rootXZ, as an XZ vector in fractions of plant height.
float2 FableWindSway(float2 rootXZ, float time, out float gustIntensity) The same, plus the 0โ€“1 gust front at that root (the front itself, not its wake), for effects such as a colour shimmer.
float2 FableBreeze(float2 rootXZ, float time) The breeze alone.
float2 FableGust(float2 rootXZ, float time) The gust push alone.
float FableGustShape(float2 rootXZ, float time, out float glow) The gust push shape, 0โ€“1, before _GustStrength; glow is the front alone.

Sample the wind at the plant's root, not per vertex, so the whole plant moves as one and neighbours move together. Pass _Time.y as the time, as the grass does. Multiply the result by a height mask that is 0 at the root.

The grass bends each vertex around its root and keeps the stem's length. In a URP vertex function, the same approach looks like this:

float3 rootWS = TransformObjectToWorld(float3(0, 0, 0));   // the plant's pivot, at its root
float3 posWS  = TransformObjectToWorld(input.positionOS.xyz);
float  mask   = saturate(input.positionOS.y);              // 0 at the root, rising up the plant

float2 sway = FableWindSway(rootWS.xz, _Time.y) * mask;
float3 stem = posWS - rootWS;
float  len  = length(stem);
stem.xz += sway;
if (len > 1e-4)
    stem = normalize(stem) * len;
posWS = rootWS + stem;

The global values, all in real units, are listed at the top of FableWind.hlsl: _WindDirection (XZ unit vector), _WindStrength, _WindSwayAmount, _WindWaveSize, _WindWaveSpeed, _GustDirection, _GustStrength, _GustInterval, _GustFrontSpeed, _GustFrontWidth and _GustRecoverTime. When the Wind module is disabled, it sets wind and gust strength to 0.

Two more globals are available:

  • _FableNightFactor (Skybox module): 0 by day, 1 by night.
  • The cloud field (Clouds module): include Packages/com.theycallmealfred.fable/Shaders/Shared/CloudField.hlsl and call FableCloudCoverage(FableCloudNoise(worldXZ)) for the 0โ€“1 cloud cover above a world point. _FableCloudField.w is 1 while the field is published.