 
     float atten = max( 1.0 - dot( dist, dist ) * 0.0000015, 0.0 );
 
-    color += engamma( vec4( sea_water_color * ( height_detailed( vPosition_World.xz * sea_scale ) ) * 0.05 * atten, 1.0 ) );
+    color += engamma( vec4( sea_water_color * cached_height * 0.05 * atten, 1.0 ) );
 
     color += engamma( vec4( get_specular( normal, lightdir, -view, 100.0 ) ) * 0.35 );
     
-    // actual foam
-    color = mix( color, vec4( 1.0, 1.0, 1.0, 1.0 ), foam( vPosition_World.xyz ) );
+    color = mix( color, vec4( 1.0, 1.0, 1.0, 1.0 ), foam( vPosition_World.xz * sea_scale, cached_height ) );
 
     gl_FragColor = degamma( color );
 }

    return height;
}

float foam( vec3 pos )
{
    // foaminess is modulated by height
    float base_foaminess = vPosition_World.y / 2.5;
    // base_foaminess = height_detail( pos.xz * sea_scale ); -- slightly more detail, but more expensive

    float detail = foam_detail( pos.xz * sea_scale );
   
    // poke some holes in foam to simulate appearance of bubbles
    // first term is large bubbles (to reduce noticeable artifacting at close range, we reduce large bubble alpha)
    // second term is tiny bubbles (no noticeable artifacting unless at a particular distance, but that's a sampling artifact)
    float fizziness = clamp( abs( noise( pos.xz * sea_scale * 25.0 ) ) * 0.04 + abs( noise( pos.xz * sea_scale * 380.0 ) ) * 0.2, 0.0, 1.0 );

    // the smoothstep is actually quite important in producing the end result. We purposefully (artistically :) pick
    // a range in the produced noise that looks reasonably passable as foam

}

void main( void ) {
    float cached_height = height_detailed( vPosition_World.xz * sea_scale );

    float dist = length( cPosition_World - vPosition_World );
    vec3 view = normalize( -( vPosition.xyz / vPosition.w ) );

    vec3 normal = normalize( uNormalMVMatrix * get_normal( vPosition_World.xz * sea_scale, cached_height, dist * 0.001 ) );

    vec3 reflected = uInverseViewMatrix * ( -reflect( view, normal ) );
    vec4 ibl_specular = engamma( textureCube( environment, reflected ) * 0.9 );
