diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 0a04954091..470ce04131 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -161,7 +161,7 @@ CSMWorld::Data::Data(ToUTF8::FromType encoding, const Files::PathContainer& data defines["radialFog"] = "0"; defines["lightingModel"] = "0"; defines["reverseZ"] = "0"; - defines["refraction_enabled"] = "0"; + defines["waterRefraction"] = "0"; for (const auto& define : shadowDefines) defines[define.first] = define.second; mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index acc8976219..dc71e455b2 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -441,7 +441,7 @@ namespace MWRender globalDefines["radialFog"] = (exponentialFog || Settings::fog().mRadialFog) ? "1" : "0"; globalDefines["exponentialFog"] = exponentialFog ? "1" : "0"; globalDefines["skyBlending"] = mSkyBlending ? "1" : "0"; - globalDefines["refraction_enabled"] = "0"; + globalDefines["waterRefraction"] = "0"; globalDefines["useGPUShader4"] = "0"; globalDefines["useOVR_multiview"] = "0"; globalDefines["numViews"] = "1"; diff --git a/apps/openmw/mwrender/ripples.cpp b/apps/openmw/mwrender/ripples.cpp index 28427c3671..d0069d8d92 100644 --- a/apps/openmw/mwrender/ripples.cpp +++ b/apps/openmw/mwrender/ripples.cpp @@ -100,7 +100,7 @@ namespace MWRender { auto& shaderManager = mResourceSystem->getSceneManager()->getShaderManager(); - Shader::ShaderManager::DefineMap defineMap = { { "ripple_map_size", std::to_string(sRTTSize) + ".0" } }; + Shader::ShaderManager::DefineMap defineMap = { { "rippleMapSize", std::to_string(sRTTSize) + ".0" } }; osg::ref_ptr vertex = shaderManager.getShader("fullscreen_tri.vert", {}, osg::Shader::VERTEX); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 62266d6e2d..a28ca0b7b7 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -700,11 +700,11 @@ namespace MWRender { // use a define map to conditionally compile the shader std::map defineMap; - defineMap["refraction_enabled"] = std::string(mRefraction ? "1" : "0"); + defineMap["waterRefraction"] = std::string(mRefraction ? "1" : "0"); const int rippleDetail = Settings::water().mRainRippleDetail; - defineMap["rain_ripple_detail"] = std::to_string(rippleDetail); - defineMap["ripple_map_world_scale"] = std::to_string(RipplesSurface::sWorldScaleFactor); - defineMap["ripple_map_size"] = std::to_string(RipplesSurface::sRTTSize) + ".0"; + defineMap["rainRippleDetail"] = std::to_string(rippleDetail); + defineMap["rippleMapWorldScale"] = std::to_string(RipplesSurface::sWorldScaleFactor); + defineMap["rippleMapSize"] = std::to_string(RipplesSurface::sRTTSize) + ".0"; defineMap["sunlightScattering"] = Settings::water().mSunlightScattering ? "1" : "0"; defineMap["wobblyShores"] = Settings::water().mWobblyShores ? "1" : "0"; diff --git a/files/shaders/compatibility/ripples_blobber.frag b/files/shaders/compatibility/ripples_blobber.frag index ea874af83e..d9cadcda98 100644 --- a/files/shaders/compatibility/ripples_blobber.frag +++ b/files/shaders/compatibility/ripples_blobber.frag @@ -13,7 +13,7 @@ uniform vec2 offset; void main() { - vec2 uv = (gl_FragCoord.xy + offset) / @ripple_map_size; + vec2 uv = (gl_FragCoord.xy + offset) / @rippleMapSize; vec4 color = texture2D(imageIn, uv); float wavesizeMultiplier = getTemporalWaveSizeMultiplier(osg_SimulationTime); diff --git a/files/shaders/compatibility/ripples_simulate.frag b/files/shaders/compatibility/ripples_simulate.frag index f36cab5b40..fb416df2c6 100644 --- a/files/shaders/compatibility/ripples_simulate.frag +++ b/files/shaders/compatibility/ripples_simulate.frag @@ -6,9 +6,9 @@ uniform sampler2D imageIn; void main() { - vec2 uv = gl_FragCoord.xy / @ripple_map_size; + vec2 uv = gl_FragCoord.xy / @rippleMapSize; - float pixelSize = 1.0 / @ripple_map_size; + float pixelSize = 1.0 / @rippleMapSize; float oneOffset = pixelSize; float oneAndHalfOffset = 1.5 * pixelSize; diff --git a/files/shaders/compatibility/water.frag b/files/shaders/compatibility/water.frag index 2debf2fac0..d1324e01bd 100644 --- a/files/shaders/compatibility/water.frag +++ b/files/shaders/compatibility/water.frag @@ -10,8 +10,6 @@ #include "lib/core/fragment.h.glsl" -#define REFRACTION @refraction_enabled - // Inspired by Blender GLSL Water by martinsh ( https://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html ) // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- @@ -20,18 +18,11 @@ const float VISIBILITY = 2500.0; const float VISIBILITY_DEPTH = VISIBILITY * 1.5; const float DEPTH_FADE = 0.15; -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; -const float MID_WAVES_RAIN_X = 0.2; -const float MID_WAVES_RAIN_Y = 0.2; - -const float SMALL_WAVES_X = 0.1; // strength of small waves -const float SMALL_WAVES_Y = 0.1; -const float SMALL_WAVES_RAIN_X = 0.3; -const float SMALL_WAVES_RAIN_Y = 0.3; +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); const float WAVE_CHOPPYNESS = 0.05; // wave choppyness const float WAVE_SCALE = 75.0; // overall wave scale @@ -133,70 +124,57 @@ void main(void) float distortionLevel = 2.0; rippleAdd += distortionLevel * vec3(texture2D(rippleMap, rippleMapUV).ba * blendFar * blendClose, 0.0); - 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); + vec2 bigWaves = BIG_WAVES; + vec2 midWaves = mix(MID_WAVES, MID_WAVES_RAIN, rainIntensity); + vec2 smallWaves = mix(SMALL_WAVES, SMALL_WAVES_RAIN, rainIntensity); float bump = mix(BUMP,BUMP_RAIN,rainIntensity); 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)); - vec3 lVec = normalize((gl_ModelViewMatrixInverse * vec4(lcalcPosition(0).xyz, 0.0)).xyz); + vec3 sunWorldDir = normalize((gl_ModelViewMatrixInverse * vec4(lcalcPosition(0).xyz, 0.0)).xyz); vec3 cameraPos = (gl_ModelViewMatrixInverse * vec4(0,0,0,1)).xyz; - vec3 vVec = normalize(position.xyz - cameraPos.xyz); + vec3 viewDir = normalize(position.xyz - cameraPos.xyz); float sunFade = length(gl_LightModel.ambient.xyz); // fresnel float ior = (cameraPos.z>0.0)?(1.333/1.0):(1.0/1.333); // air to water; water to air - float fresnel = clamp(fresnel_dielectric(vVec, normal, ior), 0.0, 1.0); - - float radialise = 1.0; - -#if @radialFog - float radialDepth = distance(position.xyz, cameraPos); - // 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; -#else - float radialDepth = 0.0; -#endif + float fresnel = clamp(fresnel_dielectric(viewDir, normal, ior), 0.0, 1.0); vec2 screenCoordsOffset = normal.xy * REFL_BUMP; -#if REFRACTION - float depthSample = linearizeDepth(sampleRefractionDepthMap(screenCoords), near, far) * radialise; - float surfaceDepth = linearizeDepth(gl_FragCoord.z, near, far) * radialise; +#if @waterRefraction + float depthSample = linearizeDepth(sampleRefractionDepthMap(screenCoords), near, far); + float surfaceDepth = linearizeDepth(gl_FragCoord.z, near, far); float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum - float depthSampleDistorted = linearizeDepth(sampleRefractionDepthMap(screenCoords - screenCoordsOffset), near, far) * radialise; + float depthSampleDistorted = linearizeDepth(sampleRefractionDepthMap(screenCoords - screenCoordsOffset), near, far); float waterDepthDistorted = max(depthSampleDistorted - surfaceDepth, 0.0); - screenCoordsOffset *= clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); + screenCoordsOffset *= clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH, 0.0, 1.0); #endif // reflection vec3 reflection = sampleReflectionMap(screenCoords + screenCoordsOffset).rgb; - // specular - float specular = pow(max(dot(reflect(vVec, normal), lVec), 0.0),SPEC_HARDNESS) * shadow; - vec3 waterColor = WATER_COLOR * sunFade; vec4 sunSpec = lcalcSpecular(0); // alpha component is sun visibility; we want to start fading lighting effects when visibility is low sunSpec.a = min(1.0, sunSpec.a / SUN_SPEC_FADING_THRESHOLD); + // specular + float specular = pow(max(dot(reflect(viewDir, normal), sunWorldDir), 0.0), SPEC_HARDNESS) * shadow * sunSpec.a; + // 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; + float waterTransparency = clamp(fresnel * 6.0 + specular, 0.0, 1.0); -#if REFRACTION - // no alpha here, so make sure raindrop ripple specularity gets properly subdued - rainSpecular *= clamp(fresnel*6.0 + specular * sunSpec.a, 0.0, 1.0); - +#if @waterRefraction // 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; + depthSampleDistorted = linearizeDepth(sampleRefractionDepthMap(screenCoords - screenCoordsOffset), near, far); waterDepthDistorted = max(depthSampleDistorted - surfaceDepth, 0.0); // fade to realWaterDepth at a distance to compensate for physically inaccurate depth calculation @@ -217,35 +195,45 @@ void main(void) } #if @sunlightScattering - // 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); - 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); + 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; + vec3 scatterColour = mix(SCATTER_COLOUR * vec3(1.0, 0.4, 0.0), SCATTER_COLOUR, max(1.0 - exp(-sunHeight * SUN_EXT), 0.0)); + 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); + float lightScatter = scatterLambert * scatterReflectAngle * SCATTER_AMOUNT * sunFade * sunSpec.a * max(1.0 - exp(-sunHeight), 0.0); refraction = mix(refraction, scatterColour, lightScatter); #endif - gl_FragData[0].xyz = mix(refraction, reflection, fresnel) + specular * sunSpec.rgb * sunSpec.a + rainSpecular; - gl_FragData[0].w = 1.0; + 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 -#if @wobblyShores + gl_FragData[0].rgb += specular * sunSpec.rgb + rainSpecular; + +#if @waterRefraction && @wobblyShores // 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; - float verticalWaterDepth = realWaterDepth * mix(abs(vVec.z), 1.0, 0.2); // an estimate + float viewFactor = mix(abs(viewDir.z), 1.0, 0.2); + float verticalWaterDepth = realWaterDepth * viewFactor; // an estimate 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); + float fuzzFactor = min(1.0, 1000.0 / surfaceDepth) * viewFactor; shoreOffset *= fuzzFactor; shoreOffset = clamp(mix(shoreOffset, 1.0, clamp(linearDepth / WOBBLY_SHORE_FADE_DISTANCE, 0.0, 1.0)), 0.0, 1.0); - gl_FragData[0].xyz = mix(rawRefraction, gl_FragData[0].xyz, shoreOffset); + gl_FragData[0].rgb = mix(rawRefraction, gl_FragData[0].rgb, shoreOffset); #endif +#if @radialFog + float radialDepth = distance(position.xyz, cameraPos); #else - 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); + float radialDepth = 0.0; #endif gl_FragData[0] = applyFogAtDist(gl_FragData[0], radialDepth, linearDepth, far); diff --git a/files/shaders/compatibility/water.vert b/files/shaders/compatibility/water.vert index 93796a7b9c..a67f412a07 100644 --- a/files/shaders/compatibility/water.vert +++ b/files/shaders/compatibility/water.vert @@ -21,7 +21,7 @@ void main(void) position = gl_Vertex; worldPos = position.xyz + nodePosition.xyz; - rippleMapUV = (worldPos.xy - playerPos.xy + (@ripple_map_size * @ripple_map_world_scale / 2.0)) / @ripple_map_size / @ripple_map_world_scale; + rippleMapUV = (worldPos.xy - playerPos.xy + (@rippleMapSize * @rippleMapWorldScale / 2.0)) / @rippleMapSize / @rippleMapWorldScale; vec4 viewPos = modelToView(gl_Vertex); linearDepth = getLinearDepth(gl_Position.z, viewPos.z); diff --git a/files/shaders/lib/core/fragment.glsl b/files/shaders/lib/core/fragment.glsl index 68fbe5e39d..9b983148cb 100644 --- a/files/shaders/lib/core/fragment.glsl +++ b/files/shaders/lib/core/fragment.glsl @@ -9,7 +9,7 @@ vec4 sampleReflectionMap(vec2 uv) return texture2D(reflectionMap, uv); } -#if @refraction_enabled +#if @waterRefraction uniform sampler2D refractionMap; uniform sampler2D refractionDepthMap; diff --git a/files/shaders/lib/core/fragment.h.glsl b/files/shaders/lib/core/fragment.h.glsl index 1bc2a1f79a..b8c3f9a32b 100644 --- a/files/shaders/lib/core/fragment.h.glsl +++ b/files/shaders/lib/core/fragment.h.glsl @@ -6,7 +6,7 @@ vec4 sampleReflectionMap(vec2 uv); -#if @refraction_enabled +#if @waterRefraction vec4 sampleRefractionMap(vec2 uv); float sampleRefractionDepthMap(vec2 uv); #endif diff --git a/files/shaders/lib/core/fragment_multiview.glsl b/files/shaders/lib/core/fragment_multiview.glsl index cc804d6c80..2880087104 100644 --- a/files/shaders/lib/core/fragment_multiview.glsl +++ b/files/shaders/lib/core/fragment_multiview.glsl @@ -12,7 +12,7 @@ vec4 sampleReflectionMap(vec2 uv) return texture(reflectionMap, vec3((uv), gl_ViewID_OVR)); } -#if @refraction_enabled +#if @waterRefraction uniform sampler2DArray refractionMap; uniform sampler2DArray refractionDepthMap; diff --git a/files/shaders/lib/water/rain_ripples.glsl b/files/shaders/lib/water/rain_ripples.glsl index 4e5f85017b..6ec3f101fe 100644 --- a/files/shaders/lib/water/rain_ripples.glsl +++ b/files/shaders/lib/water/rain_ripples.glsl @@ -1,8 +1,6 @@ #ifndef LIB_WATER_RIPPLES #define LIB_WATER_RIPPLES -#define RAIN_RIPPLE_DETAIL @rain_ripple_detail - const float RAIN_RIPPLE_GAPS = 10.0; const float RAIN_RIPPLE_RADIUS = 0.2; @@ -51,7 +49,7 @@ vec4 circle(vec2 coords, vec2 corner, float adjusted_time) float d = length(toCenter); float ringfollower = (phase-d/r)/RAIN_RING_TIME_OFFSET-1.0; // -1.0 ~ +1.0 cover the breadth of the ripple's ring -#if RAIN_RIPPLE_DETAIL > 0 +#if @rainRippleDetail > 0 // normal mapped ripples if(ringfollower < -1.0 || ringfollower > 1.0) return vec4(0.0); @@ -88,7 +86,7 @@ vec4 rain(vec2 uv, float time) vec2 f_part = fract(uv); vec2 i_part = floor(uv); float adjusted_time = time * 1.2 + randPhase(i_part); -#if RAIN_RIPPLE_DETAIL > 0 +#if @rainRippleDetail > 0 vec4 a = circle(f_part, i_part, adjusted_time); vec4 b = circle(f_part, i_part, adjusted_time - RAIN_RING_TIME_OFFSET); vec4 c = circle(f_part, i_part, adjusted_time - RAIN_RING_TIME_OFFSET*2.0); @@ -115,11 +113,11 @@ vec4 rainCombined(vec2 uv, float time) // returns ripple normal in xyz and fake return rain(uv, time) + rain(complex_mult(uv, vec2(0.4, 0.7)) + vec2(1.2, 3.0),time) - #if RAIN_RIPPLE_DETAIL == 2 +#if @rainRippleDetail == 2 + rain(uv * 0.75 + vec2( 3.7,18.9),time) + rain(uv * 0.9 + vec2( 5.7,30.1),time) + rain(uv * 1.0 + vec2(10.5 ,5.7),time) - #endif +#endif ; }