Water Filter : underwater shader

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@7599 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
rem..om 14 years ago
parent fae5029629
commit 95e709f820
  1. BIN
      engine/src/core-data/Common/MatDefs/Water/Textures/caustics.jpg
  2. 115
      engine/src/core-data/Common/MatDefs/Water/Water.frag
  3. 11
      engine/src/core-data/Common/MatDefs/Water/Water.j3md
  4. 154
      engine/src/core-data/Common/MatDefs/Water/Water15.frag
  5. 6
      engine/src/desktop-fx/com/jme3/post/filters/FogFilter.java
  6. 4
      engine/src/desktop-fx/com/jme3/post/filters/LightScatteringFilter.java
  7. 76
      engine/src/desktop-fx/com/jme3/water/WaterFilter.java
  8. 65
      engine/src/test/jme3test/water/TestPostWater.java

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@ -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,9 +232,9 @@ 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); gl_FragColor = underWater();
return ; return ;
} }
@ -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;
} }

@ -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,7 +40,9 @@ MaterialDef Advanced Water {
Boolean UseHQShoreline Boolean UseHQShoreline
Boolean UseSpecular Boolean UseSpecular
Boolean UseFoam Boolean UseFoam
Boolean UseCaustics
Boolean UseRefraction Boolean UseRefraction
} }
Technique { Technique {
@ -53,6 +56,12 @@ 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
} }
} }

@ -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;
@ -126,21 +238,16 @@ vec4 main_multiSample(int sampleNum){
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; vec3 eyeVec = position - m_CameraPosition;
float diff = level - position.y;
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));

@ -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;

@ -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;
} }
} }

@ -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,6 +179,8 @@ 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());
} }
//if we're under water no need to compute reflection
if (sceneCam.getLocation().y >= waterHeight) {
boolean rtb = true; boolean rtb = true;
if (!renderManager.isHandleTranslucentBucket()) { if (!renderManager.isHandleTranslucentBucket()) {
renderManager.setHandleTranslucentBucket(true); renderManager.setHandleTranslucentBucket(true);
@ -192,6 +192,10 @@ public class WaterFilter extends Filter {
} }
renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer()); renderManager.getRenderer().setFrameBuffer(viewPort.getOutputFrameBuffer());
renderManager.setCamera(sceneCam, false); renderManager.setCamera(sceneCam, false);
underWater=false;
}else{
underWater=true;
}
} }
@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;
} }
} }

@ -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.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.setLocation(new Vector3f(-700, 100, 300));
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,13 +109,20 @@ 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); dof.setFocusRange(100);
fpp.addFilter(new TranslucentBucketFilter());
fpp.addFilter(dof); fpp.addFilter(dof);
//
// fpp.addFilter(new TranslucentBucketFilter());
//
// fpp.setNumSamples(4); // fpp.setNumSamples(4);
@ -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(); // createBox();
createFire(); // 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));
}
} }
} }

Loading…
Cancel
Save