Home | History | Annotate | Download | only in Water
      1 #import "Common/ShaderLib/MultiSample.glsllib"
      2 
      3 // Water pixel shader
      4 // Copyright (C) JMonkeyEngine 3.0
      5 // by Remy Bouquet (nehon) for JMonkeyEngine 3.0
      6 // original HLSL version by Wojciech Toman 2009
      7 
      8 uniform COLORTEXTURE m_Texture;
      9 uniform DEPTHTEXTURE m_DepthTexture;
     10 
     11 
     12 uniform sampler2D m_HeightMap;
     13 uniform sampler2D m_NormalMap;
     14 uniform sampler2D m_FoamMap;
     15 uniform sampler2D m_CausticsMap;
     16 uniform sampler2D m_ReflectionMap;
     17 
     18 uniform mat4 m_ViewProjectionMatrixInverse;
     19 uniform mat4 m_TextureProjMatrix;
     20 uniform vec3 m_CameraPosition;
     21 
     22 uniform float m_WaterHeight;
     23 uniform float m_Time;
     24 uniform float m_WaterTransparency;
     25 uniform float m_NormalScale;
     26 uniform float m_R0;
     27 uniform float m_MaxAmplitude;
     28 uniform vec3 m_LightDir;
     29 uniform vec4 m_LightColor;
     30 uniform float m_ShoreHardness;
     31 uniform float m_FoamHardness;
     32 uniform float m_RefractionStrength;
     33 uniform vec3 m_FoamExistence;
     34 uniform vec3 m_ColorExtinction;
     35 uniform float m_Shininess;
     36 uniform vec4 m_WaterColor;
     37 uniform vec4 m_DeepWaterColor;
     38 uniform vec2 m_WindDirection;
     39 uniform float m_SunScale;
     40 uniform float m_WaveScale;
     41 uniform float m_UnderWaterFogDistance;
     42 uniform float m_CausticsIntensity;
     43 
     44 
     45 vec2 scale = vec2(m_WaveScale, m_WaveScale);
     46 float refractionScale = m_WaveScale;
     47 
     48 // Modifies 4 sampled normals. Increase first values to have more
     49 // smaller "waves" or last to have more bigger "waves"
     50 const vec4 normalModifier = vec4(3.0, 2.0, 4.0, 10.0);
     51 // Strength of displacement along normal.
     52 uniform float m_ReflectionDisplace;
     53 // Water transparency along eye vector.
     54 const float visibility = 3.0;
     55 // foam intensity
     56 uniform float m_FoamIntensity ;
     57 
     58 in vec2 texCoord;
     59 out vec4 outFragColor;
     60 
     61 mat3 MatrixInverse(in mat3 inMatrix){
     62     float det = dot(cross(inMatrix[0], inMatrix[1]), inMatrix[2]);
     63     mat3 T = transpose(inMatrix);
     64     return mat3(cross(T[1], T[2]),
     65         cross(T[2], T[0]),
     66         cross(T[0], T[1])) / det;
     67 }
     68 
     69 
     70 mat3 computeTangentFrame(in vec3 N, in vec3 P, in vec2 UV) {
     71     vec3 dp1 = dFdx(P);
     72     vec3 dp2 = dFdy(P);
     73     vec2 duv1 = dFdx(UV);
     74     vec2 duv2 = dFdy(UV);
     75 
     76     // solve the linear system
     77     vec3 dp1xdp2 = cross(dp1, dp2);
     78     mat2x3 inverseM = mat2x3(cross(dp2, dp1xdp2), cross(dp1xdp2, dp1));
     79 
     80     vec3 T = inverseM * vec2(duv1.x, duv2.x);
     81     vec3 B = inverseM * vec2(duv1.y, duv2.y);
     82 
     83     // construct tangent frame
     84     float maxLength = max(length(T), length(B));
     85     T = T / maxLength;
     86     B = B / maxLength;
     87 
     88     return mat3(T, B, N);
     89 }
     90 
     91 float saturate(in float val){
     92     return clamp(val,0.0,1.0);
     93 }
     94 
     95 vec3 saturate(in vec3 val){
     96     return clamp(val,vec3(0.0),vec3(1.0));
     97 }
     98 
     99 vec3 getPosition(in float depth, in vec2 uv){
    100     vec4 pos = vec4(uv, depth, 1.0) * 2.0 - 1.0;
    101     pos = m_ViewProjectionMatrixInverse * pos;
    102     return pos.xyz / pos.w;
    103 }
    104 
    105 // Function calculating fresnel term.
    106 // - normal - normalized normal vector
    107 // - eyeVec - normalized eye vector
    108 float fresnelTerm(in vec3 normal,in vec3 eyeVec){
    109     float angle = 1.0 - max(0.0, dot(normal, eyeVec));
    110     float fresnel = angle * angle;
    111     fresnel = fresnel * fresnel;
    112     fresnel = fresnel * angle;
    113     return saturate(fresnel * (1.0 - saturate(m_R0)) + m_R0 - m_RefractionStrength);
    114 }
    115 
    116 vec2 m_FrustumNearFar=vec2(1.0,m_UnderWaterFogDistance);
    117 const float LOG2 = 1.442695;
    118 
    119 vec4 underWater(int sampleNum){
    120 
    121 
    122     float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
    123     vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb;
    124     
    125     vec3 position = getPosition(sceneDepth, texCoord);
    126     float level = m_WaterHeight;
    127 
    128     vec3 eyeVec = position - m_CameraPosition;    
    129  
    130     // Find intersection with water surface
    131     vec3 eyeVecNorm = normalize(eyeVec);
    132     float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
    133     vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
    134 
    135     vec2 texC = vec2(0.0);
    136 
    137     float cameraDepth = length(m_CameraPosition - surfacePoint);  
    138     texC = (surfacePoint.xz + eyeVecNorm.xz) * scale + m_Time * 0.03 * m_WindDirection;
    139     float bias = texture(m_HeightMap, texC).r;
    140     level += bias * m_MaxAmplitude;
    141     t = (level - m_CameraPosition.y) / eyeVecNorm.y;
    142     surfacePoint = m_CameraPosition + eyeVecNorm * t; 
    143     eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
    144 
    145     // Find normal of water surface
    146     float normal1 = textureOffset(m_HeightMap, texC, ivec2(-1.0,  0.0)).r;
    147     float normal2 = textureOffset(m_HeightMap, texC, ivec2( 1.0,  0.0)).r;
    148     float normal3 = textureOffset(m_HeightMap, texC, ivec2( 0.0, -1.0)).r;
    149     float normal4 = textureOffset(m_HeightMap, texC, ivec2( 0.0,  1.0)).r;
    150 
    151     vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
    152     vec3 normal = myNormal*-1.0;
    153     float fresnel = fresnelTerm(normal, eyeVecNorm); 
    154 
    155     vec3 refraction = color2;
    156     #ifdef ENABLE_REFRACTION
    157         texC = texCoord.xy *sin (fresnel+1.0);
    158         #ifdef RESOLVE_MS
    159             ivec2 iTexC = ivec2(texC * textureSize(m_Texture));
    160             refraction = texelFetch(m_Texture, iTexC, sampleNum).rgb;
    161         #else
    162             ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
    163             refraction = texelFetch(m_Texture, iTexC, 0).rgb;
    164         #endif
    165     #endif 
    166 
    167    float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
    168    refraction = mix(mix(refraction, m_DeepWaterColor.rgb * waterCol, m_WaterTransparency),  m_WaterColor.rgb* waterCol,m_WaterTransparency);
    169 
    170     vec3 foam = vec3(0.0);
    171     #ifdef ENABLE_FOAM    
    172         texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
    173         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;
    174 
    175         if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
    176             foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity  * m_FoamIntensity * 0.3 *
    177                saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
    178         }
    179         foam *= m_LightColor.rgb;    
    180     #endif
    181 
    182 
    183 
    184     vec3 specular = vec3(0.0);   
    185     vec3 color ;
    186     float fogFactor;
    187 
    188     if(position.y>level){
    189         #ifdef ENABLE_SPECULAR
    190             if(step(0.9999,sceneDepth)==1.0){
    191                 vec3 lightDir=normalize(m_LightDir);
    192                 vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
    193                 float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
    194                 specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
    195                 specular += specular * 25.0 * saturate(m_Shininess - 0.05);
    196                 specular=specular * m_LightColor.rgb * 100.0;
    197             }
    198         #endif
    199         float fogIntensity= 8.0 * m_WaterTransparency;
    200         fogFactor = exp2( -fogIntensity * fogIntensity * cameraDepth * 0.03 * LOG2 );
    201         fogFactor = clamp(fogFactor, 0.0, 1.0);        
    202         color =mix(m_DeepWaterColor.rgb,refraction,fogFactor);   
    203         specular=specular*fogFactor;    
    204         color = saturate(color + max(specular, foam ));
    205     }else{
    206         vec3 caustics = vec3(0.0);
    207         #ifdef ENABLE_CAUSTICS 
    208             vec2 windDirection=m_WindDirection;
    209             texC = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time  + position.x) * 0.01;
    210             vec2 texCoord2 = (position.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * windDirection + sin(m_Time  + position.z) * 0.01;
    211             caustics += (texture2D(m_CausticsMap, texC)+ texture2D(m_CausticsMap, texCoord2)).rgb;                  
    212             caustics=saturate(mix(m_WaterColor.rgb,caustics,m_CausticsIntensity));            
    213             color=mix(color2,caustics,m_CausticsIntensity);
    214         #else
    215             color=color2;
    216         #endif
    217                 
    218         float fogDepth= (2.0 * m_FrustumNearFar.x) / (m_FrustumNearFar.y + m_FrustumNearFar.x - sceneDepth* (m_FrustumNearFar.y-m_FrustumNearFar.x));
    219         float fogIntensity= 18 * m_WaterTransparency;
    220         fogFactor = exp2( -fogIntensity * fogIntensity * fogDepth *  fogDepth * LOG2 );
    221         fogFactor = clamp(fogFactor, 0.0, 1.0);
    222         color =mix(m_DeepWaterColor.rgb,color,fogFactor);
    223     }
    224 
    225     return vec4(color, 1.0);   
    226 }
    227 // NOTE: This will be called even for single-sampling
    228 vec4 main_multiSample(int sampleNum){
    229     // If we are underwater let's call the underwater function
    230     if(m_WaterHeight >= m_CameraPosition.y){
    231 
    232         return underWater(sampleNum);
    233     }
    234 
    235     float sceneDepth = fetchTextureSample(m_DepthTexture, texCoord, sampleNum).r;
    236     vec3 color2 = fetchTextureSample(m_Texture, texCoord, sampleNum).rgb;
    237 
    238     vec3 color = color2;
    239     vec3 position = getPosition(sceneDepth, texCoord);
    240 
    241     float level = m_WaterHeight;
    242     
    243     float isAtFarPlane = step(0.99998, sceneDepth);
    244     //#ifndef ENABLE_RIPPLES
    245     // This optimization won't work on NVIDIA cards if ripples are enabled
    246     if(position.y > level + m_MaxAmplitude + isAtFarPlane * 100.0){
    247 
    248         return vec4(color2, 1.0);
    249     }
    250     //#endif
    251 
    252     vec3 eyeVec = position - m_CameraPosition;    
    253     float cameraDepth = m_CameraPosition.y - position.y;
    254 
    255     // Find intersection with water surface
    256     vec3 eyeVecNorm = normalize(eyeVec);
    257     float t = (level - m_CameraPosition.y) / eyeVecNorm.y;
    258     vec3 surfacePoint = m_CameraPosition + eyeVecNorm * t;
    259 
    260     vec2 texC = vec2(0.0);
    261     int samples = 1;
    262     #ifdef ENABLE_HQ_SHORELINE
    263         samples = 10;
    264     #endif
    265 
    266     float biasFactor = 1.0 / samples;
    267     for (int i = 0; i < samples; i++){
    268         texC = (surfacePoint.xz + eyeVecNorm.xz * biasFactor) * scale + m_Time * 0.03 * m_WindDirection;
    269 
    270         float bias = texture(m_HeightMap, texC).r;
    271 
    272         bias *= biasFactor;
    273         level += bias * m_MaxAmplitude;
    274         t = (level - m_CameraPosition.y) / eyeVecNorm.y;
    275         surfacePoint = m_CameraPosition + eyeVecNorm * t;
    276     }
    277 
    278     float depth = length(position - surfacePoint);
    279     float depth2 = surfacePoint.y - position.y;
    280 
    281     // XXX: HACK ALERT: Increase water depth to infinity if at far plane
    282     // Prevents "foam on horizon" issue
    283     // For best results, replace the "100.0" below with the
    284     // highest value in the m_ColorExtinction vec3
    285     depth  += isAtFarPlane * 100.0;
    286     depth2 += isAtFarPlane * 100.0;
    287 
    288     eyeVecNorm = normalize(m_CameraPosition - surfacePoint);
    289 
    290     // Find normal of water surface
    291     float normal1 = textureOffset(m_HeightMap, texC, ivec2(-1.0,  0.0)).r;
    292     float normal2 = textureOffset(m_HeightMap, texC, ivec2( 1.0,  0.0)).r;
    293     float normal3 = textureOffset(m_HeightMap, texC, ivec2( 0.0, -1.0)).r;
    294     float normal4 = textureOffset(m_HeightMap, texC, ivec2( 0.0,  1.0)).r;
    295 
    296     vec3 myNormal = normalize(vec3((normal1 - normal2) * m_MaxAmplitude,m_NormalScale,(normal3 - normal4) * m_MaxAmplitude));
    297     vec3 normal = vec3(0.0);
    298 
    299     #ifdef ENABLE_RIPPLES
    300         texC = surfacePoint.xz * 0.8 + m_WindDirection * m_Time* 1.6;
    301         mat3 tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
    302         vec3 normal0a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
    303 
    304         texC = surfacePoint.xz * 0.4 + m_WindDirection * m_Time* 0.8;
    305         tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
    306         vec3 normal1a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
    307 
    308         texC = surfacePoint.xz * 0.2 + m_WindDirection * m_Time * 0.4;
    309         tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
    310         vec3 normal2a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
    311 
    312         texC = surfacePoint.xz * 0.1 + m_WindDirection * m_Time * 0.2;
    313         tangentFrame = computeTangentFrame(myNormal, eyeVecNorm, texC);
    314         vec3 normal3a = normalize(tangentFrame*(2.0 * texture(m_NormalMap, texC).xyz - 1.0));
    315 
    316         normal = normalize(normal0a * normalModifier.x + normal1a * normalModifier.y +normal2a * normalModifier.z + normal3a * normalModifier.w);
    317         // XXX: Here's another way to fix the terrain edge issue,
    318         // But it requires GLSL 1.3 and still looks kinda incorrect
    319         // around edges
    320         normal = isnan(normal.x) ? myNormal : normal;
    321         //if (position.y > level){
    322         //    gl_FragColor = vec4(color2 + normal*0.0001, 1.0);
    323         //    return;
    324         //}
    325     #else
    326         normal = myNormal;
    327     #endif
    328 
    329     vec3 refraction = color2;
    330     #ifdef ENABLE_REFRACTION
    331        // texC = texCoord.xy+ m_ReflectionDisplace * normal.x;
    332         texC = texCoord.xy;
    333         texC += sin(m_Time*1.8  + 3.0 * abs(position.y)) * (refractionScale * min(depth2, 1.0));
    334         #ifdef RESOLVE_MS
    335             ivec2 iTexC = ivec2(texC * textureSize(m_Texture));
    336             refraction = texelFetch(m_Texture, iTexC, sampleNum).rgb;
    337         #else
    338             ivec2 iTexC = ivec2(texC * textureSize(m_Texture, 0));
    339             refraction = texelFetch(m_Texture, iTexC, 0).rgb;
    340         #endif
    341     #endif
    342 
    343     vec3 waterPosition = surfacePoint.xyz;
    344     waterPosition.y -= (level - m_WaterHeight);
    345     vec4 texCoordProj = m_TextureProjMatrix * vec4(waterPosition, 1.0);
    346 
    347     texCoordProj.x = texCoordProj.x + m_ReflectionDisplace * normal.x;
    348     texCoordProj.z = texCoordProj.z + m_ReflectionDisplace * normal.z;
    349     texCoordProj /= texCoordProj.w;
    350     texCoordProj.y = 1.0 - texCoordProj.y;
    351 
    352     vec3 reflection = texture(m_ReflectionMap, texCoordProj.xy).rgb;
    353 
    354     float fresnel = fresnelTerm(normal, eyeVecNorm);
    355 
    356     float depthN = depth * m_WaterTransparency;
    357     float waterCol = saturate(length(m_LightColor.rgb) / m_SunScale);
    358     refraction = mix(mix(refraction, m_WaterColor.rgb * waterCol, saturate(depthN / visibility)),
    359         m_DeepWaterColor.rgb * waterCol, saturate(depth2 / m_ColorExtinction));
    360 
    361 
    362 
    363 
    364     vec3 foam = vec3(0.0);
    365     #ifdef ENABLE_FOAM
    366         texC = (surfacePoint.xz + eyeVecNorm.xz * 0.1) * 0.05 + m_Time * 0.05 * m_WindDirection + sin(m_Time * 0.001 + position.x) * 0.005;
    367         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;
    368 
    369         if(depth2 < m_FoamExistence.x){
    370             foam = (texture2D(m_FoamMap, texC).r + texture2D(m_FoamMap, texCoord2)).rgb * vec3(m_FoamIntensity);
    371         }else if(depth2 < m_FoamExistence.y){
    372             foam = mix((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity , vec4(0.0),
    373                 (depth2 - m_FoamExistence.x) / (m_FoamExistence.y - m_FoamExistence.x)).rgb;
    374         }
    375 
    376         
    377         if(m_MaxAmplitude - m_FoamExistence.z> 0.0001){
    378             foam += ((texture2D(m_FoamMap, texC) + texture2D(m_FoamMap, texCoord2)) * m_FoamIntensity  * m_FoamIntensity * 0.3 *
    379                saturate((level - (m_WaterHeight + m_FoamExistence.z)) / (m_MaxAmplitude - m_FoamExistence.z))).rgb;
    380         }
    381         foam *= m_LightColor.rgb;
    382     #endif
    383 
    384     vec3 specular = vec3(0.0);
    385     #ifdef ENABLE_SPECULAR
    386         vec3 lightDir=normalize(m_LightDir);
    387         vec3 mirrorEye = (2.0 * dot(eyeVecNorm, normal) * normal - eyeVecNorm);
    388         float dotSpec = saturate(dot(mirrorEye.xyz, -lightDir) * 0.5 + 0.5);
    389         specular = vec3((1.0 - fresnel) * saturate(-lightDir.y) * ((pow(dotSpec, 512.0)) * (m_Shininess * 1.8 + 0.2)));
    390         specular += specular * 25.0 * saturate(m_Shininess - 0.05);
    391         //foam does not shine
    392         specular=specular * m_LightColor.rgb - (5.0 * foam);
    393     #endif
    394 
    395     color = mix(refraction, reflection, fresnel);
    396     color = mix(refraction, color, saturate(depth * m_ShoreHardness));
    397     color = saturate(color + max(specular, foam ));
    398     color = mix(refraction, color, saturate(depth* m_FoamHardness));
    399 
    400 
    401     // XXX: HACK ALERT:
    402     // We trick the GeForces to think they have
    403     // to calculate the derivatives for all these pixels by using step()!
    404     // That way we won't get pixels around the edges of the terrain,
    405     // Where the derivatives are undefined
    406     return vec4(mix(color, color2, step(level, position.y)), 1.0);
    407 }
    408 
    409 void main(){
    410     #ifdef RESOLVE_MS
    411         vec4 color = vec4(0.0);
    412         for (int i = 0; i < m_NumSamples; i++){
    413             color += main_multiSample(i);
    414         }
    415         outFragColor = color / m_NumSamples;
    416     #else
    417         outFragColor = main_multiSample(0);
    418     #endif
    419 }