Quickstart
Vendor one header, route your foliage through it, and do the same in your shadow pass. On a conventional pack this takes about ten minutes and you will see grass move on the first reload.
spec v6 CC0 1.0 no mod required
Note
You do not need WindLink, or any mod, to integrate MCWIND. With no provider installed the header runs its own analytic field (a prevailing heading that veers over minutes, curl-noise eddies, travelling gust fronts, a diurnal cycle) plus a grass response and a canopy response. A provider adds live weather, presets and terrain shelter on top, and your pack does not change to receive them.
1 · Vendor the file
Drop mcwind.glsl into your pack, conventionally at
shaders/lib/mcwind.glsl, and include it with a pack-root-absolute
path. The leading slash matters.
your-pack/
shaders/
lib/
mcwind.glsl ← here
gbuffers_terrain.vsh
shadow.vsh
It is guarded by MCWIND_GLSL, so double-including is safe. The file
is the intersection of GLSL 1.20 and 3.30 core, so it compiles on Iris and OptiFine, in gbuffers
and shadow alike.
2 · Check four things
Each of these has a silent failure mode: nothing errors, you just get the wrong picture and no clue why.
worldPos must be ABSOLUTE
Chocapic-lineage packs (Chocapic13, BSL,
Complementary, Eclipse and most descendants) carry a camera-relative position through the
vertex shader. Pass worldPos + cameraPosition. Check what your own waving
function is fed. If its call sites add cameraPosition, so must yours.
symptom: the whole field slides with the camera
at_midBlock yourself, in both passes
MCWIND cannot declare it: a duplicate
attribute declaration is a hard compile error. Guard on
IRIS_FEATURE_BLOCK_EMISSION_ATTRIBUTE; .xyz covers both shapes.
If your pack already declares it behind a feature guard, declare yours under the exact
negation of that guard.
symptom: grass translates off its block, or a duplicate-declaration error
frameTimeCounter,
worldTime, rainStrength. Grep the actual file you are editing,
not the pack in general. One well-maintained pack we integrated declared exactly
one of the three in the stage being edited.
symptom: compile error, or a field that never changes
MCWIND is not a layer on top. This means more
than deleting a calcMovePlants call. Disable any competing grass
generation, including geometry-stage systems a vertex displacement cannot reach.
Confirm the effective value, including any user override file.
symptom: doubled motion, an un-planted base, or nothing changing at all
3 · Add the lines
Find where your pack decides a block is waving foliage, and replace that branch. Five lines for grass, two more for canopy.
#include "/lib/mcwind.glsl"
vec3 blockCentre = worldPos +
clamp(at_midBlock.xyz / 64.0, -2.0, 2.0);
// grass
float h = mcw_grassHeight(worldPos, blockCentre,
isUpperHalf);
vec2 push = mcw_grassPush(blockCentre, h);
position.xz += push;
// leaves
float weld = mcw_leafWeld(worldPos, blockCentre);
position.xyz += mcw_leafSway(worldPos,
blockCentre, weld);
The clamp is ±2.0, not ±1.0
at_midBlock is a signed byte in 1/64-block units, so it
carries ±2 blocks. Bushy-leaf resource packs build leaf blocks from plane fronds whose free
ends sit about 1.3 blocks from the block centre, and a ±1.0 clamp truncates those vertices
by different amounts per vertex, which destroys the one property every
consumer of blockCentre depends on: that it is constant for every vertex of a
block. The symptom is not a crash, it is plants shearing for reasons nobody can find. Earlier
drafts of mcwind.glsl shipped ±1.0.
isUpperHalf is 1.0 for the top block of a two-tall plant
(tall grass, large fern) and 0.0 otherwise. That single float is what welds the two
halves into one continuous blade.
Optional, v5. Debris the provider is blowing about (torn leaves,
grass flecks, dust) drafts the grass it skims past. The line goes in the grass branch, between
mcw_grassPush and position.xz += push, with the same h. It
needs a v5 provider: without one it returns zero, so calling it unconditionally is safe and does
nothing.
push += mcw_gustWake(blockCentre,
cameraPosition, h);
Grass first
If mcw_grassPush is not working in your pack yet, get that
right before you touch leaves. The canopy reuses the same prerequisites, and debugging both at
once is how people conclude MCWIND is broken. When you are ready, the canopy has its own guide:
Integrating the
canopy →. It covers finding your leaf branch, dropping your lightmap weight, why
Minecraft's own leaf distance blockstate does not work, and the eight canopy
dials.
4 · Repeat in the shadow pass
Shadow maps are rendered by a separate program. If foliage bends in gbuffers but not here, it sways in and out of its own static shadow and the contact lighting crawls. Depending on sun angle this reads as “the shadow moves but the grass doesn't”, and the moving shadow can mask the real motion entirely.
Paste the same lines, with the same numbers. Two traps: at_midBlock
and the three uniforms are declared per-file, so the shadow pass needs its own copies; and your
pack's distance gate on waving may differ between the two passes. One pack we integrated gates
geometry waving at 64 blocks and shadow waving at 24.
5 · Verify
- Grass leans and surges with travelling gusts, and stands near-upright between fronts.
- In dead calm it still wanders slightly rather than freezing.
- The field does not move with the camera.
- Two-tall grass does not shear at its middle seam.
- A cross-model plant does not split into two quads.
- Shadows track the geometry.
If something is wrong
| Symptom | Likely cause |
|---|---|
| Nothing moves at all | Your own wave is still running and cancelling, or a competing geometry-stage grass system generates the blades downstream of your edit. |
| The whole field slides with the camera | worldPos is camera-relative. Add cameraPosition. |
| Foliage translates off its block instead of bending | at_midBlock is missing or wrongly signed, so blockCentre is not a block centre. |
| Plants or leaves shear apart for no visible reason | Your blockCentre clamp is ±1.0. It must be ±2.0. |
| Shadow flickers, or the shadow moves and the grass doesn't | Shadow pass not patched. Shadow maps are a separate program. |
| Everything judders at ~20 Hz | A provider is publishing a per-tick phase. Not fixable in the pack. Report it. |
| Presets from a wind mod do nothing | The provider is not reaching your program: mcw_windProvider reads 0.0. Ask the mod author to verify their uniforms register on the terrain and shadow programs. |
mcw_gustWake does nothing | No v5 provider. It returns zero below mcw_providerVersion 4.0, by design, and there is nothing to fix in the pack. |
| Compile error: duplicate declaration | You declared a uniform or attribute MCWIND already has, or your pack declares it behind a guard you did not negate. |
Fast way to prove the provider seam
Add position.y += mcw_windProvider * 0.5; temporarily. Grass
floating half a block means the uniforms are arriving and the problem is downstream; grass at
normal height means they are not, and it is the mod side. It is a position offset on purpose:
no varying to add, no fragment-shader change, and it cannot be confused with a lighting or
tint difference. Remove it afterwards.