forked from Mirrorlandia_minetest/minetest
31578303a4
* Pass perspective distortion parameters as uniforms * Set all perspective bias parameters via ShadowRenderer * Recalibrate perspective distortion and shadow range to render less shadow geometry with the same quality and observed shadow distance
546 lines
16 KiB
GLSL
546 lines
16 KiB
GLSL
uniform sampler2D baseTexture;
|
|
|
|
uniform vec4 emissiveColor;
|
|
uniform vec3 dayLight;
|
|
uniform vec4 skyBgColor;
|
|
uniform float fogDistance;
|
|
uniform vec3 eyePosition;
|
|
|
|
varying vec3 vNormal;
|
|
varying vec3 vPosition;
|
|
varying vec3 worldPosition;
|
|
varying lowp vec4 varColor;
|
|
#ifdef GL_ES
|
|
varying mediump vec2 varTexCoord;
|
|
#else
|
|
centroid varying vec2 varTexCoord;
|
|
#endif
|
|
|
|
varying vec3 eyeVec;
|
|
varying float nightRatio;
|
|
|
|
varying float vIDiff;
|
|
|
|
const float e = 2.718281828459;
|
|
const float BS = 10.0;
|
|
const float fogStart = FOG_START;
|
|
const float fogShadingParameter = 1.0 / (1.0 - fogStart);
|
|
|
|
#ifdef ENABLE_DYNAMIC_SHADOWS
|
|
// shadow texture
|
|
uniform sampler2D ShadowMapSampler;
|
|
// shadow uniforms
|
|
uniform vec3 v_LightDirection;
|
|
uniform float f_textureresolution;
|
|
uniform mat4 m_ShadowViewProj;
|
|
uniform float f_shadowfar;
|
|
uniform float f_timeofday;
|
|
uniform float f_shadow_strength;
|
|
varying float normalOffsetScale;
|
|
varying float adj_shadow_strength;
|
|
varying float cosLight;
|
|
varying float f_normal_length;
|
|
#endif
|
|
|
|
#ifdef ENABLE_DYNAMIC_SHADOWS
|
|
uniform float xyPerspectiveBias0;
|
|
uniform float xyPerspectiveBias1;
|
|
uniform float zPerspectiveBias;
|
|
|
|
vec4 getPerspectiveFactor(in vec4 shadowPosition)
|
|
{
|
|
|
|
float pDistance = length(shadowPosition.xy);
|
|
float pFactor = pDistance * xyPerspectiveBias0 + xyPerspectiveBias1;
|
|
|
|
shadowPosition.xyz *= vec3(vec2(1.0 / pFactor), zPerspectiveBias);
|
|
|
|
return shadowPosition;
|
|
}
|
|
|
|
vec3 getLightSpacePosition()
|
|
{
|
|
vec4 pLightSpace;
|
|
// some drawtypes have zero normals, so we need to handle it :(
|
|
#if DRAW_TYPE == NDT_PLANTLIKE
|
|
pLightSpace = m_ShadowViewProj * vec4(worldPosition, 1.0);
|
|
#else
|
|
pLightSpace = m_ShadowViewProj * vec4(worldPosition + normalOffsetScale * normalize(vNormal), 1.0);
|
|
#endif
|
|
pLightSpace = getPerspectiveFactor(pLightSpace);
|
|
return pLightSpace.xyz * 0.5 + 0.5;
|
|
}
|
|
// custom smoothstep implementation because it's not defined in glsl1.2
|
|
// https://docs.gl/sl4/smoothstep
|
|
float mtsmoothstep(in float edge0, in float edge1, in float x)
|
|
{
|
|
float t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
|
|
return t * t * (3.0 - 2.0 * t);
|
|
}
|
|
|
|
#ifdef COLORED_SHADOWS
|
|
|
|
// c_precision of 128 fits within 7 base-10 digits
|
|
const float c_precision = 128.0;
|
|
const float c_precisionp1 = c_precision + 1.0;
|
|
|
|
float packColor(vec3 color)
|
|
{
|
|
return floor(color.b * c_precision + 0.5)
|
|
+ floor(color.g * c_precision + 0.5) * c_precisionp1
|
|
+ floor(color.r * c_precision + 0.5) * c_precisionp1 * c_precisionp1;
|
|
}
|
|
|
|
vec3 unpackColor(float value)
|
|
{
|
|
vec3 color;
|
|
color.b = mod(value, c_precisionp1) / c_precision;
|
|
color.g = mod(floor(value / c_precisionp1), c_precisionp1) / c_precision;
|
|
color.r = floor(value / (c_precisionp1 * c_precisionp1)) / c_precision;
|
|
return color;
|
|
}
|
|
|
|
vec4 getHardShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|
{
|
|
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy).rgba;
|
|
|
|
float visibility = step(0.0, realDistance - texDepth.r);
|
|
vec4 result = vec4(visibility, vec3(0.0,0.0,0.0));//unpackColor(texDepth.g));
|
|
if (visibility < 0.1) {
|
|
visibility = step(0.0, realDistance - texDepth.b);
|
|
result = vec4(visibility, unpackColor(texDepth.a));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
#else
|
|
|
|
float getHardShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|
{
|
|
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
|
|
float visibility = step(0.0, realDistance - texDepth);
|
|
return visibility;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
#if SHADOW_FILTER == 2
|
|
#define PCFBOUND 3.5
|
|
#define PCFSAMPLES 64.0
|
|
#elif SHADOW_FILTER == 1
|
|
#define PCFBOUND 1.5
|
|
#if defined(POISSON_FILTER)
|
|
#define PCFSAMPLES 32.0
|
|
#else
|
|
#define PCFSAMPLES 16.0
|
|
#endif
|
|
#else
|
|
#define PCFBOUND 0.0
|
|
#if defined(POISSON_FILTER)
|
|
#define PCFSAMPLES 4.0
|
|
#else
|
|
#define PCFSAMPLES 1.0
|
|
#endif
|
|
#endif
|
|
#ifdef COLORED_SHADOWS
|
|
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|
{
|
|
vec4 texDepth = texture2D(shadowsampler, smTexCoord.xy);
|
|
float depth = max(realDistance - texDepth.r, realDistance - texDepth.b);
|
|
return depth;
|
|
}
|
|
#else
|
|
float getHardShadowDepth(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|
{
|
|
float texDepth = texture2D(shadowsampler, smTexCoord.xy).r;
|
|
float depth = realDistance - texDepth;
|
|
return depth;
|
|
}
|
|
#endif
|
|
|
|
float getBaseLength(vec2 smTexCoord)
|
|
{
|
|
float l = length(2.0 * smTexCoord.xy - 1.0); // length in texture coords
|
|
return xyPerspectiveBias1 / (1.0 / l - xyPerspectiveBias0); // return to undistorted coords
|
|
}
|
|
|
|
float getDeltaPerspectiveFactor(float l)
|
|
{
|
|
return 0.1 / (xyPerspectiveBias0 * l + xyPerspectiveBias1); // original distortion factor, divided by 10
|
|
}
|
|
|
|
float getPenumbraRadius(sampler2D shadowsampler, vec2 smTexCoord, float realDistance, float multiplier)
|
|
{
|
|
float baseLength = getBaseLength(smTexCoord);
|
|
float perspectiveFactor;
|
|
|
|
// Return fast if sharp shadows are requested
|
|
if (PCFBOUND == 0.0)
|
|
return 0.0;
|
|
|
|
if (SOFTSHADOWRADIUS <= 1.0) {
|
|
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
|
return max(2 * length(smTexCoord.xy) * 2048 / f_textureresolution / pow(perspectiveFactor, 3), SOFTSHADOWRADIUS);
|
|
}
|
|
|
|
vec2 clampedpos;
|
|
float texture_size = 1.0 / (2048 /*f_textureresolution*/ * 0.5);
|
|
float y, x;
|
|
float depth = 0.0;
|
|
float pointDepth;
|
|
float maxRadius = SOFTSHADOWRADIUS * 5.0 * multiplier;
|
|
|
|
float bound = clamp(PCFBOUND * (1 - baseLength), 0.0, PCFBOUND);
|
|
int n = 0;
|
|
|
|
for (y = -bound; y <= bound; y += 1.0)
|
|
for (x = -bound; x <= bound; x += 1.0) {
|
|
clampedpos = vec2(x,y);
|
|
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * maxRadius);
|
|
clampedpos = clampedpos * texture_size * perspectiveFactor * maxRadius * perspectiveFactor + smTexCoord.xy;
|
|
|
|
pointDepth = getHardShadowDepth(shadowsampler, clampedpos.xy, realDistance);
|
|
if (pointDepth > -0.01) {
|
|
depth += pointDepth;
|
|
n += 1;
|
|
}
|
|
}
|
|
|
|
depth = depth / n;
|
|
depth = pow(clamp(depth, 0.0, 1000.0), 1.6) / 0.001;
|
|
|
|
perspectiveFactor = getDeltaPerspectiveFactor(baseLength);
|
|
return max(length(smTexCoord.xy) * 2 * 2048 / f_textureresolution / pow(perspectiveFactor, 3), depth * maxRadius);
|
|
}
|
|
|
|
#ifdef POISSON_FILTER
|
|
const vec2[64] poissonDisk = vec2[64](
|
|
vec2(0.170019, -0.040254),
|
|
vec2(-0.299417, 0.791925),
|
|
vec2(0.645680, 0.493210),
|
|
vec2(-0.651784, 0.717887),
|
|
vec2(0.421003, 0.027070),
|
|
vec2(-0.817194, -0.271096),
|
|
vec2(-0.705374, -0.668203),
|
|
vec2(0.977050, -0.108615),
|
|
vec2(0.063326, 0.142369),
|
|
vec2(0.203528, 0.214331),
|
|
vec2(-0.667531, 0.326090),
|
|
vec2(-0.098422, -0.295755),
|
|
vec2(-0.885922, 0.215369),
|
|
vec2(0.566637, 0.605213),
|
|
vec2(0.039766, -0.396100),
|
|
vec2(0.751946, 0.453352),
|
|
vec2(0.078707, -0.715323),
|
|
vec2(-0.075838, -0.529344),
|
|
vec2(0.724479, -0.580798),
|
|
vec2(0.222999, -0.215125),
|
|
vec2(-0.467574, -0.405438),
|
|
vec2(-0.248268, -0.814753),
|
|
vec2(0.354411, -0.887570),
|
|
vec2(0.175817, 0.382366),
|
|
vec2(0.487472, -0.063082),
|
|
vec2(0.355476, 0.025357),
|
|
vec2(-0.084078, 0.898312),
|
|
vec2(0.488876, -0.783441),
|
|
vec2(0.470016, 0.217933),
|
|
vec2(-0.696890, -0.549791),
|
|
vec2(-0.149693, 0.605762),
|
|
vec2(0.034211, 0.979980),
|
|
vec2(0.503098, -0.308878),
|
|
vec2(-0.016205, -0.872921),
|
|
vec2(0.385784, -0.393902),
|
|
vec2(-0.146886, -0.859249),
|
|
vec2(0.643361, 0.164098),
|
|
vec2(0.634388, -0.049471),
|
|
vec2(-0.688894, 0.007843),
|
|
vec2(0.464034, -0.188818),
|
|
vec2(-0.440840, 0.137486),
|
|
vec2(0.364483, 0.511704),
|
|
vec2(0.034028, 0.325968),
|
|
vec2(0.099094, -0.308023),
|
|
vec2(0.693960, -0.366253),
|
|
vec2(0.678884, -0.204688),
|
|
vec2(0.001801, 0.780328),
|
|
vec2(0.145177, -0.898984),
|
|
vec2(0.062655, -0.611866),
|
|
vec2(0.315226, -0.604297),
|
|
vec2(-0.780145, 0.486251),
|
|
vec2(-0.371868, 0.882138),
|
|
vec2(0.200476, 0.494430),
|
|
vec2(-0.494552, -0.711051),
|
|
vec2(0.612476, 0.705252),
|
|
vec2(-0.578845, -0.768792),
|
|
vec2(-0.772454, -0.090976),
|
|
vec2(0.504440, 0.372295),
|
|
vec2(0.155736, 0.065157),
|
|
vec2(0.391522, 0.849605),
|
|
vec2(-0.620106, -0.328104),
|
|
vec2(0.789239, -0.419965),
|
|
vec2(-0.545396, 0.538133),
|
|
vec2(-0.178564, -0.596057)
|
|
);
|
|
|
|
#ifdef COLORED_SHADOWS
|
|
|
|
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|
{
|
|
vec2 clampedpos;
|
|
vec4 visibility = vec4(0.0);
|
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
|
|
if (radius < 0.1) {
|
|
// we are in the middle of even brightness, no need for filtering
|
|
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
|
}
|
|
|
|
float baseLength = getBaseLength(smTexCoord);
|
|
float perspectiveFactor;
|
|
|
|
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
|
int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
|
|
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
|
int end_offset = int(samples) + init_offset;
|
|
|
|
for (int x = init_offset; x < end_offset; x++) {
|
|
clampedpos = poissonDisk[x];
|
|
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
|
|
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
|
|
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
|
}
|
|
|
|
return visibility / samples;
|
|
}
|
|
|
|
#else
|
|
|
|
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|
{
|
|
vec2 clampedpos;
|
|
float visibility = 0.0;
|
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.5); // scale to align with PCF
|
|
if (radius < 0.1) {
|
|
// we are in the middle of even brightness, no need for filtering
|
|
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
|
}
|
|
|
|
float baseLength = getBaseLength(smTexCoord);
|
|
float perspectiveFactor;
|
|
|
|
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
|
int samples = int(clamp(PCFSAMPLES * (1 - baseLength) * (1 - baseLength), PCFSAMPLES / 4, PCFSAMPLES));
|
|
int init_offset = int(floor(mod(((smTexCoord.x * 34.0) + 1.0) * smTexCoord.y, 64.0-samples)));
|
|
int end_offset = int(samples) + init_offset;
|
|
|
|
for (int x = init_offset; x < end_offset; x++) {
|
|
clampedpos = poissonDisk[x];
|
|
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius);
|
|
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor + smTexCoord.xy;
|
|
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
|
}
|
|
|
|
return visibility / samples;
|
|
}
|
|
|
|
#endif
|
|
|
|
#else
|
|
/* poisson filter disabled */
|
|
|
|
#ifdef COLORED_SHADOWS
|
|
|
|
vec4 getShadowColor(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|
{
|
|
vec2 clampedpos;
|
|
vec4 visibility = vec4(0.0);
|
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
|
|
if (radius < 0.1) {
|
|
// we are in the middle of even brightness, no need for filtering
|
|
return getHardShadowColor(shadowsampler, smTexCoord.xy, realDistance);
|
|
}
|
|
|
|
float baseLength = getBaseLength(smTexCoord);
|
|
float perspectiveFactor;
|
|
|
|
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
|
float y, x;
|
|
float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
|
|
int n = 0;
|
|
|
|
// basic PCF filter
|
|
for (y = -bound; y <= bound; y += 1.0)
|
|
for (x = -bound; x <= bound; x += 1.0) {
|
|
clampedpos = vec2(x,y); // screen offset
|
|
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
|
|
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
|
|
visibility += getHardShadowColor(shadowsampler, clampedpos.xy, realDistance);
|
|
n += 1;
|
|
}
|
|
|
|
return visibility / n;
|
|
}
|
|
|
|
#else
|
|
float getShadow(sampler2D shadowsampler, vec2 smTexCoord, float realDistance)
|
|
{
|
|
vec2 clampedpos;
|
|
float visibility = 0.0;
|
|
float radius = getPenumbraRadius(shadowsampler, smTexCoord, realDistance, 1.0);
|
|
if (radius < 0.1) {
|
|
// we are in the middle of even brightness, no need for filtering
|
|
return getHardShadow(shadowsampler, smTexCoord.xy, realDistance);
|
|
}
|
|
|
|
float baseLength = getBaseLength(smTexCoord);
|
|
float perspectiveFactor;
|
|
|
|
float texture_size = 1.0 / (f_textureresolution * 0.5);
|
|
float y, x;
|
|
float bound = clamp(PCFBOUND * (1 - baseLength), PCFBOUND / 2, PCFBOUND);
|
|
int n = 0;
|
|
|
|
// basic PCF filter
|
|
for (y = -bound; y <= bound; y += 1.0)
|
|
for (x = -bound; x <= bound; x += 1.0) {
|
|
clampedpos = vec2(x,y); // screen offset
|
|
perspectiveFactor = getDeltaPerspectiveFactor(baseLength + length(clampedpos) * texture_size * radius / bound);
|
|
clampedpos = clampedpos * texture_size * perspectiveFactor * radius * perspectiveFactor / bound + smTexCoord.xy; // both dx,dy and radius are adjusted
|
|
visibility += getHardShadow(shadowsampler, clampedpos.xy, realDistance);
|
|
n += 1;
|
|
}
|
|
|
|
return visibility / n;
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|
|
#endif
|
|
|
|
#if ENABLE_TONE_MAPPING
|
|
/* Hable's UC2 Tone mapping parameters
|
|
A = 0.22;
|
|
B = 0.30;
|
|
C = 0.10;
|
|
D = 0.20;
|
|
E = 0.01;
|
|
F = 0.30;
|
|
W = 11.2;
|
|
equation used: ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F
|
|
*/
|
|
|
|
vec3 uncharted2Tonemap(vec3 x)
|
|
{
|
|
return ((x * (0.22 * x + 0.03) + 0.002) / (x * (0.22 * x + 0.3) + 0.06)) - 0.03333;
|
|
}
|
|
|
|
vec4 applyToneMapping(vec4 color)
|
|
{
|
|
color = vec4(pow(color.rgb, vec3(2.2)), color.a);
|
|
const float gamma = 1.6;
|
|
const float exposureBias = 5.5;
|
|
color.rgb = uncharted2Tonemap(exposureBias * color.rgb);
|
|
// Precalculated white_scale from
|
|
//vec3 whiteScale = 1.0 / uncharted2Tonemap(vec3(W));
|
|
vec3 whiteScale = vec3(1.036015346);
|
|
color.rgb *= whiteScale;
|
|
return vec4(pow(color.rgb, vec3(1.0 / gamma)), color.a);
|
|
}
|
|
#endif
|
|
|
|
void main(void)
|
|
{
|
|
vec3 color;
|
|
vec2 uv = varTexCoord.st;
|
|
vec4 base = texture2D(baseTexture, uv).rgba;
|
|
|
|
// If alpha is zero, we can just discard the pixel. This fixes transparency
|
|
// on GPUs like GC7000L, where GL_ALPHA_TEST is not implemented in mesa,
|
|
// and also on GLES 2, where GL_ALPHA_TEST is missing entirely.
|
|
#ifdef USE_DISCARD
|
|
if (base.a == 0.0)
|
|
discard;
|
|
#endif
|
|
#ifdef USE_DISCARD_REF
|
|
if (base.a < 0.5)
|
|
discard;
|
|
#endif
|
|
|
|
color = base.rgb;
|
|
vec4 col = vec4(color.rgb, base.a);
|
|
col.rgb *= varColor.rgb;
|
|
col.rgb *= vIDiff;
|
|
|
|
#ifdef ENABLE_DYNAMIC_SHADOWS
|
|
if (f_shadow_strength > 0.0) {
|
|
float shadow_int = 0.0;
|
|
vec3 shadow_color = vec3(0.0, 0.0, 0.0);
|
|
vec3 posLightSpace = getLightSpacePosition();
|
|
|
|
float distance_rate = (1 - pow(clamp(2.0 * length(posLightSpace.xy - 0.5),0.0,1.0), 50.0));
|
|
float f_adj_shadow_strength = max(adj_shadow_strength-mtsmoothstep(0.9,1.1, posLightSpace.z),0.0);
|
|
|
|
if (distance_rate > 1e-7) {
|
|
|
|
#ifdef COLORED_SHADOWS
|
|
vec4 visibility;
|
|
if (cosLight > 0.0)
|
|
visibility = getShadowColor(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
|
|
else
|
|
visibility = vec4(1.0, 0.0, 0.0, 0.0);
|
|
shadow_int = visibility.r;
|
|
shadow_color = visibility.gba;
|
|
#else
|
|
if (cosLight > 0.0)
|
|
shadow_int = getShadow(ShadowMapSampler, posLightSpace.xy, posLightSpace.z);
|
|
else
|
|
shadow_int = 1.0;
|
|
#endif
|
|
shadow_int *= distance_rate;
|
|
shadow_int = clamp(shadow_int, 0.0, 1.0);
|
|
|
|
}
|
|
|
|
// turns out that nightRatio falls off much faster than
|
|
// actual brightness of artificial light in relation to natual light.
|
|
// Power ratio was measured on torches in MTG (brightness = 14).
|
|
float adjusted_night_ratio = pow(max(0.0, nightRatio), 0.6);
|
|
|
|
// cosine of the normal-to-light angle when
|
|
// we start to apply self-shadowing
|
|
const float self_shadow_cutoff_cosine = 0.14;
|
|
if (f_normal_length != 0 && cosLight < self_shadow_cutoff_cosine) {
|
|
shadow_int = max(shadow_int, 1 - clamp(cosLight, 0.0, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
|
|
shadow_color = mix(vec3(0.0), shadow_color, min(cosLight, self_shadow_cutoff_cosine)/self_shadow_cutoff_cosine);
|
|
}
|
|
|
|
shadow_int *= f_adj_shadow_strength;
|
|
|
|
// calculate fragment color from components:
|
|
col.rgb =
|
|
adjusted_night_ratio * col.rgb + // artificial light
|
|
(1.0 - adjusted_night_ratio) * ( // natural light
|
|
col.rgb * (1.0 - shadow_int * (1.0 - shadow_color)) + // filtered texture color
|
|
dayLight * shadow_color * shadow_int); // reflected filtered sunlight/moonlight
|
|
}
|
|
#endif
|
|
|
|
#if ENABLE_TONE_MAPPING
|
|
col = applyToneMapping(col);
|
|
#endif
|
|
|
|
// Due to a bug in some (older ?) graphics stacks (possibly in the glsl compiler ?),
|
|
// the fog will only be rendered correctly if the last operation before the
|
|
// clamp() is an addition. Else, the clamp() seems to be ignored.
|
|
// E.g. the following won't work:
|
|
// float clarity = clamp(fogShadingParameter
|
|
// * (fogDistance - length(eyeVec)) / fogDistance), 0.0, 1.0);
|
|
// As additions usually come for free following a multiplication, the new formula
|
|
// should be more efficient as well.
|
|
// Note: clarity = (1 - fogginess)
|
|
float clarity = clamp(fogShadingParameter
|
|
- fogShadingParameter * length(eyeVec) / fogDistance, 0.0, 1.0);
|
|
col = mix(skyBgColor, col, clarity);
|
|
gl_FragColor = vec4(col.rgb, base.a);
|
|
}
|