From 2346c5338e93effffdaa6c281ef4c07ede421763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Wed, 20 Sep 2017 16:34:27 +0200 Subject: [PATCH 1/9] increase water fudge to get rid of artifacts --- apps/openmw/mwrender/water.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 0ed389bdf..2329e7afa 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; + const float clipFudge = -30; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); @@ -336,8 +336,7 @@ public: void setWaterLevel(float waterLevel) { - setViewMatrix(osg::Matrix::translate(0,0,-waterLevel) * osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,waterLevel)); - + setViewMatrix(osg::Matrix::scale(1,1,-1) * osg::Matrix::translate(0,0,2 * waterLevel)); mClipCullNode->setPlane(osg::Plane(osg::Vec3d(0,0,1), osg::Vec3d(0,0,waterLevel))); } From 16d9773c6c75e2069104da1302d3a31a3620a7c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:25:36 +0200 Subject: [PATCH 2/9] fix water shader artifacts at shores --- apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 29 ++++++++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 2329e7afa..68c07c1ab 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -30; + const float clipFudge = -5; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index c04233fcf..b5d7d1a6a 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,6 +31,8 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness +const float REFLECTION_BUMP_SUPRESS_DEPTH = 150.0; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) + const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -74,6 +76,13 @@ uniform float near; uniform float far; uniform vec3 nodePosition; +float transformDepth(float depth) // helper for transforming refraction depth + { + float z_n = 2.0 * depth - 1.0; + depth = 2.0 * near * far / (far + near - z_n * (far - near)); + return depth - depthPassthrough; + } + void main(void) { vec3 worldPos = position.xyz + nodePosition.xyz; @@ -147,8 +156,12 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); + float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); + + float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPRESS_DEPTH,0,1); + // reflection - vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP)).rgb; + vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; // refraction #if REFRACTION @@ -165,10 +178,7 @@ void main(void) vec3 waterColor = WATER_COLOR; waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float refractionDepth = texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x; - float z_n = 2.0 * refractionDepth - 1.0; - refractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); - + float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); float waterDepth = refractionDepth - depthPassthrough; if (cameraPos.z > 0.0) @@ -185,6 +195,15 @@ void main(void) #if REFRACTION gl_FragData[0].w = 1.0; + +/*float nonRefractionDepth = texture2D(refractionDepthMap, screenCoords).x; +z_n = 2.0 * nonRefractionDepth - 1.0; +nonRefractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); + +float realWaterDepth = nonRefractionDepth - depthPassthrough; +*/ +//gl_FragData[0] = vec4(refractionSuppressor,0,0,0); + #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif From c43baf6e946efa4a4baf25e1aba048a3d660abbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:31:26 +0200 Subject: [PATCH 3/9] remove commented code --- files/shaders/water_fragment.glsl | 9 --------- 1 file changed, 9 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index b5d7d1a6a..6e4edfb84 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -195,15 +195,6 @@ void main(void) #if REFRACTION gl_FragData[0].w = 1.0; - -/*float nonRefractionDepth = texture2D(refractionDepthMap, screenCoords).x; -z_n = 2.0 * nonRefractionDepth - 1.0; -nonRefractionDepth = 2.0 * near * far / (far + near - z_n * (far - near)); - -float realWaterDepth = nonRefractionDepth - depthPassthrough; -*/ -//gl_FragData[0] = vec4(refractionSuppressor,0,0,0); - #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); #endif From 658fa0fdae4039714bd7563a2312c82c9db9124a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Thu, 21 Sep 2017 22:33:57 +0200 Subject: [PATCH 4/9] fix typo --- files/shaders/water_fragment.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 6e4edfb84..867a24a70 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPRESS_DEPTH = 150.0; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float REFLECTION_BUMP_SUPPRESS_DEPTH = 150; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -158,7 +158,7 @@ void main(void) float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPRESS_DEPTH,0,1); + float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; From 8df79625e8d691109ea8dc0e53500d769ebe8373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 10:53:02 +0200 Subject: [PATCH 5/9] fix water shader --- apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 68c07c1ab..9679533be 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; + const float clipFudge = -6; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 867a24a70..bb56e95c6 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -76,7 +76,7 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float transformDepth(float depth) // helper for transforming refraction depth +float transformDepth(float depth) // helper for transforming water depth { float z_n = 2.0 * depth - 1.0; depth = 2.0 * near * far / (far + near - z_n * (far - near)); @@ -156,27 +156,30 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); +#if REFRACTION float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); +#else + float shore = 1.0; +#endif // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; // refraction #if REFRACTION - vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP)).rgb; + vec3 refraction = texture2D(refractionMap, screenCoords-(normal.xy*REFR_BUMP*shore)).rgb; // brighten up the refraction underwater refraction = (cameraPos.z < 0.0) ? clamp(refraction * 1.5, 0.0, 1.0) : refraction; #endif - // specular vec3 R = reflect(vVec, normal); float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS) * shadow; vec3 waterColor = WATER_COLOR; waterColor = waterColor * length(gl_LightModel.ambient.xyz); + #if REFRACTION float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); float waterDepth = refractionDepth - depthPassthrough; From f274bc84cc16fd3f7e8519421a3807751c6b8a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:03:09 +0200 Subject: [PATCH 6/9] fix depth computation in water shader --- files/shaders/water_fragment.glsl | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index bb56e95c6..88ca33335 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPPRESS_DEPTH = 150; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float REFLECTION_BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -76,7 +76,7 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float transformDepth(float depth) // helper for transforming water depth +float linearizeDepth(float depth) // helper for transforming water depth { float z_n = 2.0 * depth - 1.0; depth = 2.0 * near * far / (far + near - z_n * (far - near)); @@ -157,12 +157,11 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); #if REFRACTION - float realWaterDepth = transformDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / REFLECTION_BUMP_SUPPRESS_DEPTH,0,1); + float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); + float shore = clamp(realWaterDepth / (REFLECTION_BUMP_SUPPRESS_DEPTH * (far - near)),0,1); #else float shore = 1.0; #endif - // reflection vec3 reflection = texture2D(reflectionMap, screenCoords+(normal.xy*REFL_BUMP*shore)).rgb; @@ -181,8 +180,7 @@ void main(void) waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float refractionDepth = transformDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); - float waterDepth = refractionDepth - depthPassthrough; + float waterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); if (cameraPos.z > 0.0) refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); @@ -200,5 +198,5 @@ void main(void) gl_FragData[0].w = 1.0; #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); -#endif +#endi } From 28f58d5a3251c8ab21792674979d24ee64d601d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:06:03 +0200 Subject: [PATCH 7/9] add deleted letter in macro --- files/shaders/water_fragment.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 88ca33335..db319ac70 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -198,5 +198,5 @@ void main(void) gl_FragData[0].w = 1.0; #else gl_FragData[0].w = clamp(fresnel*2.0 + specular, 0.0, 1.0); -#endi +#endif } From 9dececcbd25ddcd67394cd0b1f59bc138c18a178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Fri, 22 Sep 2017 21:10:05 +0200 Subject: [PATCH 8/9] rename a constant in water shader --- files/shaders/water_fragment.glsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index db319ac70..1e3a1e17b 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float REFLECTION_BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bump map will be supressed for reflections (prevents artifacts at shores) +const float BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -158,7 +158,7 @@ void main(void) #if REFRACTION float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / (REFLECTION_BUMP_SUPPRESS_DEPTH * (far - near)),0,1); + float shore = clamp(realWaterDepth / (BUMP_SUPPRESS_DEPTH * (far - near)),0,1); #else float shore = 1.0; #endif From cde2c1390002ac631f1279b5950770fd87b025c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20=C4=8C=C3=AD=C5=BE?= Date: Tue, 26 Sep 2017 14:14:28 +0200 Subject: [PATCH 9/9] make water depth independent of view frustum --- apps/openmw/mwrender/renderingmanager.cpp | 8 +++++- apps/openmw/mwrender/renderingmanager.hpp | 3 +++ apps/openmw/mwrender/water.cpp | 2 +- files/shaders/water_fragment.glsl | 32 ++++++++++++++--------- 4 files changed, 30 insertions(+), 15 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5c22de12e..3a66c264b 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -279,11 +279,14 @@ namespace MWRender mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "Camera"); mFirstPersonFieldOfView = Settings::Manager::getFloat("first person field of view", "Camera"); - updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); + + mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near"); + mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far"); + updateProjectionMatrix(); } RenderingManager::~RenderingManager() @@ -889,6 +892,9 @@ namespace MWRender if (mFieldOfViewOverridden) fov = mFieldOfViewOverride; mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); + + mUniformNear->set(mNearClip); + mUniformFar->set(mViewDistance); } void RenderingManager::updateTextureFiltering() diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e575456d9..f0087e43d 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -83,6 +83,9 @@ namespace MWRender SceneUtil::UnrefQueue* getUnrefQueue(); Terrain::World* getTerrain(); + osg::Uniform* mUniformNear; + osg::Uniform* mUniformFar; + void preloadCommonAssets(); double getReferenceTime() const; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 9679533be..68c07c1ab 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -112,7 +112,7 @@ class ClipCullNode : public osg::Group } // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -6; + const float clipFudge = -5; modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index 1e3a1e17b..9c8e56191 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -6,7 +6,7 @@ // tweakables -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -const float VISIBILITY = 1200.0; // how far you can look through water +const float VISIBILITY = 2.5; const float BIG_WAVES_X = 0.1; // strength of big waves const float BIG_WAVES_Y = 0.1; @@ -31,7 +31,7 @@ const vec3 SUN_EXT = vec3(0.45, 0.55, 0.68); //sunlight extinction const float SPEC_HARDNESS = 256.0; // specular highlights hardness -const float BUMP_SUPPRESS_DEPTH = 0.03; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) +const float BUMP_SUPPRESS_DEPTH = 0.3; // at what water depth bumpmap will be supressed for reflections and refractions (prevents artifacts at shores) const vec2 WIND_DIR = vec2(0.5f, -0.8f); const float WIND_SPEED = 0.2f; @@ -58,9 +58,9 @@ float fresnel_dielectric(vec3 Incoming, vec3 Normal, float eta) return result; } -varying vec3 screenCoordsPassthrough; -varying vec4 position; -varying float depthPassthrough; +varying vec3 screenCoordsPassthrough; +varying vec4 position; +varying float depthPassthrough; uniform sampler2D normalMap; @@ -76,15 +76,18 @@ uniform float near; uniform float far; uniform vec3 nodePosition; -float linearizeDepth(float depth) // helper for transforming water depth +float frustumDepth; + +float linearizeDepth(float depth) // takes <0,1> non-linear depth value and returns <0,1> linearized value { float z_n = 2.0 * depth - 1.0; - depth = 2.0 * near * far / (far + near - z_n * (far - near)); - return depth - depthPassthrough; + depth = 2.0 * near * far / (far + near - z_n * frustumDepth); + return depth / frustumDepth; } void main(void) { + frustumDepth = abs(far - near); vec3 worldPos = position.xyz + nodePosition.xyz; vec2 UV = worldPos.xy / (8192.0*5.0) * 3.0; UV.y *= -1.0; @@ -157,8 +160,13 @@ void main(void) fresnel = clamp(fresnel, 0.0, 1.0); #if REFRACTION - float realWaterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords).x); - float shore = clamp(realWaterDepth / (BUMP_SUPPRESS_DEPTH * (far - near)),0,1); + float normalization = frustumDepth / 1000; + float depthSample = linearizeDepth(texture2D(refractionDepthMap,screenCoords).x) * normalization; + float depthSampleDistorted = linearizeDepth(texture2D(refractionDepthMap,screenCoords-(normal.xy*REFR_BUMP)).x) * normalization; + float surfaceDepth = linearizeDepth(gl_FragCoord.z) * normalization; + float realWaterDepth = depthSample - surfaceDepth; // undistorted water depth in view direction, independent of frustum + + float shore = clamp(realWaterDepth / BUMP_SUPPRESS_DEPTH,0,1); #else float shore = 1.0; #endif @@ -180,10 +188,8 @@ void main(void) waterColor = waterColor * length(gl_LightModel.ambient.xyz); #if REFRACTION - float waterDepth = linearizeDepth(texture2D(refractionDepthMap, screenCoords-(normal.xy*REFR_BUMP)).x); - if (cameraPos.z > 0.0) - refraction = mix(refraction, waterColor, clamp(waterDepth/VISIBILITY, 0.0, 1.0)); + refraction = mix(refraction, waterColor, clamp(depthSampleDistorted/VISIBILITY, 0.0, 1.0)); gl_FragData[0].xyz = mix( mix(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * gl_LightSource[0].specular.xyz; #else