2015-10-26 21:36:19 +01:00
#version 120
2021-03-14 21:42:34 -07:00
#if @useUBO
# extension GL_ARB_uniform_buffer_object : require
#endif
#if @useGPUShader4
# extension GL_EXT_gpu_shader4 : require
#endif
2021-02-21 10:38:15 -08:00
2023-02-25 11:03:39 -08:00
#include "lib/core/fragment.h.glsl"
2022-04-27 17:37:07 +02:00
2015-10-28 21:22:14 +01:00
#define REFRACTION @refraction_enabled
2015-10-26 21:36:19 +01:00
2018-03-08 21:23:24 +01:00
// Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html )
2015-10-26 21:36:19 +01:00
// tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
2019-05-12 10:22:49 +04:00
const float VISIBILITY = 2500.0 ;
2024-02-06 10:58:40 +04:00
const float VISIBILITY_DEPTH = VISIBILITY * 1.5 ;
const float DEPTH_FADE = 0.15 ;
2015-10-26 21:36:19 +01:00
const float BIG_WAVES_X = 0.1 ; // strength of big waves
const float BIG_WAVES_Y = 0.1 ;
const float MID_WAVES_X = 0.1 ; // strength of middle sized waves
const float MID_WAVES_Y = 0.1 ;
2018-07-11 17:03:59 +02:00
const float MID_WAVES_RAIN_X = 0.2 ;
const float MID_WAVES_RAIN_Y = 0.2 ;
2015-10-26 21:36:19 +01:00
const float SMALL_WAVES_X = 0.1 ; // strength of small waves
const float SMALL_WAVES_Y = 0.1 ;
2018-07-11 17:03:59 +02:00
const float SMALL_WAVES_RAIN_X = 0.3 ;
const float SMALL_WAVES_RAIN_Y = 0.3 ;
2015-10-26 21:36:19 +01: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 17:03:59 +02:00
const float BUMP_RAIN = 2.5 ;
2015-10-28 18:54:49 +01:00
const float REFL_BUMP = 0.10 ; // reflection distortion amount
const float REFR_BUMP = 0.07 ; // refraction distortion amount
2015-10-26 21:36:19 +01:00
2021-03-30 15:32:01 +04: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
2015-10-26 21:36:19 +01:00
const vec3 SUN_EXT = vec3 ( 0.45 , 0.55 , 0.68 ) ; //sunlight extinction
2023-10-29 04:11:31 +03:00
const float SUN_SPEC_FADING_THRESHOLD = 0.15 ; // visibility at which sun specularity starts to fade
2015-10-26 21:36:19 +01:00
const float SPEC_HARDNESS = 256.0 ; // specular highlights hardness
2020-06-27 01:20:57 +02: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 10:58:40 +04: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 22:25:36 +02:00
2015-10-26 21:36:19 +01:00
const vec2 WIND_DIR = vec2 ( 0.5 f , - 0.8 f ) ;
const float WIND_SPEED = 0.2 f ;
2015-10-28 19:13:55 +01:00
const vec3 WATER_COLOR = vec3 ( 0.090195 , 0.115685 , 0.12745 ) ;
2021-08-04 17:49:57 -07: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
2015-10-26 21:36:19 +01:00
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
2017-09-27 17:13:21 +02:00
vec2 normalCoords ( vec2 uv , float scale , float speed , float time , float timer1 , float timer2 , vec3 previousNormal )
2023-02-25 11:03:39 -08: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 21:36:19 +01:00
2023-04-01 09:09:45 +04:00
uniform sampler2D rippleMap ;
uniform vec3 playerPos ;
varying vec3 worldPos ;
varying vec2 rippleMapUV ;
2017-09-26 14:14:28 +02:00
varying vec4 position ;
2020-03-14 16:39:32 +04:00
varying float linearDepth ;
2015-10-26 21:36:19 +01:00
2015-10-28 20:24:52 +01:00
uniform sampler2D normalMap ;
2015-10-26 21:36:19 +01:00
uniform float osg_SimulationTime ;
2015-10-28 18:59:35 +01:00
uniform float near ;
2023-02-25 11:03:39 -08:00
uniform float far ;
2015-10-28 18:59:35 +01:00
2017-09-28 19:04:31 +02:00
uniform float rainIntensity ;
2023-12-21 14:48:06 +03:00
uniform bool enableRainRipples ;
2017-09-28 19:04:31 +02:00
2021-11-04 00:37:09 -04:00
uniform vec2 screenRes ;
2021-03-29 00:13:35 -07:00
#define PER_PIXEL_LIGHTING 0
2018-06-24 23:40:52 +01:00
#include "shadows_fragment.glsl"
2023-02-25 11:03:39 -08:00
#include "lib/light/lighting.glsl"
2022-06-06 22:40:38 +02:00
#include "fog.glsl"
2023-02-25 11:03:39 -08:00
#include "lib/water/fresnel.glsl"
2023-04-01 09:09:45 +04:00
#include "lib/water/rain_ripples.glsl"
2023-02-25 11:03:39 -08:00
#include "lib/view/depth.glsl"
2017-09-21 22:25:36 +02:00
2015-10-26 21:36:19 +01:00
void main ( void )
{
vec2 UV = worldPos . xy / ( 8192.0 * 5.0 ) * 3.0 ;
UV . y * = - 1.0 ;
2020-03-14 16:39:32 +04:00
float shadow = unshadowedLightRatio ( linearDepth ) ;
2015-10-26 21:36:19 +01:00
2021-11-04 00:37:09 -04:00
vec2 screenCoords = gl_FragCoord . xy / screenRes ;
2015-10-26 21:36:19 +01:00
# define waterTimer osg_SimulationTime
2018-03-08 21:23:24 +01: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 17:13:21 +02: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 21:36:19 +01:00
2017-09-28 19:04:31 +02:00
vec4 rainRipple ;
2023-12-21 14:48:06 +03:00
if ( rainIntensity > 0.01 && enableRainRipples )
2023-04-21 09:02:12 +04:00
rainRipple = rainCombined ( position . xy / 1000.0 , waterTimer ) * clamp ( rainIntensity , 0.0 , 1.0 ) ;
2017-09-28 19:04:31 +02:00
else
2023-04-21 09:02:12 +04:00
rainRipple = vec4 ( 0.0 ) ;
2018-03-08 21:23:24 +01:00
2021-10-31 10:33:28 -04:00
vec3 rippleAdd = rainRipple . xyz * 10.0 ;
2017-09-27 21:25:14 +02:00
2023-04-01 09:09:45 +04: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 14:02:40 +04:00
float distortionLevel = 2.0 ;
rippleAdd + = distortionLevel * vec3 ( texture2D ( rippleMap , rippleMapUV ) . ba * blendFar * blendClose , 0.0 ) ;
2023-04-01 09:09:45 +04:00
2018-07-11 17:03:59 +02:00
vec2 bigWaves = vec2 ( BIG_WAVES_X , BIG_WAVES_Y ) ;
vec2 midWaves = mix ( vec2 ( MID_WAVES_X , MID_WAVES_Y ) , vec2 ( MID_WAVES_RAIN_X , MID_WAVES_RAIN_Y ) , rainIntensity ) ;
vec2 smallWaves = mix ( vec2 ( SMALL_WAVES_X , SMALL_WAVES_Y ) , vec2 ( SMALL_WAVES_RAIN_X , SMALL_WAVES_RAIN_Y ) , rainIntensity ) ;
float bump = mix ( BUMP , BUMP_RAIN , rainIntensity ) ;
2019-08-30 22:01:03 +03: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 21:36:19 +01:00
2021-04-08 12:42:11 -07:00
vec3 lVec = normalize ( ( gl_ModelViewMatrixInverse * vec4 ( lcalcPosition ( 0 ) . xyz , 0.0 ) ) . xyz ) ;
2015-10-26 21:36:19 +01:00
vec3 cameraPos = ( gl_ModelViewMatrixInverse * vec4 ( 0 , 0 , 0 , 1 ) ) . xyz ;
vec3 vVec = normalize ( position . xyz - cameraPos . xyz ) ;
float sunFade = length ( gl_LightModel . ambient . xyz ) ;
// fresnel
2017-09-27 21:25:14 +02:00
float ior = ( cameraPos . z > 0.0 ) ? ( 1.333 / 1.0 ) : ( 1.0 / 1.333 ) ; // air to water; water to air
2019-08-30 22:01:03 +03:00
float fresnel = clamp ( fresnel_dielectric ( vVec , normal , ior ) , 0.0 , 1.0 ) ;
2015-10-26 21:36:19 +01:00
2020-04-18 12:30:01 +03:00
float radialise = 1.0 ;
2020-03-14 16:39:32 +04:00
#if @radialFog
float radialDepth = distance ( position . xyz , cameraPos ) ;
2020-04-18 12:30:01 +03:00
// TODO: Figure out how to properly radialise refraction depth and thus underwater fog
// while avoiding oddities when the water plane is close to the clipping plane
// radialise = radialDepth / linearDepth;
2022-06-06 22:40:38 +02:00
#else
float radialDepth = 0.0 ;
2020-03-14 16:39:32 +04:00
#endif
2020-04-18 12:30:01 +03:00
2019-08-30 22:01:03 +03:00
vec2 screenCoordsOffset = normal . xy * REFL_BUMP ;
2017-09-22 10:53:02 +02:00
#if REFRACTION
2023-02-25 11:03:39 -08:00
float depthSample = linearizeDepth ( sampleRefractionDepthMap ( screenCoords ) , near , far ) * radialise ;
float surfaceDepth = linearizeDepth ( gl_FragCoord . z , near , far ) * radialise ;
2018-03-08 21:23:24 +01:00
float realWaterDepth = depthSample - surfaceDepth ; // undistorted water depth in view direction, independent of frustum
2024-02-06 10:58:40 +04:00
float depthSampleDistorted = linearizeDepth ( sampleRefractionDepthMap ( screenCoords - screenCoordsOffset ) , near , far ) * radialise ;
float waterDepthDistorted = max ( depthSampleDistorted - surfaceDepth , 0.0 ) ;
2021-03-30 15:32:01 +04:00
screenCoordsOffset * = clamp ( realWaterDepth / BUMP_SUPPRESS_DEPTH , 0 , 1 ) ;
2017-09-22 10:53:02 +02:00
#endif
2015-10-26 21:36:19 +01:00
// reflection
2023-02-25 11:03:39 -08:00
vec3 reflection = sampleReflectionMap ( screenCoords + screenCoordsOffset ) . rgb ;
2015-10-26 21:36:19 +01:00
// specular
2019-08-30 22:01:03 +03:00
float specular = pow ( max ( dot ( reflect ( vVec , normal ) , lVec ) , 0.0 ) , SPEC_HARDNESS ) * shadow ;
2015-10-26 21:36:19 +01:00
2019-08-30 22:01:03 +03:00
vec3 waterColor = WATER_COLOR * sunFade ;
2017-09-22 10:53:02 +02:00
2021-04-08 12:42:11 -07:00
vec4 sunSpec = lcalcSpecular ( 0 ) ;
2023-10-07 00:53:07 +03:00
// alpha component is sun visibility; we want to start fading lighting effects when visibility is low
2023-10-29 04:11:31 +03:00
sunSpec . a = min ( 1.0 , sunSpec . a / SUN_SPEC_FADING_THRESHOLD ) ;
2021-03-14 21:42:34 -07:00
2021-10-31 10:33:28 -04: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 ;
2015-10-26 21:36:19 +01:00
#if REFRACTION
2021-10-31 10:33:28 -04:00
// no alpha here, so make sure raindrop ripple specularity gets properly subdued
2023-10-29 04:11:31 +03:00
rainSpecular * = clamp ( fresnel * 6.0 + specular * sunSpec . a , 0.0 , 1.0 ) ;
2021-10-31 10:33:28 -04:00
2024-02-06 10:58:40 +04: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 ) ;
depthSampleDistorted = linearizeDepth ( sampleRefractionDepthMap ( screenCoords - screenCoordsOffset ) , near , far ) * radialise ;
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 22:01:03 +03:00
// refraction
2023-02-25 11:03:39 -08:00
vec3 refraction = sampleRefractionMap ( screenCoords - screenCoordsOffset ) . rgb ;
2021-03-19 21:49:17 -04:00
vec3 rawRefraction = refraction ;
2019-08-30 22:01:03 +03:00
// brighten up the refraction underwater
if ( cameraPos . z < 0.0 )
refraction = clamp ( refraction * 1.5 , 0.0 , 1.0 ) ;
else
2024-02-06 10:58:40 +04: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 21:36:19 +01:00
2019-08-30 22:01:03 +03:00
// sunlight scattering
// normal for sunlight scattering
vec3 lNormal = ( 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 ) ;
lNormal = normalize ( vec3 ( - lNormal . x * bump , - lNormal . y * bump , lNormal . z ) ) ;
float sunHeight = lVec . z ;
vec3 scatterColour = mix ( SCATTER_COLOUR * vec3 ( 1.0 , 0.4 , 0.0 ) , SCATTER_COLOUR , clamp ( 1.0 - exp ( - sunHeight * SUN_EXT ) , 0.0 , 1.0 ) ) ;
vec3 lR = reflect ( lVec , lNormal ) ;
2023-10-07 00:53:07 +03:00
float lightScatter = clamp ( dot ( lVec , lNormal ) * 0.7 + 0.3 , 0.0 , 1.0 ) * clamp ( dot ( lR , vVec ) * 2.0 - 1.2 , 0.0 , 1.0 ) * SCATTER_AMOUNT * sunFade * sunSpec . a * clamp ( 1.0 - exp ( - sunHeight ) , 0.0 , 1.0 ) ;
2023-10-29 04:11:31 +03:00
gl_FragData [ 0 ] . xyz = mix ( mix ( refraction , scatterColour , lightScatter ) , reflection , fresnel ) + specular * sunSpec . rgb * sunSpec . a + rainSpecular ;
2019-08-30 22:01:03 +03:00
gl_FragData [ 0 ] . w = 1.0 ;
2021-03-19 21:49:17 -04: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 ;
2021-03-20 13:11:19 -04:00
float verticalWaterDepth = realWaterDepth * mix ( abs ( vVec . z ) , 1.0 , 0.2 ) ; // an estimate
2021-08-04 17:49:57 -07:00
float shoreOffset = verticalWaterDepth - ( normal2 . r + mix ( 0.0 , normalShoreRippleRain . r , rainIntensity ) + 0.15 ) * 8.0 ;
float fuzzFactor = min ( 1.0 , 1000.0 / surfaceDepth ) * mix ( abs ( vVec . z ) , 1.0 , 0.2 ) ;
2021-03-20 13:11:19 -04:00
shoreOffset * = fuzzFactor ;
2021-08-04 17:49:57 -07:00
shoreOffset = clamp ( mix ( shoreOffset , 1.0 , clamp ( linearDepth / WOBBLY_SHORE_FADE_DISTANCE , 0.0 , 1.0 ) ) , 0.0 , 1.0 ) ;
2021-03-19 21:49:17 -04:00
gl_FragData [ 0 ] . xyz = mix ( rawRefraction , gl_FragData [ 0 ] . xyz , shoreOffset ) ;
2015-10-26 21:36:19 +01:00
#else
2023-10-29 04:11:31 +03:00
gl_FragData [ 0 ] . xyz = mix ( reflection , waterColor , ( 1.0 - fresnel ) * 0.5 ) + specular * sunSpec . rgb * sunSpec . a + rainSpecular ;
gl_FragData [ 0 ] . w = clamp ( fresnel * 6.0 + specular * sunSpec . a , 0.0 , 1.0 ) ; //clamp(fresnel*2.0 + specular * gl_LightSource[0].specular.a, 0.0, 1.0);
2015-10-26 21:36:19 +01:00
#endif
2019-08-30 22:01:03 +03:00
2023-02-25 11:03:39 -08:00
gl_FragData [ 0 ] = applyFogAtDist ( gl_FragData [ 0 ] , radialDepth , linearDepth , far ) ;
2015-10-26 21:36:19 +01:00
2022-05-13 18:58:00 -07:00
#if !@disableNormals
2023-01-19 08:39:38 -08:00
gl_FragData [ 1 ] . rgb = normalize ( gl_NormalMatrix * normal ) * 0.5 + 0.5 ;
2022-05-13 18:58:00 -07:00
#endif
2018-06-28 17:24:36 +01:00
applyShadowDebugOverlay ( ) ;
2015-10-26 21:36:19 +01:00
}