   return x * x * (3.0 - 2.0 * x);  
 }
 
+float smoothCurve(float x)
+{  
+  return x * x * (3.0 - 2.0 * x);  
+}
+
 vec4 triangleWave(vec4 x) 
+{  
+  return abs(fract(x + 0.5) * 2.0 - 1.0);  
+}
+
+float triangleWave(float x) 
 {  
   return abs(fract(x + 0.5) * 2.0 - 1.0);  
 }

  inout vec3 vPos,
  vec3 vNormal,
  vec3 objectPosition,
  float fDetailPhase,
  float fBranchPhase,
  float fTime,
  float fEdgeAtten,
  float fBranchAtten,
  float fBranchAmp,
  float fSpeed,
  float fDetailFreq,
  float fDetailAmp)
{
  float fObjPhase = dot(objectPosition.xyz, vec3(1.0));  
  fBranchPhase += fObjPhase;
  float fVtxPhase = dot(vPos.xyz, vec3(fDetailPhase + fBranchPhase));  

  vec2 vWavesIn = fTime + vec2(fVtxPhase, fBranchPhase);
  vec4 vWaves = (fract(vWavesIn.xxyy *
             vec4(SIDE_TO_SIDE_FREQ1, SIDE_TO_SIDE_FREQ2, 
                  UP_AND_DOWN_FREQ1, UP_AND_DOWN_FREQ2)) *
             2.0 - 1.0) * fSpeed * fDetailFreq;
  vWaves = smoothTriangleWave(vWaves);
  vec2 vWavesSum = vWaves.xz + vWaves.yw;  

  vPos.xyz += vWavesSum.x * vec3(fEdgeAtten * fDetailAmp * vNormal.xyz);
  vPos.y += vWavesSum.y * fBranchAtten * fBranchAmp;
}

void applyMainBending(inout vec3 pos, vec2 wind, float bendScale)
{
  float length = length(pos);
  float bf = pos.y * bendScale;
  bf += 1.0;
  bf *= bf;

  float time,
  vec2 windStrength)
{
  const vec2 detailStrength = clamp(
      vec2(
        noise(vec3(worldPos.x * 2.0 + time * grassFreq, 0.0, 0.0)) * 0.5 + 0.5,
        noise(vec3(worldPos.z * 2.0 + time * grassFreq, 0.0, 0.0)) * 0.5 + 0.5
      )
      , vec2(0.0), vec2(1.0));
  const vec2 mainStrength = clamp(
    vec2(
        (smoothTriangleWave(worldPos.x * 0.05 + time * grassFreq * 0.25) * 0.5 + 0.5) * 0.8 + 0.2,
        (smoothTriangleWave(worldPos.z * 0.05 + time * grassFreq * 0.25) * 0.5 + 0.5) * 0.8 + 0.2
      )
      , vec2(0.0), vec2(1.0));

  const vec2 wind = grassIntensFact
    * windStrength
    * ((mainStrength + detailStrength) * 0.5);

  applyGrassBending(localPos, wind);
} 
