201 lines
6.7 KiB
GLSL
201 lines
6.7 KiB
GLSL
/**
|
||
*
|
||
* RenderPipeline
|
||
*
|
||
* Copyright (c) 2014-2016 tobspr <tobias.springer1@gmail.com>
|
||
*
|
||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
* of this software and associated documentation files (the "Software"), to deal
|
||
* in the Software without restriction, including without limitation the rights
|
||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
* copies of the Software, and to permit persons to whom the Software is
|
||
* furnished to do so, subject to the following conditions:
|
||
*
|
||
* The above copyright notice and this permission notice shall be included in
|
||
* all copies or substantial portions of the Software.
|
||
*
|
||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
* THE SOFTWARE.
|
||
*
|
||
*/
|
||
|
||
#pragma once
|
||
|
||
#pragma include "includes/color_spaces.inc.glsl"
|
||
|
||
/*
|
||
|
||
Tonemapping Operators, some are from:
|
||
http://filmicgames.com/archives/75
|
||
|
||
A good sample using them can be found here:
|
||
https://www.shadertoy.com/view/lslGzl
|
||
|
||
*/
|
||
|
||
|
||
const float exposure_adjustment = 2.0;
|
||
|
||
|
||
// No tonemapping
|
||
vec3 tonemap_none(vec3 color) {
|
||
color *= exposure_adjustment;
|
||
return color;
|
||
}
|
||
|
||
// Different versions of the reinhard tonemap operators
|
||
vec3 tonemap_reinhard(vec3 color)
|
||
{
|
||
color *= exposure_adjustment;
|
||
|
||
#if ENUM_V_ACTIVE(color_correction, reinhard_version, rgb)
|
||
|
||
// Simple reinhard operator in rgb space
|
||
vec3 rgb = color / (1.0 + color);
|
||
|
||
#elif ENUM_V_ACTIVE(color_correction, reinhard_version, luminance)
|
||
|
||
// Simple reinhard operator based on luminance
|
||
float luminance = get_luminance(color);
|
||
vec3 rgb = color / (1.0 + luminance);
|
||
|
||
#elif ENUM_V_ACTIVE(color_correction, reinhard_version, white_preserve)
|
||
|
||
// Reinhard operator based on luminance, but white preserving
|
||
float white = 5.0;
|
||
float luminance = get_luminance(color);
|
||
vec3 rgb = color * (1.0 + luminance / (white * white)) / (1.0 + luminance);
|
||
|
||
#elif ENUM_V_ACTIVE(color_correction, reinhard_version, luminosity)
|
||
|
||
// Reinhard operator in the CIE-Yxy color space
|
||
vec3 xyY = rgb_to_xyY(color);
|
||
|
||
// This saturates too much?
|
||
xyY.z = xyY.z / (1.0 + xyY.z);
|
||
|
||
// White preserving approach, doesn't work out well, too
|
||
// xyY.z = xyY.z * (1.0 + xyY.z * (white*white)) / (1.0 + xyY.z);
|
||
vec3 rgb = xyY_to_rgb(xyY);
|
||
|
||
#else
|
||
#error Unkown reinhard operator version!
|
||
#endif
|
||
|
||
return rgb;
|
||
}
|
||
|
||
|
||
// Optimized version of the Haarm-Peter Duiker’s curve
|
||
vec3 tonemap_optimized(vec3 color)
|
||
{
|
||
color *= exposure_adjustment;
|
||
vec3 x = max(vec3(0.0), color - 0.004);
|
||
return (x * (6.2 * x + 0.5)) / (x * (6.2 * x + 1.7) + 0.06);
|
||
}
|
||
|
||
// Exponential tonemapping
|
||
vec3 tonemap_exponential(vec3 color) {
|
||
color *= exposure_adjustment;
|
||
color = 1.0 - exp(-GET_SETTING(color_correction, exponential_factor) * color);
|
||
return color;
|
||
}
|
||
|
||
// Alternative exponential tonemapping
|
||
vec3 tonemap_exponential_2(vec3 color) {
|
||
color *= exposure_adjustment;
|
||
color = exp(-1.0 / (2.72 * color + 0.15));
|
||
return color;
|
||
}
|
||
|
||
|
||
// Uncharted 2 tonemapping formula
|
||
// See: http://de.slideshare.net/ozlael/hable-john-uncharted2-hdr-lighting
|
||
vec3 uncharted_2_tonemap_formula(vec3 x)
|
||
{
|
||
const float A = GET_SETTING(color_correction, uc2t_shoulder_strength);
|
||
const float B = GET_SETTING(color_correction, uc2t_linear_strength);
|
||
const float C = GET_SETTING(color_correction, uc2t_linear_angle);
|
||
const float D = GET_SETTING(color_correction, uc2t_toe_strength);
|
||
const float E = GET_SETTING(color_correction, uc2t_toe_numerator);
|
||
const float F = GET_SETTING(color_correction, uc2t_toe_denumerator);
|
||
return ((x * (A * x + C * B) + D * E) / (x * (A * x + B) + D * F)) - E / F;
|
||
}
|
||
|
||
// Uncharted 2 tonemap operator
|
||
vec3 tonemap_uncharted2(vec3 color)
|
||
{
|
||
const float white_base = GET_SETTING(color_correction, uc2t_reference_white);
|
||
color *= exposure_adjustment;
|
||
const float exposure_bias = 2.0;
|
||
vec3 curr = uncharted_2_tonemap_formula(exposure_bias * color);
|
||
vec3 white = uncharted_2_tonemap_formula(vec3(white_base));
|
||
return curr / white;
|
||
}
|
||
|
||
// Tonemapping selector
|
||
vec3 do_tonemapping(vec3 color) {
|
||
|
||
// Clamp extreme values of the color
|
||
color = clamp(color, 1e-5, 1000.0);
|
||
|
||
// Select tonemapping operator
|
||
#if ENUM_V_ACTIVE(color_correction, tonemap_operator, none)
|
||
color = tonemap_none(color);
|
||
#elif ENUM_V_ACTIVE(color_correction, tonemap_operator, optimized)
|
||
color = tonemap_optimized(color);
|
||
return color;
|
||
#elif ENUM_V_ACTIVE(color_correction, tonemap_operator, reinhard)
|
||
color = tonemap_reinhard(color);
|
||
#elif ENUM_V_ACTIVE(color_correction, tonemap_operator, uncharted2)
|
||
color = tonemap_uncharted2(color);
|
||
#elif ENUM_V_ACTIVE(color_correction, tonemap_operator, exponential)
|
||
color = tonemap_exponential(color);
|
||
#elif ENUM_V_ACTIVE(color_correction, tonemap_operator, exponential2)
|
||
color = tonemap_exponential_2(color);
|
||
#else
|
||
#error Unkown tonemapping operator!
|
||
#endif
|
||
|
||
return rgb_to_srgb(color);
|
||
}
|
||
|
||
|
||
// From:
|
||
// http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf
|
||
|
||
float computeEV100(float aperture, float shutter_time, float ISO) {
|
||
// EV number is defined as:
|
||
// 2^ EV_s = N^2 / t and EV_s = EV_100 + log2 (S /100)
|
||
// This gives
|
||
// EV_s = log2 (N^2 / t)
|
||
// EV_100 + log2 (S /100) = log2 (N^2 / t)
|
||
// EV_100 = log2 (N^2 / t) - log2 (S /100)
|
||
// EV_100 = log2 (N^2 / t . 100 / S)
|
||
return log2((aperture * aperture) / shutter_time * 100 / ISO);
|
||
}
|
||
|
||
float computeEV100FromAvgLuminance(float avg_luminance) {
|
||
// We later use the middle gray at 12.7% in order to have
|
||
// a middle gray at 18% with a sqrt (2) room for specular highlights
|
||
// But here we deal with the spot meter measuring the middle gray
|
||
// which is fixed at 12.5 for matching standard camera
|
||
// constructor settings (i.e. calibration constant K = 12.5)
|
||
return log2(avg_luminance * 100.0 / 12.5);
|
||
}
|
||
|
||
float convertEV100ToExposure(float EV100) {
|
||
// Compute the maximum luminance possible with H_sbs sensitivity
|
||
// maxLum = 78 / ( S * q ) * N^2 / t
|
||
// = 78 / ( S * q ) * 2^ EV_100
|
||
// = 78 / (100 * 0.65) * 2^ EV_100
|
||
// = 1.2 * 2^ EV
|
||
float max_luminance = 1.2 * pow(2.0, EV100);
|
||
return 1.0 / max_luminance;
|
||
}
|