Use settings values for Shaders settings

macos_ci_fix
elsid 1 year ago
parent f5ddf55cdc
commit 08902371b4
No known key found for this signature in database
GPG Key ID: 4DE04C198CBA7625

@ -2,6 +2,8 @@
#include "sdlinit.hpp" #include "sdlinit.hpp"
#include <components/settings/values.hpp>
#include <QMessageBox> #include <QMessageBox>
#include <QScreen> #include <QScreen>
@ -144,10 +146,18 @@ bool Launcher::GraphicsPage::loadSettings()
// Lighting // Lighting
int lightingMethod = 1; int lightingMethod = 1;
if (Settings::Manager::getString("lighting method", "Shaders") == "legacy") switch (Settings::shaders().mLightingMethod)
lightingMethod = 0; {
else if (Settings::Manager::getString("lighting method", "Shaders") == "shaders") case SceneUtil::LightingMethod::FFP:
lightingMethod = 2; lightingMethod = 0;
break;
case SceneUtil::LightingMethod::PerObjectUniform:
lightingMethod = 1;
break;
case SceneUtil::LightingMethod::SingleUBO:
lightingMethod = 2;
break;
}
lightingMethodComboBox->setCurrentIndex(lightingMethod); lightingMethodComboBox->setCurrentIndex(lightingMethod);
// Shadows // Shadows
@ -246,10 +256,12 @@ void Launcher::GraphicsPage::saveSettings()
} }
// Lighting // Lighting
static std::array<std::string, 3> lightingMethodMap = { "legacy", "shaders compatibility", "shaders" }; static constexpr std::array<SceneUtil::LightingMethod, 3> lightingMethodMap = {
const std::string& cLightingMethod = lightingMethodMap[lightingMethodComboBox->currentIndex()]; SceneUtil::LightingMethod::FFP,
if (cLightingMethod != Settings::Manager::getString("lighting method", "Shaders")) SceneUtil::LightingMethod::PerObjectUniform,
Settings::Manager::setString("lighting method", "Shaders", cLightingMethod); SceneUtil::LightingMethod::SingleUBO,
};
Settings::shaders().mLightingMethod.set(lightingMethodMap[lightingMethodComboBox->currentIndex()]);
// Shadows // Shadows
int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0; int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0;

@ -87,10 +87,10 @@ namespace CSVRender
mView->getCamera()->setGraphicsContext(window); mView->getCamera()->setGraphicsContext(window);
SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; osg::ref_ptr<SceneUtil::LightManager> lightMgr = new SceneUtil::LightManager;
lightMgr->setStartLight(1); lightMgr->setStartLight(1);
lightMgr->setLightingMask(Mask_Lighting); lightMgr->setLightingMask(Mask_Lighting);
mRootNode = lightMgr; mRootNode = std::move(lightMgr);
mView->getCamera()->setViewport(new osg::Viewport(0, 0, width(), height())); mView->getCamera()->setViewport(new osg::Viewport(0, 0, width(), height()));

@ -147,7 +147,7 @@ namespace
constexpr int min = 8; constexpr int min = 8;
constexpr int max = 32; constexpr int max = 32;
constexpr int increment = 8; constexpr int increment = 8;
int maxLights = Settings::Manager::getInt("max lights", "Shaders"); const int maxLights = Settings::shaders().mMaxLights;
// show increments of 8 in dropdown // show increments of 8 in dropdown
if (maxLights >= min && maxLights <= max && !(maxLights % increment)) if (maxLights >= min && maxLights <= max && !(maxLights % increment))
box->setIndexSelected((maxLights / increment) - 1); box->setIndexSelected((maxLights / increment) - 1);
@ -559,7 +559,8 @@ namespace MWGui
MWBase::Environment::get().getWindowManager()->interactiveMessageBox( MWBase::Environment::get().getWindowManager()->interactiveMessageBox(
"#{OMWEngine:ChangeRequiresRestart}", { "#{Interface:OK}" }, true); "#{OMWEngine:ChangeRequiresRestart}", { "#{Interface:OK}" }, true);
Settings::Manager::setString("lighting method", "Shaders", *_sender->getItemDataAt<std::string>(pos)); Settings::shaders().mLightingMethod.set(
Settings::parseLightingMethod(*_sender->getItemDataAt<std::string>(pos)));
apply(); apply();
} }
@ -630,9 +631,7 @@ namespace MWGui
void SettingsWindow::onMaxLightsChanged(MyGUI::ComboBox* _sender, size_t pos) void SettingsWindow::onMaxLightsChanged(MyGUI::ComboBox* _sender, size_t pos)
{ {
int count = 8 * (pos + 1); Settings::shaders().mMaxLights.set(8 * (pos + 1));
Settings::Manager::setInt("max lights", "Shaders", count);
apply(); apply();
configureWidgets(mMainWidget, false); configureWidgets(mMainWidget, false);
} }
@ -653,8 +652,7 @@ namespace MWGui
Settings::shaders().mMaxLights.reset(); Settings::shaders().mMaxLights.reset();
Settings::shaders().mLightingMethod.reset(); Settings::shaders().mLightingMethod.reset();
const SceneUtil::LightingMethod lightingMethod const SceneUtil::LightingMethod lightingMethod = Settings::shaders().mLightingMethod;
= SceneUtil::LightManager::getLightingMethodFromString(Settings::shaders().mLightingMethod);
const std::size_t lightIndex = mLightingMethodButton->findItemIndexWith(lightingMethodToStr(lightingMethod)); const std::size_t lightIndex = mLightingMethodButton->findItemIndexWith(lightingMethodToStr(lightingMethod));
mLightingMethodButton->setIndexSelected(lightIndex); mLightingMethodButton->setIndexSelected(lightIndex);
updateMaxLightsComboBox(mMaxLights); updateMaxLightsComboBox(mMaxLights);

@ -24,7 +24,7 @@
#include <components/sceneutil/nodecallback.hpp> #include <components/sceneutil/nodecallback.hpp>
#include <components/sceneutil/rtt.hpp> #include <components/sceneutil/rtt.hpp>
#include <components/sceneutil/shadow.hpp> #include <components/sceneutil/shadow.hpp>
#include <components/settings/settings.hpp> #include <components/settings/values.hpp>
#include <components/stereo/multiview.hpp> #include <components/stereo/multiview.hpp>
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
@ -34,6 +34,7 @@
#include "../mwmechanics/weapontype.hpp" #include "../mwmechanics/weapontype.hpp"
#include "npcanimation.hpp" #include "npcanimation.hpp"
#include "util.hpp"
#include "vismask.hpp" #include "vismask.hpp"
namespace MWRender namespace MWRender
@ -154,7 +155,7 @@ namespace MWRender
public: public:
CharacterPreviewRTTNode(uint32_t sizeX, uint32_t sizeY) CharacterPreviewRTTNode(uint32_t sizeX, uint32_t sizeY)
: RTTNode(sizeX, sizeY, Settings::Manager::getInt("antialiasing", "Video"), false, 0, : RTTNode(sizeX, sizeY, Settings::Manager::getInt("antialiasing", "Video"), false, 0,
StereoAwareness::Unaware_MultiViewShaders) StereoAwareness::Unaware_MultiViewShaders, shouldAddMSAAIntermediateTarget())
, mAspectRatio(static_cast<float>(sizeX) / static_cast<float>(sizeY)) , mAspectRatio(static_cast<float>(sizeX) / static_cast<float>(sizeY))
{ {
if (SceneUtil::AutoDepth::isReversed()) if (SceneUtil::AutoDepth::isReversed())
@ -226,9 +227,13 @@ namespace MWRender
mRTTNode = new CharacterPreviewRTTNode(sizeX, sizeY); mRTTNode = new CharacterPreviewRTTNode(sizeX, sizeY);
mRTTNode->setNodeMask(Mask_RenderToTexture); mRTTNode->setNodeMask(Mask_RenderToTexture);
bool ffp = mResourceSystem->getSceneManager()->getLightingMethod() == SceneUtil::LightingMethod::FFP; osg::ref_ptr<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager(SceneUtil::LightSettings{
.mLightingMethod = mResourceSystem->getSceneManager()->getLightingMethod(),
osg::ref_ptr<SceneUtil::LightManager> lightManager = new SceneUtil::LightManager(ffp); .mMaxLights = Settings::shaders().mMaxLights,
.mMaximumLightDistance = Settings::shaders().mMaximumLightDistance,
.mLightFadeStart = Settings::shaders().mLightFadeStart,
.mLightBoundsMultiplier = Settings::shaders().mLightBoundsMultiplier,
});
lightManager->setStartLight(1); lightManager->setStartLight(1);
osg::ref_ptr<osg::StateSet> stateset = lightManager->getOrCreateStateSet(); osg::ref_ptr<osg::StateSet> stateset = lightManager->getOrCreateStateSet();
stateset->setDefine("FORCE_OPAQUE", "1", osg::StateAttribute::ON); stateset->setDefine("FORCE_OPAQUE", "1", osg::StateAttribute::ON);

@ -30,6 +30,7 @@
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "util.hpp"
#include "vismask.hpp" #include "vismask.hpp"
namespace namespace
@ -679,7 +680,7 @@ namespace MWRender
LocalMapRenderToTexture::LocalMapRenderToTexture(osg::Node* sceneRoot, int res, int mapWorldSize, float x, float y, LocalMapRenderToTexture::LocalMapRenderToTexture(osg::Node* sceneRoot, int res, int mapWorldSize, float x, float y,
const osg::Vec3d& upVector, float zmin, float zmax) const osg::Vec3d& upVector, float zmin, float zmax)
: RTTNode(res, res, 0, false, 0, StereoAwareness::Unaware_MultiViewShaders) : RTTNode(res, res, 0, false, 0, StereoAwareness::Unaware_MultiViewShaders, shouldAddMSAAIntermediateTarget())
, mSceneRoot(sceneRoot) , mSceneRoot(sceneRoot)
, mActive(true) , mActive(true)
{ {

@ -122,7 +122,6 @@ namespace MWRender
, mReload(false) , mReload(false)
, mEnabled(false) , mEnabled(false)
, mUsePostProcessing(Settings::postProcessing().mEnabled) , mUsePostProcessing(Settings::postProcessing().mEnabled)
, mSoftParticles(false)
, mDisableDepthPasses(false) , mDisableDepthPasses(false)
, mLastFrameNumber(0) , mLastFrameNumber(0)
, mLastSimulationTime(0.f) , mLastSimulationTime(0.f)
@ -135,8 +134,6 @@ namespace MWRender
, mPassLights(false) , mPassLights(false)
, mPrevPassLights(false) , mPrevPassLights(false)
{ {
mSoftParticles = Settings::Manager::getBool("soft particles", "Shaders");
osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext(); osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext();
osg::GLExtensions* ext = gc->getState()->get<osg::GLExtensions>(); osg::GLExtensions* ext = gc->getState()->get<osg::GLExtensions>();
@ -155,7 +152,7 @@ namespace MWRender
else else
Log(Debug::Error) << "'glDisablei' unsupported, pass normals will not be available to shaders."; Log(Debug::Error) << "'glDisablei' unsupported, pass normals will not be available to shaders.";
if (mSoftParticles) if (Settings::shaders().mSoftParticles)
{ {
for (int i = 0; i < 2; ++i) for (int i = 0; i < 2; ++i)
{ {
@ -172,7 +169,8 @@ namespace MWRender
mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330; mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330;
mStateUpdater = new fx::StateUpdater(mUBO); mStateUpdater = new fx::StateUpdater(mUBO);
if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !mUsePostProcessing) if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles
&& !mUsePostProcessing)
return; return;
enable(mUsePostProcessing); enable(mUsePostProcessing);
@ -239,7 +237,7 @@ namespace MWRender
const bool postPass = Settings::postProcessing().mTransparentPostpass; const bool postPass = Settings::postProcessing().mTransparentPostpass;
mUsePostProcessing = usePostProcessing; mUsePostProcessing = usePostProcessing;
mDisableDepthPasses = !mSoftParticles && !postPass; mDisableDepthPasses = !Settings::shaders().mSoftParticles && !postPass;
#ifdef ANDROID #ifdef ANDROID
mDisableDepthPasses = true; mDisableDepthPasses = true;
@ -276,10 +274,10 @@ namespace MWRender
void PostProcessor::disable() void PostProcessor::disable()
{ {
if (!mSoftParticles) if (!Settings::shaders().mSoftParticles)
osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(nullptr); osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(nullptr);
if (!SceneUtil::AutoDepth::isReversed() && !mSoftParticles) if (!SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles)
{ {
removeChild(mHUDCamera); removeChild(mHUDCamera);
setCullCallback(nullptr); setCullCallback(nullptr);

@ -175,8 +175,6 @@ namespace MWRender
bool isEnabled() const { return mUsePostProcessing && mEnabled; } bool isEnabled() const { return mUsePostProcessing && mEnabled; }
bool softParticlesEnabled() const { return mSoftParticles; }
bool getHDR() const { return mHDR; } bool getHDR() const { return mHDR; }
void disable(); void disable();
@ -247,7 +245,6 @@ namespace MWRender
bool mReload; bool mReload;
bool mEnabled; bool mEnabled;
bool mUsePostProcessing; bool mUsePostProcessing;
bool mSoftParticles;
bool mDisableDepthPasses; bool mDisableDepthPasses;
size_t mLastFrameNumber; size_t mLastFrameNumber;

@ -8,6 +8,7 @@
#include <components/sceneutil/depth.hpp> #include <components/sceneutil/depth.hpp>
#include <components/sceneutil/positionattitudetransform.hpp> #include <components/sceneutil/positionattitudetransform.hpp>
#include <components/sceneutil/util.hpp> #include <components/sceneutil/util.hpp>
#include <components/settings/values.hpp>
#include <components/shader/shadermanager.hpp> #include <components/shader/shadermanager.hpp>
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
@ -112,7 +113,7 @@ namespace MWRender
mCamera->attach(osg::Camera::DEPTH_BUFFER, mDepthTexture); mCamera->attach(osg::Camera::DEPTH_BUFFER, mDepthTexture);
mCamera->addChild(mSceneNode); mCamera->addChild(mSceneNode);
mCamera->setSmallFeatureCullingPixelSize( mCamera->setSmallFeatureCullingPixelSize(
Settings::Manager::getFloat("weather particle occlusion small feature culling pixel size", "Shaders")); Settings::shaders().mWeatherParticleOcclusionSmallFeatureCullingPixelSize);
SceneUtil::setCameraClearDepth(mCamera); SceneUtil::setCameraClearDepth(mCamera);
} }

@ -82,6 +82,7 @@
#include "screenshotmanager.hpp" #include "screenshotmanager.hpp"
#include "sky.hpp" #include "sky.hpp"
#include "terrainstorage.hpp" #include "terrainstorage.hpp"
#include "util.hpp"
#include "vismask.hpp" #include "vismask.hpp"
#include "water.hpp" #include "water.hpp"
@ -312,7 +313,6 @@ namespace MWRender
, mResourceSystem(resourceSystem) , mResourceSystem(resourceSystem)
, mWorkQueue(workQueue) , mWorkQueue(workQueue)
, mNavigator(navigator) , mNavigator(navigator)
, mMinimumAmbientLuminance(0.f)
, mNightEyeFactor(0.f) , mNightEyeFactor(0.f)
// TODO: Near clip should not need to be bounded like this, but too small values break OSG shadow calculations // TODO: Near clip should not need to be bounded like this, but too small values break OSG shadow calculations
// CPU-side. See issue: #6072 // CPU-side. See issue: #6072
@ -325,46 +325,40 @@ namespace MWRender
, mGroundCoverStore(groundcoverStore) , mGroundCoverStore(groundcoverStore)
{ {
bool reverseZ = SceneUtil::AutoDepth::isReversed(); bool reverseZ = SceneUtil::AutoDepth::isReversed();
auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString( const SceneUtil::LightingMethod lightingMethod = Settings::shaders().mLightingMethod;
Settings::Manager::getString("lighting method", "Shaders"));
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
// Shadows and radial fog have problems with fixed-function mode. // Shadows and radial fog have problems with fixed-function mode.
bool forceShaders = Settings::fog().mRadialFog || Settings::fog().mExponentialFog bool forceShaders = Settings::fog().mRadialFog || Settings::fog().mExponentialFog
|| Settings::Manager::getBool("soft particles", "Shaders") || Settings::shaders().mSoftParticles || Settings::shaders().mForceShaders
|| Settings::Manager::getBool("force shaders", "Shaders")
|| Settings::Manager::getBool("enable shadows", "Shadows") || Settings::Manager::getBool("enable shadows", "Shadows")
|| lightingMethod != SceneUtil::LightingMethod::FFP || reverseZ || mSkyBlending || Stereo::getMultiview(); || lightingMethod != SceneUtil::LightingMethod::FFP || reverseZ || mSkyBlending || Stereo::getMultiview();
resourceSystem->getSceneManager()->setForceShaders(forceShaders); resourceSystem->getSceneManager()->setForceShaders(forceShaders);
// FIXME: calling dummy method because terrain needs to know whether lighting is clamped // FIXME: calling dummy method because terrain needs to know whether lighting is clamped
resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); resourceSystem->getSceneManager()->setClampLighting(Settings::shaders().mClampLighting);
resourceSystem->getSceneManager()->setAutoUseNormalMaps( resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::shaders().mAutoUseObjectNormalMaps);
Settings::Manager::getBool("auto use object normal maps", "Shaders")); resourceSystem->getSceneManager()->setNormalMapPattern(Settings::shaders().mNormalMapPattern);
resourceSystem->getSceneManager()->setNormalMapPattern( resourceSystem->getSceneManager()->setNormalHeightMapPattern(Settings::shaders().mNormalHeightMapPattern);
Settings::Manager::getString("normal map pattern", "Shaders")); resourceSystem->getSceneManager()->setAutoUseSpecularMaps(Settings::shaders().mAutoUseObjectSpecularMaps);
resourceSystem->getSceneManager()->setNormalHeightMapPattern( resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::shaders().mSpecularMapPattern);
Settings::Manager::getString("normal height map pattern", "Shaders"));
resourceSystem->getSceneManager()->setAutoUseSpecularMaps(
Settings::Manager::getBool("auto use object specular maps", "Shaders"));
resourceSystem->getSceneManager()->setSpecularMapPattern(
Settings::Manager::getString("specular map pattern", "Shaders"));
resourceSystem->getSceneManager()->setApplyLightingToEnvMaps( resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(
Settings::Manager::getBool("apply lighting to environment maps", "Shaders")); Settings::shaders().mApplyLightingToEnvironmentMaps);
resourceSystem->getSceneManager()->setConvertAlphaTestToAlphaToCoverage( resourceSystem->getSceneManager()->setConvertAlphaTestToAlphaToCoverage(shouldAddMSAAIntermediateTarget());
Settings::Manager::getBool("antialias alpha test", "Shaders")
&& Settings::Manager::getInt("antialiasing", "Video") > 1);
resourceSystem->getSceneManager()->setAdjustCoverageForAlphaTest( resourceSystem->getSceneManager()->setAdjustCoverageForAlphaTest(
Settings::Manager::getBool("adjust coverage for alpha test", "Shaders")); Settings::shaders().mAdjustCoverageForAlphaTest);
// Let LightManager choose which backend to use based on our hint. For methods besides legacy lighting, this // Let LightManager choose which backend to use based on our hint. For methods besides legacy lighting, this
// depends on support for various OpenGL extensions. // depends on support for various OpenGL extensions.
osg::ref_ptr<SceneUtil::LightManager> sceneRoot osg::ref_ptr<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(SceneUtil::LightSettings{
= new SceneUtil::LightManager(lightingMethod == SceneUtil::LightingMethod::FFP); .mLightingMethod = lightingMethod,
.mMaxLights = Settings::shaders().mMaxLights,
.mMaximumLightDistance = Settings::shaders().mMaximumLightDistance,
.mLightFadeStart = Settings::shaders().mLightFadeStart,
.mLightBoundsMultiplier = Settings::shaders().mLightBoundsMultiplier,
});
resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod()); resourceSystem->getSceneManager()->setLightingMethod(sceneRoot->getLightingMethod());
resourceSystem->getSceneManager()->setSupportedLightingMethods(sceneRoot->getSupportedLightingMethods()); resourceSystem->getSceneManager()->setSupportedLightingMethods(sceneRoot->getSupportedLightingMethods());
mMinimumAmbientLuminance
= std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
sceneRoot->setLightingMask(Mask_Lighting); sceneRoot->setLightingMask(Mask_Lighting);
mSceneRoot = sceneRoot; mSceneRoot = sceneRoot;
@ -396,10 +390,9 @@ namespace MWRender
for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++)
globalDefines[itr->first] = itr->second; globalDefines[itr->first] = itr->second;
globalDefines["forcePPL"] = Settings::Manager::getBool("force per pixel lighting", "Shaders") ? "1" : "0"; globalDefines["forcePPL"] = Settings::shaders().mForcePerPixelLighting ? "1" : "0";
globalDefines["clamp"] = Settings::Manager::getBool("clamp lighting", "Shaders") ? "1" : "0"; globalDefines["clamp"] = Settings::shaders().mClampLighting ? "1" : "0";
globalDefines["preLightEnv"] globalDefines["preLightEnv"] = Settings::shaders().mApplyLightingToEnvironmentMaps ? "1" : "0";
= Settings::Manager::getBool("apply lighting to environment maps", "Shaders") ? "1" : "0";
const bool exponentialFog = Settings::fog().mExponentialFog; const bool exponentialFog = Settings::fog().mExponentialFog;
globalDefines["radialFog"] = (exponentialFog || Settings::fog().mRadialFog) ? "1" : "0"; globalDefines["radialFog"] = (exponentialFog || Settings::fog().mRadialFog) ? "1" : "0";
globalDefines["exponentialFog"] = exponentialFog ? "1" : "0"; globalDefines["exponentialFog"] = exponentialFog ? "1" : "0";
@ -445,11 +438,11 @@ namespace MWRender
mEffectManager = std::make_unique<EffectManager>(sceneRoot, mResourceSystem); mEffectManager = std::make_unique<EffectManager>(sceneRoot, mResourceSystem);
const std::string& normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders"); const std::string& normalMapPattern = Settings::shaders().mNormalMapPattern;
const std::string& heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders"); const std::string& heightMapPattern = Settings::shaders().mNormalHeightMapPattern;
const std::string& specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders"); const std::string& specularMapPattern = Settings::shaders().mTerrainSpecularMapPattern;
const bool useTerrainNormalMaps = Settings::Manager::getBool("auto use terrain normal maps", "Shaders"); const bool useTerrainNormalMaps = Settings::shaders().mAutoUseTerrainNormalMaps;
const bool useTerrainSpecularMaps = Settings::Manager::getBool("auto use terrain specular maps", "Shaders"); const bool useTerrainSpecularMaps = Settings::shaders().mAutoUseTerrainSpecularMaps;
mTerrainStorage = std::make_unique<TerrainStorage>(mResourceSystem, normalMapPattern, heightMapPattern, mTerrainStorage = std::make_unique<TerrainStorage>(mResourceSystem, normalMapPattern, heightMapPattern,
useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps); useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps);
@ -472,8 +465,9 @@ namespace MWRender
resourceSystem->getSceneManager()->setOpaqueDepthTex( resourceSystem->getSceneManager()->setOpaqueDepthTex(
mPostProcessor->getTexture(PostProcessor::Tex_OpaqueDepth, 0), mPostProcessor->getTexture(PostProcessor::Tex_OpaqueDepth, 0),
mPostProcessor->getTexture(PostProcessor::Tex_OpaqueDepth, 1)); mPostProcessor->getTexture(PostProcessor::Tex_OpaqueDepth, 1));
resourceSystem->getSceneManager()->setSoftParticles(mPostProcessor->softParticlesEnabled()); resourceSystem->getSceneManager()->setSoftParticles(Settings::shaders().mSoftParticles);
resourceSystem->getSceneManager()->setSupportsNormalsRT(mPostProcessor->getSupportsNormalsRT()); resourceSystem->getSceneManager()->setSupportsNormalsRT(mPostProcessor->getSupportsNormalsRT());
resourceSystem->getSceneManager()->setWeatherParticleOcclusion(Settings::shaders().mWeatherParticleOcclusion);
// water goes after terrain for correct waterculling order // water goes after terrain for correct waterculling order
mWater = std::make_unique<Water>( mWater = std::make_unique<Water>(
@ -680,15 +674,16 @@ namespace MWRender
// we already work in linear RGB so no conversions are needed for the luminosity function // 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(); float relativeLuminance = pR * ambient.r() + pG * ambient.g() + pB * ambient.b();
if (relativeLuminance < mMinimumAmbientLuminance) const float minimumAmbientLuminance = Settings::shaders().mMinimumInteriorBrightness;
if (relativeLuminance < minimumAmbientLuminance)
{ {
// brighten ambient so it reaches the minimum threshold but no more, we want to mess with content data // brighten ambient so it reaches the minimum threshold but no more, we want to mess with content data
// as least we can // as least we can
if (ambient.r() == 0.f && ambient.g() == 0.f && ambient.b() == 0.f) if (ambient.r() == 0.f && ambient.g() == 0.f && ambient.b() == 0.f)
ambient = osg::Vec4( ambient = osg::Vec4(
mMinimumAmbientLuminance, mMinimumAmbientLuminance, mMinimumAmbientLuminance, ambient.a()); minimumAmbientLuminance, minimumAmbientLuminance, minimumAmbientLuminance, ambient.a());
else else
ambient *= mMinimumAmbientLuminance / relativeLuminance; ambient *= minimumAmbientLuminance / relativeLuminance;
} }
} }
@ -1408,8 +1403,6 @@ namespace MWRender
} }
else if (it->first == "Shaders" && it->second == "minimum interior brightness") else if (it->first == "Shaders" && it->second == "minimum interior brightness")
{ {
mMinimumAmbientLuminance
= std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f);
if (MWMechanics::getPlayer().isInCell()) if (MWMechanics::getPlayer().isInCell())
configureAmbient(*MWMechanics::getPlayer().getCell()->getCell()); configureAmbient(*MWMechanics::getPlayer().getCell()->getCell());
} }
@ -1418,13 +1411,15 @@ namespace MWRender
|| it->second == "light fade start" || it->second == "max lights")) || it->second == "light fade start" || it->second == "max lights"))
{ {
auto* lightManager = getLightRoot(); auto* lightManager = getLightRoot();
lightManager->processChangedSettings(changed);
lightManager->processChangedSettings(Settings::shaders().mLightBoundsMultiplier,
Settings::shaders().mMaximumLightDistance, Settings::shaders().mLightFadeStart);
if (it->second == "max lights" && !lightManager->usingFFP()) if (it->second == "max lights" && !lightManager->usingFFP())
{ {
mViewer->stopThreading(); mViewer->stopThreading();
lightManager->updateMaxLights(); lightManager->updateMaxLights(Settings::shaders().mMaxLights);
auto defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); auto defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines();
for (const auto& [name, key] : lightManager->getLightDefines()) for (const auto& [name, key] : lightManager->getLightDefines())

@ -342,7 +342,6 @@ namespace MWRender
osg::ref_ptr<PerViewUniformStateUpdater> mPerViewUniformStateUpdater; osg::ref_ptr<PerViewUniformStateUpdater> mPerViewUniformStateUpdater;
osg::Vec4f mAmbientColor; osg::Vec4f mAmbientColor;
float mMinimumAmbientLuminance;
float mNightEyeFactor; float mNightEyeFactor;
float mNearClip; float mNearClip;

@ -35,6 +35,7 @@
#include "renderbin.hpp" #include "renderbin.hpp"
#include "skyutil.hpp" #include "skyutil.hpp"
#include "util.hpp"
#include "vismask.hpp" #include "vismask.hpp"
namespace namespace
@ -205,7 +206,8 @@ namespace
{ {
public: public:
SkyRTT(osg::Vec2f size, osg::Group* earlyRenderBinRoot) SkyRTT(osg::Vec2f size, osg::Group* earlyRenderBinRoot)
: RTTNode(static_cast<int>(size.x()), static_cast<int>(size.y()), 0, false, 1, StereoAwareness::Aware) : RTTNode(static_cast<int>(size.x()), static_cast<int>(size.y()), 0, false, 1, StereoAwareness::Aware,
MWRender::shouldAddMSAAIntermediateTarget())
, mEarlyRenderBinRoot(earlyRenderBinRoot) , mEarlyRenderBinRoot(earlyRenderBinRoot)
{ {
setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8); setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8);
@ -292,7 +294,7 @@ namespace MWRender
mRootNode->addChild(mEarlyRenderBinRoot); mRootNode->addChild(mEarlyRenderBinRoot);
mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot); mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot);
mPrecipitationOcclusion = Settings::Manager::getBool("weather particle occlusion", "Shaders"); mPrecipitationOcclusion = Settings::shaders().mWeatherParticleOcclusion;
mPrecipitationOccluder = std::make_unique<PrecipitationOccluder>(skyroot, parentNode, rootNode, camera); mPrecipitationOccluder = std::make_unique<PrecipitationOccluder>(skyroot, parentNode, rootNode, camera);
} }

@ -7,6 +7,7 @@
#include <components/resource/imagemanager.hpp> #include <components/resource/imagemanager.hpp>
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/sceneutil/visitor.hpp> #include <components/sceneutil/visitor.hpp>
#include <components/settings/values.hpp>
namespace MWRender namespace MWRender
{ {
@ -67,4 +68,9 @@ namespace MWRender
node->setStateSet(stateset); node->setStateSet(stateset);
} }
bool shouldAddMSAAIntermediateTarget()
{
return Settings::shaders().mAntialiasAlphaTest && Settings::Manager::getInt("antialiasing", "Video") > 1;
}
} }

@ -3,6 +3,7 @@
#include <osg/NodeCallback> #include <osg/NodeCallback>
#include <osg/ref_ptr> #include <osg/ref_ptr>
#include <string> #include <string>
namespace osg namespace osg
@ -35,6 +36,8 @@ namespace MWRender
// no traverse() // no traverse()
} }
}; };
bool shouldAddMSAAIntermediateTarget();
} }
#endif #endif

@ -35,11 +35,14 @@
#include <components/fallback/fallback.hpp> #include <components/fallback/fallback.hpp>
#include <components/settings/values.hpp>
#include "../mwworld/cellstore.hpp" #include "../mwworld/cellstore.hpp"
#include "renderbin.hpp" #include "renderbin.hpp"
#include "ripples.hpp" #include "ripples.hpp"
#include "ripplesimulation.hpp" #include "ripplesimulation.hpp"
#include "util.hpp"
#include "vismask.hpp" #include "vismask.hpp"
namespace MWRender namespace MWRender
@ -234,7 +237,7 @@ namespace MWRender
{ {
public: public:
Refraction(uint32_t rttSize) Refraction(uint32_t rttSize)
: RTTNode(rttSize, rttSize, 0, false, 1, StereoAwareness::Aware) : RTTNode(rttSize, rttSize, 0, false, 1, StereoAwareness::Aware, shouldAddMSAAIntermediateTarget())
, mNodeMask(Refraction::sDefaultCullMask) , mNodeMask(Refraction::sDefaultCullMask)
{ {
setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8); setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8);
@ -315,7 +318,7 @@ namespace MWRender
{ {
public: public:
Reflection(uint32_t rttSize, bool isInterior) Reflection(uint32_t rttSize, bool isInterior)
: RTTNode(rttSize, rttSize, 0, false, 0, StereoAwareness::Aware) : RTTNode(rttSize, rttSize, 0, false, 0, StereoAwareness::Aware, shouldAddMSAAIntermediateTarget())
{ {
setInterior(isInterior); setInterior(isInterior);
setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8); setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8);

@ -107,7 +107,7 @@ add_component_dir (sceneutil
clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller
lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer
detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt
screencapture depth color riggeometryosgaextension extradata unrefqueue lightcommon screencapture depth color riggeometryosgaextension extradata unrefqueue lightcommon lightingmethod
) )
add_component_dir (nif add_component_dir (nif

@ -1118,10 +1118,10 @@ namespace Resource
stats->setAttribute(frameNumber, "Node", mCache->getCacheSize()); stats->setAttribute(frameNumber, "Node", mCache->getCacheSize());
} }
Shader::ShaderVisitor* SceneManager::createShaderVisitor(const std::string& shaderPrefix) osg::ref_ptr<Shader::ShaderVisitor> SceneManager::createShaderVisitor(const std::string& shaderPrefix)
{ {
Shader::ShaderVisitor* shaderVisitor osg::ref_ptr<Shader::ShaderVisitor> shaderVisitor(
= new Shader::ShaderVisitor(*mShaderManager.get(), *mImageManager, shaderPrefix); new Shader::ShaderVisitor(*mShaderManager.get(), *mImageManager, shaderPrefix));
shaderVisitor->setForceShaders(mForceShaders); shaderVisitor->setForceShaders(mForceShaders);
shaderVisitor->setAutoUseNormalMaps(mAutoUseNormalMaps); shaderVisitor->setAutoUseNormalMaps(mAutoUseNormalMaps);
shaderVisitor->setNormalMapPattern(mNormalMapPattern); shaderVisitor->setNormalMapPattern(mNormalMapPattern);
@ -1132,6 +1132,7 @@ namespace Resource
shaderVisitor->setConvertAlphaTestToAlphaToCoverage(mConvertAlphaTestToAlphaToCoverage); shaderVisitor->setConvertAlphaTestToAlphaToCoverage(mConvertAlphaTestToAlphaToCoverage);
shaderVisitor->setAdjustCoverageForAlphaTest(mAdjustCoverageForAlphaTest); shaderVisitor->setAdjustCoverageForAlphaTest(mAdjustCoverageForAlphaTest);
shaderVisitor->setSupportsNormalsRT(mSupportsNormalsRT); shaderVisitor->setSupportsNormalsRT(mSupportsNormalsRT);
shaderVisitor->setWeatherParticleOcclusion(mWeatherParticleOcclusion);
return shaderVisitor; return shaderVisitor;
} }
} }

@ -227,8 +227,10 @@ namespace Resource
void setSoftParticles(bool enabled) { mSoftParticles = enabled; } void setSoftParticles(bool enabled) { mSoftParticles = enabled; }
bool getSoftParticles() const { return mSoftParticles; } bool getSoftParticles() const { return mSoftParticles; }
void setWeatherParticleOcclusion(bool value) { mWeatherParticleOcclusion = value; }
private: private:
Shader::ShaderVisitor* createShaderVisitor(const std::string& shaderPrefix = "objects"); osg::ref_ptr<Shader::ShaderVisitor> createShaderVisitor(const std::string& shaderPrefix = "objects");
osg::ref_ptr<osg::Node> loadErrorMarker(); osg::ref_ptr<osg::Node> loadErrorMarker();
osg::ref_ptr<osg::Node> cloneErrorMarker(); osg::ref_ptr<osg::Node> cloneErrorMarker();
@ -248,6 +250,7 @@ namespace Resource
bool mSupportsNormalsRT; bool mSupportsNormalsRT;
std::array<osg::ref_ptr<osg::Texture>, 2> mOpaqueDepthTex; std::array<osg::ref_ptr<osg::Texture>, 2> mOpaqueDepthTex;
bool mSoftParticles = false; bool mSoftParticles = false;
bool mWeatherParticleOcclusion = false;
osg::ref_ptr<Resource::SharedStateManager> mSharedStateManager; osg::ref_ptr<Resource::SharedStateManager> mSharedStateManager;
mutable std::mutex mSharedStateMutex; mutable std::mutex mSharedStateMutex;

@ -0,0 +1,14 @@
#ifndef OPENMW_COMPONENTS_SCENEUTIL_LIGHTINGMETHOD_H
#define OPENMW_COMPONENTS_SCENEUTIL_LIGHTINGMETHOD_H
namespace SceneUtil
{
enum class LightingMethod
{
FFP,
PerObjectUniform,
SingleUBO,
};
}
#endif

@ -23,8 +23,6 @@
namespace namespace
{ {
constexpr int maxLightsLowerLimit = 2;
constexpr int maxLightsUpperLimit = 64;
constexpr int ffpMaxLights = 8; constexpr int ffpMaxLights = 8;
bool sortLights(const SceneUtil::LightManager::LightSourceViewBound* left, bool sortLights(const SceneUtil::LightManager::LightSourceViewBound* left,
@ -817,7 +815,7 @@ namespace SceneUtil
return ""; return "";
} }
LightManager::LightManager(bool ffp) LightManager::LightManager(const LightSettings& settings)
: mStartLight(0) : mStartLight(0)
, mLightingMask(~0u) , mLightingMask(~0u)
, mSun(nullptr) , mSun(nullptr)
@ -835,18 +833,15 @@ namespace SceneUtil
setUpdateCallback(new LightManagerUpdateCallback); setUpdateCallback(new LightManagerUpdateCallback);
if (ffp) if (settings.mLightingMethod == LightingMethod::FFP)
{ {
initFFP(ffpMaxLights); initFFP(ffpMaxLights);
return; return;
} }
const std::string& lightingMethodString = Settings::Manager::getString("lighting method", "Shaders");
auto lightingMethod = LightManager::getLightingMethodFromString(lightingMethodString);
static bool hasLoggedWarnings = false; static bool hasLoggedWarnings = false;
if (lightingMethod == LightingMethod::SingleUBO && !hasLoggedWarnings) if (settings.mLightingMethod == LightingMethod::SingleUBO && !hasLoggedWarnings)
{ {
if (!supportsUBO) if (!supportsUBO)
Log(Debug::Warning) Log(Debug::Warning)
@ -857,15 +852,12 @@ namespace SceneUtil
hasLoggedWarnings = true; hasLoggedWarnings = true;
} }
const int targetLights if (!supportsUBO || !supportsGPU4 || settings.mLightingMethod == LightingMethod::PerObjectUniform)
= std::clamp(Settings::Manager::getInt("max lights", "Shaders"), maxLightsLowerLimit, maxLightsUpperLimit); initPerObjectUniform(settings.mMaxLights);
if (!supportsUBO || !supportsGPU4 || lightingMethod == LightingMethod::PerObjectUniform)
initPerObjectUniform(targetLights);
else else
initSingleUBO(targetLights); initSingleUBO(settings.mMaxLights);
updateSettings(); updateSettings(settings.mLightBoundsMultiplier, settings.mMaximumLightDistance, settings.mLightFadeStart);
getOrCreateStateSet()->addUniform(new osg::Uniform("PointLightCount", 0)); getOrCreateStateSet()->addUniform(new osg::Uniform("PointLightCount", 0));
@ -931,18 +923,18 @@ namespace SceneUtil
return defines; return defines;
} }
void LightManager::processChangedSettings(const Settings::CategorySettingVector& changed) void LightManager::processChangedSettings(
float lightBoundsMultiplier, float maximumLightDistance, float lightFadeStart)
{ {
updateSettings(); updateSettings(lightBoundsMultiplier, maximumLightDistance, lightFadeStart);
} }
void LightManager::updateMaxLights() void LightManager::updateMaxLights(int maxLights)
{ {
if (usingFFP()) if (usingFFP())
return; return;
setMaxLights( setMaxLights(maxLights);
std::clamp(Settings::Manager::getInt("max lights", "Shaders"), maxLightsLowerLimit, maxLightsUpperLimit));
if (getLightingMethod() == LightingMethod::PerObjectUniform) if (getLightingMethod() == LightingMethod::PerObjectUniform)
{ {
@ -954,20 +946,15 @@ namespace SceneUtil
cache.clear(); cache.clear();
} }
void LightManager::updateSettings() void LightManager::updateSettings(float lightBoundsMultiplier, float maximumLightDistance, float lightFadeStart)
{ {
if (getLightingMethod() == LightingMethod::FFP) if (getLightingMethod() == LightingMethod::FFP)
return; return;
mPointLightRadiusMultiplier mPointLightRadiusMultiplier = lightBoundsMultiplier;
= std::clamp(Settings::Manager::getFloat("light bounds multiplier", "Shaders"), 0.f, 5.f); mPointLightFadeEnd = maximumLightDistance;
mPointLightFadeEnd = std::max(0.f, Settings::Manager::getFloat("maximum light distance", "Shaders"));
if (mPointLightFadeEnd > 0) if (mPointLightFadeEnd > 0)
{ mPointLightFadeStart = mPointLightFadeEnd * lightFadeStart;
mPointLightFadeStart = std::clamp(Settings::Manager::getFloat("light fade start", "Shaders"), 0.f, 1.f);
mPointLightFadeStart = mPointLightFadeEnd * mPointLightFadeStart;
}
} }
void LightManager::initFFP(int targetLights) void LightManager::initFFP(int targetLights)

@ -12,7 +12,8 @@
#include <osg/observer_ptr> #include <osg/observer_ptr>
#include <components/sceneutil/nodecallback.hpp> #include <components/sceneutil/nodecallback.hpp>
#include <components/settings/settings.hpp>
#include "lightingmethod.hpp"
namespace SceneUtil namespace SceneUtil
{ {
@ -82,13 +83,6 @@ namespace SceneUtil
std::array<osg::ref_ptr<osg::Uniform>, 2> mUniformCount; std::array<osg::ref_ptr<osg::Uniform>, 2> mUniformCount;
}; };
enum class LightingMethod
{
FFP,
PerObjectUniform,
SingleUBO,
};
/// LightSource managed by a LightManager. /// LightSource managed by a LightManager.
/// @par Typically used for point lights. Spot lights are not supported yet. Directional lights affect the whole /// @par Typically used for point lights. Spot lights are not supported yet. Directional lights affect the whole
/// scene /// scene
@ -186,6 +180,15 @@ namespace SceneUtil
osg::ref_ptr<LightBuffer> mTemplate; osg::ref_ptr<LightBuffer> mTemplate;
}; };
struct LightSettings
{
LightingMethod mLightingMethod = LightingMethod::FFP;
int mMaxLights = 0;
float mMaximumLightDistance = 0;
float mLightFadeStart = 0;
float mLightBoundsMultiplier = 0;
};
/// @brief Decorator node implementing the rendering of any number of LightSources that can be anywhere in the /// @brief Decorator node implementing the rendering of any number of LightSources that can be anywhere in the
/// subgraph. /// subgraph.
class LightManager : public osg::Group class LightManager : public osg::Group
@ -212,7 +215,7 @@ namespace SceneUtil
META_Node(SceneUtil, LightManager) META_Node(SceneUtil, LightManager)
LightManager(bool ffp = true); explicit LightManager(const LightSettings& settings = LightSettings{});
LightManager(const LightManager& copy, const osg::CopyOp& copyop); LightManager(const LightManager& copy, const osg::CopyOp& copyop);
@ -264,10 +267,10 @@ namespace SceneUtil
std::map<std::string, std::string> getLightDefines() const; std::map<std::string, std::string> getLightDefines() const;
void processChangedSettings(const Settings::CategorySettingVector& changed); void processChangedSettings(float lightBoundsMultiplier, float maximumLightDistance, float lightFadeStart);
/// Not thread safe, it is the responsibility of the caller to stop/start threading on the viewer /// Not thread safe, it is the responsibility of the caller to stop/start threading on the viewer
void updateMaxLights(); void updateMaxLights(int maxLights);
osg::ref_ptr<osg::Uniform> generateLightBufferUniform(const osg::Matrixf& sun); osg::ref_ptr<osg::Uniform> generateLightBufferUniform(const osg::Matrixf& sun);
@ -281,7 +284,7 @@ namespace SceneUtil
void initPerObjectUniform(int targetLights); void initPerObjectUniform(int targetLights);
void initSingleUBO(int targetLights); void initSingleUBO(int targetLights);
void updateSettings(); void updateSettings(float lightBoundsMultiplier, float maximumLightDistance, float lightFadeStart);
void setLightingMethod(LightingMethod method); void setLightingMethod(LightingMethod method);
void setMaxLights(int value); void setMaxLights(int value);

@ -20,7 +20,7 @@ namespace SceneUtil
}; };
RTTNode::RTTNode(uint32_t textureWidth, uint32_t textureHeight, uint32_t samples, bool generateMipmaps, RTTNode::RTTNode(uint32_t textureWidth, uint32_t textureHeight, uint32_t samples, bool generateMipmaps,
int renderOrderNum, StereoAwareness stereoAwareness) int renderOrderNum, StereoAwareness stereoAwareness, bool addMSAAIntermediateTarget)
: mTextureWidth(textureWidth) : mTextureWidth(textureWidth)
, mTextureHeight(textureHeight) , mTextureHeight(textureHeight)
, mSamples(samples) , mSamples(samples)
@ -29,6 +29,7 @@ namespace SceneUtil
, mDepthBufferInternalFormat(SceneUtil::AutoDepth::depthInternalFormat()) , mDepthBufferInternalFormat(SceneUtil::AutoDepth::depthInternalFormat())
, mRenderOrderNum(renderOrderNum) , mRenderOrderNum(renderOrderNum)
, mStereoAwareness(stereoAwareness) , mStereoAwareness(stereoAwareness)
, mAddMSAAIntermediateTarget(addMSAAIntermediateTarget)
{ {
addCullCallback(new CullCallback); addCullCallback(new CullCallback);
setCullingActive(false); setCullingActive(false);
@ -206,7 +207,8 @@ namespace SceneUtil
camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0,
Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps, mSamples); Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps, mSamples);
SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER,
vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps); vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps,
mAddMSAAIntermediateTarget);
} }
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0) if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0)
@ -234,8 +236,8 @@ namespace SceneUtil
{ {
vdd->mColorTexture = createTexture(mColorBufferInternalFormat); vdd->mColorTexture = createTexture(mColorBufferInternalFormat);
camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, 0, mGenerateMipmaps, mSamples); camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, 0, mGenerateMipmaps, mSamples);
SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera( SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER,
camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, 0, mGenerateMipmaps); vdd->mColorTexture, 0, 0, mGenerateMipmaps, mAddMSAAIntermediateTarget);
} }
if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0) if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0)

@ -49,7 +49,7 @@ namespace SceneUtil
}; };
RTTNode(uint32_t textureWidth, uint32_t textureHeight, uint32_t samples, bool generateMipmaps, RTTNode(uint32_t textureWidth, uint32_t textureHeight, uint32_t samples, bool generateMipmaps,
int renderOrderNum, StereoAwareness stereoAwareness); int renderOrderNum, StereoAwareness stereoAwareness, bool addMSAAIntermediateTarget);
~RTTNode(); ~RTTNode();
osg::Texture* getColorTexture(osgUtil::CullVisitor* cv); osg::Texture* getColorTexture(osgUtil::CullVisitor* cv);
@ -110,6 +110,7 @@ namespace SceneUtil
GLint mDepthBufferInternalFormat; GLint mDepthBufferInternalFormat;
int mRenderOrderNum; int mRenderOrderNum;
StereoAwareness mStereoAwareness; StereoAwareness mStereoAwareness;
bool mAddMSAAIntermediateTarget;
}; };
} }
#endif #endif

@ -239,13 +239,12 @@ namespace SceneUtil
return glowUpdater; return glowUpdater;
} }
bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer, void attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer,
osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration) osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration,
bool addMSAAIntermediateTarget)
{ {
unsigned int samples = 0; unsigned int samples = 0;
unsigned int colourSamples = 0; unsigned int colourSamples = 0;
bool addMSAAIntermediateTarget = Settings::Manager::getBool("antialias alpha test", "Shaders")
&& Settings::Manager::getInt("antialiasing", "Video") > 1;
if (addMSAAIntermediateTarget) if (addMSAAIntermediateTarget)
{ {
// Alpha-to-coverage requires a multisampled framebuffer. // Alpha-to-coverage requires a multisampled framebuffer.
@ -255,7 +254,6 @@ namespace SceneUtil
colourSamples = 1; colourSamples = 1;
} }
camera->attach(buffer, texture, level, face, mipMapGeneration, samples, colourSamples); camera->attach(buffer, texture, level, face, mipMapGeneration, samples, colourSamples);
return addMSAAIntermediateTarget;
} }
OperationSequence::OperationSequence(bool keep) OperationSequence::OperationSequence(bool keep)

@ -96,8 +96,9 @@ namespace SceneUtil
const osg::Vec4f& glowColor, float glowDuration = -1); const osg::Vec4f& glowColor, float glowDuration = -1);
// Alpha-to-coverage requires a multisampled framebuffer, so we need to set that up for RTTs // Alpha-to-coverage requires a multisampled framebuffer, so we need to set that up for RTTs
bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer, void attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer,
osg::Texture* texture, unsigned int level = 0, unsigned int face = 0, bool mipMapGeneration = false); osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration,
bool addMSAAIntermediateTarget);
class OperationSequence : public osg::Operation class OperationSequence : public osg::Operation
{ {

@ -1,6 +1,7 @@
#ifndef OPENMW_COMPONENTS_SETTINGS_CATEGORIES_SHADERS_H #ifndef OPENMW_COMPONENTS_SETTINGS_CATEGORIES_SHADERS_H
#define OPENMW_COMPONENTS_SETTINGS_CATEGORIES_SHADERS_H #define OPENMW_COMPONENTS_SETTINGS_CATEGORIES_SHADERS_H
#include "components/sceneutil/lightingmethod.hpp"
#include "components/settings/sanitizerimpl.hpp" #include "components/settings/sanitizerimpl.hpp"
#include "components/settings/settingvalue.hpp" #include "components/settings/settingvalue.hpp"
@ -30,11 +31,11 @@ namespace Settings
SettingValue<std::string> mSpecularMapPattern{ mIndex, "Shaders", "specular map pattern" }; SettingValue<std::string> mSpecularMapPattern{ mIndex, "Shaders", "specular map pattern" };
SettingValue<std::string> mTerrainSpecularMapPattern{ mIndex, "Shaders", "terrain specular map pattern" }; SettingValue<std::string> mTerrainSpecularMapPattern{ mIndex, "Shaders", "terrain specular map pattern" };
SettingValue<bool> mApplyLightingToEnvironmentMaps{ mIndex, "Shaders", "apply lighting to environment maps" }; SettingValue<bool> mApplyLightingToEnvironmentMaps{ mIndex, "Shaders", "apply lighting to environment maps" };
SettingValue<std::string> mLightingMethod{ mIndex, "Shaders", "lighting method", SettingValue<SceneUtil::LightingMethod> mLightingMethod{ mIndex, "Shaders", "lighting method" };
makeEnumSanitizerString({ "legacy", "shaders compatibility", "shaders" }) };
SettingValue<float> mLightBoundsMultiplier{ mIndex, "Shaders", "light bounds multiplier", SettingValue<float> mLightBoundsMultiplier{ mIndex, "Shaders", "light bounds multiplier",
makeClampSanitizerFloat(0, 5) }; makeClampSanitizerFloat(0, 5) };
SettingValue<float> mMaximumLightDistance{ mIndex, "Shaders", "maximum light distance" }; SettingValue<float> mMaximumLightDistance{ mIndex, "Shaders", "maximum light distance",
makeMaxSanitizerFloat(0) };
SettingValue<float> mLightFadeStart{ mIndex, "Shaders", "light fade start", makeClampSanitizerFloat(0, 1) }; SettingValue<float> mLightFadeStart{ mIndex, "Shaders", "light fade start", makeClampSanitizerFloat(0, 1) };
SettingValue<int> mMaxLights{ mIndex, "Shaders", "max lights", makeClampSanitizerInt(2, 64) }; SettingValue<int> mMaxLights{ mIndex, "Shaders", "max lights", makeClampSanitizerInt(2, 64) };
SettingValue<float> mMinimumInteriorBrightness{ mIndex, "Shaders", "minimum interior brightness", SettingValue<float> mMinimumInteriorBrightness{ mIndex, "Shaders", "minimum interior brightness",

@ -16,6 +16,7 @@
#endif #endif
#include <components/debug/debuglog.hpp>
#include <components/files/configurationmanager.hpp> #include <components/files/configurationmanager.hpp>
#include <components/misc/strings/algorithm.hpp> #include <components/misc/strings/algorithm.hpp>
#include <components/misc/strings/conversion.hpp> #include <components/misc/strings/conversion.hpp>
@ -87,6 +88,21 @@ namespace Settings
stream << value; stream << value;
return stream.str(); return stream.str();
} }
std::string toString(SceneUtil::LightingMethod value)
{
switch (value)
{
case SceneUtil::LightingMethod::FFP:
return "legacy";
case SceneUtil::LightingMethod::PerObjectUniform:
return "shaders compatibility";
case SceneUtil::LightingMethod::SingleUBO:
return "shaders";
}
throw std::invalid_argument("Invalid LightingMethod value: " + std::to_string(static_cast<int>(value)));
}
} }
CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap();
@ -459,6 +475,11 @@ namespace Settings
setString(setting, category, value.print()); setString(setting, category, value.print());
} }
void Manager::set(std::string_view setting, std::string_view category, SceneUtil::LightingMethod value)
{
setString(setting, category, toString(value));
}
void Manager::recordInit(std::string_view setting, std::string_view category) void Manager::recordInit(std::string_view setting, std::string_view category)
{ {
sInitialized.emplace(category, setting); sInitialized.emplace(category, setting);
@ -491,4 +512,18 @@ namespace Settings
throw std::invalid_argument("Invalid navigation mesh rendering mode: " + std::string(value)); throw std::invalid_argument("Invalid navigation mesh rendering mode: " + std::string(value));
} }
SceneUtil::LightingMethod parseLightingMethod(std::string_view value)
{
if (value == "legacy")
return SceneUtil::LightingMethod::FFP;
if (value == "shaders compatibility")
return SceneUtil::LightingMethod::PerObjectUniform;
if (value == "shaders")
return SceneUtil::LightingMethod::SingleUBO;
constexpr const char* fallback = "shaders compatibility";
Log(Debug::Warning) << "Unknown lighting method '" << value << "', returning fallback '" << fallback << "'";
return SceneUtil::LightingMethod::PerObjectUniform;
}
} }

@ -5,7 +5,8 @@
#include "gyroscopeaxis.hpp" #include "gyroscopeaxis.hpp"
#include "navmeshrendermode.hpp" #include "navmeshrendermode.hpp"
#include "components/detournavigator/collisionshapetype.hpp" #include <components/detournavigator/collisionshapetype.hpp>
#include <components/sceneutil/lightingmethod.hpp>
#include <filesystem> #include <filesystem>
#include <set> #include <set>
@ -110,6 +111,7 @@ namespace Settings
static void set(std::string_view setting, std::string_view category, DetourNavigator::CollisionShapeType value); static void set(std::string_view setting, std::string_view category, DetourNavigator::CollisionShapeType value);
static void set(std::string_view setting, std::string_view category, const std::vector<std::string>& value); static void set(std::string_view setting, std::string_view category, const std::vector<std::string>& value);
static void set(std::string_view setting, std::string_view category, const MyGUI::Colour& value); static void set(std::string_view setting, std::string_view category, const MyGUI::Colour& value);
static void set(std::string_view setting, std::string_view category, SceneUtil::LightingMethod value);
private: private:
static std::set<std::pair<std::string_view, std::string_view>> sInitialized; static std::set<std::pair<std::string_view, std::string_view>> sInitialized;
@ -215,6 +217,15 @@ namespace Settings
{ {
return parseNavMeshRenderMode(getString(setting, category)); return parseNavMeshRenderMode(getString(setting, category));
} }
SceneUtil::LightingMethod parseLightingMethod(std::string_view value);
template <>
inline SceneUtil::LightingMethod Manager::getImpl<SceneUtil::LightingMethod>(
std::string_view setting, std::string_view category)
{
return parseLightingMethod(getString(setting, category));
}
} }
#endif // COMPONENTS_SETTINGS_H #endif // COMPONENTS_SETTINGS_H

@ -40,6 +40,7 @@ namespace Settings
MyGuiColour, MyGuiColour,
GyroscopeAxis, GyroscopeAxis,
NavMeshRenderMode, NavMeshRenderMode,
LightingMethod,
}; };
template <class T> template <class T>
@ -147,6 +148,12 @@ namespace Settings
return SettingValueType::NavMeshRenderMode; return SettingValueType::NavMeshRenderMode;
} }
template <>
inline constexpr SettingValueType getSettingValueType<SceneUtil::LightingMethod>()
{
return SettingValueType::LightingMethod;
}
inline constexpr std::string_view getSettingValueTypeName(SettingValueType type) inline constexpr std::string_view getSettingValueTypeName(SettingValueType type)
{ {
switch (type) switch (type)
@ -185,6 +192,8 @@ namespace Settings
return "gyroscope axis"; return "gyroscope axis";
case SettingValueType::NavMeshRenderMode: case SettingValueType::NavMeshRenderMode:
return "navmesh render mode"; return "navmesh render mode";
case SettingValueType::LightingMethod:
return "lighting method";
} }
return "unsupported"; return "unsupported";
} }

@ -680,8 +680,7 @@ namespace Shader
bool particleOcclusion = false; bool particleOcclusion = false;
node.getUserValue("particleOcclusion", particleOcclusion); node.getUserValue("particleOcclusion", particleOcclusion);
defineMap["particleOcclusion"] defineMap["particleOcclusion"] = particleOcclusion && mWeatherParticleOcclusion ? "1" : "0";
= particleOcclusion && Settings::Manager::getBool("weather particle occlusion", "Shaders") ? "1" : "0";
if (reqs.mAlphaBlend && mSupportsNormalsRT) if (reqs.mAlphaBlend && mSupportsNormalsRT)
{ {

@ -51,6 +51,8 @@ namespace Shader
void setSupportsNormalsRT(bool supports) { mSupportsNormalsRT = supports; } void setSupportsNormalsRT(bool supports) { mSupportsNormalsRT = supports; }
void setWeatherParticleOcclusion(bool value) { mWeatherParticleOcclusion = value; }
void apply(osg::Node& node) override; void apply(osg::Node& node) override;
void apply(osg::Drawable& drawable) override; void apply(osg::Drawable& drawable) override;
@ -78,6 +80,7 @@ namespace Shader
bool mAdjustCoverageForAlphaTest; bool mAdjustCoverageForAlphaTest;
bool mSupportsNormalsRT; bool mSupportsNormalsRT;
bool mWeatherParticleOcclusion = false;
ShaderManager& mShaderManager; ShaderManager& mShaderManager;
Resource::ImageManager& mImageManager; Resource::ImageManager& mImageManager;

Loading…
Cancel
Save