forked from Mirrorlandia_minetest/minetest
76 lines
2.5 KiB
Plaintext
76 lines
2.5 KiB
Plaintext
|
#define exposure texture0
|
||
|
#define screen texture1
|
||
|
|
||
|
struct ExposureParams {
|
||
|
float luminanceMin;
|
||
|
float luminanceMax;
|
||
|
float exposureCorrection;
|
||
|
float luminanceKey;
|
||
|
float speedDarkBright;
|
||
|
float speedBrightDark;
|
||
|
float centerWeightPower;
|
||
|
float compensationFactor;
|
||
|
};
|
||
|
|
||
|
uniform sampler2D exposure;
|
||
|
uniform sampler2D screen;
|
||
|
|
||
|
#ifdef ENABLE_BLOOM
|
||
|
uniform float bloomStrength;
|
||
|
#else
|
||
|
const float bloomStrength = 1.0;
|
||
|
#endif
|
||
|
uniform ExposureParams exposureParams;
|
||
|
uniform float animationTimerDelta;
|
||
|
|
||
|
|
||
|
const vec3 luminanceFactors = vec3(0.213, 0.715, 0.072);
|
||
|
|
||
|
float getLuminance(vec3 color)
|
||
|
{
|
||
|
return dot(color, luminanceFactors);
|
||
|
}
|
||
|
|
||
|
void main(void)
|
||
|
{
|
||
|
float previousExposure = texture2D(exposure, vec2(0.5, 0.5)).r;
|
||
|
|
||
|
vec3 averageColor = vec3(0.);
|
||
|
float n = 0.;
|
||
|
|
||
|
// Scan the screen with center-weighting and sample average color
|
||
|
for (float _x = 0.1; _x < 0.9; _x += 0.17) {
|
||
|
float x = pow(_x, exposureParams.centerWeightPower);
|
||
|
for (float _y = 0.1; _y < 0.9; _y += 0.17) {
|
||
|
float y = pow(_y, exposureParams.centerWeightPower);
|
||
|
averageColor += texture2D(screen, vec2(0.5 + 0.5 * x, 0.5 + 0.5 * y)).rgb;
|
||
|
averageColor += texture2D(screen, vec2(0.5 + 0.5 * x, 0.5 - 0.5 * y)).rgb;
|
||
|
averageColor += texture2D(screen, vec2(0.5 - 0.5 * x, 0.5 + 0.5 * y)).rgb;
|
||
|
averageColor += texture2D(screen, vec2(0.5 - 0.5 * x, 0.5 - 0.5 * y)).rgb;
|
||
|
n += 4.;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
float luminance = getLuminance(averageColor);
|
||
|
luminance /= n;
|
||
|
|
||
|
luminance /= pow(2., previousExposure) * bloomStrength * exposureParams.compensationFactor; // compensate for the configurable factors
|
||
|
|
||
|
luminance = clamp(luminance, exposureParams.luminanceMin, exposureParams.luminanceMax);
|
||
|
|
||
|
// From https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/course-notes-moving-frostbite-to-pbr-v2.pdf
|
||
|
// 1. EV100 = log2(luminance * S / K) where S = 100, K = 0.125 = log2(luminance) + 3
|
||
|
// 2. Lmax = 1.2 * 2 ^ (EV100 - EC)
|
||
|
// => Lmax = 1.2 * 2^3 * luminance / 2^EC = 9.6 * luminance / 2^EC
|
||
|
// 3. exposure = 1 / Lmax
|
||
|
// => exposure = 2^EC / (9.6 * luminance)
|
||
|
float wantedExposure = exposureParams.exposureCorrection - log(luminance)/0.693147180559945 - 3.263034405833794;
|
||
|
|
||
|
if (wantedExposure < previousExposure)
|
||
|
wantedExposure = mix(wantedExposure, previousExposure, exp(-animationTimerDelta * exposureParams.speedDarkBright)); // dark -> bright
|
||
|
else
|
||
|
wantedExposure = mix(wantedExposure, previousExposure, exp(-animationTimerDelta * exposureParams.speedBrightDark)); // bright -> dark
|
||
|
|
||
|
gl_FragColor = vec4(vec3(wantedExposure), 1.);
|
||
|
}
|