Merge branch 'hdr_quick' into 'master'

Fix auto exposure

See merge request OpenMW/openmw!2174
check_span
psi29a 2 years ago
commit 26bd907b0b

@ -149,7 +149,7 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(postprocessEnabledCheckBox, "enabled", "Post Processing");
loadSettingBool(postprocessLiveReloadCheckBox, "live reload", "Post Processing");
loadSettingBool(postprocessTransparentPostpassCheckBox, "transparent postpass", "Post Processing");
postprocessHDRTimeComboBox->setValue(Settings::Manager::getDouble("hdr exposure time", "Post Processing"));
postprocessHDRTimeComboBox->setValue(Settings::Manager::getDouble("auto exposure speed", "Post Processing"));
connect(skyBlendingCheckBox, SIGNAL(toggled(bool)), this, SLOT(slotSkyBlendingToggled(bool)));
loadSettingBool(radialFogCheckBox, "radial fog", "Fog");
@ -305,8 +305,8 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(postprocessLiveReloadCheckBox, "live reload", "Post Processing");
saveSettingBool(postprocessTransparentPostpassCheckBox, "transparent postpass", "Post Processing");
double hdrExposureTime = postprocessHDRTimeComboBox->value();
if (hdrExposureTime != Settings::Manager::getDouble("hdr exposure time", "Post Processing"))
Settings::Manager::setDouble("hdr exposure time", "Post Processing", hdrExposureTime);
if (hdrExposureTime != Settings::Manager::getDouble("auto exposure speed", "Post Processing"))
Settings::Manager::setDouble("auto exposure speed", "Post Processing", hdrExposureTime);
saveSettingBool(radialFogCheckBox, "radial fog", "Fog");
saveSettingBool(exponentialFogCheckBox, "exponential fog", "Fog");

@ -23,7 +23,7 @@ add_openmw_dir (mwrender
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover
postprocessor pingpongcull hdr pingpongcanvas transparentpass navmeshmode
postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass navmeshmode
)
add_openmw_dir (mwinput

@ -1,123 +0,0 @@
#include "hdr.hpp"
#include <components/settings/settings.hpp>
#include <components/shader/shadermanager.hpp>
#include "pingpongcanvas.hpp"
namespace MWRender
{
HDRDriver::HDRDriver(Shader::ShaderManager& shaderManager)
: mCompiled(false)
, mEnabled(false)
, mWidth(1)
, mHeight(1)
{
const float hdrExposureTime = std::clamp(Settings::Manager::getFloat("hdr exposure time", "Post Processing"), 0.f, 1.f);
constexpr float minLog = -9.0;
constexpr float maxLog = 4.0;
constexpr float logLumRange = (maxLog - minLog);
constexpr float invLogLumRange = 1.0 / logLumRange;
constexpr float epsilon = 0.004;
Shader::ShaderManager::DefineMap defines = {
{"minLog", std::to_string(minLog)},
{"maxLog", std::to_string(maxLog)},
{"logLumRange", std::to_string(logLumRange)},
{"invLogLumRange", std::to_string(invLogLumRange)},
{"hdrExposureTime", std::to_string(hdrExposureTime)},
{"epsilon", std::to_string(epsilon)},
};
auto vertex = shaderManager.getShader("fullscreen_tri_vertex.glsl", {}, osg::Shader::VERTEX);
auto hdrLuminance = shaderManager.getShader("hdr_luminance_fragment.glsl", defines, osg::Shader::FRAGMENT);
auto hdr = shaderManager.getShader("hdr_fragment.glsl", defines, osg::Shader::FRAGMENT);
mProgram = shaderManager.getProgram(vertex, hdr);
mLuminanceProgram = shaderManager.getProgram(vertex, hdrLuminance);
}
void HDRDriver::compile()
{
int mipmapLevels = osg::Image::computeNumberOfMipmapLevels(mWidth, mHeight);
for (auto& buffer : mBuffers)
{
buffer.texture = new osg::Texture2D;
buffer.texture->setInternalFormat(GL_R16F);
buffer.texture->setSourceFormat(GL_RED);
buffer.texture->setSourceType(GL_FLOAT);
buffer.texture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR_MIPMAP_NEAREST);
buffer.texture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
buffer.texture->setTextureSize(mWidth, mHeight);
buffer.texture->setNumMipmapLevels(mipmapLevels);
buffer.finalTexture = new osg::Texture2D;
buffer.finalTexture->setInternalFormat(GL_R16F);
buffer.finalTexture->setSourceFormat(GL_RED);
buffer.finalTexture->setSourceType(GL_FLOAT);
buffer.finalTexture->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
buffer.finalTexture->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
buffer.finalTexture->setTextureSize(1, 1);
buffer.finalFbo = new osg::FrameBufferObject;
buffer.finalFbo->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(buffer.finalTexture));
buffer.fullscreenFbo = new osg::FrameBufferObject;
buffer.fullscreenFbo->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(buffer.texture));
buffer.mipmapFbo = new osg::FrameBufferObject;
buffer.mipmapFbo->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(buffer.texture, mipmapLevels - 1));
buffer.fullscreenStateset = new osg::StateSet;
buffer.fullscreenStateset->setAttributeAndModes(mLuminanceProgram);
buffer.fullscreenStateset->addUniform(new osg::Uniform("sceneTex", 0));
buffer.mipmapStateset = new osg::StateSet;
buffer.mipmapStateset->setAttributeAndModes(mProgram);
buffer.mipmapStateset->setTextureAttributeAndModes(0, buffer.texture);
buffer.mipmapStateset->addUniform(new osg::Uniform("luminanceSceneTex", 0));
buffer.mipmapStateset->addUniform(new osg::Uniform("prevLuminanceSceneTex", 1));
}
mBuffers[0].mipmapStateset->setTextureAttributeAndModes(1, mBuffers[1].finalTexture);
mBuffers[1].mipmapStateset->setTextureAttributeAndModes(1, mBuffers[0].finalTexture);
mCompiled = true;
}
void HDRDriver::draw(const PingPongCanvas& canvas, osg::RenderInfo& renderInfo, osg::State& state, osg::GLExtensions* ext, size_t frameId)
{
if (!mEnabled)
return;
if (!mCompiled)
compile();
auto& hdrBuffer = mBuffers[frameId];
hdrBuffer.fullscreenFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
hdrBuffer.fullscreenStateset->setTextureAttributeAndModes(0, canvas.getSceneTexture(frameId));
state.apply(hdrBuffer.fullscreenStateset);
canvas.drawGeometry(renderInfo);
state.applyTextureAttribute(0, hdrBuffer.texture);
ext->glGenerateMipmap(GL_TEXTURE_2D);
hdrBuffer.mipmapFbo->apply(state, osg::FrameBufferObject::READ_FRAMEBUFFER);
hdrBuffer.finalFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
ext->glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_LINEAR);
state.apply(hdrBuffer.mipmapStateset);
canvas.drawGeometry(renderInfo);
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0);
}
osg::ref_ptr<osg::Texture2D> HDRDriver::getLuminanceTexture(size_t frameId) const
{
return mBuffers[frameId].finalTexture;
}
}

@ -1,71 +0,0 @@
#ifndef OPENMW_MWRENDER_HDR_H
#define OPENMW_MWRENDER_HDR_H
#include <array>
#include <osg/FrameBufferObject>
#include <osg/Texture2D>
#include <osg/Program>
namespace Shader
{
class ShaderManager;
}
namespace MWRender
{
class PingPongCanvas;
class HDRDriver
{
public:
HDRDriver() = default;
HDRDriver(Shader::ShaderManager& shaderManager);
void draw(const PingPongCanvas& canvas, osg::RenderInfo& renderInfo, osg::State& state, osg::GLExtensions* ext, size_t frameId);
bool isEnabled() const { return mEnabled; }
void enable() { mEnabled = true; }
void disable() { mEnabled = false; }
void dirty(int w, int h)
{
mWidth = w;
mHeight = h;
mCompiled = false;
}
osg::ref_ptr<osg::Texture2D> getLuminanceTexture(size_t frameId) const;
private:
void compile();
struct HDRContainer
{
osg::ref_ptr<osg::FrameBufferObject> fullscreenFbo;
osg::ref_ptr<osg::FrameBufferObject> mipmapFbo;
osg::ref_ptr<osg::FrameBufferObject> finalFbo;
osg::ref_ptr<osg::Texture2D> texture;
osg::ref_ptr<osg::Texture2D> finalTexture;
osg::ref_ptr<osg::StateSet> fullscreenStateset;
osg::ref_ptr<osg::StateSet> mipmapStateset;
};
std::array<HDRContainer, 2> mBuffers;
osg::ref_ptr<osg::Program> mLuminanceProgram;
osg::ref_ptr<osg::Program> mProgram;
bool mCompiled;
bool mEnabled;
int mWidth;
int mHeight;
};
}
#endif

@ -0,0 +1,134 @@
#include "luminancecalculator.hpp"
#include <components/settings/settings.hpp>
#include <components/shader/shadermanager.hpp>
#include "pingpongcanvas.hpp"
namespace MWRender
{
LuminanceCalculator::LuminanceCalculator(Shader::ShaderManager& shaderManager)
{
const float hdrExposureTime = std::max(Settings::Manager::getFloat("auto exposure speed", "Post Processing"), 0.0001f);
constexpr float minLog = -9.0;
constexpr float maxLog = 4.0;
constexpr float logLumRange = (maxLog - minLog);
constexpr float invLogLumRange = 1.0 / logLumRange;
constexpr float epsilon = 0.004;
Shader::ShaderManager::DefineMap defines = {
{"minLog", std::to_string(minLog)},
{"maxLog", std::to_string(maxLog)},
{"logLumRange", std::to_string(logLumRange)},
{"invLogLumRange", std::to_string(invLogLumRange)},
{"hdrExposureTime", std::to_string(hdrExposureTime)},
{"epsilon", std::to_string(epsilon)},
};
auto vertex = shaderManager.getShader("fullscreen_tri_vertex.glsl", {}, osg::Shader::VERTEX);
auto luminanceFragment = shaderManager.getShader("hdr_luminance_fragment.glsl", defines, osg::Shader::FRAGMENT);
auto resolveFragment = shaderManager.getShader("hdr_resolve_fragment.glsl", defines, osg::Shader::FRAGMENT);
mResolveProgram = shaderManager.getProgram(vertex, resolveFragment);
mLuminanceProgram = shaderManager.getProgram(vertex, luminanceFragment);
}
void LuminanceCalculator::compile()
{
int mipmapLevels = osg::Image::computeNumberOfMipmapLevels(mWidth, mHeight);
for (auto& buffer : mBuffers)
{
buffer.mipmappedSceneLuminanceTex = new osg::Texture2D;
buffer.mipmappedSceneLuminanceTex->setInternalFormat(GL_R16F);
buffer.mipmappedSceneLuminanceTex->setSourceFormat(GL_RED);
buffer.mipmappedSceneLuminanceTex->setSourceType(GL_FLOAT);
buffer.mipmappedSceneLuminanceTex->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::LINEAR_MIPMAP_NEAREST);
buffer.mipmappedSceneLuminanceTex->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::LINEAR);
buffer.mipmappedSceneLuminanceTex->setTextureSize(mWidth, mHeight);
buffer.mipmappedSceneLuminanceTex->setNumMipmapLevels(mipmapLevels);
buffer.luminanceTex = new osg::Texture2D;
buffer.luminanceTex->setInternalFormat(GL_R16F);
buffer.luminanceTex->setSourceFormat(GL_RED);
buffer.luminanceTex->setSourceType(GL_FLOAT);
buffer.luminanceTex->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
buffer.luminanceTex->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
buffer.luminanceTex->setTextureSize(1, 1);
buffer.luminanceProxyTex = new osg::Texture2D(*buffer.luminanceTex);
buffer.resolveFbo = new osg::FrameBufferObject;
buffer.resolveFbo->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(buffer.luminanceTex));
buffer.luminanceProxyFbo = new osg::FrameBufferObject;
buffer.luminanceProxyFbo->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(buffer.luminanceProxyTex));
buffer.resolveSceneLumFbo = new osg::FrameBufferObject;
buffer.resolveSceneLumFbo->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(buffer.mipmappedSceneLuminanceTex, mipmapLevels - 1));
buffer.sceneLumFbo = new osg::FrameBufferObject;
buffer.sceneLumFbo->setAttachment(osg::FrameBufferObject::BufferComponent::COLOR_BUFFER0, osg::FrameBufferAttachment(buffer.mipmappedSceneLuminanceTex));
buffer.sceneLumSS = new osg::StateSet;
buffer.sceneLumSS->setAttributeAndModes(mLuminanceProgram);
buffer.sceneLumSS->addUniform(new osg::Uniform("sceneTex", 0));
buffer.resolveSS = new osg::StateSet;
buffer.resolveSS->setAttributeAndModes(mResolveProgram);
buffer.resolveSS->setTextureAttributeAndModes(0, buffer.luminanceProxyTex);
buffer.resolveSS->addUniform(new osg::Uniform("luminanceSceneTex", 0));
buffer.resolveSS->addUniform(new osg::Uniform("prevLuminanceSceneTex", 1));
}
mBuffers[0].resolveSS->setTextureAttributeAndModes(1, mBuffers[1].luminanceTex);
mBuffers[1].resolveSS->setTextureAttributeAndModes(1, mBuffers[0].luminanceTex);
mCompiled = true;
}
void LuminanceCalculator::draw(const PingPongCanvas& canvas, osg::RenderInfo& renderInfo, osg::State& state, osg::GLExtensions* ext, size_t frameId)
{
if (!mEnabled)
return;
bool dirty = !mCompiled;
if (dirty)
compile();
auto& buffer = mBuffers[frameId];
buffer.sceneLumFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
buffer.sceneLumSS->setTextureAttributeAndModes(0, canvas.getSceneTexture(frameId));
state.apply(buffer.sceneLumSS);
canvas.drawGeometry(renderInfo);
state.applyTextureAttribute(0, buffer.mipmappedSceneLuminanceTex);
ext->glGenerateMipmap(GL_TEXTURE_2D);
buffer.resolveSceneLumFbo->apply(state, osg::FrameBufferObject::READ_FRAMEBUFFER);
buffer.luminanceProxyFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
ext->glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
if (dirty) {
// Use current frame data for previous frame to warm up calculations and prevent popin
mBuffers[(frameId + 1) % 2].resolveFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
ext->glBlitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, GL_COLOR_BUFFER_BIT, GL_NEAREST);
buffer.luminanceProxyFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
}
buffer.resolveFbo->apply(state, osg::FrameBufferObject::DRAW_FRAMEBUFFER);
state.apply(buffer.resolveSS);
canvas.drawGeometry(renderInfo);
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, state.getGraphicsContext() ? state.getGraphicsContext()->getDefaultFboId() : 0);
}
osg::ref_ptr<osg::Texture2D> LuminanceCalculator::getLuminanceTexture(size_t frameId) const
{
return mBuffers[frameId].luminanceTex;
}
}

@ -0,0 +1,74 @@
#ifndef OPENMW_MWRENDER_LUMINANCECALCULATOR_H
#define OPENMW_MWRENDER_LUMINANCECALCULATOR_H
#include <array>
#include <osg/FrameBufferObject>
#include <osg/Texture2D>
#include <osg/Program>
namespace Shader
{
class ShaderManager;
}
namespace MWRender
{
class PingPongCanvas;
class LuminanceCalculator
{
public:
LuminanceCalculator() = default;
LuminanceCalculator(Shader::ShaderManager& shaderManager);
void draw(const PingPongCanvas& canvas, osg::RenderInfo& renderInfo, osg::State& state, osg::GLExtensions* ext, size_t frameId);
bool isEnabled() const { return mEnabled; }
void enable() { mEnabled = true; }
void disable() { mEnabled = false; }
void dirty(int w, int h)
{
constexpr float scale = 0.5;
mWidth = w * scale;
mHeight = h * scale;
mCompiled = false;
}
osg::ref_ptr<osg::Texture2D> getLuminanceTexture(size_t frameId) const;
private:
void compile();
struct Container
{
osg::ref_ptr<osg::FrameBufferObject> sceneLumFbo;
osg::ref_ptr<osg::FrameBufferObject> resolveSceneLumFbo;
osg::ref_ptr<osg::FrameBufferObject> resolveFbo;
osg::ref_ptr<osg::FrameBufferObject> luminanceProxyFbo;
osg::ref_ptr<osg::Texture2D> mipmappedSceneLuminanceTex;
osg::ref_ptr<osg::Texture2D> luminanceTex;
osg::ref_ptr<osg::Texture2D> luminanceProxyTex;
osg::ref_ptr<osg::StateSet> sceneLumSS;
osg::ref_ptr<osg::StateSet> resolveSS;
};
std::array<Container, 2> mBuffers;
osg::ref_ptr<osg::Program> mLuminanceProgram;
osg::ref_ptr<osg::Program> mResolveProgram;
bool mCompiled = false;
bool mEnabled = false;
int mWidth = 1;
int mHeight = 1;
};
}
#endif

@ -27,8 +27,8 @@ namespace MWRender
addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 3));
mHDRDriver = HDRDriver(shaderManager);
mHDRDriver.disable();
mLuminanceCalculator = LuminanceCalculator(shaderManager);
mLuminanceCalculator.disable();
Shader::ShaderManager::DefineMap defines;
Stereo::Manager::instance().shaderStereoDefines(defines);
@ -158,7 +158,7 @@ namespace MWRender
mMultiviewResolveStateSet->setTextureAttribute(PostProcessor::Unit_LastShader, (osg::Texture*)mMultiviewResolveFramebuffer->getAttachment(osg::Camera::COLOR_BUFFER0).getTexture());
}
mHDRDriver.dirty(bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
mLuminanceCalculator.dirty(bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
if (Stereo::getStereo())
mRenderViewport = new osg::Viewport(0, 0, bufferData.sceneTex->getTextureWidth(), bufferData.sceneTex->getTextureHeight());
@ -174,10 +174,10 @@ namespace MWRender
{GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT}
}};
(bufferData.hdr) ? mHDRDriver.enable() : mHDRDriver.disable();
(bufferData.hdr) ? mLuminanceCalculator.enable() : mLuminanceCalculator.disable();
// A histogram based approach is superior way to calculate scene luminance. Using mipmaps is more broadly supported, so that's what we use for now.
mHDRDriver.draw(*this, renderInfo, state, ext, frameId);
mLuminanceCalculator.draw(*this, renderInfo, state, ext, frameId);
auto buffer = buffers[0];
@ -217,7 +217,7 @@ namespace MWRender
node.mRootStateSet->setTextureAttribute(PostProcessor::Unit_Depth, bufferData.depthTex);
if (bufferData.hdr)
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_EyeAdaptation, mHDRDriver.getLuminanceTexture(frameId));
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_EyeAdaptation, mLuminanceCalculator.getLuminanceTexture(frameId));
if (bufferData.normalsTex)
node.mRootStateSet->setTextureAttribute(PostProcessor::TextureUnits::Unit_Normals, bufferData.normalsTex);

@ -11,7 +11,7 @@
#include <components/fx/technique.hpp>
#include "postprocessor.hpp"
#include "hdr.hpp"
#include "luminancecalculator.hpp"
namespace Shader
{
@ -55,7 +55,7 @@ namespace MWRender
private:
void copyNewFrameData(size_t frameId) const;
mutable HDRDriver mHDRDriver;
mutable LuminanceCalculator mLuminanceCalculator;
osg::ref_ptr<osg::Program> mFallbackProgram;
osg::ref_ptr<osg::Program> mMultiviewResolveProgram;

@ -34,12 +34,12 @@ Automatically reloads a shader if the file has been changed. This is useful for
.. warning::
This should be disabled for normal gameplay
hdr exposure time
-----------------
auto exposure speed
-------------------
:Type: float
:Range: 0.0 to 1.0
:Default: 0.05
:Range: Any number > 0.0001
:Default: 0.9
Use for eye adaptation to control speed at which average scene luminance can change from one frame to the next.
Average scene luminance is used in some shader effects for features such as dynamic eye adaptation.

@ -1204,7 +1204,7 @@ chain =
live reload = false
# Used for eye adaptation to control speed at which scene luminance can change from one frame to the next. No effect when HDR is not being utilized.
hdr exposure time = 0.05
auto exposure speed = 0.9
# Transparent depth postpass. Re-renders transparent objects with alpha-clipping forced with a fixed threshold.
transparent postpass = true

@ -50,7 +50,7 @@ set(SHADER_FILES
sky_fragment.glsl
skypasses.glsl
softparticles.glsl
hdr_fragment.glsl
hdr_resolve_fragment.glsl
hdr_luminance_fragment.glsl
fullscreen_tri_vertex.glsl
fullscreen_tri_fragment.glsl

@ -1,14 +0,0 @@
#version 120
varying vec2 uv;
uniform sampler2D luminanceSceneTex;
uniform sampler2D prevLuminanceSceneTex;
void main()
{
float prevLum = texture2D(prevLuminanceSceneTex, vec2(0.5, 0.5)).r;
float l = texture2D(luminanceSceneTex, vec2(0.5, 0.5)).r;
float weightedAvgLum = exp2((l * @logLumRange) + @minLog);
gl_FragColor.r = prevLum + (weightedAvgLum - prevLum) * @hdrExposureTime;
}

@ -6,12 +6,7 @@ uniform sampler2D sceneTex;
void main()
{
float lum = dot(texture2D(sceneTex, uv).rgb, vec3(0.2126, 0.7152, 0.0722));
if (lum < @epsilon)
{
gl_FragColor.r = 0.0;
return;
}
lum = max(lum, @epsilon);
gl_FragColor.r = clamp((log2(lum) - @minLog) * @invLogLumRange, 0.0, 1.0);
}

@ -0,0 +1,16 @@
#version 120
varying vec2 uv;
uniform sampler2D luminanceSceneTex;
uniform sampler2D prevLuminanceSceneTex;
uniform float osg_DeltaFrameTime;
void main()
{
float prevLum = texture2D(prevLuminanceSceneTex, vec2(0.5, 0.5)).r;
float currLum = texture2D(luminanceSceneTex, vec2(0.5, 0.5)).r;
float avgLum = exp2((currLum * @logLumRange) + @minLog);
gl_FragColor.r = prevLum + (avgLum - prevLum) * (1.0 - exp(-osg_DeltaFrameTime * @hdrExposureTime));
}

@ -695,7 +695,7 @@
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Controls how much eye adaptation can change from frame to frame. Smaller values makes for slower transitions.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>HDR exposure time</string>
<string>Auto exposure speed</string>
</property>
</widget>
</item>
@ -708,10 +708,10 @@
<number>3</number>
</property>
<property name="minimum">
<double>0.000000000000000</double>
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>

Loading…
Cancel
Save