diff --git a/include/openspace/rendering/abufferrenderer.h b/include/openspace/rendering/abufferrenderer.h index bcf8d12204..51179398c3 100644 --- a/include/openspace/rendering/abufferrenderer.h +++ b/include/openspace/rendering/abufferrenderer.h @@ -73,6 +73,7 @@ public: void setBloomNewFactor(float newFactor) override; void enableBloom(bool enable) override; + void enableHistogram(bool enable) override; float hdrBackground() const override; int nAaSamples() const override; @@ -151,6 +152,7 @@ private: float _bloomOrigFactor = 1.0; float _bloomNewFactor = 1.0; int _toneMapOperator = 0; + bool _histogramEnabled = false; std::vector _mSAAPattern; diff --git a/include/openspace/rendering/framebufferrenderer.h b/include/openspace/rendering/framebufferrenderer.h index 32a40913fd..57f20c2ca1 100644 --- a/include/openspace/rendering/framebufferrenderer.h +++ b/include/openspace/rendering/framebufferrenderer.h @@ -79,6 +79,8 @@ public: void updateHDRAndFiltering(); void updateAveLum(); void updateBloomConfig(); + void updateHistogramConfig(); + void updateTMOViaMipMappingConfig(); void updateMSAASamplingPattern(); void setResolution(glm::ivec2 res) override; @@ -92,8 +94,16 @@ public: void setBloomThreMax(float maxV) override; void setBloomOrigFactor(float origFactor) override; void setBloomNewFactor(float newFactor) override; + void setKey(float key); + void setYwhite(float white); + void setTmoSaturation(float sat); + void setHue(float hue); + void setValue(float value); + void setSaturation(float sat); + void setLightness(float lightness); void enableBloom(bool enable) override; + void enableHistogram(bool enable) override; float hdrBackground() const override; int nAaSamples() const override; @@ -119,6 +129,8 @@ private: float computeBufferAveLuminance(); float computeBufferAveLuminanceGPU(); void applyBloomFilter(); + void computeImageHistogram(); + void computeMipMappingFromHDRBuffer(GLuint oglImageBuffer); private: std::map _raycastData; @@ -133,17 +145,26 @@ private: std::unique_ptr _aveLumProgram; std::unique_ptr _bloomProgram; std::unique_ptr _bloomResolveProgram; + std::unique_ptr _histoProgram; + std::unique_ptr _histoApplyProgram; + std::unique_ptr _tmoProgram; std::unique_ptr _resolveProgram; UniformCache(mainColorTexture, blackoutFactor, nAaSamples) _uniformCache; UniformCache(deferredResultsTexture, blackoutFactor, backgroundConstant, - backgroundExposure, gamma, toneMapOperator, aveLum, maxWhite) + backgroundExposure, gamma, toneMapOperator, aveLum, maxWhite, + Hue, Saturation, Value, Lightness) _hdrUniformCache; UniformCache(renderedImage, bloomImage, bloomThresholdMin, bloomThresholdMax, bloomOrigFactor, bloomNewFactor) _bloomUniformCache; + UniformCache(renderedImage, maxWhite, imageWidth, + imageHeight) _histoUniformCache; + + UniformCache(hdrSampler, key, Ywhite, sat) _tmoUniformCache; + GLuint _screenQuad; GLuint _vertexPositionBuffer; GLuint _mainColorTexture; @@ -157,6 +178,10 @@ private: GLuint _exitFramebuffer; GLuint _hdrFilteringFramebuffer; GLuint _hdrFilteringTexture; + GLuint _histoFramebuffer; + GLuint _histoTexture; + GLuint _histoVao; + GLuint _histoVbo; GLuint _bloomFilterFBO[3]; GLuint _bloomTexture[3]; @@ -164,6 +189,11 @@ private: GLuint _computeAveLumFBO; GLuint _computeAveLumTexture; + // New TMO via mipmapping + GLuint _tmoTexture; + GLuint _tmoFramebuffer; + GLuint _tmoHdrSampler; + bool _dirtyDeferredcastData; bool _dirtyRaycastData; bool _dirtyResolution; @@ -181,8 +211,18 @@ private: float _bloomOrigFactor = 1.0; float _bloomNewFactor = 1.0; int _toneMapOperator = 0; + bool _histogramEnabled = false; + int _numberOfBins = 1024; // JCC TODO: Add a parameter control for this. + float _tmoKey = 0.18f; + float _tmoYwhite = 1e6f; + float _tmoSaturation = 1.0f; + float _hue = 1.f; + float _saturation = 1.f; + float _value = 1.f; + float _lightness = 1.f; std::vector _mSAAPattern; + std::vector _histoPoints; ghoul::Dictionary _rendererData; }; diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 239a5faa18..20d06223c2 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -205,16 +205,31 @@ private: float _currentFadeTime = 0.f; int _fadeDirection = 0; properties::IntProperty _nAaSamples; - properties::FloatProperty _hdrExposure; - properties::FloatProperty _hdrBackground; - properties::FloatProperty _gamma; - properties::FloatProperty _maxWhite; + + + properties::PropertyOwner _bloomOwner; properties::BoolProperty _enableBloom; properties::FloatProperty _bloomThreshouldMin; properties::FloatProperty _bloomThreshouldMax; properties::FloatProperty _bloomOrigColorFactor; properties::FloatProperty _bloomNewColorFactor; + + properties::PropertyOwner _tmoOwner; + properties::FloatProperty _hdrExposure; + properties::FloatProperty _hdrBackground; + properties::FloatProperty _maxWhite; properties::OptionProperty _toneMapOperator; + properties::FloatProperty _tmoKey; + properties::FloatProperty _tmoYwhite; + properties::FloatProperty _tmoSaturation; + + properties::PropertyOwner _imageOwner; + properties::FloatProperty _gamma; + properties::FloatProperty _hue; + properties::FloatProperty _saturation; + properties::FloatProperty _value; + properties::FloatProperty _lightness; + uint64_t _frameNumber = 0; diff --git a/include/openspace/rendering/renderer.h b/include/openspace/rendering/renderer.h index a6a62f8d82..29dc9a0d55 100644 --- a/include/openspace/rendering/renderer.h +++ b/include/openspace/rendering/renderer.h @@ -59,8 +59,16 @@ public: virtual void setBloomThreMax(float maxV) = 0; virtual void setBloomOrigFactor(float origFactor) = 0; virtual void setBloomNewFactor(float newFactor) = 0; - + virtual void setKey(float key) = 0; + virtual void setYwhite(float white) = 0; + virtual void setTmoSaturation(float sat) = 0; + virtual void setHue(float hue) = 0; + virtual void setValue(float value) = 0; + virtual void setSaturation(float sat) = 0; + virtual void setLightness(float lightness) = 0; + virtual void enableBloom(bool enable) = 0; + virtual void enableHistogram(bool enable) = 0; virtual float hdrBackground() const = 0; virtual int nAaSamples() const = 0; diff --git a/openspace.cfg b/openspace.cfg index 58e0446fca..d311247fea 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -162,7 +162,7 @@ LoadingScreen = { ShowNodeNames = true, ShowProgressbar = false } -CheckOpenGLState = false +CheckOpenGLState = true LogEachOpenGLCall = false ShutdownCountdown = 3 diff --git a/shaders/framebuffer/computeAveLum.frag b/shaders/framebuffer/computeAveLum.frag index faa3bde1f8..a4b4cc2f50 100644 --- a/shaders/framebuffer/computeAveLum.frag +++ b/shaders/framebuffer/computeAveLum.frag @@ -43,7 +43,7 @@ void main() { vec2 texCoord = vec2(float(i) / fH, float(j) / fW); vec4 tmpColor = texture(hdrTexture, texCoord); float lum = dot(tmpColor.xyz, vec3(0.2126f, 0.7152f, 0.0722f)); - sum += log(lum + 0.00001); + sum += log(lum + 0.00001); // 0.00001 to avoid log(0) from black pixels } } diff --git a/shaders/framebuffer/computeHistogram_fs.glsl b/shaders/framebuffer/computeHistogram_fs.glsl new file mode 100644 index 0000000000..066da34759 --- /dev/null +++ b/shaders/framebuffer/computeHistogram_fs.glsl @@ -0,0 +1,35 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout (location = 0) out vec4 finalColor; + +in vec3 pColor; + +void main() +{ + //finalColor = vec4(1.0, 0.0, 0.0, 1.0); + finalColor = vec4(pColor, 1.0); +} \ No newline at end of file diff --git a/shaders/framebuffer/computeHistogram_vs.glsl b/shaders/framebuffer/computeHistogram_vs.glsl new file mode 100644 index 0000000000..e03b268311 --- /dev/null +++ b/shaders/framebuffer/computeHistogram_vs.glsl @@ -0,0 +1,63 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout(location = 0) in vec4 pixelCoord; + +uniform float maxWhite; +//uniform int numberOfPixels; +//uniform int numberOfBins; +uniform float imageWidth; +uniform float imageHeight; + +uniform sampler2D renderedImage; + +flat out vec3 pColor; + +void main() +{ + vec2 texCoord; + texCoord.x = float(int(pixelCoord.x / imageWidth)) / imageWidth; + texCoord.y = float(int(pixelCoord.x) % int(imageWidth)) / imageHeight; + vec3 pixelColor = texture(renderedImage, texCoord).xyz; + pColor = pixelColor; + float pixelLuminosity = dot(pixelColor, vec3(0.2126f, 0.7152f, 0.0722f)); + + //gl_Position = vec4(-1.0 + (2.0 * pixelLuminosity / maxWhite), 0.0, 0.0, 1.0); + + //gl_Position = vec4(2.0 * texCoord - vec2(1.0), 0.0, 1.0); + + //gl_Position = vec4(0.5, 2.0 * texCoord.y - 1.0, 0.0, 1.0); + + //gl_Position = vec4(-1.0 + (pixelLuminosity * 0.0078125), -1.0, 0.0, 1.0); + + //gl_Position = vec4(0.5, -1.0 + (pixelLuminosity * 0.0078125), 0.0, 1.0); + + //gl_Position = vec4(0.0, -1.0 + (2.0 * pixelLuminosity / maxWhite), 0.0, 1.0); + + gl_Position = vec4((2.0 * pixelLuminosity / maxWhite) - 1.0, 2.0 * texCoord.y - 1.0, 0.0, 1.0); + + gl_PointSize = 1.0; +} \ No newline at end of file diff --git a/shaders/framebuffer/computeTMO_fs.glsl b/shaders/framebuffer/computeTMO_fs.glsl new file mode 100644 index 0000000000..d8b2fc16b6 --- /dev/null +++ b/shaders/framebuffer/computeTMO_fs.glsl @@ -0,0 +1,82 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "hdr.glsl" + +layout (location = 0) out vec4 finalColor; + +uniform float key; +uniform float Ywhite; +uniform float sat; + +uniform sampler2D hdrSampler; + +in vec2 texCoord; + +vec3 toneMapGlobal(vec3 hdrColor, float logAvgLum) { + vec3 XYZ = srgbToXYZ(hdrColor); + + float Y = (key / logAvgLum) * XYZ.y; + float Yd = (Y * (1.0 + Y/(Ywhite * Ywhite))) / (1.0 + Y); + + return pow(hdrColor / XYZ.y, vec3(sat)) * Yd; +} + +vec3 toneMapLocal(vec3 hdrColor, float logAvgLum) { + vec3 XYZ = srgbToXYZ(hdrColor); + + float Y = (key / logAvgLum) * XYZ.y; + float LocalAdaptation; + float factor = key / logAvgLum; + float epsilon = 0.05; + float phi = 8.0; + float scale[7] = float[7](1, 2, 4, 8, 16, 32, 64); + + for (int i = 0; i < 7; ++i) { + float V1 = exp(texture(hdrSampler, texCoord, i).a) * factor; + float V2 = exp(texture(hdrSampler, texCoord, i+1).a) * factor; + + if ( abs(V1-V2) / ((key * pow(2, phi) / (scale[i] * scale[i])) + V1) + > epsilon ) { + LocalAdaptation = V1; + break; + } else { + LocalAdaptation = V2; + } + } + + float Yd = Y / (1.0 + LocalAdaptation); + + return pow(hdrColor / XYZ.y, vec3(sat)) * Yd; +} + +void main() { + vec3 hdrColor = texture(hdrSampler, texCoord).rgb; + + float logAvgLum = exp(texture(hdrSampler, texCoord, 20).a); + + finalColor.rgb = toneMapGlobal(hdrColor, logAvgLum); +} diff --git a/shaders/framebuffer/computeTMO_vs.glsl b/shaders/framebuffer/computeTMO_vs.glsl new file mode 100644 index 0000000000..2ddb63b462 --- /dev/null +++ b/shaders/framebuffer/computeTMO_vs.glsl @@ -0,0 +1,33 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2018 * + * * + * 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. * + ****************************************************************************************/ + +#version __CONTEXT__ + +layout(location = 0) in vec4 position; +out vec2 texCoord; + +void main() { + texCoord = 0.5 + position.xy * 0.5; + gl_Position = position; +} \ No newline at end of file diff --git a/shaders/framebuffer/hdrAndFiltering.frag b/shaders/framebuffer/hdrAndFiltering.frag index 64e3a5b993..e61bf0a9c3 100644 --- a/shaders/framebuffer/hdrAndFiltering.frag +++ b/shaders/framebuffer/hdrAndFiltering.frag @@ -34,6 +34,10 @@ uniform float blackoutFactor; uniform float gamma; uniform float maxWhite; uniform float aveLum; +uniform float Hue; +uniform float Saturation; +uniform float Value; +uniform float Lightness; uniform int toneMapOperator; uniform sampler2D deferredResultsTexture; @@ -85,7 +89,13 @@ void main() { if (toneMapOperator == EXPONENTIAL) { vec3 tColor = exponentialToneMapping(color.rgb, backgroundExposure, gamma); - finalColor = vec4(tColor, color.a); + vec3 hslColor = rgb2hsl(tColor); + hslColor.x *= Hue; + hslColor.y *= Saturation; + hslColor.z *= Lightness; + + finalColor = vec4(hsl2rgb(hslColor), color.a); + } else if (toneMapOperator == LINEAR) { vec3 tColor = linearToneMapping(color.rgb, backgroundExposure); finalColor = vec4(gammaCorrection(tColor, gamma), color.a); @@ -109,7 +119,13 @@ void main() { finalColor = vec4(gammaCorrection(tColor, gamma), color.a); } else if (toneMapOperator == COSTA) { vec3 tColor = jToneMapping(color.rgb, backgroundExposure); - finalColor = vec4(gammaCorrection(tColor, gamma), color.a); + vec3 hsvColor = rgb2hsv(tColor); + hsvColor.x *= Hue; + hsvColor.y *= Saturation; + hsvColor.z *= Value; + + finalColor = vec4(gammaCorrection(hsv2rgb(hsvColor), gamma), color.a); + } else if (toneMapOperator == ADAPTIVE) { vec3 tColor = vec3(adaptiveToneMap()); finalColor = vec4(gammaCorrection(tColor, gamma), color.a); diff --git a/shaders/hdr.glsl b/shaders/hdr.glsl index 5902c7a846..1e9728182f 100644 --- a/shaders/hdr.glsl +++ b/shaders/hdr.glsl @@ -35,19 +35,130 @@ #define GLOBAL 10 #define PHOTOGRAPHIC_REINHARD 11 -const mat3 rgb2xyz = mat3( - 0.4124564, 0.2126729, 0.0193339, - 0.3575761, 0.7151522, 0.1191920, - 0.1804375, 0.0721750, 0.9503041 ); +const float HCV_EPSILON = 1e-10; +const float HSL_EPSILON = 1e-10; +const float HCY_EPSILON = 1e-10; -const mat3 xyz2rgb = mat3( - 3.2404542, -0.9692660, 0.0556434, - -1.5371385, 1.8760108, -0.2040259, - -0.4985314, 0.0415560, 1.0572252 ); +// White given by D65 +const mat3 RGB2XYZ = mat3( + vec3(0.4124, 0.2126, 0.0193), + vec3(0.3576, 0.7152, 0.1192), + vec3(0.1805, 0.0722, 0.9505) + ); + +const mat3 XYZ2RGB = mat3( + vec3(3.2406, -0.9689, 0.0557), + vec3(-1.5372, 1.8758, -0.2040), + vec3(-0.4986, 0.0415, 1.0570) + ); + +// Gamma correction for linear RGB to sRGB +// See wiki: https://en.wikipedia.org/wiki/SRGB#The_sRGB_transfer_function_.28.22gamma.22.29 +float gammaF(const float u) { + if (u < 0.0031308) { + return 12.92 * u; + } else { + return 1.055 * pow(u, 1.0/2.4) - 0.055; + } +} + +float invgammaF(const float u) { + if (u < 0.04045) { + return u / 12.92; + } else { + return pow((u+0.055)/1.055, 2.4); + } +} + +vec3 rgbToSRGB(const vec3 rgb) { + return vec3(gammaF(rgb.r), gammaF(rgb.g), gammaF(rgb.b)); +} + +vec3 srgbToRGB(const vec3 srgb) { + return vec3(invgammaF(srgb.r), invgammaF(srgb.g), invgammaF(srgb.b)); +} + +vec3 srgbToXYZ(const vec3 srgb) { + //return RGB2XYZ * srgb; + vec3 rgb = srgbToRGB(srgb); + return RGB2XYZ * rgb; +} + +vec3 XYZToSRGB(const vec3 XYZ) { + vec3 rgb = XYZ2RGB * XYZ; + return rgbToSRGB(rgb); +} + +// HSV code taken from http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl. +vec3 rgb2hsv(const vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +// All components are in the range [0…1], including hue. +vec3 hsv2rgb(const vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +// Code to convert from rgb to hsl is licensed by: +/* +GLSL Color Space Utility Functions +(c) 2015 tobspr +------------------------------------------------------------------------------- +The MIT License (MIT) +Copyright (c) 2015 + +See top of the file for full license terms. +*/ + +// Converts from pure Hue to linear RGB +vec3 hue2rgb(float hue) +{ + float R = abs(hue * 6 - 3) - 1; + float G = 2 - abs(hue * 6 - 2); + float B = 2 - abs(hue * 6 - 4); + return clamp(vec3(R,G,B), 0, 1); +} +// Converts a value from linear RGB to HCV (Hue, Chroma, Value) +vec3 rgb2hcv(vec3 rgb) +{ + // Based on work by Sam Hocevar and Emil Persson + vec4 P = (rgb.g < rgb.b) ? vec4(rgb.bg, -1.0, 2.0/3.0) : vec4(rgb.gb, 0.0, -1.0/3.0); + vec4 Q = (rgb.r < P.x) ? vec4(P.xyw, rgb.r) : vec4(rgb.r, P.yzx); + float C = Q.x - min(Q.w, Q.y); + float H = abs((Q.w - Q.y) / (6 * C + HCV_EPSILON) + Q.z); + return vec3(H, C, Q.x); +} + +// Converts from HSL to linear RGB +vec3 hsl2rgb(vec3 hsl) +{ + vec3 rgb = hue2rgb(hsl.x); + float C = (1 - abs(2 * hsl.z - 1)) * hsl.y; + return (rgb - 0.5) * C + hsl.z; +} + +// Converts from linear rgb to HSL +vec3 rgb2hsl(vec3 rgb) +{ + vec3 HCV = rgb2hcv(rgb); + float L = HCV.z - HCV.y * 0.5; + float S = HCV.y / (1 - abs(L * 2 - 1) + HSL_EPSILON); + return vec3(HCV.x, S, L); +} vec3 globalToneMappingOperatorRTR(vec3 color, float exposure, float maxWhite, float aveLum) { // Convert color to XYZ - vec3 xyzCol = rgb2xyz * color; + vec3 xyzCol = RGB2XYZ * color; // Convert from XYZ to xyY float xyzSum = xyzCol.x + xyzCol.y + xyzCol.z; @@ -63,7 +174,7 @@ vec3 globalToneMappingOperatorRTR(vec3 color, float exposure, float maxWhite, fl xyzCol.z = (L * (1 - xyYCol.x - xyYCol.y))/xyYCol.y; // Convert back to RGB and send to output buffer - return xyz2rgb * xyzCol; + return XYZ2RGB * xyzCol; } vec3 exponentialToneMapping(vec3 color, float exposure, float gamma) { @@ -89,6 +200,7 @@ vec3 simpleReinhardToneMapping(vec3 color, float exposure) { } vec3 lumaBasedReinhardToneMapping(vec3 color, float exposure) { + float luma = dot(color, vec3(0.2126f, 0.7152f, 0.0722f)); float toneMappedLuma = luma / (1.f + luma); color *= toneMappedLuma / luma; diff --git a/src/rendering/abufferrenderer.cpp b/src/rendering/abufferrenderer.cpp index f1005a0b35..6290738fdf 100644 --- a/src/rendering/abufferrenderer.cpp +++ b/src/rendering/abufferrenderer.cpp @@ -759,6 +759,10 @@ void ABufferRenderer::enableBloom(bool enable) { _bloomEnabled = enable; } +void ABufferRenderer::enableHistogram(bool enable) { + _histogramEnabled = enable; +} + float ABufferRenderer::hdrBackground() const { return _hdrBackground; } diff --git a/src/rendering/framebufferrenderer.cpp b/src/rendering/framebufferrenderer.cpp index 7a04b6d325..fcac8371a1 100644 --- a/src/rendering/framebufferrenderer.cpp +++ b/src/rendering/framebufferrenderer.cpp @@ -55,16 +55,25 @@ namespace { "mainColorTexture", "blackoutFactor", "nAaSamples" }; - constexpr const std::array HDRUniformNames = { + constexpr const std::array HDRUniformNames = { "deferredResultsTexture", "blackoutFactor", "backgroundConstant", - "backgroundExposure", "gamma", "toneMapOperator", "aveLum", "maxWhite" + "backgroundExposure", "gamma", "toneMapOperator", "aveLum", "maxWhite", + "Hue", "Saturation", "Value", "Lightness" }; - constexpr const std::array BLoomUniformNames = { + constexpr const std::array BloomUniformNames = { "renderedImage", "bloomImage", "bloomThresholdMin", "bloomThresholdMax", "bloomOrigFactor", "bloomNewFactor" }; + constexpr const std::array HistoUniformNames = { + "renderedImage", "maxWhite", "imageWidth", "imageHeight" + }; + + constexpr const std::array TMOUniformNames = { + "hdrSampler", "key", "Ywhite", "sat" + }; + constexpr const char* ExitFragmentShaderPath = "${SHADERS}/framebuffer/exitframebuffer.frag"; constexpr const char* RaycastFragmentShaderPath = @@ -160,7 +169,20 @@ void FramebufferRenderer::initialize() { // Bloom Filter glGenFramebuffers(3, _bloomFilterFBO); glGenTextures(3, _bloomTexture); - + + // Histogram + glGenFramebuffers(1, &_histoFramebuffer); + glGenTextures(1, &_histoTexture); + glGenVertexArrays(1, &_histoVao); + glBindVertexArray(_histoVao); + glGenBuffers(1, &_histoVbo); + + // TMO via mipmapping + glGenFramebuffers(1, &_tmoFramebuffer); + glGenTextures(1, &_tmoTexture); + glGenSamplers(1, &_tmoHdrSampler); + glSamplerParameteri(_tmoHdrSampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); + updateResolution(); updateRendererData(); updateRaycastData(); @@ -281,13 +303,45 @@ void FramebufferRenderer::initialize() { } } + // Builds Histogram FBO + glBindFramebuffer(GL_FRAMEBUFFER, _histoFramebuffer); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + _histoTexture, + 0 + ); + + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Histogram framebuffer is not complete"); + } + + // Buids TMO via mipmapping FBO + glBindFramebuffer(GL_FRAMEBUFFER, _tmoFramebuffer); + glFramebufferTexture2D( + GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + _tmoTexture, + 0 + ); + + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + LERROR("Histogram framebuffer is not complete"); + } + // JCC: Moved to here to avoid NVidia: "Program/shader state performance warning" // Builds HDR and Filtering programs updateHDRAndFiltering(); updateAveLum(); updateBloomConfig(); + updateHistogramConfig(); // Builds deferred casters programs updateDeferredcastData(); + updateTMOViaMipMappingConfig(); _dirtyMsaaSamplingPattern = true; @@ -312,8 +366,27 @@ void FramebufferRenderer::initialize() { ghoul::opengl::updateUniformLocations( *_bloomResolveProgram, _bloomUniformCache, - BLoomUniformNames + BloomUniformNames ); + + ghoul::opengl::updateUniformLocations( + *_histoProgram, + _histoUniformCache, + HistoUniformNames + ); + + // /*ghoul::opengl::updateUniformLocations( + // *_histoApplyProgram, + // _histoApplyUniformCache, + // HistoApplyUniformNames + // );*/ + + ghoul::opengl::updateUniformLocations( + *_tmoProgram, + _tmoUniformCache, + TMOUniformNames + ); + global::raycasterManager.addListener(*this); global::deferredcasterManager.addListener(*this); } @@ -326,6 +399,8 @@ void FramebufferRenderer::deinitialize() { glDeleteFramebuffers(1, &_hdrFilteringFramebuffer); glDeleteFramebuffers(1, &_computeAveLumFBO); glDeleteFramebuffers(3, _bloomFilterFBO); + glDeleteFramebuffers(1, &_histoFramebuffer); + glDeleteFramebuffers(1, &_tmoFramebuffer); glDeleteTextures(1, &_mainColorTexture); glDeleteTextures(1, &_mainDepthTexture); @@ -335,6 +410,8 @@ void FramebufferRenderer::deinitialize() { glDeleteTextures(1, &_mainNormalTexture); glDeleteTextures(1, &_computeAveLumTexture); glDeleteTextures(3, _bloomTexture); + glDeleteTextures(1, &_histoTexture); + glDeleteTextures(1, &_tmoTexture); glDeleteTextures(1, &_exitColorTexture); glDeleteTextures(1, &_exitDepthTexture); @@ -342,6 +419,8 @@ void FramebufferRenderer::deinitialize() { glDeleteBuffers(1, &_vertexPositionBuffer); glDeleteVertexArrays(1, &_screenQuad); + glDeleteSamplers(1, &_tmoHdrSampler); + global::raycasterManager.removeListener(*this); global::deferredcasterManager.removeListener(*this); } @@ -532,6 +611,114 @@ void FramebufferRenderer::applyBloomFilter() { glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); } +void FramebufferRenderer::computeImageHistogram() { + glBindFramebuffer(GL_FRAMEBUFFER, _histoFramebuffer); + GLenum textureBuffer[] = { + GL_COLOR_ATTACHMENT0 + }; + glDrawBuffers(1, textureBuffer); + + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, _resolution.x, _resolution.y); + + GLboolean depthTestEnabled = glIsEnabled(GL_DEPTH_TEST); + + glDisable(GL_DEPTH_TEST); + + // Saving Blending State + GLboolean blendEnabled = glIsEnabled(GL_BLEND); + GLenum blendEquationRGB; + GLenum blendEquationAlpha; + GLenum blendDestAlpha; + GLenum blendDestRGB; + GLenum blendSrcAlpha; + GLenum blendSrcRGB; + + glGetIntegerv(GL_BLEND_EQUATION_RGB, &blendEquationRGB); + glGetIntegerv(GL_BLEND_EQUATION_ALPHA, &blendEquationAlpha); + glGetIntegerv(GL_BLEND_DST_ALPHA, &blendDestAlpha); + glGetIntegerv(GL_BLEND_DST_RGB, &blendDestRGB); + glGetIntegerv(GL_BLEND_SRC_ALPHA, &blendSrcAlpha); + glGetIntegerv(GL_BLEND_SRC_RGB, &blendSrcRGB); + + // Changing blending functions for histogram computation + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_ONE, GL_ONE); + glEnable(GL_BLEND); + + glBindVertexArray(_histoVao); + + _histoProgram->activate(); + + ghoul::opengl::TextureUnit renderedImage; + renderedImage.activate(); + glBindTexture(GL_TEXTURE_2D, _hdrFilteringTexture); + _histoProgram->setUniform(_histoUniformCache.renderedImage, renderedImage); + _histoProgram->setUniform(_histoUniformCache.imageWidth, static_cast(_resolution.x)); + _histoProgram->setUniform(_histoUniformCache.imageHeight, static_cast(_resolution.y)); + _histoProgram->setUniform(_histoUniformCache.maxWhite, _maxWhite); + + glDrawArrays(GL_POINTS, 0, _resolution.x * _resolution.y); + + glFlush(); + + _histoProgram->deactivate(); + + // Testing + std::vector gpuHistogram; + saveTextureToMemory(GL_COLOR_ATTACHMENT0, _numberOfBins, 1, gpuHistogram); + + + // Restores blending state + if (!blendEnabled) { + glDisable(GL_BLEND); + } + else { + glBlendEquationSeparate(blendEquationRGB, blendEquationAlpha); + glBlendFuncSeparate(blendSrcRGB, blendDestRGB, blendSrcAlpha, blendDestAlpha); + } + + // Restores Depth test state + if (depthTestEnabled) { + glEnable(GL_DEPTH_TEST); + } +} + +void FramebufferRenderer::computeMipMappingFromHDRBuffer(GLuint oglImageBuffer) { + ghoul::opengl::TextureUnit samplerUnit; + glBindSampler(samplerUnit, _tmoHdrSampler); + samplerUnit.activate(); + glBindTexture(GL_TEXTURE_2D, oglImageBuffer); + + glGenerateMipmap(GL_TEXTURE_2D); + + _tmoProgram->setUniform(_tmoUniformCache.hdrSampler, samplerUnit); + _tmoProgram->setUniform(_tmoUniformCache.key, _tmoKey); + _tmoProgram->setUniform(_tmoUniformCache.Ywhite, _tmoYwhite); + _tmoProgram->setUniform(_tmoUniformCache.sat, _tmoSaturation); + + glBindFramebuffer(GL_FRAMEBUFFER, _tmoFramebuffer); + GLenum textureBuffer[] = { + GL_COLOR_ATTACHMENT0 + }; + glDrawBuffers(1, textureBuffer); + + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + glViewport(0, 0, _resolution.x, _resolution.y); + + glBindVertexArray(_screenQuad); + + _tmoProgram->activate(); + + glDrawArrays(GL_TRIANGLES, 0, 6); + + _tmoProgram->deactivate(); + + glBindVertexArray(0); +} + void FramebufferRenderer::update() { if (_dirtyMsaaSamplingPattern) { updateMSAASamplingPattern(); @@ -552,7 +739,6 @@ void FramebufferRenderer::update() { if (_resolveProgram->isDirty()) { _resolveProgram->rebuildFromFile(); - ghoul::opengl::updateUniformLocations( *_resolveProgram, _uniformCache, @@ -573,10 +759,28 @@ void FramebufferRenderer::update() { ghoul::opengl::updateUniformLocations( *_bloomResolveProgram, _bloomUniformCache, - BLoomUniformNames + BloomUniformNames ); } + if (_histoProgram->isDirty()) { + _histoProgram->rebuildFromFile(); + ghoul::opengl::updateUniformLocations( + *_histoProgram, + _histoUniformCache, + HistoUniformNames + ); + } + + //if (_histoApplyProgram->isDirty()) { + // _histoApplyProgram->rebuildFromFile(); + // /*ghoul::opengl::updateUniformLocations( + // *_histoApplyProgram, + // _histoApplyUniformCache, + // HistoApplyUniformNames + // );*/ + //} + if (_hdrFilteringProgram->isDirty()) { _hdrFilteringProgram->rebuildFromFile(); @@ -587,6 +791,15 @@ void FramebufferRenderer::update() { ); } + if (_tmoProgram->isDirty()) { + _tmoProgram->rebuildFromFile(); + ghoul::opengl::updateUniformLocations( + *_tmoProgram, + _tmoUniformCache, + TMOUniformNames + ); + } + using K = VolumeRaycaster*; using V = std::unique_ptr; for (const std::pair& program : _exitPrograms) { @@ -716,8 +929,63 @@ void FramebufferRenderer::updateResolution() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } - glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainPositionTexture); + // Histogram Texture + glBindTexture(GL_TEXTURE_2D, _histoTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA32F, + _numberOfBins, + 1, + 0, + GL_RGBA, + GL_FLOAT, + nullptr + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glBindVertexArray(_histoVao); + glBindBuffer(GL_ARRAY_BUFFER, _histoVbo); + + _histoPoints.clear(); + _histoPoints.reserve(_resolution.x * _resolution.y); + for (int i = 0; i < _resolution.x * _resolution.y; ++i) { + _histoPoints.push_back(i); + } + + glBufferData( + GL_ARRAY_BUFFER, + sizeof(float) * _histoPoints.size(), + _histoPoints.data(), + GL_DYNAMIC_DRAW + ); + + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, 0, nullptr); + + glBindVertexArray(0); + + // TMO via mipmapping + glBindTexture(GL_TEXTURE_2D, _tmoTexture); + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_SRGB8, + _resolution.x, + _resolution.y, + 0, + GL_RGB, + GL_UNSIGNED_BYTE, + nullptr + ); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + // G-Buffer main position + glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, _mainPositionTexture); glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, _nAaSamples, @@ -937,6 +1205,36 @@ void FramebufferRenderer::updateBloomConfig() { //_bloomResolveProgram->setIgnoreUniformLocationError(IgnoreError::Yes); } +void FramebufferRenderer::updateHistogramConfig() { + _histoProgram = ghoul::opengl::ProgramObject::Build( + "Computes Histogram from Image", + absPath("${SHADERS}/framebuffer/computeHistogram_vs.glsl"), + absPath("${SHADERS}/framebuffer/computeHistogram_fs.glsl") + ); + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + //_histoProgram->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); + //_histoProgram->setIgnoreUniformLocationError(IgnoreError::Yes); + + /*_histoApplyProgram = ghoul::opengl::ProgramObject::Build( + "Applies histogram on the image", + absPath("${SHADERS}/framebuffer/applyHistogram.vert"), + absPath("${SHADERS}/framebuffer/applyHistogram.frag") + );*/ + //_histoApplyProgram->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); + //_histoApplyProgram->setIgnoreUniformLocationError(IgnoreError::Yes); +} + +void FramebufferRenderer::updateTMOViaMipMappingConfig() { + _tmoProgram = ghoul::opengl::ProgramObject::Build( + "Computes TMO via MipMapping", + absPath("${SHADERS}/framebuffer/computeTMO_vs.glsl"), + absPath("${SHADERS}/framebuffer/computeTMO_fs.glsl") + ); + using IgnoreError = ghoul::opengl::ProgramObject::IgnoreError; + //_tmoProgram ->setIgnoreSubroutineUniformLocationError(IgnoreError::Yes); + //_tmoProgram ->setIgnoreUniformLocationError(IgnoreError::Yes); +} + void FramebufferRenderer::updateHDRAndFiltering() { _hdrFilteringProgram = ghoul::opengl::ProgramObject::Build( "HDR and Filtering Program", @@ -1422,12 +1720,27 @@ void FramebufferRenderer::render(Scene* scene, Camera* camera, float blackoutFac _hdrFilteringProgram->setUniform(_hdrUniformCache.toneMapOperator, _toneMapOperator); _hdrFilteringProgram->setUniform(_hdrUniformCache.aveLum, averageLuminaceInFB); _hdrFilteringProgram->setUniform(_hdrUniformCache.maxWhite, _maxWhite); + _hdrFilteringProgram->setUniform(_hdrUniformCache.Hue, _hue); + _hdrFilteringProgram->setUniform(_hdrUniformCache.Saturation, _saturation); + _hdrFilteringProgram->setUniform(_hdrUniformCache.Value, _value); + _hdrFilteringProgram->setUniform(_hdrUniformCache.Lightness, _lightness); glBindVertexArray(_screenQuad); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); _hdrFilteringProgram->deactivate(); + + //================================ + // Adjusting color and brightness + //================================ + + // Histogram Equalization + computeImageHistogram(); + + computeMipMappingFromHDRBuffer(_hdrFilteringTexture); + + glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); } //glBindFramebuffer(GL_FRAMEBUFFER, defaultFbo); @@ -1670,10 +1983,42 @@ void FramebufferRenderer::setBloomNewFactor(float newFactor) { _bloomNewFactor = newFactor; } +void FramebufferRenderer::setKey(float key) { + _tmoKey = key; +} + +void FramebufferRenderer::setYwhite(float white) { + _tmoYwhite = white; +} + +void FramebufferRenderer::setTmoSaturation(float sat) { + _tmoSaturation = sat; +} + +void FramebufferRenderer::setHue(float hue) { + _hue = hue; +} + +void FramebufferRenderer::setValue(float value) { + _value = value; +} + +void FramebufferRenderer::setSaturation(float sat) { + _saturation = sat; +} + +void FramebufferRenderer::setLightness(float lightness) { + _lightness = lightness; +} + void FramebufferRenderer::enableBloom(bool enable) { _bloomEnabled = enable; } +void FramebufferRenderer::enableHistogram(bool enable) { + _histogramEnabled = enable; +} + float FramebufferRenderer::hdrBackground() const { return _hdrBackground; } diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 3fe10c6a2b..e0b97cebf6 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -189,6 +189,24 @@ namespace { "equivalent of an electronic image sensor for the background image." }; + constexpr openspace::properties::Property::PropertyInfo TMOSaturationInfo = { + "TMOSaturation", + "TMO Saturation", + "TMO Saturation" + }; + + constexpr openspace::properties::Property::PropertyInfo TMOYWhiteInfo = { + "TMOYWhite", + "Ywhite", + "Ywhite" + }; + + constexpr openspace::properties::Property::PropertyInfo TMOKeyInfo = { + "TMOKey", + "Key", + "Key" + }; + constexpr openspace::properties::Property::PropertyInfo GammaInfo = { "Gamma", "Gamma Correction", @@ -238,6 +256,48 @@ namespace { "Enable/Disable Bloom", "Enable/Disable Bloom." }; + + constexpr openspace::properties::Property::PropertyInfo HueInfo = { + "Hue", + "Hue", + "Hue" + }; + + constexpr openspace::properties::Property::PropertyInfo SaturationInfo = { + "Saturation", + "Saturation", + "Saturation" + }; + + constexpr openspace::properties::Property::PropertyInfo ValueInfo = { + "Value", + "Value", + "Value" + }; + + constexpr openspace::properties::Property::PropertyInfo LightnessInfo = { + "Lightness", + "Lightness", + "Lightness" + }; + + openspace::properties::PropertyOwner::PropertyOwnerInfo BloomInfo = { + "BloomOp", + "Bloom Options", + "" + }; + + openspace::properties::PropertyOwner::PropertyOwnerInfo TMOInfo = { + "ToneMappingOp", + "Tone Mapping Options", + "" + }; + + openspace::properties::PropertyOwner::PropertyOwnerInfo ImageInfo = { + "ImageOp", + "Rendered Image Options", + "" + }; } // namespace @@ -255,17 +315,28 @@ RenderEngine::RenderEngine() , _showFrameNumber(ShowFrameNumberInfo, false) , _disableMasterRendering(DisableMasterInfo, false) , _disableSceneTranslationOnMaster(DisableTranslationInfo, false) - , _nAaSamples(AaSamplesInfo, 4, 1, 8) - , _hdrExposure(HDRExposureInfo, 0.4f, 0.01f, 10.0f) - , _hdrBackground(BackgroundExposureInfo, 2.8f, 0.01f, 10.0f) - , _gamma(GammaInfo, 2.2f, 0.01f, 10.0f) - , _maxWhite(MaxWhiteInfo, 4.f, 0.001f, 10000.0f) + , _nAaSamples(AaSamplesInfo, 4, 1, 8) + , _bloomOwner(BloomInfo) , _enableBloom(EnableBloomInfo, false) , _bloomThreshouldMin(BloomThreshouldMinInfo, 0.5, 0.0, 100.0) , _bloomThreshouldMax(BloomThreshouldMaxInfo, 1.0, 0.0, 100.0) , _bloomOrigColorFactor(BloomOrigColorFactorInfo, 1.0, 0.0, 100.0) , _bloomNewColorFactor(BloomNewColorFactorInfo, 1.0, 0.0, 100.0) + , _tmoOwner(TMOInfo) + , _hdrExposure(HDRExposureInfo, 0.4f, 0.01f, 10.0f) + , _hdrBackground(BackgroundExposureInfo, 2.8f, 0.01f, 10.0f) + , _maxWhite(MaxWhiteInfo, 4.f, 0.001f, 10000.0f) , _toneMapOperator(ToneMapOperatorInfo, properties::OptionProperty::DisplayType::Dropdown) + , _tmoKey(TMOKeyInfo, 0.18f, 0.0f, 1.0f) + , _tmoYwhite(TMOYWhiteInfo, 1e6f, 0.0f, 1e10f) + , _tmoSaturation(TMOSaturationInfo, 1.f, 0.0f, 1.0f) + , _imageOwner(ImageInfo) + , _gamma(GammaInfo, 2.2f, 0.01f, 10.0f) + , _hue(HueInfo, 1.f, 0.0f, 10.0f) + , _saturation(SaturationInfo, 1.f, 0.0f, 10.0f) + , _value(ValueInfo, 1.f, 0.0f, 10.0f) + , _lightness(LightnessInfo, 1.f, 0.0f, 10.0f) + { _doPerformanceMeasurements.onChange([this](){ global::performanceManager.setEnabled(_doPerformanceMeasurements); @@ -284,6 +355,7 @@ RenderEngine::RenderEngine() }); addProperty(_nAaSamples); + _hdrExposure.onChange([this]() { if (_renderer) { _renderer->setHDRExposure(_hdrExposure); @@ -298,20 +370,14 @@ RenderEngine::RenderEngine() }); addProperty(_hdrBackground); - _gamma.onChange([this]() { - if (_renderer) { - _renderer->setGamma(_gamma); - } - }); - addProperty(_gamma); - _maxWhite.onChange([this]() { if (_renderer) { _renderer->setMaxWhite(_maxWhite); } }); + addProperty(_maxWhite); - + _toneMapOperator.addOption(static_cast(ToneMapOperators::EXPONENTIAL), "Exponential"); _toneMapOperator.addOption(static_cast(ToneMapOperators::LINEAR), "Linear"); _toneMapOperator.addOption(static_cast(ToneMapOperators::SIMPLE_REINHARD), "Simple Reinhard"); @@ -333,6 +399,73 @@ RenderEngine::RenderEngine() }); addProperty(_toneMapOperator); + + _tmoKey.onChange([this]() { + if (_renderer) { + _renderer->setKey(_tmoKey); + } + }); + + addProperty(_tmoKey); + + _tmoYwhite.onChange([this]() { + if (_renderer) { + _renderer->setYwhite(_tmoYwhite); + } + }); + + addProperty(_tmoYwhite); + + _tmoSaturation.onChange([this]() { + if (_renderer) { + _renderer->setTmoSaturation(_tmoSaturation); + } + }); + + addProperty(_tmoSaturation); + + //this->addPropertySubOwner(_tmoOwner); + + + _gamma.onChange([this]() { + if (_renderer) { + _renderer->setGamma(_gamma); + } + }); + addProperty(_gamma); + + _hue.onChange([this]() { + if (_renderer) { + _renderer->setHue(_hue); + } + }); + + addProperty(_hue); + + _saturation.onChange([this]() { + if (_renderer) { + _renderer->setSaturation(_saturation); + } + }); + + addProperty(_saturation); + + _value.onChange([this]() { + if (_renderer) { + _renderer->setValue(_value); + } + }); + + addProperty(_value); + + _lightness.onChange([this]() { + if (_renderer) { + _renderer->setLightness(_lightness); + } + }); + addProperty(_lightness); + + //this->addPropertySubOwner(_imageOwner); _enableBloom.onChange([this]() { if (_renderer) { @@ -369,6 +502,8 @@ RenderEngine::RenderEngine() _renderer->setBloomNewFactor(_bloomNewColorFactor); } }); + + //this->addPropertySubOwner(_bloomOwner); addProperty(_applyWarping);