Fix incorrect minimum ambient

pull/593/head
glassmancody.info 4 years ago
parent 280fd2b162
commit 3d713e8602

@ -49,6 +49,7 @@ Programmers
Cédric Mocquillon Cédric Mocquillon
Chris Boyce (slothlife) Chris Boyce (slothlife)
Chris Robinson (KittyCat) Chris Robinson (KittyCat)
Cody Glassman (Wazabear)
Coleman Smith (olcoal) Coleman Smith (olcoal)
Cory F. Cohen (cfcohen) Cory F. Cohen (cfcohen)
Cris Mihalache (Mirceam) Cris Mihalache (Mirceam)

@ -537,7 +537,32 @@ namespace MWRender
void RenderingManager::configureAmbient(const ESM::Cell *cell) void RenderingManager::configureAmbient(const ESM::Cell *cell)
{ {
setAmbientColour(SceneUtil::colourFromRGB(cell->mAmbi.mAmbient)); bool needsAdjusting = false;
if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP)
needsAdjusting = !cell->isExterior() && !(cell->mData.mFlags & ESM::Cell::QuasiEx);
auto ambient = SceneUtil::colourFromRGB(cell->mAmbi.mAmbient);
if (needsAdjusting)
{
static constexpr float pR = 0.2126;
static constexpr float pG = 0.7152;
static constexpr float pB = 0.0722;
// we already work in linear RGB so no conversions are needed for the luminosity function
float relativeLuminance = pR*ambient.r() + pG*ambient.g() + pB*ambient.b();
if (relativeLuminance < mMinimumAmbientLuminance)
{
// brighten ambient so it reaches the minimum threshold but no more, we want to mess with content data as least we can
float targetBrightnessIncreaseFactor = mMinimumAmbientLuminance / relativeLuminance;
if (ambient.r() == 0.f && ambient.g() == 0.f && ambient.b() == 0.f)
ambient = osg::Vec4(targetBrightnessIncreaseFactor, targetBrightnessIncreaseFactor, targetBrightnessIncreaseFactor, ambient.a());
else
ambient *= targetBrightnessIncreaseFactor;
}
}
setAmbientColour(ambient);
osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight); osg::Vec4f diffuse = SceneUtil::colourFromRGB(cell->mAmbi.mSunlight);
mSunLight->setDiffuse(diffuse); mSunLight->setDiffuse(diffuse);
@ -1076,25 +1101,7 @@ namespace MWRender
osg::Vec4f color = mAmbientColor; osg::Vec4f color = mAmbientColor;
if (mNightEyeFactor > 0.f) if (mNightEyeFactor > 0.f)
{
color += osg::Vec4f(0.7, 0.7, 0.7, 0.0) * mNightEyeFactor; color += osg::Vec4f(0.7, 0.7, 0.7, 0.0) * mNightEyeFactor;
}
// optionally brighten up ambient interiors when using a non-FFP emulated lighting method
else if (mResourceSystem->getSceneManager()->getLightingMethod() != SceneUtil::LightingMethod::FFP)
{
static constexpr float pR = 0.2126;
static constexpr float pG = 0.7152;
static constexpr float pB = 0.0722;
// we already work in linear RGB so no conversions are needed for the luminosity function
float relativeLuminance = pR*color.r() + pG*color.g() + pB*color.b();
if (relativeLuminance < mMinimumAmbientLuminance)
{
// brighten ambient so it reaches the minimum threshold but no more, we want to mess with content data as least we can
float targetBrightnessIncreaseFactor = mMinimumAmbientLuminance / relativeLuminance;
color *= targetBrightnessIncreaseFactor;
}
}
mStateUpdater->setAmbientColor(color); mStateUpdater->setAmbientColor(color);
} }

@ -381,27 +381,14 @@ namespace SceneUtil
void apply(osg::State &state) const override void apply(osg::State &state) const override
{ {
osg::Matrix modelViewMatrix = state.getModelViewMatrix();
state.applyModelViewMatrix(state.getInitialViewMatrix());
LightStateCache* cache = getLightStateCache(state.getContextID(), mLightManager->getMaxLights());
for (size_t i = 0; i < mLights.size(); ++i) for (size_t i = 0; i < mLights.size(); ++i)
{ {
osg::Light* current = cache->lastAppliedLight[i];
auto light = mLights[i]; auto light = mLights[i];
if (current != light.get()) mLightManager->getLightUniform(i+1, LightManager::UniformKey::Diffuse)->set(light->getDiffuse());
{ mLightManager->getLightUniform(i+1, LightManager::UniformKey::Ambient)->set(light->getAmbient());
mLightManager->getLightUniform(i+1, LightManager::UniformKey::Diffuse)->set(light->getDiffuse()); mLightManager->getLightUniform(i+1, LightManager::UniformKey::Attenuation)->set(osg::Vec4(light->getConstantAttenuation(), light->getLinearAttenuation(), light->getQuadraticAttenuation(), getLightRadius(light)));
mLightManager->getLightUniform(i+1, LightManager::UniformKey::Ambient)->set(light->getAmbient()); mLightManager->getLightUniform(i+1, LightManager::UniformKey::Position)->set(light->getPosition() * state.getInitialViewMatrix());
mLightManager->getLightUniform(i+1, LightManager::UniformKey::Attenuation)->set(osg::Vec4(light->getConstantAttenuation(), light->getLinearAttenuation(), light->getQuadraticAttenuation(), getLightRadius(light)));
mLightManager->getLightUniform(i+1, LightManager::UniformKey::Position)->set(light->getPosition() * state.getModelViewMatrix());
cache->lastAppliedLight[i] = mLights[i];
}
} }
state.applyModelViewMatrix(modelViewMatrix);
} }
private: private:
@ -643,7 +630,7 @@ namespace SceneUtil
mDummyProgram->addBindUniformBlock("LightBufferBinding", static_cast<int>(Shader::UBOBinding::LightBuffer)); mDummyProgram->addBindUniformBlock("LightBufferBinding", static_cast<int>(Shader::UBOBinding::LightBuffer));
// Needed to query the layout of the buffer object. The layout specifier needed to use the std140 layout is not reliably // Needed to query the layout of the buffer object. The layout specifier needed to use the std140 layout is not reliably
// available, regardless of extensions, until GLSL 140. // available, regardless of extensions, until GLSL 140.
mLightManager->getOrCreateStateSet()->setAttributeAndModes(mDummyProgram, osg::StateAttribute::ON|osg::StateAttribute::PROTECTED); mLightManager->getOrCreateStateSet()->setAttributeAndModes(mDummyProgram, osg::StateAttribute::ON);
} }
LightManagerStateAttribute(const LightManagerStateAttribute& copy, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY) LightManagerStateAttribute(const LightManagerStateAttribute& copy, const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
@ -756,9 +743,10 @@ namespace SceneUtil
, mPointLightFadeEnd(0.f) , mPointLightFadeEnd(0.f)
, mPointLightFadeStart(0.f) , mPointLightFadeStart(0.f)
{ {
setUpdateCallback(new LightManagerUpdateCallback);
if (ffp) if (ffp)
{ {
setLightingMethod(LightingMethod::FFP);
initFFP(LightManager::mFFPMaxLights); initFFP(LightManager::mFFPMaxLights);
return; return;
} }
@ -769,11 +757,7 @@ namespace SceneUtil
{ {
Log(Debug::Error) << "Invalid option for 'lighting method': got '" << lightingMethodString Log(Debug::Error) << "Invalid option for 'lighting method': got '" << lightingMethodString
<< "', expected legacy, shaders compatible, or shaders. Falling back to 'shaders compatible'."; << "', expected legacy, shaders compatible, or shaders. Falling back to 'shaders compatible'.";
setLightingMethod(LightingMethod::PerObjectUniform); lightingMethod = LightingMethod::PerObjectUniform;
}
else
{
setLightingMethod(lightingMethod);
} }
mPointLightRadiusMultiplier = std::clamp(Settings::Manager::getFloat("light bounds multiplier", "Shaders"), 0.f, 10.f); mPointLightRadiusMultiplier = std::clamp(Settings::Manager::getFloat("light bounds multiplier", "Shaders"), 0.f, 10.f);
@ -791,7 +775,7 @@ namespace SceneUtil
static bool hasLoggedWarnings = false; static bool hasLoggedWarnings = false;
if (getLightingMethod() == LightingMethod::SingleUBO && !hasLoggedWarnings) if (lightingMethod == LightingMethod::SingleUBO && !hasLoggedWarnings)
{ {
if (!supportsUBO) if (!supportsUBO)
Log(Debug::Warning) << "GL_ARB_uniform_buffer_object not supported: switching to shader compatibility lighting mode"; Log(Debug::Warning) << "GL_ARB_uniform_buffer_object not supported: switching to shader compatibility lighting mode";
@ -802,19 +786,13 @@ namespace SceneUtil
int targetLights = Settings::Manager::getInt("max lights", "Shaders"); int targetLights = Settings::Manager::getInt("max lights", "Shaders");
if (!supportsUBO || !supportsGPU4 || getLightingMethod() == LightingMethod::PerObjectUniform) if (!supportsUBO || !supportsGPU4 || lightingMethod == LightingMethod::PerObjectUniform)
{
setLightingMethod(LightingMethod::PerObjectUniform);
initPerObjectUniform(targetLights); initPerObjectUniform(targetLights);
}
else else
{
initSingleUBO(targetLights); initSingleUBO(targetLights);
}
getOrCreateStateSet()->addUniform(new osg::Uniform("PointLightCount", 0)); getOrCreateStateSet()->addUniform(new osg::Uniform("PointLightCount", 0));
setUpdateCallback(new LightManagerUpdateCallback);
addCullCallback(new LightManagerCullCallback(this)); addCullCallback(new LightManagerCullCallback(this));
} }
@ -876,18 +854,18 @@ namespace SceneUtil
void LightManager::initFFP(int targetLights) void LightManager::initFFP(int targetLights)
{ {
setLightingMethod(LightingMethod::FFP);
setMaxLights(targetLights); setMaxLights(targetLights);
for (int i = 0; i < getMaxLights(); ++i) for (int i = 0; i < getMaxLights(); ++i)
mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light>>())); mDummies.push_back(new FFPLightStateAttribute(i, std::vector<osg::ref_ptr<osg::Light>>()));
setUpdateCallback(new LightManagerUpdateCallback);
} }
void LightManager::initPerObjectUniform(int targetLights) void LightManager::initPerObjectUniform(int targetLights)
{ {
auto* stateset = getOrCreateStateSet(); auto* stateset = getOrCreateStateSet();
setLightingMethod(LightingMethod::PerObjectUniform);
setMaxLights(std::max(2, targetLights)); setMaxLights(std::max(2, targetLights));
mLightUniforms.resize(getMaxLights()+1); mLightUniforms.resize(getMaxLights()+1);
@ -918,6 +896,7 @@ namespace SceneUtil
void LightManager::initSingleUBO(int targetLights) void LightManager::initSingleUBO(int targetLights)
{ {
setLightingMethod(LightingMethod::SingleUBO);
setMaxLights(std::clamp(targetLights, 2, getMaxLightsInScene() / 2)); setMaxLights(std::clamp(targetLights, 2, getMaxLightsInScene() / 2));
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
@ -1059,6 +1038,7 @@ namespace SceneUtil
const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum) const std::vector<LightManager::LightSourceViewBound>& LightManager::getLightsInViewSpace(osg::Camera *camera, const osg::RefMatrix* viewMatrix, size_t frameNum)
{ {
bool isReflectionCamera = camera->getName() == "ReflectionCamera";
osg::observer_ptr<osg::Camera> camPtr (camera); osg::observer_ptr<osg::Camera> camPtr (camera);
auto it = mLightsInViewSpace.find(camPtr); auto it = mLightsInViewSpace.find(camPtr);
@ -1075,17 +1055,18 @@ namespace SceneUtil
osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), radius * mPointLightRadiusMultiplier); osg::BoundingSphere viewBound = osg::BoundingSphere(osg::Vec3f(0,0,0), radius * mPointLightRadiusMultiplier);
transformBoundingSphere(worldViewMat, viewBound); transformBoundingSphere(worldViewMat, viewBound);
static const float fadeDelta = mPointLightFadeEnd - mPointLightFadeStart; if (!isReflectionCamera)
if (mPointLightFadeEnd != 0.f)
{ {
float fade = 1 - std::clamp((viewBound.center().length() - mPointLightFadeStart) / fadeDelta, 0.f, 1.f); static const float fadeDelta = mPointLightFadeEnd - mPointLightFadeStart;
if (mPointLightFadeEnd != 0.f)
if (fade == 0.f) {
continue; float fade = 1 - std::clamp((viewBound.center().length() - mPointLightFadeStart) / fadeDelta, 0.f, 1.f);
if (fade == 0.f)
continue;
auto* light = transform.mLightSource->getLight(frameNum); auto* light = transform.mLightSource->getLight(frameNum);
light->setDiffuse(light->getDiffuse() * fade); light->setDiffuse(light->getDiffuse() * fade);
}
} }
LightSourceViewBound l; LightSourceViewBound l;

@ -160,12 +160,12 @@ Sets the internal handling of light sources.
'legacy' is restricted to 8 lights per object and emulates fixed function 'legacy' is restricted to 8 lights per object and emulates fixed function
pipeline compatible lighting. pipeline compatible lighting.
'shaders compatibility' removes the light limit via :ref:`max lights` and 'shaders compatibility' removes the light limit controllable through :ref:`max
follows a modifed attenuation formula which can drastically reduce light popping lights` and follows a modifed attenuation formula which can drastically reduce
and seams. This mode also enables lighting on groundcover and a configurable light popping and seams. This mode also enables lighting on groundcover and a
light fade. It is recommended to use this with older hardware and a light limit configurable light fade. It is recommended to use this with older hardware and a
closer to 8. Because of its wide range of compatibility it is set as the light limit closer to 8. Because of its wide range of compatibility it is set as
default. the default.
'shaders' carries all of the benefits that 'shaders compatibility' does, but 'shaders' carries all of the benefits that 'shaders compatibility' does, but
uses a modern approach that allows for a higher :ref:`max lights` count with uses a modern approach that allows for a higher :ref:`max lights` count with
@ -174,9 +174,9 @@ this mode when supported and where the GPU is not a bottleneck. On some weaker
devices, using this mode along with :ref:`force per pixel lighting` can carry devices, using this mode along with :ref:`force per pixel lighting` can carry
performance penalties. performance penalties.
Note that when enabled, groundcover lighting is forced to be vertex lighting, Note that when enabled groundcover lighting is forced to be vertex lighting,
unless normal maps are provided. This is due to some groundcover mods using the unless normal maps are provided. This is due to some groundcover mods using the
Z-Up Normals technique to avoid some common issues with shading. As a Z-Up normals technique to avoid some common issues with shading. As a
consequence, per pixel lighting would give undesirable results. consequence, per pixel lighting would give undesirable results.
This setting has no effect if :ref:`force shaders` is 'false'. This setting has no effect if :ref:`force shaders` is 'false'.

@ -451,11 +451,11 @@ radial fog = false
# 'force per pixel lighting' is enabled. # 'force per pixel lighting' is enabled.
lighting method = shaders compatibility lighting method = shaders compatibility
# Sets the bounding sphere multiplier of light sources, which are used to # Sets the bounding sphere multiplier of light sources if 'lighting method' is
# determine if an object should receive lighting. Higher values will allow for # not 'legacy'. These are used to determine if an object should receive
# smoother transitions of light sources, but may carry a performance cost and # lighting. Higher values will allow for smoother transitions of light sources,
# requires a higher number of 'max lights' set. It is recommended to keep this # but may carry a performance cost and requires a higher number of 'max lights'
# at 1.0 with 'legacy' lighting enabled. # set.
light bounds multiplier = 1.75 light bounds multiplier = 1.75
# The distance from the camera at which lights fade away completely. # The distance from the camera at which lights fade away completely.
@ -470,7 +470,7 @@ light fade start = 0.85
max lights = 8 max lights = 8
# Sets minimum ambient brightness of interior cells. Levels below this threshold will have their # Sets minimum ambient brightness of interior cells. Levels below this threshold will have their
# ambient values adjusted to balance the darker interiors. # ambient values adjusted to balance the darker interiors.
# When 'lighting method' is set to 'legacy', this setting will have no effect. # When 'lighting method' is set to 'legacy', this setting will have no effect.
minimum interior brightness = 0.1 minimum interior brightness = 0.1

Loading…
Cancel
Save