Index: binaries/data/mods/public/shaders/glsl/water_high.fs =================================================================== --- binaries/data/mods/public/shaders/glsl/water_high.fs +++ binaries/data/mods/public/shaders/glsl/water_high.fs @@ -64,18 +64,31 @@ #endif #endif -vec3 getNormal(vec4 fancyeffects) +const float tide = 7.7; // Yards; controls how wide the wet coast look extends +const float water_specular_power = 33.3; +const float dispersion_factor = 0.5 / ( 1.0 - pow(0.5, (1.0 / water_specular_power)) ); +const float reflection_distort = 3.3; // Controls distortion of reflecte objects (not sky). + + +float LOD_bias_from_spec_power_for_512( float spec_pwr ) +{ + return clamp( 7.0 - ( 0.5 * log2(spec_pwr) ), 0.1, 6.9 ); +} + +vec3 getNormalSub(vec4 fancyeffects, float rescale, float rotate) { float wavyEffect = waveParams1.r; - float baseScale = waveParams1.g; + float baseScale = waveParams1.g * rescale; float flattenism = waveParams1.b; float baseBump = waveParams1.a; float BigMovement = waveParams2.b; + + vec4 switchedCoords = mix( normalCoords.stzw, normalCoords.tswz, rotate ); // This method uses 60 animated water frames. We're blending between each two frames // Scale the normal textures by waviness so that big waviness means bigger waves. - vec3 ww1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; - vec3 ww2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; + vec3 ww1 = texture2D(normalMap, (switchedCoords.st + switchedCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; + vec3 ww2 = texture2D(normalMap2, (switchedCoords.st + switchedCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; vec3 wwInterp = mix(ww1, ww2, moddedTime) - vec3(0.5, 0.0, 0.5); ww1.x = wwInterp.x * WindCosSin.x - wwInterp.z * WindCosSin.y; @@ -92,21 +105,30 @@ normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); #endif - return vec3(-normal.x, normal.y, -normal.z); + return normalize( vec3(-normal.x, normal.y, -normal.z) * vec3( 3.5, 1.0, 3.5 ) ); +} + +vec3 getNormal(vec4 fancyeffects) +{ + vec3 result = vec3(0.0, 1.0, 0.0); + result = result + vec3(1.0) * getNormalSub(fancyeffects,1.0,0.0); + result = result + vec3(0.25) * getNormalSub(fancyeffects,0.5,1.0); + return normalize(result); +} + +float sunReflIntensity( vec3 normal ) +{ + vec3 half_vec = normalize( normalize(-v_eyeVec) + normalize(sunDir) ); + float phong_factor = pow( clamp(dot(normal, half_vec), 0.0, 1.0 ), water_specular_power ); + return phong_factor * dispersion_factor * getShadow(); // This is the sun reflecting; shadow matters! } -vec3 getSpecular(vec3 normal, vec3 eyeVec) +vec3 getSpecularSunlight(vec3 normal, vec3 eyeVec) { - // Specular lighting vectors - vec3 specularVector = reflect(sunDir, normal); - // pow is undefined for null or negative values, except on intel it seems. - float specularIntensity = pow(max(dot(specularVector, eyeVec), 0.0), 100.0); - // Workaround to fix too flattened water. - specularIntensity = smoothstep(0.6, 1.0, specularIntensity) * 1.2; - return clamp(specularIntensity * sunColor, 0.0, 1.0); + return sunColor * vec3(sunReflIntensity(normal)); } -vec4 getReflection(vec3 normal, vec3 eyeVec) +vec3 getReflections(vec3 normal, vec3 eyeVec) { // Reflections // 3 level of settings: @@ -114,26 +136,16 @@ // -If a player has refraction OR reflection, we return a reflection of the actual skybox used. // -If a player has reflection enabled, we also return a reflection of actual entities where applicable. - // reflMod reduces the intensity of reflections somewhat since they kind of wash refractions out otherwise. - float reflMod = 0.75; vec3 eye = reflect(eyeVec, normal); #if USE_REFLECTION - float refVY = clamp(eyeVec.y * 2.0, 0.05, 1.0); - + float refVY = clamp(eyeVec.y * 2.0, 0.01, 1.0); // Distort the reflection coords based on waves. - vec2 reflCoords = (0.5 * reflectionCoords.xy - 15.0 * normal.zx / refVY) / reflectionCoords.z + 0.5; + vec2 reflCoords = (0.5 * reflectionCoords.xy - vec2(reflection_distort)*normal.zx / refVY) / reflectionCoords.z + 0.5; vec4 refTex = texture2D(reflectionMap, reflCoords); - - vec3 reflColor = refTex.rgb; - - // Interpolate between the sky color and nearby objects. - // Only do this when alpha is rather low, or transparent leaves show up as extremely white. - if (refTex.a < 0.4) - reflColor = mix(textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb, refTex.rgb, refTex.a); - - // Let actual objects be reflected fully. - reflMod = max(refTex.a, 0.75); + float LOD_bias = LOD_bias_from_spec_power_for_512( water_specular_power ); + vec3 skyColor = textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz, LOD_bias).rgb; + vec3 reflColor = mix( skyColor, refTex.rgb, refTex.a ); #elif USE_REFRACTION vec3 reflColor = textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb; #else // !USE_REFLECTION && !USE_REFRACTION @@ -141,7 +153,7 @@ vec3 reflColor = mix(vec3(0.76, 0.84, 0.92), vec3(0.24, 0.43, 0.71), -eye.y); #endif - return vec4(reflColor, reflMod); + return reflColor; } #if USE_REFRACTION && USE_REAL_DEPTH @@ -157,7 +169,7 @@ } #endif -vec4 getRefraction(vec3 normal, vec3 eyeVec, float depthLimit) +vec4 getRefractedColor(vec3 normal, vec3 eyeVec, float depthLimit) { #if USE_REFRACTION && USE_REAL_DEPTH // Compute real depth at the target point. @@ -219,6 +231,7 @@ blurColor += vec4(tex.rgb * tex.a, tex.a); tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.z, -blur)); blurColor += vec4(tex.rgb * tex.a, tex.a); + blurColor /= blurColor.a; float blurFactor = (distoFactor / 7.0); refColor = (refColor + blurColor.rgb * blurFactor) / (1.0 + blurFactor); @@ -243,12 +256,13 @@ vec3 colll = mix(refColor * tint, refColor, ColextFact); vec3 refrColor = mix(color, colll, extFact); - float alpha = clamp(depth, 0.0, 1.0); + float alpha = clamp(depth, 0.0, tide) / tide; #if !USE_REFRACTION alpha = (1.4 - extFact) * alpha; #endif - return vec4(refrColor, alpha); + vec3 mulfactor = vec3(1.0); + return vec4(mulfactor*refrColor, alpha); } vec4 getFoam(vec4 fancyeffects, float shadow) @@ -273,6 +287,15 @@ #endif } +float SchlickApproximateReflectionCoefficient( float rayDotNormal, float From_IOR, float To_IOR ) +{ + const float funny_constant = 1.15; // Sh.be 1.0, but < 1.15 -> artifacts on land. + float R0 = (To_IOR - From_IOR) / (From_IOR + To_IOR); + R0 = R0 * R0; + float angle_part = pow( clamp(funny_constant-rayDotNormal,0.01,0.99), 5.0 ); + return R0 + (1.0 - R0) * angle_part; +} + void main() { #if USE_FANCY_EFFECTS @@ -283,32 +306,34 @@ vec3 eyeVec = normalize(v_eyeVec); vec3 normal = getNormal(fancyeffects); - - vec4 refrColor = getRefraction(normal, eyeVec, fancyeffects.a); - vec4 reflColor = getReflection(normal, eyeVec); + vec4 temp4 = getRefractedColor(normal, eyeVec, fancyeffects.a); + vec3 refrColor = temp4.rgb; + float tidal = temp4.a; + refrColor = mix( refrColor, refrColor * vec3(0.6,0.9,0.7), sqrt(tidal) ); + tidal *= temp4.a; + vec3 specLight = getReflections(normal, eyeVec).rgb; + specLight += getSpecularSunlight(normal, eyeVec); + specLight = specLight * vec3(tidal); // How perpendicular to the normal our view is. Used for fresnel. float ndotv = clamp(dot(normal, eyeVec), 0.0, 1.0); // Fresnel for "how much reflection vs how much refraction". - float fresnel = clamp(((pow(1.1 - ndotv, 2.0)) * 1.5), 0.1, 0.75); // Approximation. I'm using 1.1 and not 1.0 because it causes artifacts, see #1714 - - vec3 specular = getSpecular(normal, eyeVec); + float fresnel = SchlickApproximateReflectionCoefficient( ndotv, 1.0, 1.55 ); // H2O's RI = 1.33, but salty's > ... #if USE_SHADOW float shadow = getShadowOnLandscape(); - fresnel = mix(fresnel, fresnel * shadow, 0.05 + murkiness * 0.2); #else float shadow = 1.0; #endif - vec3 color = mix(refrColor.rgb, reflColor.rgb, fresnel * reflColor.a); - color += shadow * specular; - - vec4 foam = getFoam(fancyeffects, shadow); - color = clamp(mix(color, foam.rgb, foam.a), 0.0, 1.0); + vec3 refrLight = textureCube(skyCube, (vec4(0.0, 1.0, 0.0 , 0.0) * skyBoxRot).xyz, 9.9).rgb; + refrLight = refrLight + dot(normalize(-sunDir),normal) * sunColor * shadow; + refrLight = refrLight * refrColor; + vec3 color = mix(refrLight, specLight, fresnel ); // Period! + vec4 foam = getFoam(fancyeffects, getShadow()); + color = clamp(mix(color, foam.rgb * vec3(tidal), foam.a), 0.0, 1.0); color = applyFog(color); - - gl_FragColor = vec4(color * getLOS(), refrColor.a); + gl_FragColor = vec4(color * getLOS(), tidal); }