aboutsummaryrefslogtreecommitdiff
path: root/engine/src/core-effects/Common/MatDefs/Water/Water.frag
diff options
context:
space:
mode:
Diffstat (limited to 'engine/src/core-effects/Common/MatDefs/Water/Water.frag')
-rw-r--r--engine/src/core-effects/Common/MatDefs/Water/Water.frag402
1 files changed, 402 insertions, 0 deletions
diff --git a/engine/src/core-effects/Common/MatDefs/Water/Water.frag b/engine/src/core-effects/Common/MatDefs/Water/Water.frag
new file mode 100644
index 0000000..928ee22
--- /dev/null
+++ b/engine/src/core-effects/Common/MatDefs/Water/Water.frag
@@ -0,0 +1,402 @@
+// Water pixel shader
+// Copyright (C) JMonkeyEngine 3.0
+// by Remy Bouquet (nehon) for JMonkeyEngine 3.0
+// original HLSL version by Wojciech Toman 2009
+
+uniform sampler2D m_HeightMap;
+uniform sampler2D m_Texture;
+uniform sampler2D m_DepthTexture;
+uniform sampler2D m_NormalMap;
+uniform sampler2D m_FoamMap;
+uniform sampler2D m_CausticsMap;
+uniform sampler2D m_ReflectionMap;
+
+uniform mat4 m_ViewProjectionMatrixInverse;
+uniform mat4 m_TextureProjMatrix;
+uniform vec3 m_CameraPosition;
+
+uniform float m_WaterHeight;
+uniform float m_Time;
+uniform float m_WaterTransparency;
+uniform float m_NormalScale;
+uniform float m_R0;
+uniform float m_MaxAmplitude;
+uniform vec3 m_LightDir;
+uniform vec4 m_LightColor;
+uniform float m_ShoreHardness;
+uniform float m_FoamHardness;
+uniform float m_RefractionStrength;
+uniform vec3 m_FoamExistence;
+uniform vec3 m_ColorExtinction;
+uniform float m_Shininess;
+uniform vec4 m_WaterColor;
+uniform vec4 m_DeepWaterColor;
+uniform vec2 m_WindDirection;
+uniform float m_SunScale;
+uniform float m_WaveScale;
+uniform float m_UnderWaterFogDistance;
+uniform float m_CausticsIntensity;
+
+vec2 scale = vec2(m_WaveScale, m_WaveScale);
+float refractionScale = m_WaveScale;
+
+// Modifies 4 sampled normals. Increase first values to have more
+// smaller "waves" or last to have more bigger "waves"
+const vec4 normalModifier = vec4(3.0, 2.0, 4.0, 10.0);
+// Strength of displacement along normal.
+// Strength of displacement along normal.
+uniform float m_ReflectionDisplace;
+// Water transparency along eye vector.
+const float visibility = 3.0;
+// foam intensity
+uniform float m_FoamIntensity ;
+
+varying vec2 texCoord;
+
+mat3 MatrixInverse(in mat3 inMatrix){
+ float det = dot(cross(inMatrix[0], inMatrix[1]), inMatrix[2]);
+ mat3 T = transpose(inMatrix);
+ return mat3(cross(T[1], T[2]),
+ cross(T[2], T[0]),
+ cross(T[0], T[1])) / det;
+}
+
+
+mat3 computeTangentFrame(in vec3 N, in vec3 P, in vec2 UV) {
+ vec3 dp1 = dFdx(P);
+ vec3 dp2 = dFdy(P);
+ vec2 duv1 = dFdx(UV);
+ vec2 duv2 = dFdy(UV);
+
+ // solve the linear system
+ mat3 M = mat3(dp1, dp2, cross(dp1, dp2));
+ //vec3 dp1xdp2 = cross(dp1, dp2);
+ mat3 inverseM = MatrixInverse(M);
+ //mat2x3 inverseM = mat2x3(cross(dp2, dp1xdp2), cross(dp1xdp2, dp1));
+
+ vec3 T = inverseM * vec3(duv1.x, duv2.x, 0.0);
+ vec3 B = inverseM * vec3(duv1.y, duv2.y, 0.0);
+
+ //vec3 T = inverseM * vec2(duv1.x, duv2.x);
+ //vec3 B = inverseM * vec2(duv1.y, duv2.y);
+
+ // construct tangent frame
+ float maxLength = max(length(T), length(B));
+ T = T / maxLength;
+ B = B / maxLength;
+
+ //vec3 tangent = normalize(T);
+ //vec3 binormal = normalize(B);
+
+ return mat3(T, B, N);
+}
+
+float saturate(in float val){
+ return clamp(val,0.0,1.0);
+}
+
+vec3 saturate(in vec3 val){
+ return clamp(val,vec3(0.0),vec3(1.0));
+}
+
+
+vec3 getPosition(in float depth, in vec2 uv){
+ vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
+ pos = m_ViewProjectionMatrixInverse * pos;
+ return pos.xyz / pos.w;
+}
+
+// Function calculating fresnel term.
+// - normal - normalized normal vector
+// - eyeVec - normalized eye vector
+float fresnelTerm(in vec3 normal,in vec3 eyeVec){
+ float angle = 1.0 - saturate(dot(normal, eyeVec));
+ float fresnel = angle * angle;
+ fresnel = fresnel * fresnel;
+ fresnel = fresnel * angle;
+ return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
+}
+
+vec2 m_FrustumNearFar=vec2(1.0,m_UnderWaterFogDistance);
+const float LOG2 = 1.442695;
+
+vec4 underWater(){
+
+
+ float sceneDepth = texture2D(m_DepthTexture, texCoord).r;
+ vec3 color2 = texture2D(m_Texture, texCoord).rgb;
+
+ vec3 position = getPosition(sceneDepth, texCoord);
+ float level = m_WaterHeight;
+
+ vec3 eyeVec = position - m_CameraPosition;
+
+ // Find intersection with water surface
+ vec3 eyeVecNorm = normalize(eyeVec);
+ float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+ vec2 texC = vec2(0.0);
+
+ float cameraDepth = length(m_CameraPosition - surfacePoint);
+ texC = (surfacePoint.xz + eyeVecNorm.xz) * scale + m_Time * 0.03 * m_WindDirection;
+ float bias = texture2D(m_HeightMap, texC).r;
+ level += bias * m_MaxAmplitude;
+ t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ surfacePoint = m_CameraPosition + eyeVecNorm * t;
+ eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+ // Find normal of water surface
+ float normal1 = texture2D(m_HeightMap, (texC + vec2(-1.0, 0.0) / 256.0)).r;
+ float normal2 = texture2D(m_HeightMap, (texC + vec2(1.0, 0.0) / 256.0)).r;
+ float normal3 = texture2D(m_HeightMap, (texC + vec2(0.0, -1.0) / 256.0)).r;
+ float normal4 = texture2D(m_HeightMap, (texC + vec2(0.0, 1.0) / 256.0)).r;
+
+ vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+ vec3 normal = myNormal*-1.0;
+ float fresnel = fresnelTerm(normal, eyeVecNorm);
+
+ vec3 refraction = color2;
+ #ifdef ENABLE_REFRACTION
+ texC = texCoord.xy *sin (fresnel+1.0);
+ refraction = texture2D(m_Texture, texC).rgb;
+ #endif
+
+ float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+ refraction = mix(mix(refraction, m_DeepWaterColor.rgb * waterCol, m_WaterTransparency), m_WaterColor.rgb* waterCol,m_WaterTransparency);
+
+ vec3 foam = vec3(0.0);
+ #ifdef ENABLE_FOAM
+ texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+ vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+ if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
+ foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity * m_FoamIntensity * 0.3 *
+ saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+ }
+ foam *= m_LightColor.rgb;
+ #endif
+
+
+
+ vec3 specular = vec3(0.0);
+ vec3 color ;
+ float fogFactor;
+
+ if(position.y>level){
+ #ifdef ENABLE_SPECULAR
+ if(step(0.9999,sceneDepth)==1.0){
+ vec3 lightDir=normalize(m_LightDir);
+ vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+ float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+ specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+ specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+ specular=specular * m_LightColor.rgb * 100.0;
+ }
+ #endif
+ float fogIntensity= 8.0 * m_WaterTransparency;
+ fogFactor = exp2( -fogIntensity * fogIntensity * cameraDepth * 0.03 * LOG2 );
+ fogFactor = clamp(fogFactor, 0.0, 1.0);
+ color =mix(m_DeepWaterColor.rgb,refraction,fogFactor);
+ specular=specular*fogFactor;
+ color = saturate(color + max(specular, foam ));
+ }else{
+ vec3 caustics = vec3(0.0);
+ #ifdef ENABLE_CAUSTICS
+ vec2 windDirection=m_WindDirection;
+ texC = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time + position.x) * 0.01;
+ vec2 texCoord2 = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time + position.z) * 0.01;
+ caustics += (texture2D(m_CausticsMap, texC)+ texture2D(m_CausticsMap, texCoord2)).rgb;
+ caustics=saturate(mix(m_WaterColor.rgb,caustics,m_CausticsIntensity));
+ color=mix(color2,caustics,m_CausticsIntensity);
+ #else
+ color=color2;
+ #endif
+
+ float fogDepth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - sceneDepth* (m_FrustumNearFar.y-m_FrustumNearFar.x));
+ float fogIntensity= 18 * m_WaterTransparency;
+ fogFactor = exp2( -fogIntensity * fogIntensity * fogDepth * fogDepth * LOG2 );
+ fogFactor = clamp(fogFactor, 0.0, 1.0);
+ color =mix(m_DeepWaterColor.rgb,color,fogFactor);
+ }
+
+ return vec4(color, 1.0);
+}
+
+void main(){
+ float sceneDepth = texture2D(m_DepthTexture, texCoord).r;
+ float isAtFarPlane = step(0.99998, sceneDepth);
+
+ vec3 color2 = texture2D(m_Texture, texCoord).rgb;
+ vec3 color = color2;
+
+ vec3 position = getPosition(sceneDepth,texCoord);
+
+ float level = m_WaterHeight;
+
+ // If we are underwater let's go to under water function
+ if(level >= m_CameraPosition.y){
+ gl_FragColor = underWater();
+ return ;
+ }
+
+ //#ifndef ENABLE_RIPPLES
+ // This optimization won't work on NVIDIA cards if ripples are enabled
+ if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){
+ gl_FragColor = vec4(color2, 1.0);
+ return;
+ }
+ //#endif
+
+ vec3 eyeVec = position - m_CameraPosition;
+ float diff = level - position.y;
+ float cameraDepth = m_CameraPosition.y - position.y;
+
+ // Find intersection with water surface
+ vec3 eyeVecNorm = normalize(eyeVec);
+ float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
+
+ vec2 texC;
+ int samples = 1;
+ #ifdef ENABLE_HQ_SHORELINE
+ samples = 10;
+ #endif
+ float biasFactor = 1.0/samples;
+ for (int i = 0; i < samples; i++){
+ texC = (surfacePoint.xz + eyeVecNorm.xz * biasFactor) * scale + m_Time * 0.03 * m_WindDirection;
+
+ float bias = texture2D(m_HeightMap, texC).r;
+
+ bias *= biasFactor;
+ level += bias * m_MaxAmplitude;
+ t = (level - m_CameraPosition.y) / eyeVecNorm.y;
+ surfacePoint = m_CameraPosition + eyeVecNorm * t;
+ }
+
+ float depth = length(position - surfacePoint);
+ float depth2 = surfacePoint.y - position.y;
+
+ // XXX: HACK ALERT: Increase water depth to infinity if at far plane
+ // Prevents "foam on horizon" issue
+ // For best results, replace the "100.0" below with the
+ // highest value in the m_ColorExtinction vec3
+ depth += isAtFarPlane * 100.0;
+ depth2 += isAtFarPlane * 100.0;
+
+ eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
+
+ // Find normal of water surface
+ float normal1 = texture2D(m_HeightMap, (texC + vec2(-1.0, 0.0) / 256.0)).r;
+ float normal2 = texture2D(m_HeightMap, (texC + vec2(1.0, 0.0) / 256.0)).r;
+ float normal3 = texture2D(m_HeightMap, (texC + vec2(0.0, -1.0) / 256.0)).r;
+ float normal4 = texture2D(m_HeightMap, (texC + vec2(0.0, 1.0) / 256.0)).r;
+
+ vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
+ vec3 normal = vec3(0.0);
+
+ #ifdef ENABLE_RIPPLES
+ texC = surfacePoint.xz * 0.8 + m_WindDirection * m_Time* 1.6;
+ mat3 tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal0a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.4 + m_WindDirection * m_Time* 0.8;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal1a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.2 + m_WindDirection * m_Time * 0.4;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal2a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+ texC = surfacePoint.xz * 0.1 + m_WindDirection * m_Time * 0.2;
+ tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
+ vec3 normal3a = normalize(tangentFrame*(2.0 * texture2D(m_NormalMap, texC).xyz - 1.0));
+
+ normal = normalize(normal0a * normalModifier.x + normal1a * normalModifier.y +normal2a * normalModifier.z + normal3a * normalModifier.w);
+ // XXX: Here's another way to fix the terrain edge issue,
+ // But it requires GLSL 1.3 and still looks kinda incorrect
+ // around edges
+ // To make the shader 1.2 compatible we use a trick :
+ // we clamp the x value of the normal and compare it to it's former value instead of using isnan.
+ normal = clamp(normal.x,0.0,1.0)!=normal.x ? myNormal : normal;
+ //if (position.y > level){
+ // gl_FragColor = vec4(color2 + normal*0.0001, 1.0);
+ // return;
+ //}
+ #else
+ normal = myNormal;
+ #endif
+
+ vec3 refraction = color2;
+ #ifdef ENABLE_REFRACTION
+ texC = texCoord.xy;
+ texC += sin(m_Time*1.8 + 3.0 * abs(position.y)) * (refractionScale * min(depth2, 1.0));
+ refraction = texture2D(m_Texture, texC).rgb;
+ #endif
+
+ vec3 waterPosition = surfacePoint.xyz;
+ waterPosition.y -= (level - m_WaterHeight);
+ vec4 texCoordProj = m_TextureProjMatrix * vec4(waterPosition, 1.0);
+
+ texCoordProj.x = texCoordProj.x + m_ReflectionDisplace * normal.x;
+ texCoordProj.z = texCoordProj.z + m_ReflectionDisplace * normal.z;
+ texCoordProj /= texCoordProj.w;
+ texCoordProj.y = 1.0 - texCoordProj.y;
+
+ vec3 reflection = texture2D(m_ReflectionMap, texCoordProj.xy).rgb;
+
+ float fresnel = fresnelTerm(normal, eyeVecNorm);
+
+ float depthN = depth * m_WaterTransparency;
+ float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
+ refraction = mix(mix(refraction, m_WaterColor.rgb * waterCol, saturate(depthN / visibility)),
+ m_DeepWaterColor.rgb * waterCol, saturate(depth2 / m_ColorExtinction));
+
+ vec3 foam = vec3(0.0);
+ #ifdef ENABLE_FOAM
+ texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
+ vec2 texCoord2 = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.1 * m_WindDirection + sin(m_Time * 0.001 + position.z) * 0.005;
+
+ if(depth2 < m_FoamExistence.x){
+ foam = (texture2D(m_FoamMap, texC).r + texture2D(m_FoamMap, texCoord2)).rgb * m_FoamIntensity;
+ }else if(depth2 < m_FoamExistence.y){
+ foam = mix((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity, vec4(0.0),
+ (depth2 - m_FoamExistence.x) / (m_FoamExistence.y - m_FoamExistence.x)).rgb;
+ }
+
+ if(m_MaxAmplitude - m_FoamExistence.z > 0.0001){
+ foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity * m_FoamIntensity * 0.3 *
+ saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
+ }
+ foam *= m_LightColor.rgb;
+ #endif
+
+ vec3 specular =vec3(0.0);
+ #ifdef ENABLE_SPECULAR
+ vec3 lightDir=normalize(m_LightDir);
+ vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
+ float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
+ specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
+ specular += specular * 25.0 * saturate(m_Shininess - 0.05);
+ //foam does not shine
+ specular=specular * m_LightColor.rgb - (5.0 * foam);
+ #endif
+
+ color = mix(refraction, reflection, fresnel);
+ color = mix(refraction, color, saturate(depth * m_ShoreHardness));
+ color = saturate(color + max(specular, foam ));
+ color = mix(refraction, color, saturate(depth* m_FoamHardness));
+
+
+ // XXX: HACK ALERT:
+ // We trick the GeForces to think they have
+ // to calculate the derivatives for all these pixels by using step()!
+ // That way we won't get pixels around the edges of the terrain,
+ // Where the derivatives are undefined
+ if(position.y > level){
+ color = color2;
+ }
+
+ gl_FragColor = vec4(color,1.0);
+
+} \ No newline at end of file