2015-10-26 20:36:19 +00:00
#version 120
2021-03-15 04:42:34 +00:00
#if @useUBO
# extension GL_ARB_uniform_buffer_object : require
#endif
#if @useGPUShader4
# extension GL_EXT_gpu_shader4 : require
#endif
2021-02-21 18:38:15 +00:00
2023-02-25 19:03:39 +00:00
#include "lib/core/fragment.h.glsl"
2022-04-27 15:37:07 +00:00
2018-03-08 20:23:24 +00:00
// Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html )
2015-10-26 20:36:19 +00:00
// tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
2019-05-12 06:22:49 +00:00
const float VISIBILITY = 2500.0 ;
2024-02-06 06:58:40 +00:00
const float VISIBILITY_DEPTH = VISIBILITY * 1.5 ;
const float DEPTH_FADE = 0.15 ;
2015-10-26 20:36:19 +00:00
2024-03-31 22:35:50 +00:00
const vec2 BIG_WAVES = vec2 ( 0.1 , 0.1 ) ; // strength of big waves
const vec2 MID_WAVES = vec2 ( 0.1 , 0.1 ) ; // strength of middle sized waves
const vec2 MID_WAVES_RAIN = vec2 ( 0.2 , 0.2 ) ;
const vec2 SMALL_WAVES = vec2 ( 0.1 , 0.1 ) ; // strength of small waves
const vec2 SMALL_WAVES_RAIN = vec2 ( 0.3 , 0.3 ) ;
2015-10-26 20:36:19 +00:00
const float WAVE_CHOPPYNESS = 0.05 ; // wave choppyness
const float WAVE_SCALE = 75.0 ; // overall wave scale
const float BUMP = 0.5 ; // overall water surface bumpiness
2018-07-11 15:03:59 +00:00
const float BUMP_RAIN = 2.5 ;
2015-10-28 17:54:49 +00:00
const float REFL_BUMP = 0.10 ; // reflection distortion amount
const float REFR_BUMP = 0.07 ; // refraction distortion amount
2015-10-26 20:36:19 +00:00
2024-03-29 06:34:52 +00:00
#if @sunlightScattering
2021-03-30 11:32:01 +00:00
const float SCATTER_AMOUNT = 0.3 ; // amount of sunlight scattering
const vec3 SCATTER_COLOUR = vec3 ( 0.0 , 1.0 , 0.95 ) ; // colour of sunlight scattering
2024-03-29 06:34:52 +00:00
const vec3 SUN_EXT = vec3 ( 0.45 , 0.55 , 0.68 ) ; // sunlight extinction
#endif
2021-03-30 11:32:01 +00:00
2023-10-29 01:11:31 +00:00
const float SUN_SPEC_FADING_THRESHOLD = 0.15 ; // visibility at which sun specularity starts to fade
2015-10-26 20:36:19 +00:00
const float SPEC_HARDNESS = 256.0 ; // specular highlights hardness
2020-06-26 23:20:57 +00:00
const float BUMP_SUPPRESS_DEPTH = 300.0 ; // at what water depth bumpmap will be suppressed for reflections and refractions (prevents artifacts at shores)
2024-02-06 06:58:40 +00:00
const float REFR_FOG_DISTORT_DISTANCE = 3000.0 ; // at what distance refraction fog will be calculated using real water depth instead of distorted depth (prevents splotchy shores)
2017-09-21 20:25:36 +00:00
2015-10-26 20:36:19 +00:00
const vec2 WIND_DIR = vec2 ( 0.5 f , - 0.8 f ) ;
const float WIND_SPEED = 0.2 f ;
2015-10-28 18:13:55 +00:00
const vec3 WATER_COLOR = vec3 ( 0.090195 , 0.115685 , 0.12745 ) ;
2024-03-29 06:34:52 +00:00
#if @wobblyShores
2021-08-05 00:49:57 +00:00
const float WOBBLY_SHORE_FADE_DISTANCE = 6200.0 ; // fade out wobbly shores to mask precision errors, the effect is almost impossible to see at a distance
2024-03-29 06:34:52 +00:00
#endif
2021-08-05 00:49:57 +00:00
2015-10-26 20:36:19 +00:00
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
2017-09-27 15:13:21 +00:00
vec2 normalCoords ( vec2 uv , float scale , float speed , float time , float timer1 , float timer2 , vec3 previousNormal )
2023-02-25 19:03:39 +00:00
{
return uv * ( WAVE_SCALE * scale ) + WIND_DIR * time * ( WIND_SPEED * speed ) - ( previousNormal . xy / previousNormal . zz ) * WAVE_CHOPPYNESS + vec2 ( time * timer1 , time * timer2 ) ;
}
2015-10-26 20:36:19 +00:00
2023-04-01 05:09:45 +00:00
uniform sampler2D rippleMap ;
uniform vec3 playerPos ;
varying vec3 worldPos ;
varying vec2 rippleMapUV ;
2017-09-26 12:14:28 +00:00
varying vec4 position ;
2020-03-14 12:39:32 +00:00
varying float linearDepth ;
2015-10-26 20:36:19 +00:00
2015-10-28 19:24:52 +00:00
uniform sampler2D normalMap ;
2015-10-26 20:36:19 +00:00
uniform float osg_SimulationTime ;
2015-10-28 17:59:35 +00:00
uniform float near ;
2023-02-25 19:03:39 +00:00
uniform float far ;
2015-10-28 17:59:35 +00:00
2017-09-28 17:04:31 +00:00
uniform float rainIntensity ;
2023-12-21 11:48:06 +00:00
uniform bool enableRainRipples ;
2017-09-28 17:04:31 +00:00
2021-11-04 04:37:09 +00:00
uniform vec2 screenRes ;
2021-03-29 07:13:35 +00:00
#define PER_PIXEL_LIGHTING 0
2018-06-24 22:40:52 +00:00
#include "shadows_fragment.glsl"
2023-02-25 19:03:39 +00:00
#include "lib/light/lighting.glsl"
2022-06-06 20:40:38 +00:00
#include "fog.glsl"
2023-02-25 19:03:39 +00:00
#include "lib/water/fresnel.glsl"
2023-04-01 05:09:45 +00:00
#include "lib/water/rain_ripples.glsl"
2023-02-25 19:03:39 +00:00
#include "lib/view/depth.glsl"
2017-09-21 20:25:36 +00:00
2015-10-26 20:36:19 +00:00
void main ( void )
{
vec2 UV = worldPos . xy / ( 8192.0 * 5.0 ) * 3.0 ;
2020-03-14 12:39:32 +00:00
float shadow = unshadowedLightRatio ( linearDepth ) ;
2015-10-26 20:36:19 +00:00
2021-11-04 04:37:09 +00:00
vec2 screenCoords = gl_FragCoord . xy / screenRes ;
2015-10-26 20:36:19 +00:00
# define waterTimer osg_SimulationTime
2018-03-08 20:23:24 +00:00
vec3 normal0 = 2.0 * texture2D ( normalMap , normalCoords ( UV , 0.05 , 0.04 , waterTimer , - 0.015 , - 0.005 , vec3 ( 0.0 , 0.0 , 0.0 ) ) ) . rgb - 1.0 ;
2017-09-27 15:13:21 +00:00
vec3 normal1 = 2.0 * texture2D ( normalMap , normalCoords ( UV , 0.1 , 0.08 , waterTimer , 0.02 , 0.015 , normal0 ) ) . rgb - 1.0 ;
vec3 normal2 = 2.0 * texture2D ( normalMap , normalCoords ( UV , 0.25 , 0.07 , waterTimer , - 0.04 , - 0.03 , normal1 ) ) . rgb - 1.0 ;
vec3 normal3 = 2.0 * texture2D ( normalMap , normalCoords ( UV , 0.5 , 0.09 , waterTimer , 0.03 , 0.04 , normal2 ) ) . rgb - 1.0 ;
vec3 normal4 = 2.0 * texture2D ( normalMap , normalCoords ( UV , 1.0 , 0.4 , waterTimer , - 0.02 , 0.1 , normal3 ) ) . rgb - 1.0 ;
vec3 normal5 = 2.0 * texture2D ( normalMap , normalCoords ( UV , 2.0 , 0.7 , waterTimer , 0.1 , - 0.06 , normal4 ) ) . rgb - 1.0 ;
2015-10-26 20:36:19 +00:00
2017-09-28 17:04:31 +00:00
vec4 rainRipple ;
2023-12-21 11:48:06 +00:00
if ( rainIntensity > 0.01 && enableRainRipples )
2023-04-21 05:02:12 +00:00
rainRipple = rainCombined ( position . xy / 1000.0 , waterTimer ) * clamp ( rainIntensity , 0.0 , 1.0 ) ;
2017-09-28 17:04:31 +00:00
else
2023-04-21 05:02:12 +00:00
rainRipple = vec4 ( 0.0 ) ;
2018-03-08 20:23:24 +00:00
2021-10-31 14:33:28 +00:00
vec3 rippleAdd = rainRipple . xyz * 10.0 ;
2017-09-27 19:25:14 +00:00
2023-04-01 05:09:45 +00:00
float distToCenter = length ( rippleMapUV - vec2 ( 0.5 ) ) ;
float blendClose = smoothstep ( 0.001 , 0.02 , distToCenter ) ;
float blendFar = 1.0 - smoothstep ( 0.3 , 0.4 , distToCenter ) ;
2023-04-02 10:02:40 +00:00
float distortionLevel = 2.0 ;
rippleAdd + = distortionLevel * vec3 ( texture2D ( rippleMap , rippleMapUV ) . ba * blendFar * blendClose , 0.0 ) ;
2023-04-01 05:09:45 +00:00
2024-03-31 22:35:50 +00:00
vec2 bigWaves = BIG_WAVES ;
vec2 midWaves = mix ( MID_WAVES , MID_WAVES_RAIN , rainIntensity ) ;
vec2 smallWaves = mix ( SMALL_WAVES , SMALL_WAVES_RAIN , rainIntensity ) ;
2018-07-11 15:03:59 +00:00
float bump = mix ( BUMP , BUMP_RAIN , rainIntensity ) ;
2019-08-30 19:01:03 +00:00
vec3 normal = ( normal0 * bigWaves . x + normal1 * bigWaves . y + normal2 * midWaves . x +
normal3 * midWaves . y + normal4 * smallWaves . x + normal5 * smallWaves . y + rippleAdd ) ;
normal = normalize ( vec3 ( - normal . x * bump , - normal . y * bump , normal . z ) ) ;
2015-10-26 20:36:19 +00:00
2024-04-01 21:16:52 +00:00
vec3 sunWorldDir = normalize ( ( gl_ModelViewMatrixInverse * vec4 ( lcalcPosition ( 0 ) . xyz , 0.0 ) ) . xyz ) ;
2015-10-26 20:36:19 +00:00
vec3 cameraPos = ( gl_ModelViewMatrixInverse * vec4 ( 0 , 0 , 0 , 1 ) ) . xyz ;
2024-04-01 21:16:52 +00:00
vec3 viewDir = normalize ( position . xyz - cameraPos . xyz ) ;
2015-10-26 20:36:19 +00:00
float sunFade = length ( gl_LightModel . ambient . xyz ) ;
// fresnel
2017-09-27 19:25:14 +00:00
float ior = ( cameraPos . z > 0.0 ) ? ( 1.333 / 1.0 ) : ( 1.0 / 1.333 ) ; // air to water; water to air
2024-04-01 21:16:52 +00:00
float fresnel = clamp ( fresnel_dielectric ( viewDir , normal , ior ) , 0.0 , 1.0 ) ;
2015-10-26 20:36:19 +00:00
2019-08-30 19:01:03 +00:00
vec2 screenCoordsOffset = normal . xy * REFL_BUMP ;
2024-04-04 18:12:47 +00:00
#if @waterRefraction
2024-03-31 20:08:47 +00:00
float depthSample = linearizeDepth ( sampleRefractionDepthMap ( screenCoords ) , near , far ) ;
float surfaceDepth = linearizeDepth ( gl_FragCoord . z , near , far ) ;
2018-03-08 20:23:24 +00:00
float realWaterDepth = depthSample - surfaceDepth ; // undistorted water depth in view direction, independent of frustum
2024-03-31 20:08:47 +00:00
float depthSampleDistorted = linearizeDepth ( sampleRefractionDepthMap ( screenCoords - screenCoordsOffset ) , near , far ) ;
2024-02-06 06:58:40 +00:00
float waterDepthDistorted = max ( depthSampleDistorted - surfaceDepth , 0.0 ) ;
2024-03-31 22:35:50 +00:00
screenCoordsOffset * = clamp ( realWaterDepth / BUMP_SUPPRESS_DEPTH , 0.0 , 1.0 ) ;
2017-09-22 08:53:02 +00:00
#endif
2015-10-26 20:36:19 +00:00
// reflection
2023-02-25 19:03:39 +00:00
vec3 reflection = sampleReflectionMap ( screenCoords + screenCoordsOffset ) . rgb ;
2015-10-26 20:36:19 +00:00
2019-08-30 19:01:03 +00:00
vec3 waterColor = WATER_COLOR * sunFade ;
2017-09-22 08:53:02 +00:00
2021-04-08 19:42:11 +00:00
vec4 sunSpec = lcalcSpecular ( 0 ) ;
2023-10-06 21:53:07 +00:00
// alpha component is sun visibility; we want to start fading lighting effects when visibility is low
2023-10-29 01:11:31 +00:00
sunSpec . a = min ( 1.0 , sunSpec . a / SUN_SPEC_FADING_THRESHOLD ) ;
2021-03-15 04:42:34 +00:00
2024-03-31 22:35:50 +00:00
// specular
2024-04-01 21:16:52 +00:00
float specular = pow ( max ( dot ( reflect ( viewDir , normal ) , sunWorldDir ) , 0.0 ) , SPEC_HARDNESS ) * shadow * sunSpec . a ;
2024-03-31 22:35:50 +00:00
2021-10-31 14:33:28 +00:00
// artificial specularity to make rain ripples more noticeable
vec3 skyColorEstimate = vec3 ( max ( 0.0 , mix ( - 0.3 , 1.0 , sunFade ) ) ) ;
vec3 rainSpecular = abs ( rainRipple . w ) * mix ( skyColorEstimate , vec3 ( 1.0 ) , 0.05 ) * 0.5 ;
2024-03-31 22:35:50 +00:00
float waterTransparency = clamp ( fresnel * 6.0 + specular , 0.0 , 1.0 ) ;
2021-10-31 14:33:28 +00:00
2024-04-04 18:12:47 +00:00
#if @waterRefraction
2024-02-06 06:58:40 +00:00
// selectively nullify screenCoordsOffset to eliminate remaining shore artifacts, not needed for reflection
if ( cameraPos . z > 0.0 && realWaterDepth <= VISIBILITY_DEPTH && waterDepthDistorted > VISIBILITY_DEPTH )
screenCoordsOffset = vec2 ( 0.0 ) ;
2024-03-31 20:08:47 +00:00
depthSampleDistorted = linearizeDepth ( sampleRefractionDepthMap ( screenCoords - screenCoordsOffset ) , near , far ) ;
2024-02-06 06:58:40 +00:00
waterDepthDistorted = max ( depthSampleDistorted - surfaceDepth , 0.0 ) ;
// fade to realWaterDepth at a distance to compensate for physically inaccurate depth calculation
waterDepthDistorted = mix ( waterDepthDistorted , realWaterDepth , min ( surfaceDepth / REFR_FOG_DISTORT_DISTANCE , 1.0 ) ) ;
2019-08-30 19:01:03 +00:00
// refraction
2023-02-25 19:03:39 +00:00
vec3 refraction = sampleRefractionMap ( screenCoords - screenCoordsOffset ) . rgb ;
2021-03-20 01:49:17 +00:00
vec3 rawRefraction = refraction ;
2019-08-30 19:01:03 +00:00
// brighten up the refraction underwater
if ( cameraPos . z < 0.0 )
refraction = clamp ( refraction * 1.5 , 0.0 , 1.0 ) ;
else
2024-02-06 06:58:40 +00:00
{
float depthCorrection = sqrt ( 1.0 + 4.0 * DEPTH_FADE * DEPTH_FADE ) ;
float factor = DEPTH_FADE * DEPTH_FADE / ( - 0.5 * depthCorrection + 0.5 - waterDepthDistorted / VISIBILITY ) + 0.5 * depthCorrection + 0.5 ;
refraction = mix ( refraction , waterColor , clamp ( factor , 0.0 , 1.0 ) ) ;
}
2015-10-26 20:36:19 +00:00
2024-03-29 06:34:52 +00:00
#if @sunlightScattering
2024-04-01 21:16:52 +00:00
vec3 scatterNormal = ( normal0 * bigWaves . x * 0.5 + normal1 * bigWaves . y * 0.5 + normal2 * midWaves . x * 0.2 +
normal3 * midWaves . y * 0.2 + normal4 * smallWaves . x * 0.1 + normal5 * smallWaves . y * 0.1 + rippleAdd ) ;
scatterNormal = normalize ( vec3 ( - scatterNormal . xy * bump , scatterNormal . z ) ) ;
float sunHeight = sunWorldDir . z ;
2024-03-31 22:35:50 +00:00
vec3 scatterColour = mix ( SCATTER_COLOUR * vec3 ( 1.0 , 0.4 , 0.0 ) , SCATTER_COLOUR , max ( 1.0 - exp ( - sunHeight * SUN_EXT ) , 0.0 ) ) ;
2024-04-01 21:16:52 +00:00
float scatterLambert = max ( dot ( sunWorldDir , scatterNormal ) * 0.7 + 0.3 , 0.0 ) ;
float scatterReflectAngle = max ( dot ( reflect ( sunWorldDir , scatterNormal ) , viewDir ) * 2.0 - 1.2 , 0.0 ) ;
2024-03-31 22:35:50 +00:00
float lightScatter = scatterLambert * scatterReflectAngle * SCATTER_AMOUNT * sunFade * sunSpec . a * max ( 1.0 - exp ( - sunHeight ) , 0.0 ) ;
2024-03-29 06:34:52 +00:00
refraction = mix ( refraction , scatterColour , lightScatter ) ;
#endif
2024-03-31 22:35:50 +00:00
gl_FragData [ 0 ] . rgb = mix ( refraction , reflection , fresnel ) ;
gl_FragData [ 0 ] . a = 1.0 ;
// no alpha here, so make sure raindrop ripple specularity gets properly subdued
rainSpecular * = waterTransparency ;
#else
gl_FragData [ 0 ] . rgb = mix ( waterColor , reflection , ( 1.0 + fresnel ) * 0.5 ) ;
gl_FragData [ 0 ] . a = waterTransparency ;
#endif
2021-03-20 01:49:17 +00:00
2024-03-31 22:35:50 +00:00
gl_FragData [ 0 ] . rgb + = specular * sunSpec . rgb + rainSpecular ;
2024-04-04 18:12:47 +00:00
#if @waterRefraction && @wobblyShores
2021-03-20 01:49:17 +00:00
// wobbly water: hard-fade into refraction texture at extremely low depth, with a wobble based on normal mapping
vec3 normalShoreRippleRain = texture2D ( normalMap , normalCoords ( UV , 2.0 , 2.7 , - 1.0 * waterTimer , 0.05 , 0.1 , normal3 ) ) . rgb - 0.5
+ texture2D ( normalMap , normalCoords ( UV , 2.0 , 2.7 , waterTimer , 0.04 , - 0.13 , normal4 ) ) . rgb - 0.5 ;
2024-04-01 21:16:52 +00:00
float viewFactor = mix ( abs ( viewDir . z ) , 1.0 , 0.2 ) ;
2024-03-31 22:35:50 +00:00
float verticalWaterDepth = realWaterDepth * viewFactor ; // an estimate
2021-08-05 00:49:57 +00:00
float shoreOffset = verticalWaterDepth - ( normal2 . r + mix ( 0.0 , normalShoreRippleRain . r , rainIntensity ) + 0.15 ) * 8.0 ;
2024-03-31 22:35:50 +00:00
float fuzzFactor = min ( 1.0 , 1000.0 / surfaceDepth ) * viewFactor ;
2021-03-20 17:11:19 +00:00
shoreOffset * = fuzzFactor ;
2021-08-05 00:49:57 +00:00
shoreOffset = clamp ( mix ( shoreOffset , 1.0 , clamp ( linearDepth / WOBBLY_SHORE_FADE_DISTANCE , 0.0 , 1.0 ) ) , 0.0 , 1.0 ) ;
2024-03-31 22:35:50 +00:00
gl_FragData [ 0 ] . rgb = mix ( rawRefraction , gl_FragData [ 0 ] . rgb , shoreOffset ) ;
2015-10-26 20:36:19 +00:00
#endif
2019-08-30 19:01:03 +00:00
2024-03-31 20:08:47 +00:00
#if @radialFog
float radialDepth = distance ( position . xyz , cameraPos ) ;
#else
float radialDepth = 0.0 ;
#endif
2023-02-25 19:03:39 +00:00
gl_FragData [ 0 ] = applyFogAtDist ( gl_FragData [ 0 ] , radialDepth , linearDepth , far ) ;
2015-10-26 20:36:19 +00:00
2022-05-14 01:58:00 +00:00
#if !@disableNormals
2023-01-19 16:39:38 +00:00
gl_FragData [ 1 ] . rgb = normalize ( gl_NormalMatrix * normal ) * 0.5 + 0.5 ;
2022-05-14 01:58:00 +00:00
#endif
2018-06-28 16:24:36 +00:00
applyShadowDebugOverlay ( ) ;
2015-10-26 20:36:19 +00:00
}