#include "Uniforms.glsl" #include "Samplers.glsl" #include "Transform.glsl" #include "ScreenPos.glsl" #include "Fog.glsl" varying vec4 vScreenPos; varying vec2 vReflectUV; varying vec2 vWaterUV; varying vec3 vNormal; varying vec4 vEyeVec; #ifdef COMPILEVS uniform vec2 cNoiseSpeed; uniform float cNoiseTiling; #endif #ifdef COMPILEPS uniform float cNoiseStrength; uniform float cFresnelPower; uniform vec3 cWaterTint; #endif void VS() { mat4 modelMatrix = iModelMatrix; vec3 worldPos = GetWorldPos(modelMatrix); gl_Position = GetClipPos(worldPos); vScreenPos = GetScreenPos(gl_Position); // GetQuadTexCoord() returns a vec2 that is OK for quad rendering; multiply it with output W // coordinate to make it work with arbitrary meshes such as the water plane (perform divide in pixel shader) // Also because the quadTexCoord is based on the clip position, and Y is flipped when rendering to a texture // on OpenGL, must flip again to cancel it out vReflectUV = GetQuadTexCoord(gl_Position); vReflectUV.y = 1.0 - vReflectUV.y; vReflectUV *= gl_Position.w; vWaterUV = iTexCoord * cNoiseTiling + cElapsedTime * cNoiseSpeed; vNormal = GetWorldNormal(modelMatrix); vEyeVec = vec4(cCameraPos - worldPos, GetDepth(gl_Position)); } void PS() { vec2 refractUV = vScreenPos.xy / vScreenPos.w; vec2 reflectUV = vReflectUV.xy / vScreenPos.w; vec2 noise = (texture2D(sNormalMap, vWaterUV).rg - 0.5) * cNoiseStrength; refractUV += noise; // Do not shift reflect UV coordinate upward, because it will reveal the clipping of geometry below water if (noise.y < 0.0) noise.y = 0.0; reflectUV += noise; float fresnel = pow(1.0 - clamp(dot(normalize(vEyeVec.xyz), vNormal), 0.0, 1.0), cFresnelPower); vec3 refractColor = texture2D(sEnvMap, refractUV).rgb * cWaterTint; vec3 reflectColor = texture2D(sDiffMap, reflectUV).rgb; vec3 finalColor = mix(refractColor, reflectColor, fresnel); gl_FragColor = vec4(GetFog(finalColor, GetFogFactor(vEyeVec.w)), 1.0); }