float worldX = instanceMatrix[3][0];
float worldZ = instanceMatrix[3][2];
float noiseVal = fbm(vec2(worldX, worldZ) * 0.5);

float windSpeed = 0.3;
float windScale = 0.04;

vec2 windPos = vec2(worldX, worldZ) * windScale;
vec2 windFlow = windPos + vec2(uTime * windSpeed, uTime * windSpeed * 0.7);

float windStrength = fbm(windFlow);
windStrength = windStrength * 0.6 + 0.3;

float turbulence = fbm(windPos * 3.0 + uTime * 2.0) * 0.15;

vec2 windDir = vec2(
    fbm(windPos * 0.5 + vec2(uTime * 0.1, 0.0)),
    fbm(windPos * 0.5 + vec2(0.0, uTime * 0.1))
);
windDir = normalize(windDir - 0.5) * 0.8;

float taperFactor = pow(uv.y, 4.0); // Stays near 0 for long, then shoots to 1 at tip
float taper = 1.0 - taperFactor * 0.6; // Width goes from 1.0 to 0.4 at tip
transformed.x *= taper;
transformed.z *= taper;

float curveStrength = 3.0 + noiseVal * 2.0; 
float curveAmount = uv.y * uv.y * curveStrength; 

vec2 curveDir = normalize(vec2(noiseVal, fbm(vec2(worldZ, worldX))) - 0.5); // Randomize curve direction
transformed.x += curveAmount * curveDir.x * 0.5;
transformed.z += curveAmount * curveDir.y * 0.5;

float swayAmount = (windStrength + turbulence) * uv.y * uv.y;

transformed.x += swayAmount * windDir.x;
transformed.z += swayAmount * windDir.y;
transformed.y -= abs(swayAmount) * 0.2;
