Browse Source

Water Filter : underwater shader

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7599 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
rem..om 14 years ago
parent
commit
95e709f820

BIN
engine/src/core-data/Common/MatDefs/Water/Textures/caustics.jpg


+ 110 - 7
engine/src/core-data/Common/MatDefs/Water/Water.frag

@@ -8,6 +8,7 @@ uniform sampler2D m_Texture;
 uniform sampler2D m_DepthTexture;
 uniform sampler2D m_DepthTexture;
 uniform sampler2D m_NormalMap;
 uniform sampler2D m_NormalMap;
 uniform sampler2D m_FoamMap;
 uniform sampler2D m_FoamMap;
+uniform sampler2D m_CausticsMap;
 uniform sampler2D m_ReflectionMap;
 uniform sampler2D m_ReflectionMap;
 
 
 uniform mat4 m_ViewProjectionMatrixInverse;
 uniform mat4 m_ViewProjectionMatrixInverse;
@@ -114,6 +115,112 @@ float fresnelTerm(in vec3 normal,in vec3 eyeVec){
     return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
     return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
 }
 }
 
 
+vec2 m_FrustumNearFar=vec2(1.0,50);
+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 = texture(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 = textureOffset(m_HeightMap, texC, ivec2(-1,  0)).r;
+    float normal2 = textureOffset(m_HeightMap, texC, ivec2( 1,  0)).r;
+    float normal3 = textureOffset(m_HeightMap, texC, ivec2( 0, -1)).r;
+    float normal4 = textureOffset(m_HeightMap, texC, ivec2( 0,  1)).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 * 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 *= m_WaterColor.rgb;
+            color=mix(color2, caustics,0.6);
+        #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(){
 void main(){
     float sceneDepth = texture2D(m_DepthTexture, texCoord).r;
     float sceneDepth = texture2D(m_DepthTexture, texCoord).r;
     float isAtFarPlane = step(0.99998, sceneDepth);
     float isAtFarPlane = step(0.99998, sceneDepth);
@@ -125,10 +232,10 @@ void main(){
 
 
     float level = m_WaterHeight;
     float level = m_WaterHeight;
 
 
-    // If we are underwater let's leave out complex computations
+    // If we are underwater let's go to under water function
     if(level >= m_CameraPosition.y){
     if(level >= m_CameraPosition.y){
-        gl_FragColor = vec4(color2, 1.0);
-        return;
+        gl_FragColor = underWater();
+        return ;
     }
     }
 
 
     //#ifndef ENABLE_RIPPLES
     //#ifndef ENABLE_RIPPLES
@@ -284,10 +391,6 @@ void main(){
     // to calculate the derivatives for all these pixels by using step()!
     // to calculate the derivatives for all these pixels by using step()!
     // That way we won't get pixels around the edges of the terrain,
     // That way we won't get pixels around the edges of the terrain,
     // Where the derivatives are undefined
     // Where the derivatives are undefined
-/*    float coef=1.0;
-    if(position.y<level)coef=0.0;
-    gl_FragColor = vec4(mix(color, color2, coef), 1.0);
-    */
     if(position.y > level){
     if(position.y > level){
             color = color2;
             color = color2;
     }
     }

+ 13 - 2
engine/src/core-data/Common/MatDefs/Water/Water.j3md

@@ -4,6 +4,7 @@ MaterialDef Advanced Water {
         Int NumSamples
         Int NumSamples
         Int NumSamplesDepth
         Int NumSamplesDepth
         Texture2D FoamMap
         Texture2D FoamMap
+        Texture2D CausticsMap
         Texture2D NormalMap
         Texture2D NormalMap
         Texture2D ReflectionMap
         Texture2D ReflectionMap
         Texture2D HeightMap
         Texture2D HeightMap
@@ -39,10 +40,12 @@ MaterialDef Advanced Water {
         Boolean UseHQShoreline
         Boolean UseHQShoreline
         Boolean UseSpecular
         Boolean UseSpecular
         Boolean UseFoam
         Boolean UseFoam
+        Boolean UseCaustics 
         Boolean UseRefraction
         Boolean UseRefraction
+
     }
     }
 
 
-   Technique {
+    Technique {
         VertexShader   GLSL150 : Common/MatDefs/Post/Post15.vert
         VertexShader   GLSL150 : Common/MatDefs/Post/Post15.vert
         FragmentShader GLSL150 : Common/MatDefs/Water/Water15.frag
         FragmentShader GLSL150 : Common/MatDefs/Water/Water15.frag
 
 
@@ -51,8 +54,14 @@ MaterialDef Advanced Water {
         }
         }
 
 
         Defines {
         Defines {
-            RESOLVE_MS : NumSamples
+          RESOLVE_MS : NumSamples
             RESOLVE_DEPTH_MS : NumSamplesDepth
             RESOLVE_DEPTH_MS : NumSamplesDepth
+            ENABLE_RIPPLES : UseRipples
+            ENABLE_HQ_SHORELINE : UseHQShoreline
+            ENABLE_SPECULAR : UseSpecular
+            ENABLE_FOAM : UseFoam
+            ENABLE_CAUSTICS : UseCaustics
+            ENABLE_REFRACTION : UseRefraction
         }
         }
     }
     }
 
 
@@ -68,7 +77,9 @@ MaterialDef Advanced Water {
             ENABLE_HQ_SHORELINE : UseHQShoreline
             ENABLE_HQ_SHORELINE : UseHQShoreline
             ENABLE_SPECULAR : UseSpecular
             ENABLE_SPECULAR : UseSpecular
             ENABLE_FOAM : UseFoam
             ENABLE_FOAM : UseFoam
+            ENABLE_CAUSTICS : UseCaustics
             ENABLE_REFRACTION : UseRefraction
             ENABLE_REFRACTION : UseRefraction
+
         }
         }
     }
     }
 
 

+ 134 - 24
engine/src/core-data/Common/MatDefs/Water/Water15.frag

@@ -12,6 +12,7 @@ uniform DEPTHTEXTURE m_DepthTexture;
 uniform sampler2D m_HeightMap;
 uniform sampler2D m_HeightMap;
 uniform sampler2D m_NormalMap;
 uniform sampler2D m_NormalMap;
 uniform sampler2D m_FoamMap;
 uniform sampler2D m_FoamMap;
+uniform sampler2D m_CausticsMap;
 uniform sampler2D m_ReflectionMap;
 uniform sampler2D m_ReflectionMap;
 
 
 uniform mat4 m_ViewProjectionMatrixInverse;
 uniform mat4 m_ViewProjectionMatrixInverse;
@@ -38,11 +39,6 @@ uniform vec2 m_WindDirection;
 uniform float m_SunScale;
 uniform float m_SunScale;
 uniform float m_WaveScale;
 uniform float m_WaveScale;
 
 
-uniform bool m_UseRipples,
-             m_UseHQShoreline,
-             m_UseSpecular,
-             m_UseFoam,
-             m_UseRefraction;
 
 
 vec2 scale = vec2(m_WaveScale, m_WaveScale);
 vec2 scale = vec2(m_WaveScale, m_WaveScale);
 float refractionScale = m_WaveScale;
 float refractionScale = m_WaveScale;
@@ -115,8 +111,124 @@ float fresnelTerm(in vec3 normal,in vec3 eyeVec){
     return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
     return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
 }
 }
 
 
+vec2 m_FrustumNearFar=vec2(1.0,50);
+const float LOG2 = 1.442695;
+
+vec4 underWater(int sampleNum){
+
+
+    float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
+    vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).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 = texture(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 = textureOffset(m_HeightMap, texC, ivec2(-1,  0)).r;
+    float normal2 = textureOffset(m_HeightMap, texC, ivec2( 1,  0)).r;
+    float normal3 = textureOffset(m_HeightMap, texC, ivec2( 0, -1)).r;
+    float normal4 = textureOffset(m_HeightMap, texC, ivec2( 0,  1)).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);
+        #ifdef RESOLVE_MS
+            ivec2 iTexC = ivec2(texC * textureSize(m_Texture));
+            refraction = texelFetch(m_Texture, iTexC, sampleNum).rgb;
+        #else
+            ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
+            refraction = texelFetch(m_Texture, iTexC, 0).rgb;
+        #endif
+    #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 * 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 *= m_WaterColor.rgb;
+            color=mix(color2, caustics,0.6);
+        #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);   
+}
 // NOTE: This will be called even for single-sampling
 // NOTE: This will be called even for single-sampling
 vec4 main_multiSample(int sampleNum){
 vec4 main_multiSample(int sampleNum){
+    // If we are underwater let's call the underwater function
+    if(m_WaterHeight >= m_CameraPosition.y){
+
+        return underWater(sampleNum);
+    }
 
 
     float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
     float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
     vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb;
     vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb;
@@ -125,22 +237,17 @@ vec4 main_multiSample(int sampleNum){
     vec3 position = getPosition(sceneDepth, texCoord);
     vec3 position = getPosition(sceneDepth, texCoord);
 
 
     float level = m_WaterHeight;
     float level = m_WaterHeight;
-
-    // If we are underwater let's leave out complex computations
-    if(level >= m_CameraPosition.y){
-        return vec4(color2, 1.0);
-    }
-
+    
     float isAtFarPlane = step(0.99998, sceneDepth);
     float isAtFarPlane = step(0.99998, sceneDepth);
     //#ifndef ENABLE_RIPPLES
     //#ifndef ENABLE_RIPPLES
     // This optimization won't work on NVIDIA cards if ripples are enabled
     // This optimization won't work on NVIDIA cards if ripples are enabled
     if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){
     if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){
+
         return vec4(color2, 1.0);
         return vec4(color2, 1.0);
     }
     }
     //#endif
     //#endif
 
 
-    vec3 eyeVec = position - m_CameraPosition;
-    float diff = level - position.y;
+    vec3 eyeVec = position - m_CameraPosition;    
     float cameraDepth = m_CameraPosition.y - position.y;
     float cameraDepth = m_CameraPosition.y - position.y;
 
 
     // Find intersection with water surface
     // Find intersection with water surface
@@ -150,9 +257,9 @@ vec4 main_multiSample(int sampleNum){
 
 
     vec2 texC = vec2(0.0);
     vec2 texC = vec2(0.0);
     int samples = 1;
     int samples = 1;
-    if (m_UseHQShoreline){
+    #ifdef ENABLE_HQ_SHORELINE
         samples = 10;
         samples = 10;
-    }
+    #endif
 
 
     float biasFactor = 1.0 / samples;
     float biasFactor = 1.0 / samples;
     for (int i = 0; i < samples; i++){
     for (int i = 0; i < samples; i++){
@@ -187,7 +294,7 @@ vec4 main_multiSample(int sampleNum){
     vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
     vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
     vec3 normal = vec3(0.0);
     vec3 normal = vec3(0.0);
 
 
-    if (m_UseRipples){
+    #ifdef ENABLE_RIPPLES
         texC = surfacePoint.xz * 0.8 + m_WindDirection * m_Time* 1.6;
         texC = surfacePoint.xz * 0.8 + m_WindDirection * m_Time* 1.6;
         mat3 tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
         mat3 tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
         vec3 normal0a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
         vec3 normal0a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
@@ -213,12 +320,12 @@ vec4 main_multiSample(int sampleNum){
         //    gl_FragColor = vec4(color2 + normal*0.0001, 1.0);
         //    gl_FragColor = vec4(color2 + normal*0.0001, 1.0);
         //    return;
         //    return;
         //}
         //}
-    }else{
+    #else
         normal = myNormal;
         normal = myNormal;
-    }
+    #endif
 
 
     vec3 refraction = color2;
     vec3 refraction = color2;
-    if (m_UseRefraction){
+    #ifdef ENABLE_REFRACTION
        // texC = texCoord.xy+ m_ReflectionDisplace * normal.x;
        // texC = texCoord.xy+ m_ReflectionDisplace * normal.x;
         texC = texCoord.xy;
         texC = texCoord.xy;
         texC += sin(m_Time*1.8  + 3.0 * abs(position.y)) * (refractionScale * min(depth2, 1.0));
         texC += sin(m_Time*1.8  + 3.0 * abs(position.y)) * (refractionScale * min(depth2, 1.0));
@@ -229,7 +336,7 @@ vec4 main_multiSample(int sampleNum){
             ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
             ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
             refraction = texelFetch(m_Texture, iTexC, 0).rgb;
             refraction = texelFetch(m_Texture, iTexC, 0).rgb;
         #endif
         #endif
-    }
+    #endif
 
 
     vec3 waterPosition = surfacePoint.xyz;
     vec3 waterPosition = surfacePoint.xyz;
     waterPosition.y -= (level - m_WaterHeight);
     waterPosition.y -= (level - m_WaterHeight);
@@ -249,8 +356,11 @@ vec4 main_multiSample(int sampleNum){
     refraction = mix(mix(refraction, m_WaterColor.rgb * waterCol, saturate(depthN / visibility)),
     refraction = mix(mix(refraction, m_WaterColor.rgb * waterCol, saturate(depthN / visibility)),
         m_DeepWaterColor.rgb * waterCol, saturate(depth2 / m_ColorExtinction));
         m_DeepWaterColor.rgb * waterCol, saturate(depth2 / m_ColorExtinction));
 
 
+
+
+
     vec3 foam = vec3(0.0);
     vec3 foam = vec3(0.0);
-    if (m_UseFoam){
+    #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;
         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;
         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;
 
 
@@ -267,10 +377,10 @@ vec4 main_multiSample(int sampleNum){
                saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
                saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
         }
         }
         foam *= m_LightColor.rgb;
         foam *= m_LightColor.rgb;
-    }
+    #endif
 
 
     vec3 specular = vec3(0.0);
     vec3 specular = vec3(0.0);
-    if (m_UseSpecular){
+    #ifdef ENABLE_SPECULAR
         vec3 lightDir=normalize(m_LightDir);
         vec3 lightDir=normalize(m_LightDir);
         vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
         vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
         float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
         float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
@@ -278,7 +388,7 @@ vec4 main_multiSample(int sampleNum){
         specular += specular * 25.0 * saturate(m_Shininess - 0.05);
         specular += specular * 25.0 * saturate(m_Shininess - 0.05);
         //foam does not shine
         //foam does not shine
         specular=specular * m_LightColor.rgb - (5.0 * foam);
         specular=specular * m_LightColor.rgb - (5.0 * foam);
-    }
+    #endif
 
 
     color = mix(refraction, reflection, fresnel);
     color = mix(refraction, reflection, fresnel);
     color = mix(refraction, color, saturate(depth * m_ShoreHardness));
     color = mix(refraction, color, saturate(depth * m_ShoreHardness));

+ 6 - 0
engine/src/desktop-fx/com/jme3/post/filters/FogFilter.java

@@ -58,6 +58,12 @@ public class FogFilter extends Filter {
         super("FogFilter");
         super("FogFilter");
     }
     }
 
 
+    /**
+     * Create a fog filter 
+     * @param fogColor the color of the fog (default is white)
+     * @param fogDensity the density of the fog (default is 0.7)
+     * @param fogDistance the distance of the fog (default is 1000)
+     */
     public FogFilter(ColorRGBA fogColor, float fogDensity, float fogDistance) {
     public FogFilter(ColorRGBA fogColor, float fogDensity, float fogDistance) {
         this();
         this();
         this.fogColor = fogColor;
         this.fogColor = fogColor;

+ 3 - 1
engine/src/desktop-fx/com/jme3/post/filters/LightScatteringFilter.java

@@ -59,7 +59,7 @@ public class LightScatteringFilter extends Filter {
     private float lightDensity = 1.4f;
     private float lightDensity = 1.4f;
     private boolean adaptative = true;
     private boolean adaptative = true;
     Vector3f viewLightPos = new Vector3f();
     Vector3f viewLightPos = new Vector3f();
-    private boolean display;
+    private boolean display=true;
     private float innerLightDensity;
     private float innerLightDensity;
 
 
     public LightScatteringFilter() {
     public LightScatteringFilter() {
@@ -101,6 +101,8 @@ public class LightScatteringFilter extends Filter {
 //System.err.println("screenLightPos "+screenLightPos);
 //System.err.println("screenLightPos "+screenLightPos);
         if (adaptative) {
         if (adaptative) {
             innerLightDensity = Math.max(lightDensity - Math.max(screenLightPos.x, screenLightPos.y), 0.0f);
             innerLightDensity = Math.max(lightDensity - Math.max(screenLightPos.x, screenLightPos.y), 0.0f);
+        }else{
+            innerLightDensity=lightDensity;
         }
         }
     }
     }
 
 

+ 78 - 18
engine/src/desktop-fx/com/jme3/water/WaterFilter.java

@@ -67,6 +67,7 @@ public class WaterFilter extends Filter {
     protected ViewPort reflectionView;
     protected ViewPort reflectionView;
     private Texture2D normalTexture;
     private Texture2D normalTexture;
     private Texture2D foamTexture;
     private Texture2D foamTexture;
+    private Texture2D causticsTexture;
     private Texture2D heightTexture;
     private Texture2D heightTexture;
     private Plane plane;
     private Plane plane;
     private Camera reflectionCam;
     private Camera reflectionCam;
@@ -102,11 +103,13 @@ public class WaterFilter extends Filter {
     private boolean useHQShoreline = true;
     private boolean useHQShoreline = true;
     private boolean useSpecular = true;
     private boolean useSpecular = true;
     private boolean useFoam = true;
     private boolean useFoam = true;
+    private boolean useCaustics = true;
     private boolean useRefraction = true;
     private boolean useRefraction = true;
     private float time = 0;
     private float time = 0;
     private float savedTpf = 0;
     private float savedTpf = 0;
     private float reflectionDisplace = 30;
     private float reflectionDisplace = 30;
     private float foamIntensity = 0.5f;
     private float foamIntensity = 0.5f;
+    private boolean underWater;
 
 
     /**
     /**
      * Create a Water Filter
      * Create a Water Filter
@@ -126,11 +129,6 @@ public class WaterFilter extends Filter {
         return true;
         return true;
     }
     }
 
 
-    @Override
-    protected Format getDefaultPassDepthFormat() {
-        return Format.Depth;
-    }
-
     @Override
     @Override
     public void preFrame(float tpf) {
     public void preFrame(float tpf) {
         time = time + (tpf * speed);
         time = time + (tpf * speed);
@@ -181,17 +179,23 @@ public class WaterFilter extends Filter {
             reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
             reflectionCam.setAxes(reflectionCam.getLeft().negateLocal(), reflectionCam.getUp(), reflectionCam.getDirection().negateLocal());
         }
         }
 
 
-        boolean rtb = true;
-        if (!renderManager.isHandleTranslucentBucket()) {
-            renderManager.setHandleTranslucentBucket(true);
-            rtb = false;
-        }
-        renderManager.renderViewPort(reflectionView, savedTpf);
-        if (!rtb) {
-            renderManager.setHandleTranslucentBucket(false);
+        //if we're under water no need to compute reflection
+        if (sceneCam.getLocation().y >= waterHeight) {
+            boolean rtb = true;
+            if (!renderManager.isHandleTranslucentBucket()) {
+                renderManager.setHandleTranslucentBucket(true);
+                rtb = false;
+            }
+            renderManager.renderViewPort(reflectionView, savedTpf);
+            if (!rtb) {
+                renderManager.setHandleTranslucentBucket(false);
+            }
+            renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
+            renderManager.setCamera(sceneCam, false);
+            underWater=false;
+        }else{
+            underWater=true;
         }
         }
-        renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
-        renderManager.setCamera(sceneCam, false);
     }
     }
 
 
     @Override
     @Override
@@ -217,14 +221,19 @@ public class WaterFilter extends Filter {
         if (foamTexture == null) {
         if (foamTexture == null) {
             foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
             foamTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/foam.jpg");
         }
         }
+        if (causticsTexture == null) {
+            causticsTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/caustics.jpg");
+        }
         heightTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/heightmap.jpg");
         heightTexture = (Texture2D) manager.loadTexture("Common/MatDefs/Water/Textures/heightmap.jpg");
 
 
         normalTexture.setWrap(WrapMode.Repeat);
         normalTexture.setWrap(WrapMode.Repeat);
         foamTexture.setWrap(WrapMode.Repeat);
         foamTexture.setWrap(WrapMode.Repeat);
+        causticsTexture.setWrap(WrapMode.Repeat);
         heightTexture.setWrap(WrapMode.Repeat);
         heightTexture.setWrap(WrapMode.Repeat);
 
 
         material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
         material = new Material(manager, "Common/MatDefs/Water/Water.j3md");
         material.setTexture("HeightMap", heightTexture);
         material.setTexture("HeightMap", heightTexture);
+        material.setTexture("CausticsMap", causticsTexture);
         material.setTexture("FoamMap", foamTexture);
         material.setTexture("FoamMap", foamTexture);
         material.setTexture("NormalMap", normalTexture);
         material.setTexture("NormalMap", normalTexture);
         material.setTexture("ReflectionMap", reflectionPass.getRenderedTexture());
         material.setTexture("ReflectionMap", reflectionPass.getRenderedTexture());
@@ -250,6 +259,7 @@ public class WaterFilter extends Filter {
         material.setBoolean("UseHQShoreline", useHQShoreline);
         material.setBoolean("UseHQShoreline", useHQShoreline);
         material.setBoolean("UseSpecular", useSpecular);
         material.setBoolean("UseSpecular", useSpecular);
         material.setBoolean("UseFoam", useFoam);
         material.setBoolean("UseFoam", useFoam);
+        material.setBoolean("UseCaustics", useCaustics);
         material.setBoolean("UseRefraction", useRefraction);
         material.setBoolean("UseRefraction", useRefraction);
         material.setFloat("ReflectionDisplace", reflectionDisplace);
         material.setFloat("ReflectionDisplace", reflectionDisplace);
         material.setFloat("FoamIntensity", foamIntensity);
         material.setFloat("FoamIntensity", foamIntensity);
@@ -293,6 +303,10 @@ public class WaterFilter extends Filter {
         this.waterHeight = waterHeight;
         this.waterHeight = waterHeight;
     }
     }
 
 
+    /**
+     * sets the scene to render in the reflection map
+     * @param reflectionScene 
+     */
     public void setReflectionScene(Spatial reflectionScene) {
     public void setReflectionScene(Spatial reflectionScene) {
         this.reflectionScene = reflectionScene;
         this.reflectionScene = reflectionScene;
     }
     }
@@ -340,6 +354,10 @@ public class WaterFilter extends Filter {
         }
         }
     }
     }
 
 
+    /**
+     * returns the refractoin constant
+     * @return 
+     */
     public float getRefractionConstant() {
     public float getRefractionConstant() {
         return refractionConstant;
         return refractionConstant;
     }
     }
@@ -360,6 +378,10 @@ public class WaterFilter extends Filter {
         }
         }
     }
     }
 
 
+    /**
+     * return the maximum wave amplitude
+     * @return 
+     */
     public float getMaxAmplitude() {
     public float getMaxAmplitude() {
         return maxAmplitude;
         return maxAmplitude;
     }
     }
@@ -437,7 +459,7 @@ public class WaterFilter extends Filter {
     }
     }
 
 
     /**
     /**
-     * retunrs the foam hardness
+     * returns the foam hardness
      * @return
      * @return
      */
      */
     public float getFoamHardness() {
     public float getFoamHardness() {
@@ -739,7 +761,37 @@ public class WaterFilter extends Filter {
     }
     }
 
 
     /**
     /**
-     * 
+     * sets the texture to use to render caustics on the ground underwater
+     * @param causticsTexture 
+     */
+    public void setCausticsTexture(Texture2D causticsTexture) {
+        this.causticsTexture = causticsTexture;
+        if (material != null) {
+            material.setTexture("causticsMap", causticsTexture);
+        }
+    }
+
+    /**
+     * returns true if caustics are rendered
+     * @return 
+     */
+    public boolean isUseCaustics() {
+        return useCaustics;
+    }
+
+    /**
+     * set to true if you want caustics to be rendered on the ground underwater, false otherwise
+     * @param useCaustics 
+     */
+    public void setUseCaustics(boolean useCaustics) {
+        this.useCaustics = useCaustics;
+        if (material != null) {
+            material.setBoolean("UseCaustics", useCaustics);
+        }
+    }
+
+    /**
+     * return true 
      * @return
      * @return
      */
      */
     public boolean isUseHQShoreline() {
     public boolean isUseHQShoreline() {
@@ -810,7 +862,15 @@ public class WaterFilter extends Filter {
         if (material != null) {
         if (material != null) {
             material.setFloat("m_ReflectionDisplace", reflectionDisplace);
             material.setFloat("m_ReflectionDisplace", reflectionDisplace);
         }
         }
+    }
 
 
-
+    /**
+     * returns true if the camera is under the water level
+     * @return 
+     */
+    public boolean isUnderWater() {
+        return underWater;
     }
     }
+    
+    
 }
 }

+ 56 - 13
engine/src/test/jme3test/water/TestPostWater.java

@@ -2,6 +2,8 @@ package jme3test.water;
 
 
 import com.jme3.app.SimpleApplication;
 import com.jme3.app.SimpleApplication;
 import com.jme3.audio.AudioNode;
 import com.jme3.audio.AudioNode;
+import com.jme3.audio.Filter;
+import com.jme3.audio.LowPassFilter;
 import com.jme3.bounding.BoundingBox;
 import com.jme3.bounding.BoundingBox;
 import com.jme3.effect.ParticleEmitter;
 import com.jme3.effect.ParticleEmitter;
 import com.jme3.effect.ParticleMesh;
 import com.jme3.effect.ParticleMesh;
@@ -16,7 +18,9 @@ import com.jme3.math.Quaternion;
 import com.jme3.math.Vector3f;
 import com.jme3.math.Vector3f;
 
 
 import com.jme3.post.FilterPostProcessor;
 import com.jme3.post.FilterPostProcessor;
+import com.jme3.post.filters.BloomFilter;
 import com.jme3.post.filters.DepthOfFieldFilter;
 import com.jme3.post.filters.DepthOfFieldFilter;
+import com.jme3.post.filters.FogFilter;
 import com.jme3.post.filters.LightScatteringFilter;
 import com.jme3.post.filters.LightScatteringFilter;
 import com.jme3.post.filters.TranslucentBucketFilter;
 import com.jme3.post.filters.TranslucentBucketFilter;
 import com.jme3.renderer.Camera;
 import com.jme3.renderer.Camera;
@@ -34,6 +38,7 @@ import com.jme3.texture.Texture.WrapMode;
 import com.jme3.texture.Texture2D;
 import com.jme3.texture.Texture2D;
 import com.jme3.util.SkyFactory;
 import com.jme3.util.SkyFactory;
 import com.jme3.water.WaterFilter;
 import com.jme3.water.WaterFilter;
+import java.awt.image.BufferedImage;
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 import jme3tools.converters.ImageToAwt;
 import jme3tools.converters.ImageToAwt;
@@ -48,6 +53,10 @@ public class TestPostWater extends SimpleApplication {
     private WaterFilter water;
     private WaterFilter water;
     TerrainQuad terrain;
     TerrainQuad terrain;
     Material matRock;
     Material matRock;
+    AudioNode waves;
+    LowPassFilter underWaterAudioFilter = new LowPassFilter(0.5f, 0.1f);
+    LowPassFilter underWaterReverbFilter = new LowPassFilter(0.5f, 0.1f);
+    LowPassFilter aboveWaterAudioFilter = new LowPassFilter(1, 1);
 
 
     public static void main(String[] args) {
     public static void main(String[] args) {
         TestPostWater app = new TestPostWater();
         TestPostWater app = new TestPostWater();
@@ -57,6 +66,8 @@ public class TestPostWater extends SimpleApplication {
     @Override
     @Override
     public void simpleInitApp() {
     public void simpleInitApp() {
 
 
+      setDisplayFps(false);
+      setDisplayStatView(false);
 
 
         Node mainScene = new Node("Main Scene");
         Node mainScene = new Node("Main Scene");
         rootNode.attachChild(mainScene);
         rootNode.attachChild(mainScene);
@@ -72,9 +83,14 @@ public class TestPostWater extends SimpleApplication {
         l.setColor(ColorRGBA.White.clone().multLocal(0.3f));
         l.setColor(ColorRGBA.White.clone().multLocal(0.3f));
         mainScene.addLight(l);
         mainScene.addLight(l);
 
 
-        flyCam.setMoveSpeed(100);
+        flyCam.setMoveSpeed(50);
 
 
-        cam.setLocation(new Vector3f(-700, 100, 300));
+        //cam.setLocation(new Vector3f(-700, 100, 300));
+         //cam.setRotation(new Quaternion().fromAngleAxis(0.5f, Vector3f.UNIT_Z));
+        cam.setLocation(new Vector3f(-327.21957f, 61.6459f, 126.884346f));
+        cam.setRotation(new Quaternion(0.052168474f, 0.9443102f, -0.18395276f, 0.2678024f));
+
+          
         cam.setRotation(new Quaternion().fromAngles(new float[]{FastMath.PI * 0.06f, FastMath.PI * 0.65f, 0}));
         cam.setRotation(new Quaternion().fromAngles(new float[]{FastMath.PI * 0.06f, FastMath.PI * 0.65f, 0}));
 
 
 
 
@@ -83,9 +99,8 @@ public class TestPostWater extends SimpleApplication {
         mainScene.attachChild(sky);
         mainScene.attachChild(sky);
         cam.setFrustumFar(4000);
         cam.setFrustumFar(4000);
         //cam.setFrustumNear(100);
         //cam.setFrustumNear(100);
-        AudioNode waves = new AudioNode(audioRenderer, assetManager, "Sound/Environment/Ocean Waves.ogg", false);
-        waves.setLooping(true);
-        audioRenderer.playSource(waves);
+       
+        
 
 
         //private FilterPostProcessor fpp;
         //private FilterPostProcessor fpp;
 
 
@@ -94,15 +109,22 @@ public class TestPostWater extends SimpleApplication {
 
 
         FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
         FilterPostProcessor fpp = new FilterPostProcessor(assetManager);
         fpp.addFilter(water);
         fpp.addFilter(water);
-        
+        BloomFilter bloom=new BloomFilter();
+        bloom.setExposurePower(55);
+        fpp.addFilter(bloom);
+        LightScatteringFilter lsf = new LightScatteringFilter(lightDir.mult(-300));
+        lsf.setLightDensity(1.0f);
+        fpp.addFilter(lsf);
         DepthOfFieldFilter dof=new DepthOfFieldFilter();
         DepthOfFieldFilter dof=new DepthOfFieldFilter();
         dof.setFocusDistance(0);
         dof.setFocusDistance(0);
-        dof.setFocusRange(100);        
-        fpp.addFilter(new TranslucentBucketFilter());
+        dof.setFocusRange(100);     
         fpp.addFilter(dof);
         fpp.addFilter(dof);
+//        
         
         
+    //    fpp.addFilter(new TranslucentBucketFilter());
+ //       
         
         
-        //     fpp.setNumSamples(4);
+         // fpp.setNumSamples(4);
 
 
 
 
         water.setWaveScale(0.003f);
         water.setWaveScale(0.003f);
@@ -116,8 +138,17 @@ public class TestPostWater extends SimpleApplication {
         //water.setFoamHardness(0.6f);
         //water.setFoamHardness(0.6f);
 
 
         water.setWaterHeight(initialWaterHeight);
         water.setWaterHeight(initialWaterHeight);
-       
+      uw=cam.getLocation().y<waterHeight; 
       
       
+        waves = new AudioNode(audioRenderer, assetManager, "Sound/Environment/Ocean Waves.ogg", false);
+        waves.setLooping(true);
+        waves.setReverbEnabled(true);
+        if(uw){
+            waves.setDryFilter(new LowPassFilter(0.5f, 0.1f));
+        }else{
+            waves.setDryFilter(aboveWaterAudioFilter);            
+        }
+        audioRenderer.playSource(waves);
         //  
         //  
         viewPort.addProcessor(fpp);
         viewPort.addProcessor(fpp);
 
 
@@ -140,8 +171,8 @@ public class TestPostWater extends SimpleApplication {
         inputManager.addMapping("foam1", new KeyTrigger(keyInput.KEY_1));
         inputManager.addMapping("foam1", new KeyTrigger(keyInput.KEY_1));
         inputManager.addMapping("foam2", new KeyTrigger(keyInput.KEY_2));
         inputManager.addMapping("foam2", new KeyTrigger(keyInput.KEY_2));
         inputManager.addMapping("foam3", new KeyTrigger(keyInput.KEY_3));
         inputManager.addMapping("foam3", new KeyTrigger(keyInput.KEY_3));
-        createBox();
-        createFire();
+//        createBox();
+//        createFire();
     }
     }
     Geometry box;
     Geometry box;
 
 
@@ -248,7 +279,7 @@ public class TestPostWater extends SimpleApplication {
     private float time = 0.0f;
     private float time = 0.0f;
     private float waterHeight = 0.0f;
     private float waterHeight = 0.0f;
     private float initialWaterHeight = 0.8f;
     private float initialWaterHeight = 0.8f;
-
+private boolean uw=false;
     @Override
     @Override
     public void simpleUpdate(float tpf) {
     public void simpleUpdate(float tpf) {
         super.simpleUpdate(tpf);
         super.simpleUpdate(tpf);
@@ -256,5 +287,17 @@ public class TestPostWater extends SimpleApplication {
         time += tpf;
         time += tpf;
         waterHeight = (float) Math.cos(((time * 0.6f) % FastMath.TWO_PI)) * 1.5f;
         waterHeight = (float) Math.cos(((time * 0.6f) % FastMath.TWO_PI)) * 1.5f;
         water.setWaterHeight(initialWaterHeight + waterHeight);
         water.setWaterHeight(initialWaterHeight + waterHeight);
+        if(water.isUnderWater() && !uw){
+           
+            waves.setDryFilter(new LowPassFilter(0.5f, 0.1f));
+            uw=true;
+        }
+        if(!water.isUnderWater() && uw){
+            uw=false;
+             //waves.setReverbEnabled(false);
+             waves.setDryFilter(new LowPassFilter(1, 1f));
+             //waves.setDryFilter(new LowPassFilter(1,1f));
+             
+        }
     }
     }
 }
 }