mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-17 09:49:19 +02:00
80 lines
2.6 KiB
Plaintext
80 lines
2.6 KiB
Plaintext
// exposure from the luminance histogram (exposure_histogram.comp): the average log2 luminance of the pixels between the
|
|
// low and high percentile (the darkest and brightest parts of the image do not move the exposure), adapted over time to,
|
|
// faster towards the brighter. the exposure brings the adapted luminance to the key, within the limits. one work group,
|
|
// one invocation per bin; the histogram is cleared for the next frame
|
|
|
|
#include <common>
|
|
|
|
layout(local_size_x = EXPOSURE_HISTOGRAM_BINS) in;
|
|
|
|
layout(std430, binding = EXPOSURE_SSBO_BINDING) buffer exposure_ssbo
|
|
{
|
|
uint histogram[EXPOSURE_HISTOGRAM_BINS];
|
|
float adapted_luminance;
|
|
float exposure;
|
|
float average_luminance;
|
|
uint valid;
|
|
};
|
|
|
|
// x: log2 of the lowest luminance binned, y: log2 luminance per bin
|
|
layout(location = 0) uniform vec2 log_range;
|
|
// x: time since the last frame (s), y: rate of adaptation to a darker image, z: to a brighter one (1/s), w: key
|
|
layout(location = 1) uniform vec4 adaptation;
|
|
// lowest and highest exposure (multipliers)
|
|
layout(location = 2) uniform vec2 exposure_range;
|
|
|
|
const float LOW_PERCENTILE = 0.4;
|
|
const float HIGH_PERCENTILE = 0.95;
|
|
|
|
shared float shared_counts[EXPOSURE_HISTOGRAM_BINS];
|
|
|
|
void main()
|
|
{
|
|
uint index = gl_LocalInvocationIndex;
|
|
shared_counts[index] = float(histogram[index]);
|
|
histogram[index] = 0U;
|
|
barrier();
|
|
|
|
if (index != 0U)
|
|
return;
|
|
|
|
float total = 0.0;
|
|
for (uint bin = 1U; bin < EXPOSURE_HISTOGRAM_BINS; ++bin)
|
|
total += shared_counts[bin];
|
|
// an all black image (or none) leaves the exposure as it was
|
|
if (total < 1.0)
|
|
return;
|
|
|
|
float low = total * LOW_PERCENTILE;
|
|
float high = total * HIGH_PERCENTILE;
|
|
float counted = 0.0;
|
|
float logsum = 0.0;
|
|
float weight = 0.0;
|
|
for (uint bin = 1U; bin < EXPOSURE_HISTOGRAM_BINS; ++bin)
|
|
{
|
|
float count = shared_counts[bin];
|
|
// the part of the bin between the percentiles
|
|
float inside = max(min(counted + count, high) - max(counted, low), 0.0);
|
|
counted += count;
|
|
float binluminance = log_range.x + (float(bin - 1U) + 0.5) * log_range.y;
|
|
logsum += inside * binluminance;
|
|
weight += inside;
|
|
}
|
|
float averagelog = (weight > 0.0) ? logsum / weight : log_range.x;
|
|
average_luminance = exp2(averagelog);
|
|
|
|
if (valid == 0U || !(adapted_luminance > 0.0))
|
|
{
|
|
adapted_luminance = average_luminance;
|
|
valid = 1U;
|
|
}
|
|
else
|
|
{
|
|
float adaptedlog = log2(adapted_luminance);
|
|
float rate = (averagelog < adaptedlog) ? adaptation.y : adaptation.z;
|
|
adaptedlog = mix(adaptedlog, averagelog, 1.0 - exp(-adaptation.x * rate));
|
|
adapted_luminance = exp2(adaptedlog);
|
|
}
|
|
exposure = clamp(adaptation.w / adapted_luminance, exposure_range.x, exposure_range.y);
|
|
}
|