• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}