diff --git a/Effects/HDR/bloom-threshold.eff b/Effects/HDR/bloom-threshold.eff index 6d9ae5c35..96816aa4e 100644 --- a/Effects/HDR/bloom-threshold.eff +++ b/Effects/HDR/bloom-threshold.eff @@ -1,11 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> <PropertyList> <name>Effects/HDR/bloom-threshold</name> + <parameters> + <exposure-compensation> + <use>/sim/rendering/hdr/exposure-compensation</use> + </exposure-compensation> + <bloom-threshold><use>/sim/rendering/hdr/bloom-threshold</use></bloom-threshold> + </parameters> <technique n="1"> <pass> <program> <vertex-shader>Shaders/HDR/trivial.vert</vertex-shader> <fragment-shader>Shaders/HDR/bloom-threshold.frag</fragment-shader> + <fragment-shader>Shaders/HDR/exposure-include.frag</fragment-shader> </program> <uniform> <name>hdr_tex</name> @@ -17,6 +24,16 @@ <type>sampler-2d</type> <value type="int">1</value> </uniform> + <uniform> + <name>exposure_compensation</name> + <type>float</type> + <value><use>exposure-compensation</use></value> + </uniform> + <uniform> + <name>bloom_threshold</name> + <type>float</type> + <value><use>bloom-threshold</use></value> + </uniform> </pass> </technique> </PropertyList> diff --git a/Effects/HDR/postprocess.eff b/Effects/HDR/postprocess.eff index 5e8aa1cc8..f23d14a6c 100644 --- a/Effects/HDR/postprocess.eff +++ b/Effects/HDR/postprocess.eff @@ -1,11 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> <PropertyList> <name>Effects/HDR/postprocess</name> + <parameters> + <exposure-compensation> + <use>/sim/rendering/hdr/exposure-compensation</use> + </exposure-compensation> + <bloom-magnitude><use>/sim/rendering/hdr/bloom-magnitude</use></bloom-magnitude> + <debug-ev100><use>/sim/rendering/hdr/debug/display-ev100</use></debug-ev100> + </parameters> <technique n="1"> <pass> <program> <vertex-shader>Shaders/HDR/trivial.vert</vertex-shader> <fragment-shader>Shaders/HDR/postprocess.frag</fragment-shader> + <fragment-shader>Shaders/HDR/exposure-include.frag</fragment-shader> </program> <uniform> <name>hdr_tex</name> @@ -22,6 +30,21 @@ <type>sampler-2d</type> <value type="int">4</value> </uniform> + <uniform> + <name>exposure_compensation</name> + <type>float</type> + <value><use>exposure-compensation</use></value> + </uniform> + <uniform> + <name>bloom_magnitude</name> + <type>float</type> + <value><use>bloom-magnitude</use></value> + </uniform> + <uniform> + <name>debug_ev100</name> + <type>bool</type> + <value><use>debug-ev100</use></value> + </uniform> </pass> </technique> </PropertyList> diff --git a/Shaders/HDR/adapt-luminance.frag b/Shaders/HDR/adapt-luminance.frag index 2efeb64d8..e7cfa438b 100644 --- a/Shaders/HDR/adapt-luminance.frag +++ b/Shaders/HDR/adapt-luminance.frag @@ -13,7 +13,7 @@ const float TAU = 4.0; void main() { float prevLum = texelFetch(prev_lum_tex, ivec2(0), 0).r; - float currentLum = exp2(textureLod(current_lum_tex, vec2(0.5), 10.0).r); + float currentLum = exp(textureLod(current_lum_tex, vec2(0.5), 10.0).r); adaptedLum = prevLum + (currentLum - prevLum) * (1.0 - exp(-osg_DeltaFrameTime * TAU)); } diff --git a/Shaders/HDR/bloom-threshold.frag b/Shaders/HDR/bloom-threshold.frag index d940ea821..e5a0bed5f 100644 --- a/Shaders/HDR/bloom-threshold.frag +++ b/Shaders/HDR/bloom-threshold.frag @@ -7,17 +7,18 @@ in vec2 texCoord; uniform sampler2D hdr_tex; uniform sampler2D lum_tex; +uniform float bloom_threshold; + +vec3 applyExposure(vec3 color, float avgLuminance, float threshold); + void main() { vec3 hdrColor = texture(hdr_tex, texCoord).rgb; - float avgLuminance = texture(lum_tex, texCoord).r; - // XXX: Maybe we should actually control the EV compensation value itself - // instead of hardcoding a factor? - float exposure = 1.0 / (200.0 * avgLuminance); - hdrColor *= exposure; + float avgLuminance = texelFetch(lum_tex, ivec2(0), 0).r; - if (dot(hdrColor, vec3(0.333)) <= 0.001) + vec3 exposedHdrColor = applyExposure(hdrColor, avgLuminance, bloom_threshold); + if (dot(exposedHdrColor, vec3(0.333)) <= 0.001) fragColor = vec3(0.0); else - fragColor = hdrColor; + fragColor = exposedHdrColor; } diff --git a/Shaders/HDR/exposure-include.frag b/Shaders/HDR/exposure-include.frag new file mode 100644 index 000000000..12220828a --- /dev/null +++ b/Shaders/HDR/exposure-include.frag @@ -0,0 +1,27 @@ +#version 330 core + +uniform float exposure_compensation; + +const float one_over_log10 = 1.0 / log(10.0); + +float log10(float x) +{ + return one_over_log10 * log(x); +} + +// Custom exposure curve based on the one proposed on +// 'Perceptual Effects in Real-time Tone Mapping'. +// http://resources.mpi-inf.mpg.de/hdr/peffects/krawczyk05sccg.pdf +float keyValue(float L) +{ + return 0.82 - 2.0 / (log10(L + 0.84) + 2.6); +} + +vec3 applyExposure(vec3 color, float avgLuminance, float threshold) +{ + avgLuminance = max(avgLuminance, 0.001); + float linearExposure = keyValue(avgLuminance) / avgLuminance; + float exposure = log2(max(linearExposure, 0.0001)); + exposure += exposure_compensation - threshold; + return color * exp2(exposure); +} diff --git a/Shaders/HDR/luminance.frag b/Shaders/HDR/luminance.frag index 597ebf191..fb69556b7 100644 --- a/Shaders/HDR/luminance.frag +++ b/Shaders/HDR/luminance.frag @@ -9,5 +9,5 @@ uniform sampler2D hdr_tex; void main() { vec3 hdrColor = texture(hdr_tex, texCoord).rgb; - luminance = log2(max(dot(hdrColor, vec3(0.299, 0.587, 0.114)), 0.0001)); + luminance = log(max(dot(hdrColor, vec3(0.299, 0.587, 0.114)), 0.0001)); } diff --git a/Shaders/HDR/postprocess.frag b/Shaders/HDR/postprocess.frag index c7672889a..1a2e31472 100644 --- a/Shaders/HDR/postprocess.frag +++ b/Shaders/HDR/postprocess.frag @@ -10,51 +10,74 @@ uniform sampler2D bloom_tex; uniform vec2 fg_BufferSize; -const float BLOOM_INTENSITY = 1.0; -const float EXPOSURE_THRESHOLD = 0.0; +uniform float bloom_magnitude; +uniform bool debug_ev100; +vec3 applyExposure(vec3 color, float avgLuminance, float threshold); + +vec3 getDebugColor(float value) +{ + float level = value*3.14159265/2.0; + vec3 col; + col.r = sin(level); + col.g = sin(level*2.0); + col.b = cos(level); + return col; +} + +vec3 debugEV100(vec3 hdr, float avgLuminance) +{ + float level; + if (texCoord.y < 0.05) { + const float w = 0.001; + if (texCoord.x >= (0.5 - w) && texCoord.x <= (0.5 + w)) + return vec3(1.0); + return getDebugColor(texCoord.x); + } + float luminance = max(dot(hdr, vec3(0.299, 0.587, 0.114)), 0.0001); + float ev100 = log2(luminance * 8.0); + float norm = ev100 / 12.0 + 0.5; + return getDebugColor(norm); +} + +const float a = 2.51; +const float b = 0.03; +const float c = 2.43; +const float d = 0.59; +const float e = 0.14; vec3 ACESFilm(vec3 x) { - const float a = 2.51; - const float b = 0.03; - const float c = 2.43; - const float d = 0.59; - const float e = 0.14; return clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0); } -float log10(float x) +vec3 encodeSRGB(vec3 linearRGB) { - return (1.0 / log(10.0)) * log(x); -} - -float autokey(float lum) -{ - return 1.03 - 2.0 / (2.0 + log10(lum + 1.0)); + vec3 a = 12.92 * linearRGB; + vec3 b = 1.055 * pow(linearRGB, vec3(1.0 / 2.4)) - 0.055; + vec3 c = step(vec3(0.0031308), linearRGB); + return mix(a, b, c); } void main() { vec3 hdrColor = texture(hdr_tex, texCoord).rgb; - float avgLuminance = texelFetch(lum_tex, ivec2(0), 0).r; - avgLuminance = max(avgLuminance, 0.001); - // Auto-expose - float linearExposure = autokey(avgLuminance) / avgLuminance; - float exposure = log2(max(linearExposure, 0.0001)); - exposure -= EXPOSURE_THRESHOLD; - hdrColor *= exp2(exposure); + // Exposure + vec3 exposedHdrColor = applyExposure(hdrColor, avgLuminance, 0.0); + if (debug_ev100) { + fragColor = vec4(debugEV100(exposedHdrColor, avgLuminance), 1.0); + return; + } // Tonemap - vec3 color = ACESFilm(hdrColor); + vec3 color = ACESFilm(exposedHdrColor); // Gamma correction - color = pow(color, vec3(1.0/2.2)); + color = encodeSRGB(color); - // Apply bloom + // Bloom vec3 bloom = texture(bloom_tex, texCoord).rgb; - bloom *= BLOOM_INTENSITY; - color += bloom; + color += bloom.rgb * bloom_magnitude; fragColor = vec4(color, 1.0); } diff --git a/Shaders/HDR/ws30.frag b/Shaders/HDR/ws30.frag index af7aaf35a..21a5a0c8d 100644 --- a/Shaders/HDR/ws30.frag +++ b/Shaders/HDR/ws30.frag @@ -19,6 +19,7 @@ uniform float tile_width; uniform float tile_height; vec2 encodeNormal(vec3 n); +vec3 decodeSRGB(vec3 screenRGB); void main() { @@ -45,10 +46,11 @@ void main() vec3 texel = texture(atlas, vec3(st, lc)).rgb; - gbuffer0.rgb = pow(texel, vec3(2.2)); // Gamma correction + gbuffer0.rgb = decodeSRGB(texel) * color.rgb; gbuffer0.a = 1.0; gbuffer1 = encodeNormal(normalVS); - gbuffer2 = vec4(0.0, 0.9, 0.0, 0.0); + float specularity = clamp(dot(specular.rgb, vec3(0.333)), 0.0, 1.0); + gbuffer2 = vec4(0.0, 1.0-specularity, 0.0, 0.0); } diff --git a/defaults.xml b/defaults.xml index ff7a0fcc1..b9ed5d57f 100644 --- a/defaults.xml +++ b/defaults.xml @@ -382,6 +382,14 @@ Started September 2000 by David Megginson, david@megginson.com <available type="bool" userarchive="n">false</available> <enabled type="bool" userarchive="y">true</enabled> </pilot-model> + <hdr> + <debug> + <display-ev100 type="bool">false</display-ev100> + </debug> + <exposure-compensation type="float">0.0</exposure-compensation> + <bloom-magnitude type="float">1.0</bloom-magnitude> + <bloom-threshold type="float">6.0</bloom-threshold> + </hdr> </rendering> <model-hz type="int">120</model-hz> <sound>