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 @@ -1,5 +1,5 @@ #version 110 - + #include "common/fog.h" #include "common/los_fragment.h" #include "common/shadows_fragment.h" @@ -12,10 +12,10 @@ uniform vec3 cameraPos; -uniform float waviness; // "Wildness" of the reflections and refractions; choose based on texture -uniform vec3 color; // color of the water -uniform vec3 tint; // Tint for refraction (used to simulate particles in water) -uniform float murkiness; // Amount of tint to blend in with the refracted color +uniform float waviness; // "Wildness" of the reflections and refractions; choose based on texture +uniform vec3 color; // color of the water +uniform vec3 tint; // Tint for refraction (used to simulate particles in water) +uniform float murkiness; // Amount of tint to blend in with the refracted color uniform float windAngle; varying vec2 WindCosSin; @@ -38,6 +38,7 @@ #endif varying float fwaviness; +varying float sun_dimming_factor; uniform samplerCube skyCube; @@ -45,270 +46,307 @@ uniform sampler2D normalMap2; #if USE_FANCY_EFFECTS - uniform sampler2D waterEffectsTex; + uniform sampler2D waterEffectsTex; #endif uniform vec4 waveParams1; // wavyEffect, BaseScale, Flattenism, Basebump uniform vec4 waveParams2; // Smallintensity, Smallbase, Bigmovement, Smallmovement #if USE_REFLECTION - uniform sampler2D reflectionMap; + uniform sampler2D reflectionMap; #endif #if USE_REFRACTION - uniform sampler2D refractionMap; + uniform sampler2D refractionMap; #if USE_REAL_DEPTH - uniform sampler2D depthTex; - uniform mat4 projInvTransform; - uniform mat4 viewInvTransform; + uniform sampler2D depthTex; + uniform mat4 projInvTransform; + uniform mat4 viewInvTransform; #endif #endif -vec3 getNormal(vec4 fancyeffects) + +const float tide = 1.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). +const float IOR_mul = 1.1; // Visual adjustment (hack). +const vec3 sea_water_refractive_indices_at_15c = vec3( 1.350, 1.344, 1.336 ) * vec3(IOR_mul); +const vec3 frs_water_refractive_indices_at_15c = vec3( 1.344, 1.338, 1.331 ) * vec3(IOR_mul); +//from: http://research.engr.oregonstate.edu/parrish/index-refraction-seawater-and-freshwater-function-wavelength-and-temperature +const vec3 WHITE = vec3(1.0); +const vec3 wetness_RGB = vec3(0.4,0.45,0.42); +const float wave_mul = 4.7; + + +float LOD_bias_from_spec_power_for_512( float spec_pwr ) { - float wavyEffect = waveParams1.r; - float baseScale = waveParams1.g; - float flattenism = waveParams1.b; - float baseBump = waveParams1.a; - float BigMovement = waveParams2.b; - - // 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 wwInterp = mix(ww1, ww2, moddedTime) - vec3(0.5, 0.0, 0.5); - - ww1.x = wwInterp.x * WindCosSin.x - wwInterp.z * WindCosSin.y; - ww1.z = wwInterp.x * WindCosSin.y + wwInterp.z * WindCosSin.x; - ww1.y = wwInterp.y; + return clamp( 7.0 - ( 0.5 * log2(spec_pwr) ), 0.1, 6.9 ); +} - // Flatten them based on waviness. - vec3 normal = normalize(mix(vec3(0.0, 1.0, 0.0), ww1, clamp(baseBump + fwaviness / flattenism, 0.0, 1.0))); +vec3 getNormalSub(vec4 fancyeffects, float rescale, float rotate) +{ + float wavyEffect = waveParams1.r; + float baseScale = waveParams1.g * rescale; + float flattenism = waveParams1.b; + float baseBump = waveParams1.a; + float BigMovement = waveParams2.b; + + vec4 switchedCoords = mix( normalCoords.xyzw, normalCoords.yxwz, 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, (switchedCoords.xy + switchedCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).xzy; + vec3 ww2 = texture2D(normalMap2, (switchedCoords.xy + 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; + ww1.z = wwInterp.x * WindCosSin.y + wwInterp.z * WindCosSin.x; + ww1.y = wwInterp.y; + + // Flatten them based on waviness. + vec3 normal = normalize(mix(vec3(0.0, 1.0, 0.0), ww1, clamp(baseBump + fwaviness / flattenism, 0.0, 1.0))); #if USE_FANCY_EFFECTS - normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); - normal.xz = mix(normal.xz, fancyeffects.rb, fancyeffects.a / 2.0); + normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); + normal.xz = mix(normal.xz, fancyeffects.rb, fancyeffects.a / 2.0); #else - normal = mix(vec3(0.0, 1.0, 0.0), normal, 0.5 + waterInfo.r / 2.0); + 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( wave_mul, 1.0, wave_mul ) ); } -vec3 getSpecular(vec3 normal, vec3 eyeVec) +vec3 getNormal(vec4 fancyeffects) { - // 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); + vec3 result = vec3(0.0, 1.0, 0.0); + result = result + vec3(1.0) * getNormalSub(fancyeffects,1.0,0.0); + //result = result + vec3(0.7) * getNormalSub(fancyeffects,1.382,1.0); + //result = result + vec3(0.5) * getNormalSub(fancyeffects,0.618,0.0); + return normalize(result); } -vec4 getReflection(vec3 normal, vec3 eyeVec) +float sunReflIntensity( vec3 normal ) { - // Reflections - // 3 level of settings: - // -If a player has refraction and reflection disabled, we return a gradient of blue based on the Y component. - // -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); + 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; shadows matter! +} - // Distort the reflection coords based on waves. - vec2 reflCoords = (0.5 * reflectionCoords.xy - 15.0 * normal.zx / refVY) / reflectionCoords.z + 0.5; - vec4 refTex = texture2D(reflectionMap, reflCoords); +vec3 getSpecularSunlight(vec3 normal, vec3 eyeVec) +{ + return sunColor * vec3(sunReflIntensity(normal)); +} - vec3 reflColor = refTex.rgb; +vec3 getReflections(vec3 normal, vec3 eyeVec) +{ + // Reflections + // 3 level of settings: + // -If a player has refraction and reflection disabled, we return a gradient of blue based on the Y component. + // -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. - // 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); + vec3 eye = reflect(eyeVec, normal); - // Let actual objects be reflected fully. - reflMod = max(refTex.a, 0.75); +#if USE_REFLECTION + float refVY = clamp(eyeVec.y * 2.0, 0.01, 1.0); + // Distort the reflection coords based on waves. + vec2 reflCoords = (0.5 * reflectionCoords.xy - vec2(reflection_distort)*normal.zx / refVY) / reflectionCoords.z + 0.5; + vec4 refTex = texture2D(reflectionMap, reflCoords); + 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; + vec3 reflColor = textureCube(skyCube, (vec4(eye, 0.0) * skyBoxRot).xyz).rgb; #else // !USE_REFLECTION && !USE_REFRACTION - // Simplest case for reflection, return a gradient of blue based on Y component. - vec3 reflColor = mix(vec3(0.76, 0.84, 0.92), vec3(0.24, 0.43, 0.71), -eye.y); + // Simplest case for reflection, return a gradient of blue based on Y component. + 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 vec3 getWorldPositionFromRefractionDepth(vec2 uv) { - float depth = texture2D(depthTex, uv).x; - vec4 viewPosition = projInvTransform * (vec4((uv - vec2(0.5)) * 2.0, depth * 2.0 - 1.0, 1.0)); - viewPosition /= viewPosition.w; - vec3 refrWorldPos = (viewInvTransform * viewPosition).xyz; - // Depth buffer precision errors can give heights above the water. - refrWorldPos.y = min(refrWorldPos.y, worldPos.y); - return refrWorldPos; + float depth = texture2D(depthTex, uv).x; + vec4 viewPosition = projInvTransform * (vec4((uv - vec2(0.5)) * 2.0, depth * 2.0 - 1.0, 1.0)); + viewPosition /= viewPosition.w; + vec3 refrWorldPos = (viewInvTransform * viewPosition).xyz; + // Depth buffer precision errors can give heights above the water. + refrWorldPos.y = min(refrWorldPos.y, worldPos.y); + return refrWorldPos; } #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. - vec2 coords = (0.5 * refractionCoords.xy) / refractionCoords.z + 0.5; - vec3 refrWorldPos = getWorldPositionFromRefractionDepth(coords); + // Compute real depth at the target point. + vec2 coords = (0.5 * refractionCoords.xy) / refractionCoords.z + 0.5; + vec3 refrWorldPos = getWorldPositionFromRefractionDepth(coords); - // Set depth to the depth at the undistorted point. - float depth = distance(refrWorldPos, worldPos); + // Set depth to the depth at the undistorted point. + float depth = distance(refrWorldPos, worldPos); #else - // fake depth computation: take the value at the vertex, add some if we are looking at a more oblique angle. - float depth = waterDepth / (min(0.5, eyeVec.y) * 1.5 * min(0.5, eyeVec.y) * 2.0); + // fake depth computation: take the value at the vertex, add some if we are looking at a more oblique angle. + float depth = waterDepth / (min(0.5, eyeVec.y) * 1.5 * min(0.5, eyeVec.y) * 2.0); #endif #if USE_REFRACTION - // for refraction we want to distort more as depth goes down. - // 1) compute a distortion based on depth at the pixel. - // 2) Re-sample the depth at the target point - // 3) Sample refraction texture + // for refraction we want to distort more as depth goes down. + // 1) compute a distortion based on depth at the pixel. + // 2) Re-sample the depth at the target point + // 3) Sample refraction texture - // distoFactor controls the amount of distortion relative to wave normals. - float distoFactor = 0.5 + clamp(depth / 2.0, 0.0, 7.0); + // distoFactor controls the amount of distortion relative to wave normals. + float distoFactor = 0.5 + clamp(depth / 2.0, 0.0, 7.0); #if USE_REAL_DEPTH - // Distort the texture coords under where the water is to simulate refraction. - vec2 shiftedCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; - vec3 refrWorldPos2 = getWorldPositionFromRefractionDepth(shiftedCoords); - float newDepth = distance(refrWorldPos2, worldPos); - - // try to correct for fish. In general they'd look weirder without this fix. - if (depth > newDepth + 3.0) - distoFactor /= 2.0; // this in general will not fall on the fish but still look distorted. - else - depth = newDepth; + // Distort the texture coords under where the water is to simulate refraction. + vec2 shiftedCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; + vec3 refrWorldPos2 = getWorldPositionFromRefractionDepth(shiftedCoords); + float newDepth = distance(refrWorldPos2, worldPos); + + // try to correct for fish. In general they'd look weirder without this fix. + if (depth > newDepth + 3.0) + distoFactor /= 2.0; // this in general will not fall on the fish but still look distorted. + else + depth = newDepth; #endif #if USE_FANCY_EFFECTS - depth = max(depth, depthLimit); - if (waterDepth < 0.0) - depth = 0.0; -#endif - - // Distort the texture coords under where the water is to simulate refraction. - vec2 refrCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; - vec3 refColor = texture2D(refractionMap, refrCoords).rgb; - - // Note, the refraction map is cleared using (255, 0, 0), so pixels outside of the water plane are pure red. - // If we get a pure red fragment, use an undistorted/less distorted coord instead. - // blur the refraction map, distoring using normal so that it looks more random than it really is - // and thus looks much better. - float blur = (0.1 + clamp(normal.x, -0.1, 0.1)) / refractionCoords.z; - - vec4 blurColor = vec4(refColor, 1.0); - - vec4 tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.x, blur + normal.z)); - blurColor += vec4(tex.rgb * tex.a, tex.a); - tex = texture2D(refractionMap, refrCoords + vec2(-blur, blur + normal.z)); - blurColor += vec4(tex.rgb * tex.a, tex.a); - tex = texture2D(refractionMap, refrCoords + vec2(-blur, -blur + normal.x)); - 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); + depth = max(depth, depthLimit); + if (waterDepth < 0.0) + depth = 0.0; +#endif + + // Distort the texture coords under where the water is to simulate refraction. + vec2 refrCoords = (0.5 * refractionCoords.xy - normal.xz * distoFactor) / refractionCoords.z + 0.5; + vec3 refColor = texture2D(refractionMap, refrCoords).rgb; + + // Note, the refraction map is cleared using (255, 0, 0), so pixels outside of the water plane are pure red. + // If we get a pure red fragment, use an undistorted/less distorted coord instead. + // blur the refraction map, distoring using normal so that it looks more random than it really is + // and thus looks much better. + float blur = (0.1 + clamp(normal.x, -0.1, 0.1)) / refractionCoords.z; + + vec4 blurColor = vec4(refColor, 1.0); + + vec4 tex = texture2D(refractionMap, refrCoords + vec2(blur + normal.x, blur + normal.z)); + blurColor += vec4(tex.rgb * tex.a, tex.a); + tex = texture2D(refractionMap, refrCoords + vec2(-blur, blur + normal.z)); + blurColor += vec4(tex.rgb * tex.a, tex.a); + tex = texture2D(refractionMap, refrCoords + vec2(-blur, -blur + normal.x)); + 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); #else // !USE_REFRACTION #if USE_FANCY_EFFECTS - depth = max(depth, depthLimit); + depth = max(depth, depthLimit); #endif - vec3 refColor = color; + vec3 refColor = color; #endif - // for refraction, we want to adjust the value by v.y slightly otherwise it gets too different between "from above" and "from the sides". - // And it looks weird (again, we are not used to seeing water from above). - float fixedVy = max(eyeVec.y, 0.01); + // for refraction, we want to adjust the value by v.y slightly otherwise it gets too different between "from above" and "from the sides". + // And it looks weird (again, we are not used to seeing water from above). + float fixedVy = max(eyeVec.y, 0.01); - float murky = mix(200.0, 0.1, pow(murkiness, 0.25)); + float murky = mix(200.0, 0.1, pow(murkiness, 0.25)); - // Apply water tint and murk color. - float extFact = max(0.0, 1.0 - (depth * fixedVy / murky)); - float ColextFact = max(0.0, 1.0 - (depth * fixedVy / murky)); - vec3 colll = mix(refColor * tint, refColor, ColextFact); - vec3 refrColor = mix(color, colll, extFact); + // Apply water tint and murk color. + float ColextFact = max(0.0, 1.0 - (depth * fixedVy / murky)); + vec3 colll = mix(refColor * tint, refColor, ColextFact); + vec3 refrColor = mix(color, colll, ColextFact); - float alpha = clamp(depth, 0.0, 1.0); + float alpha = clamp(depth, 0.0, tide) / tide; #if !USE_REFRACTION - alpha = (1.4 - extFact) * alpha; + alpha = (1.4 - ColextFact) * alpha; #endif - return vec4(refrColor, alpha); + return vec4(refrColor, alpha); } vec4 getFoam(vec4 fancyeffects, float shadow) { #if USE_FANCY_EFFECTS - float wavyEffect = waveParams1.r; - float baseScale = waveParams1.g; - float BigMovement = waveParams2.b; - vec3 foam1 = texture2D(normalMap, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; - vec3 foam2 = texture2D(normalMap2, (normalCoords.st + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; - vec3 foam3 = texture2D(normalMap, normalCoords.st / 6.0 - normalCoords.zw * 0.02).aaa; - vec3 foam4 = texture2D(normalMap2, normalCoords.st / 6.0 - normalCoords.zw * 0.02).aaa; - vec3 foaminterp = mix(foam1, foam2, moddedTime); - foaminterp *= mix(foam3, foam4, moddedTime); + float wavyEffect = waveParams1.r; + float baseScale = waveParams1.g; + float BigMovement = waveParams2.b; + vec3 foam1 = texture2D(normalMap, (normalCoords.xy + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; + vec3 foam2 = texture2D(normalMap2, (normalCoords.xy + normalCoords.zw * BigMovement * waviness / 10.0) * (baseScale - waviness / wavyEffect)).aaa; + vec3 foam3 = texture2D(normalMap, normalCoords.xy / 6.0 - normalCoords.zw * 0.02).aaa; + vec3 foam4 = texture2D(normalMap2, normalCoords.xy / 6.0 - normalCoords.zw * 0.02).aaa; + vec3 foaminterp = mix(foam1, foam2, moddedTime); + foaminterp *= mix(foam3, foam4, moddedTime); - foam1.x = abs(foaminterp.x * WindCosSin.x) + abs(foaminterp.z * WindCosSin.y); + foam1.x = abs(foaminterp.x * WindCosSin.x) + abs(foaminterp.z * WindCosSin.y); - float alpha = (fancyeffects.g + pow(foam1.x * (3.0 + waviness), 2.6 - waviness / 5.5)) * 2.0; - return vec4(sunColor * shadow + ambient, clamp(alpha, 0.0, 1.0)); + float alpha = (fancyeffects.g + pow(foam1.x * (3.0 + waviness), 2.6 - waviness / 5.5)) * 2.0; + return vec4(sunColor * shadow + ambient, clamp(alpha, 0.0, 1.0)); #else - return vec4(0.0); + return vec4(0.0); #endif } +void RealFresnel( float NdotL, vec3 IOR_RGB, out vec3 Frefl, inout vec3 sin_t, inout vec3 cos_t ) +{ + vec3 Z2 = WHITE / IOR_RGB; // Assumes n1 = 1 thus Z1 = 1. + vec3 cos_i = vec3( NdotL ); + vec3 sin_i = sqrt( WHITE - cos_i*cos_i ); + sin_t = min(WHITE, sin_i * Z2); // Outputs sin(refraction angle). + cos_t = sqrt( WHITE - sin_t*sin_t ); // Outputs cos(refraction angle). + vec3 Rs = (Z2*cos_i-cos_t) / (Z2*cos_i+cos_t); + vec3 Rp = (Z2*cos_t-cos_i) / (Z2*cos_t+cos_i); + Frefl = mix( Rs*Rs, Rp*Rp, 0.5 ); // Outputs reflectivity. +} + void main() { + float temp; + vec2 temp2; + vec3 temp3; + vec4 temp4; #if USE_FANCY_EFFECTS - vec4 fancyeffects = texture2D(waterEffectsTex, gl_FragCoord.xy / screenSize); + vec4 fancyeffects = texture2D(waterEffectsTex, gl_FragCoord.xy / screenSize); #else - vec4 fancyeffects = vec4(0.0); + vec4 fancyeffects = vec4(0.0); #endif - vec3 eyeVec = normalize(v_eyeVec); - vec3 normal = getNormal(fancyeffects); - - vec4 refrColor = getRefraction(normal, eyeVec, fancyeffects.a); - vec4 reflColor = getReflection(normal, eyeVec); - - // 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); + vec3 eyeVec = normalize(v_eyeVec); + vec3 normal = getNormal(fancyeffects); + // How perpendicular to the normal our view is. Used for fresnel. + float ndotv = clamp(dot(normal, eyeVec), 0.0, 1.0); + vec3 F_refl_RGB; + temp4 = getRefractedColor(normal, eyeVec, fancyeffects.a); + vec3 refrColor = temp4.rgb; + float tidal = temp4.a; + // Fresnel for "how much reflection vs how much refraction". + vec3 n = mix( WHITE, sea_water_refractive_indices_at_15c, tidal ); + RealFresnel( ndotv, n, F_refl_RGB, temp3, temp3 ); + refrColor = mix( refrColor, refrColor * wetness_RGB, tidal*tidal ); + vec3 specLight = getReflections(normal, eyeVec).rgb; + specLight += getSpecularSunlight(normal, eyeVec); #if USE_SHADOW - float shadow = getShadowOnLandscape(); - fresnel = mix(fresnel, fresnel * shadow, 0.05 + murkiness * 0.2); + float shadow = getShadowOnLandscape(); #else - float shadow = 1.0; + 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); - - color = applyFog(color); + vec3 refrLight = textureCube(skyCube, (vec4(0.0, 1.0, 0.0 , 0.0) * skyBoxRot).xyz, 6.6).rgb; + refrLight = refrLight + (sun_dimming_factor * sunColor * 0.5*(shadow+1.0)); // Non-wavey shadows look bad. + refrLight = refrLight * refrColor; + vec3 color = mix(refrLight, specLight, F_refl_RGB ); // Period! + vec4 foam = getFoam(fancyeffects, getShadow()); + color = clamp(mix(color, foam.rgb * vec3(tidal), foam.a), 0.0, 1.0); - gl_FragColor = vec4(color * getLOS(), refrColor.a); + color = applyFog(color); + gl_FragColor = vec4(color * getLOS(), tidal); } Index: binaries/data/mods/public/shaders/glsl/water_high.vs =================================================================== --- binaries/data/mods/public/shaders/glsl/water_high.vs +++ binaries/data/mods/public/shaders/glsl/water_high.vs @@ -33,12 +33,23 @@ #endif varying float fwaviness; +varying float sun_dimming_factor; varying vec2 WindCosSin; attribute vec3 a_vertex; attribute vec2 a_waterInfo; attribute vec3 a_otherPosition; +// Schlick's Abomination should be good enough for sunlight getting into the water. +float SchlickApproximateRefractionCoefficient( float rayDotNormal, float From_IOR, float To_IOR ) +{ + float R0 = (To_IOR - From_IOR) / (From_IOR + To_IOR); + float angle_part = pow( (1.15-rayDotNormal), 5.0 ); + R0 = R0 * R0; + float RC = R0 + (1.0 - R0) * angle_part; + return 1.0-RC; +} + void main() { worldPos = a_vertex; @@ -70,5 +81,8 @@ // Fix the waviness for local wind strength fwaviness = waviness * (0.15 + a_waterInfo.r / 1.15); + float sun_ndotv = dot(normalize(-sunDir),vec3(0.0,1.0,0.0)); + sun_dimming_factor = sun_ndotv * SchlickApproximateRefractionCoefficient( sun_ndotv, 1.0, 1.33 ); + gl_Position = transform * vec4(a_vertex, 1.0); }