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 8uniform COLORTEXTURE m_Texture; 9uniform DEPTHTEXTURE m_DepthTexture; 10 11 12uniform sampler2D m_HeightMap; 13uniform sampler2D m_NormalMap; 14uniform sampler2D m_FoamMap; 15uniform sampler2D m_CausticsMap; 16uniform sampler2D m_ReflectionMap; 17 18uniform mat4 m_ViewProjectionMatrixInverse; 19uniform mat4 m_TextureProjMatrix; 20uniform vec3 m_CameraPosition; 21 22uniform float m_WaterHeight; 23uniform float m_Time; 24uniform float m_WaterTransparency; 25uniform float m_NormalScale; 26uniform float m_R0; 27uniform float m_MaxAmplitude; 28uniform vec3 m_LightDir; 29uniform vec4 m_LightColor; 30uniform float m_ShoreHardness; 31uniform float m_FoamHardness; 32uniform float m_RefractionStrength; 33uniform vec3 m_FoamExistence; 34uniform vec3 m_ColorExtinction; 35uniform float m_Shininess; 36uniform vec4 m_WaterColor; 37uniform vec4 m_DeepWaterColor; 38uniform vec2 m_WindDirection; 39uniform float m_SunScale; 40uniform float m_WaveScale; 41uniform float m_UnderWaterFogDistance; 42uniform float m_CausticsIntensity; 43 44 45vec2 scale = vec2(m_WaveScale, m_WaveScale); 46float 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" 50const vec4 normalModifier = vec4(3.0, 2.0, 4.0, 10.0); 51// Strength of displacement along normal. 52uniform float m_ReflectionDisplace; 53// Water transparency along eye vector. 54const float visibility = 3.0; 55// foam intensity 56uniform float m_FoamIntensity ; 57 58in vec2 texCoord; 59out vec4 outFragColor; 60 61mat3 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 70mat3 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 91float saturate(in float val){ 92 return clamp(val,0.0,1.0); 93} 94 95vec3 saturate(in vec3 val){ 96 return clamp(val,vec3(0.0),vec3(1.0)); 97} 98 99vec3 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 108float 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 116vec2 m_FrustumNearFar=vec2(1.0,m_UnderWaterFogDistance); 117const float LOG2 = 1.442695; 118 119vec4 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 228vec4 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 409void 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}