hex-world
    Preparing search index...

    Variable WIND_SWAY_VERT_BODYConst

    WIND_SWAY_VERT_BODY: "\n {\n float swayH = transformed.y;\n if (uSwayEnabled > 0.5 && uSwayAmplitude > 0.0 && swayH > 0.0) {\n vec3 swayOrigin = modelMatrix[3].xyz;\n mat3 swayBasis = mat3(modelMatrix);\n #ifdef USE_INSTANCING\n swayOrigin += swayBasis * instanceMatrix[3].xyz;\n swayBasis = swayBasis * mat3(instanceMatrix);\n #endif\n\n // The gust travels ALONG the wind: subtracting the plant's position\n // projected onto the wind direction is what makes a wave cross a wood\n // instead of the whole wood leaning together.\n float swayPhase = uWindPhase - dot(swayOrigin.xz, uWindDir) * uWindWave;\n // …plus a per-plant offset, so two trees the same distance downwind are\n // still not in lockstep with each other.\n swayPhase += fract(sin(dot(swayOrigin.xz, vec2(127.1, 311.7))) * 43758.5453) * 6.2831853;\n\n // Two rates again — the slow lean the trunk takes, and a faster shiver\n // riding on it.\n float lean = sin(swayPhase) * 0.72 + sin(swayPhase * 2.3 + 1.1) * 0.28;\n float flutter = sin(swayPhase * 3.7 + 2.4);\n\n // Stiffness is floored rather than taken raw: pow(0.0, 0.0) is undefined,\n // and at the base rel IS 0, so a stiffness of 0 would spray NaN vertices\n // along the ground line rather than bowing evenly as it reads like it\n // should.\n float rel = clamp(swayH / max(uSwayHeight, 1e-3), 0.0, 1.0);\n float bend = uSwayAmplitude * uSwayHeight * pow(rel, max(uSwayStiffness, 1e-3)) * uWindStrength;\n\n // World wind pulled into object space. `v * m` is `transpose(m) * v`, and\n // for the rotation these matrices carry the transpose IS the inverse —\n // which is how this gets there without an inverse() the GLSL1 path\n // doesn't have. Uniform instance scale divides back out in the normalize.\n vec3 windObj = vec3(uWindDir.x, 0.0, uWindDir.y) * swayBasis;\n float windLen = length(windObj);\n if (windLen > 1e-5) {\n windObj /= windLen;\n vec3 sideObj = vec3(-windObj.z, 0.0, windObj.x);\n // Biased downwind rather than centred: wind pushes one way, so the\n // plant oscillates between a fifth of its bend and all of it, never\n // back through upright into the wind's eye.\n vec3 offset = windObj * (bend * (0.6 + 0.4 * lean))\n + sideObj * (bend * uSwayFlutter * flutter);\n transformed += offset;\n // A bend is an arc, not a stretch: drop the tip by the sagitta, or a\n // leaning tree also grows taller than the still one beside it.\n transformed.y -= dot(offset.xz, offset.xz) / (2.0 * max(swayH, 1e-3));\n }\n }\n }\n" = ...

    The sway displacement itself. Goes in after <begin_vertex>, which is where transformed first exists and — being ahead of <project_vertex> — ahead of everything that derives a world position from it, so a swaying tree carries its haze and its snow with it.

    Bends transformed in object space, because that is the space the vertex is in at this point; the world wind is pulled back through the instance's own basis to get there. Normals are not re-bent — at the amplitudes a plant sways through, relighting the crown costs more than the shading error is worth.