diff --git a/apps/launcher/graphicspage.cpp b/apps/launcher/graphicspage.cpp index 5f37c0defe..9a10bf6d9c 100644 --- a/apps/launcher/graphicspage.cpp +++ b/apps/launcher/graphicspage.cpp @@ -2,6 +2,8 @@ #include "sdlinit.hpp" +#include + #include #include @@ -144,10 +146,18 @@ bool Launcher::GraphicsPage::loadSettings() // Lighting int lightingMethod = 1; - if (Settings::Manager::getString("lighting method", "Shaders") == "legacy") - lightingMethod = 0; - else if (Settings::Manager::getString("lighting method", "Shaders") == "shaders") - lightingMethod = 2; + switch (Settings::shaders().mLightingMethod) + { + case SceneUtil::LightingMethod::FFP: + lightingMethod = 0; + break; + case SceneUtil::LightingMethod::PerObjectUniform: + lightingMethod = 1; + break; + case SceneUtil::LightingMethod::SingleUBO: + lightingMethod = 2; + break; + } lightingMethodComboBox->setCurrentIndex(lightingMethod); // Shadows @@ -246,10 +256,12 @@ void Launcher::GraphicsPage::saveSettings() } // Lighting - static std::array lightingMethodMap = { "legacy", "shaders compatibility", "shaders" }; - const std::string& cLightingMethod = lightingMethodMap[lightingMethodComboBox->currentIndex()]; - if (cLightingMethod != Settings::Manager::getString("lighting method", "Shaders")) - Settings::Manager::setString("lighting method", "Shaders", cLightingMethod); + static constexpr std::array lightingMethodMap = { + SceneUtil::LightingMethod::FFP, + SceneUtil::LightingMethod::PerObjectUniform, + SceneUtil::LightingMethod::SingleUBO, + }; + Settings::shaders().mLightingMethod.set(lightingMethodMap[lightingMethodComboBox->currentIndex()]); // Shadows int cShadowDist = shadowDistanceCheckBox->checkState() != Qt::Unchecked ? shadowDistanceSpinBox->value() : 0; diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index 12170c86a0..953e3076b3 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -87,10 +87,10 @@ namespace CSVRender mView->getCamera()->setGraphicsContext(window); - SceneUtil::LightManager* lightMgr = new SceneUtil::LightManager; + osg::ref_ptr lightMgr = new SceneUtil::LightManager; lightMgr->setStartLight(1); lightMgr->setLightingMask(Mask_Lighting); - mRootNode = lightMgr; + mRootNode = std::move(lightMgr); mView->getCamera()->setViewport(new osg::Viewport(0, 0, width(), height())); diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 9fa842bfa9..ac25b5984a 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -147,7 +147,7 @@ namespace constexpr int min = 8; constexpr int max = 32; constexpr int increment = 8; - int maxLights = Settings::Manager::getInt("max lights", "Shaders"); + const int maxLights = Settings::shaders().mMaxLights; // show increments of 8 in dropdown if (maxLights >= min && maxLights <= max && !(maxLights % increment)) box->setIndexSelected((maxLights / increment) - 1); @@ -559,7 +559,8 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->interactiveMessageBox( "#{OMWEngine:ChangeRequiresRestart}", { "#{Interface:OK}" }, true); - Settings::Manager::setString("lighting method", "Shaders", *_sender->getItemDataAt(pos)); + Settings::shaders().mLightingMethod.set( + Settings::parseLightingMethod(*_sender->getItemDataAt(pos))); apply(); } @@ -630,9 +631,7 @@ namespace MWGui void SettingsWindow::onMaxLightsChanged(MyGUI::ComboBox* _sender, size_t pos) { - int count = 8 * (pos + 1); - - Settings::Manager::setInt("max lights", "Shaders", count); + Settings::shaders().mMaxLights.set(8 * (pos + 1)); apply(); configureWidgets(mMainWidget, false); } @@ -653,8 +652,7 @@ namespace MWGui Settings::shaders().mMaxLights.reset(); Settings::shaders().mLightingMethod.reset(); - const SceneUtil::LightingMethod lightingMethod - = SceneUtil::LightManager::getLightingMethodFromString(Settings::shaders().mLightingMethod); + const SceneUtil::LightingMethod lightingMethod = Settings::shaders().mLightingMethod; const std::size_t lightIndex = mLightingMethodButton->findItemIndexWith(lightingMethodToStr(lightingMethod)); mLightingMethodButton->setIndexSelected(lightIndex); updateMaxLightsComboBox(mMaxLights); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 5357f5025c..fbf5bf112a 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include "../mwworld/class.hpp" @@ -34,6 +34,7 @@ #include "../mwmechanics/weapontype.hpp" #include "npcanimation.hpp" +#include "util.hpp" #include "vismask.hpp" namespace MWRender @@ -154,7 +155,7 @@ namespace MWRender public: CharacterPreviewRTTNode(uint32_t sizeX, uint32_t sizeY) : RTTNode(sizeX, sizeY, Settings::Manager::getInt("antialiasing", "Video"), false, 0, - StereoAwareness::Unaware_MultiViewShaders) + StereoAwareness::Unaware_MultiViewShaders, shouldAddMSAAIntermediateTarget()) , mAspectRatio(static_cast(sizeX) / static_cast(sizeY)) { if (SceneUtil::AutoDepth::isReversed()) @@ -226,9 +227,13 @@ namespace MWRender mRTTNode = new CharacterPreviewRTTNode(sizeX, sizeY); mRTTNode->setNodeMask(Mask_RenderToTexture); - bool ffp = mResourceSystem->getSceneManager()->getLightingMethod() == SceneUtil::LightingMethod::FFP; - - osg::ref_ptr lightManager = new SceneUtil::LightManager(ffp); + osg::ref_ptr lightManager = new SceneUtil::LightManager(SceneUtil::LightSettings{ + .mLightingMethod = mResourceSystem->getSceneManager()->getLightingMethod(), + .mMaxLights = Settings::shaders().mMaxLights, + .mMaximumLightDistance = Settings::shaders().mMaximumLightDistance, + .mLightFadeStart = Settings::shaders().mLightFadeStart, + .mLightBoundsMultiplier = Settings::shaders().mLightBoundsMultiplier, + }); lightManager->setStartLight(1); osg::ref_ptr stateset = lightManager->getOrCreateStateSet(); stateset->setDefine("FORCE_OPAQUE", "1", osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index a07fa10b09..3d28bf477d 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -30,6 +30,7 @@ #include "../mwworld/cellstore.hpp" +#include "util.hpp" #include "vismask.hpp" namespace @@ -679,7 +680,7 @@ namespace MWRender LocalMapRenderToTexture::LocalMapRenderToTexture(osg::Node* sceneRoot, int res, int mapWorldSize, float x, float y, 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) , mActive(true) { diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index bcaba03161..9162657e30 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -122,7 +122,6 @@ namespace MWRender , mReload(false) , mEnabled(false) , mUsePostProcessing(Settings::postProcessing().mEnabled) - , mSoftParticles(false) , mDisableDepthPasses(false) , mLastFrameNumber(0) , mLastSimulationTime(0.f) @@ -135,8 +134,6 @@ namespace MWRender , mPassLights(false) , mPrevPassLights(false) { - mSoftParticles = Settings::Manager::getBool("soft particles", "Shaders"); - osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext(); osg::GLExtensions* ext = gc->getState()->get(); @@ -155,7 +152,7 @@ namespace MWRender else 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) { @@ -172,7 +169,8 @@ namespace MWRender mUBO = ext->isUniformBufferObjectSupported && mGLSLVersion >= 330; mStateUpdater = new fx::StateUpdater(mUBO); - if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !mSoftParticles && !mUsePostProcessing) + if (!Stereo::getStereo() && !SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles + && !mUsePostProcessing) return; enable(mUsePostProcessing); @@ -239,7 +237,7 @@ namespace MWRender const bool postPass = Settings::postProcessing().mTransparentPostpass; mUsePostProcessing = usePostProcessing; - mDisableDepthPasses = !mSoftParticles && !postPass; + mDisableDepthPasses = !Settings::shaders().mSoftParticles && !postPass; #ifdef ANDROID mDisableDepthPasses = true; @@ -276,10 +274,10 @@ namespace MWRender void PostProcessor::disable() { - if (!mSoftParticles) + if (!Settings::shaders().mSoftParticles) osgUtil::RenderBin::getRenderBinPrototype("DepthSortedBin")->setDrawCallback(nullptr); - if (!SceneUtil::AutoDepth::isReversed() && !mSoftParticles) + if (!SceneUtil::AutoDepth::isReversed() && !Settings::shaders().mSoftParticles) { removeChild(mHUDCamera); setCullCallback(nullptr); diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp index fa230ec2e8..4473ade836 100644 --- a/apps/openmw/mwrender/postprocessor.hpp +++ b/apps/openmw/mwrender/postprocessor.hpp @@ -175,8 +175,6 @@ namespace MWRender bool isEnabled() const { return mUsePostProcessing && mEnabled; } - bool softParticlesEnabled() const { return mSoftParticles; } - bool getHDR() const { return mHDR; } void disable(); @@ -247,7 +245,6 @@ namespace MWRender bool mReload; bool mEnabled; bool mUsePostProcessing; - bool mSoftParticles; bool mDisableDepthPasses; size_t mLastFrameNumber; diff --git a/apps/openmw/mwrender/precipitationocclusion.cpp b/apps/openmw/mwrender/precipitationocclusion.cpp index e7c9245fef..204b5c07bd 100644 --- a/apps/openmw/mwrender/precipitationocclusion.cpp +++ b/apps/openmw/mwrender/precipitationocclusion.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include "../mwbase/environment.hpp" @@ -112,7 +113,7 @@ namespace MWRender mCamera->attach(osg::Camera::DEPTH_BUFFER, mDepthTexture); mCamera->addChild(mSceneNode); mCamera->setSmallFeatureCullingPixelSize( - Settings::Manager::getFloat("weather particle occlusion small feature culling pixel size", "Shaders")); + Settings::shaders().mWeatherParticleOcclusionSmallFeatureCullingPixelSize); SceneUtil::setCameraClearDepth(mCamera); } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d470273862..b7685e0cd8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -82,6 +82,7 @@ #include "screenshotmanager.hpp" #include "sky.hpp" #include "terrainstorage.hpp" +#include "util.hpp" #include "vismask.hpp" #include "water.hpp" @@ -312,7 +313,6 @@ namespace MWRender , mResourceSystem(resourceSystem) , mWorkQueue(workQueue) , mNavigator(navigator) - , mMinimumAmbientLuminance(0.f) , mNightEyeFactor(0.f) // TODO: Near clip should not need to be bounded like this, but too small values break OSG shadow calculations // CPU-side. See issue: #6072 @@ -325,46 +325,40 @@ namespace MWRender , mGroundCoverStore(groundcoverStore) { bool reverseZ = SceneUtil::AutoDepth::isReversed(); - auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString( - Settings::Manager::getString("lighting method", "Shaders")); + const SceneUtil::LightingMethod lightingMethod = Settings::shaders().mLightingMethod; resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); // Shadows and radial fog have problems with fixed-function mode. bool forceShaders = Settings::fog().mRadialFog || Settings::fog().mExponentialFog - || Settings::Manager::getBool("soft particles", "Shaders") - || Settings::Manager::getBool("force shaders", "Shaders") + || Settings::shaders().mSoftParticles || Settings::shaders().mForceShaders || Settings::Manager::getBool("enable shadows", "Shadows") || lightingMethod != SceneUtil::LightingMethod::FFP || reverseZ || mSkyBlending || Stereo::getMultiview(); resourceSystem->getSceneManager()->setForceShaders(forceShaders); // FIXME: calling dummy method because terrain needs to know whether lighting is clamped - resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders")); - resourceSystem->getSceneManager()->setAutoUseNormalMaps( - Settings::Manager::getBool("auto use object normal maps", "Shaders")); - resourceSystem->getSceneManager()->setNormalMapPattern( - Settings::Manager::getString("normal map pattern", "Shaders")); - resourceSystem->getSceneManager()->setNormalHeightMapPattern( - 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()->setClampLighting(Settings::shaders().mClampLighting); + resourceSystem->getSceneManager()->setAutoUseNormalMaps(Settings::shaders().mAutoUseObjectNormalMaps); + resourceSystem->getSceneManager()->setNormalMapPattern(Settings::shaders().mNormalMapPattern); + resourceSystem->getSceneManager()->setNormalHeightMapPattern(Settings::shaders().mNormalHeightMapPattern); + resourceSystem->getSceneManager()->setAutoUseSpecularMaps(Settings::shaders().mAutoUseObjectSpecularMaps); + resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::shaders().mSpecularMapPattern); resourceSystem->getSceneManager()->setApplyLightingToEnvMaps( - Settings::Manager::getBool("apply lighting to environment maps", "Shaders")); - resourceSystem->getSceneManager()->setConvertAlphaTestToAlphaToCoverage( - Settings::Manager::getBool("antialias alpha test", "Shaders") - && Settings::Manager::getInt("antialiasing", "Video") > 1); + Settings::shaders().mApplyLightingToEnvironmentMaps); + resourceSystem->getSceneManager()->setConvertAlphaTestToAlphaToCoverage(shouldAddMSAAIntermediateTarget()); 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 // depends on support for various OpenGL extensions. - osg::ref_ptr sceneRoot - = new SceneUtil::LightManager(lightingMethod == SceneUtil::LightingMethod::FFP); + osg::ref_ptr sceneRoot = new SceneUtil::LightManager(SceneUtil::LightSettings{ + .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()->setSupportedLightingMethods(sceneRoot->getSupportedLightingMethods()); - mMinimumAmbientLuminance - = std::clamp(Settings::Manager::getFloat("minimum interior brightness", "Shaders"), 0.f, 1.f); sceneRoot->setLightingMask(Mask_Lighting); mSceneRoot = sceneRoot; @@ -396,10 +390,9 @@ namespace MWRender for (auto itr = shadowDefines.begin(); itr != shadowDefines.end(); itr++) globalDefines[itr->first] = itr->second; - globalDefines["forcePPL"] = Settings::Manager::getBool("force per pixel lighting", "Shaders") ? "1" : "0"; - globalDefines["clamp"] = Settings::Manager::getBool("clamp lighting", "Shaders") ? "1" : "0"; - globalDefines["preLightEnv"] - = Settings::Manager::getBool("apply lighting to environment maps", "Shaders") ? "1" : "0"; + globalDefines["forcePPL"] = Settings::shaders().mForcePerPixelLighting ? "1" : "0"; + globalDefines["clamp"] = Settings::shaders().mClampLighting ? "1" : "0"; + globalDefines["preLightEnv"] = Settings::shaders().mApplyLightingToEnvironmentMaps ? "1" : "0"; const bool exponentialFog = Settings::fog().mExponentialFog; globalDefines["radialFog"] = (exponentialFog || Settings::fog().mRadialFog) ? "1" : "0"; globalDefines["exponentialFog"] = exponentialFog ? "1" : "0"; @@ -445,11 +438,11 @@ namespace MWRender mEffectManager = std::make_unique(sceneRoot, mResourceSystem); - const std::string& normalMapPattern = Settings::Manager::getString("normal map pattern", "Shaders"); - const std::string& heightMapPattern = Settings::Manager::getString("normal height map pattern", "Shaders"); - const std::string& specularMapPattern = Settings::Manager::getString("terrain specular map pattern", "Shaders"); - const bool useTerrainNormalMaps = Settings::Manager::getBool("auto use terrain normal maps", "Shaders"); - const bool useTerrainSpecularMaps = Settings::Manager::getBool("auto use terrain specular maps", "Shaders"); + const std::string& normalMapPattern = Settings::shaders().mNormalMapPattern; + const std::string& heightMapPattern = Settings::shaders().mNormalHeightMapPattern; + const std::string& specularMapPattern = Settings::shaders().mTerrainSpecularMapPattern; + const bool useTerrainNormalMaps = Settings::shaders().mAutoUseTerrainNormalMaps; + const bool useTerrainSpecularMaps = Settings::shaders().mAutoUseTerrainSpecularMaps; mTerrainStorage = std::make_unique(mResourceSystem, normalMapPattern, heightMapPattern, useTerrainNormalMaps, specularMapPattern, useTerrainSpecularMaps); @@ -472,8 +465,9 @@ namespace MWRender resourceSystem->getSceneManager()->setOpaqueDepthTex( mPostProcessor->getTexture(PostProcessor::Tex_OpaqueDepth, 0), mPostProcessor->getTexture(PostProcessor::Tex_OpaqueDepth, 1)); - resourceSystem->getSceneManager()->setSoftParticles(mPostProcessor->softParticlesEnabled()); + resourceSystem->getSceneManager()->setSoftParticles(Settings::shaders().mSoftParticles); resourceSystem->getSceneManager()->setSupportsNormalsRT(mPostProcessor->getSupportsNormalsRT()); + resourceSystem->getSceneManager()->setWeatherParticleOcclusion(Settings::shaders().mWeatherParticleOcclusion); // water goes after terrain for correct waterculling order mWater = std::make_unique( @@ -680,15 +674,16 @@ namespace MWRender // 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) + 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 // as least we can if (ambient.r() == 0.f && ambient.g() == 0.f && ambient.b() == 0.f) ambient = osg::Vec4( - mMinimumAmbientLuminance, mMinimumAmbientLuminance, mMinimumAmbientLuminance, ambient.a()); + minimumAmbientLuminance, minimumAmbientLuminance, minimumAmbientLuminance, ambient.a()); else - ambient *= mMinimumAmbientLuminance / relativeLuminance; + ambient *= minimumAmbientLuminance / relativeLuminance; } } @@ -1408,8 +1403,6 @@ namespace MWRender } 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()) configureAmbient(*MWMechanics::getPlayer().getCell()->getCell()); } @@ -1418,13 +1411,15 @@ namespace MWRender || it->second == "light fade start" || it->second == "max lights")) { auto* lightManager = getLightRoot(); - lightManager->processChangedSettings(changed); + + lightManager->processChangedSettings(Settings::shaders().mLightBoundsMultiplier, + Settings::shaders().mMaximumLightDistance, Settings::shaders().mLightFadeStart); if (it->second == "max lights" && !lightManager->usingFFP()) { mViewer->stopThreading(); - lightManager->updateMaxLights(); + lightManager->updateMaxLights(Settings::shaders().mMaxLights); auto defines = mResourceSystem->getSceneManager()->getShaderManager().getGlobalDefines(); for (const auto& [name, key] : lightManager->getLightDefines()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index f1760d3960..22ef987c01 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -342,7 +342,6 @@ namespace MWRender osg::ref_ptr mPerViewUniformStateUpdater; osg::Vec4f mAmbientColor; - float mMinimumAmbientLuminance; float mNightEyeFactor; float mNearClip; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 05c7a1bab2..51018e93f9 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -35,6 +35,7 @@ #include "renderbin.hpp" #include "skyutil.hpp" +#include "util.hpp" #include "vismask.hpp" namespace @@ -205,7 +206,8 @@ namespace { public: SkyRTT(osg::Vec2f size, osg::Group* earlyRenderBinRoot) - : RTTNode(static_cast(size.x()), static_cast(size.y()), 0, false, 1, StereoAwareness::Aware) + : RTTNode(static_cast(size.x()), static_cast(size.y()), 0, false, 1, StereoAwareness::Aware, + MWRender::shouldAddMSAAIntermediateTarget()) , mEarlyRenderBinRoot(earlyRenderBinRoot) { setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8); @@ -292,7 +294,7 @@ namespace MWRender mRootNode->addChild(mEarlyRenderBinRoot); mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot); - mPrecipitationOcclusion = Settings::Manager::getBool("weather particle occlusion", "Shaders"); + mPrecipitationOcclusion = Settings::shaders().mWeatherParticleOcclusion; mPrecipitationOccluder = std::make_unique(skyroot, parentNode, rootNode, camera); } diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index 509ea2efa7..234b022f5d 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace MWRender { @@ -67,4 +68,9 @@ namespace MWRender node->setStateSet(stateset); } + bool shouldAddMSAAIntermediateTarget() + { + return Settings::shaders().mAntialiasAlphaTest && Settings::Manager::getInt("antialiasing", "Video") > 1; + } + } diff --git a/apps/openmw/mwrender/util.hpp b/apps/openmw/mwrender/util.hpp index 457b23f94b..64edaf8e18 100644 --- a/apps/openmw/mwrender/util.hpp +++ b/apps/openmw/mwrender/util.hpp @@ -3,6 +3,7 @@ #include #include + #include namespace osg @@ -35,6 +36,8 @@ namespace MWRender // no traverse() } }; + + bool shouldAddMSAAIntermediateTarget(); } #endif diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 51ce06069c..f823378e46 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -35,11 +35,14 @@ #include +#include + #include "../mwworld/cellstore.hpp" #include "renderbin.hpp" #include "ripples.hpp" #include "ripplesimulation.hpp" +#include "util.hpp" #include "vismask.hpp" namespace MWRender @@ -234,7 +237,7 @@ namespace MWRender { public: Refraction(uint32_t rttSize) - : RTTNode(rttSize, rttSize, 0, false, 1, StereoAwareness::Aware) + : RTTNode(rttSize, rttSize, 0, false, 1, StereoAwareness::Aware, shouldAddMSAAIntermediateTarget()) , mNodeMask(Refraction::sDefaultCullMask) { setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8); @@ -315,7 +318,7 @@ namespace MWRender { public: 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); setDepthBufferInternalFormat(GL_DEPTH24_STENCIL8); diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 5ad7562e96..dd680dc98d 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -107,7 +107,7 @@ add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer 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 diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 66fee5256d..b3c9eee5e7 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -1118,10 +1118,10 @@ namespace Resource stats->setAttribute(frameNumber, "Node", mCache->getCacheSize()); } - Shader::ShaderVisitor* SceneManager::createShaderVisitor(const std::string& shaderPrefix) + osg::ref_ptr SceneManager::createShaderVisitor(const std::string& shaderPrefix) { - Shader::ShaderVisitor* shaderVisitor - = new Shader::ShaderVisitor(*mShaderManager.get(), *mImageManager, shaderPrefix); + osg::ref_ptr shaderVisitor( + new Shader::ShaderVisitor(*mShaderManager.get(), *mImageManager, shaderPrefix)); shaderVisitor->setForceShaders(mForceShaders); shaderVisitor->setAutoUseNormalMaps(mAutoUseNormalMaps); shaderVisitor->setNormalMapPattern(mNormalMapPattern); @@ -1132,6 +1132,7 @@ namespace Resource shaderVisitor->setConvertAlphaTestToAlphaToCoverage(mConvertAlphaTestToAlphaToCoverage); shaderVisitor->setAdjustCoverageForAlphaTest(mAdjustCoverageForAlphaTest); shaderVisitor->setSupportsNormalsRT(mSupportsNormalsRT); + shaderVisitor->setWeatherParticleOcclusion(mWeatherParticleOcclusion); return shaderVisitor; } } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index e8a9640ce9..c7663a4d91 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -227,8 +227,10 @@ namespace Resource void setSoftParticles(bool enabled) { mSoftParticles = enabled; } bool getSoftParticles() const { return mSoftParticles; } + void setWeatherParticleOcclusion(bool value) { mWeatherParticleOcclusion = value; } + private: - Shader::ShaderVisitor* createShaderVisitor(const std::string& shaderPrefix = "objects"); + osg::ref_ptr createShaderVisitor(const std::string& shaderPrefix = "objects"); osg::ref_ptr loadErrorMarker(); osg::ref_ptr cloneErrorMarker(); @@ -248,6 +250,7 @@ namespace Resource bool mSupportsNormalsRT; std::array, 2> mOpaqueDepthTex; bool mSoftParticles = false; + bool mWeatherParticleOcclusion = false; osg::ref_ptr mSharedStateManager; mutable std::mutex mSharedStateMutex; diff --git a/components/sceneutil/lightingmethod.hpp b/components/sceneutil/lightingmethod.hpp new file mode 100644 index 0000000000..00aafd1cb7 --- /dev/null +++ b/components/sceneutil/lightingmethod.hpp @@ -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 diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index ea7d3459ae..6bca92fdb4 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -23,8 +23,6 @@ namespace { - constexpr int maxLightsLowerLimit = 2; - constexpr int maxLightsUpperLimit = 64; constexpr int ffpMaxLights = 8; bool sortLights(const SceneUtil::LightManager::LightSourceViewBound* left, @@ -817,7 +815,7 @@ namespace SceneUtil return ""; } - LightManager::LightManager(bool ffp) + LightManager::LightManager(const LightSettings& settings) : mStartLight(0) , mLightingMask(~0u) , mSun(nullptr) @@ -835,18 +833,15 @@ namespace SceneUtil setUpdateCallback(new LightManagerUpdateCallback); - if (ffp) + if (settings.mLightingMethod == LightingMethod::FFP) { initFFP(ffpMaxLights); return; } - const std::string& lightingMethodString = Settings::Manager::getString("lighting method", "Shaders"); - auto lightingMethod = LightManager::getLightingMethodFromString(lightingMethodString); - static bool hasLoggedWarnings = false; - if (lightingMethod == LightingMethod::SingleUBO && !hasLoggedWarnings) + if (settings.mLightingMethod == LightingMethod::SingleUBO && !hasLoggedWarnings) { if (!supportsUBO) Log(Debug::Warning) @@ -857,15 +852,12 @@ namespace SceneUtil hasLoggedWarnings = true; } - const int targetLights - = std::clamp(Settings::Manager::getInt("max lights", "Shaders"), maxLightsLowerLimit, maxLightsUpperLimit); - - if (!supportsUBO || !supportsGPU4 || lightingMethod == LightingMethod::PerObjectUniform) - initPerObjectUniform(targetLights); + if (!supportsUBO || !supportsGPU4 || settings.mLightingMethod == LightingMethod::PerObjectUniform) + initPerObjectUniform(settings.mMaxLights); else - initSingleUBO(targetLights); + initSingleUBO(settings.mMaxLights); - updateSettings(); + updateSettings(settings.mLightBoundsMultiplier, settings.mMaximumLightDistance, settings.mLightFadeStart); getOrCreateStateSet()->addUniform(new osg::Uniform("PointLightCount", 0)); @@ -931,18 +923,18 @@ namespace SceneUtil 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()) return; - setMaxLights( - std::clamp(Settings::Manager::getInt("max lights", "Shaders"), maxLightsLowerLimit, maxLightsUpperLimit)); + setMaxLights(maxLights); if (getLightingMethod() == LightingMethod::PerObjectUniform) { @@ -954,20 +946,15 @@ namespace SceneUtil cache.clear(); } - void LightManager::updateSettings() + void LightManager::updateSettings(float lightBoundsMultiplier, float maximumLightDistance, float lightFadeStart) { if (getLightingMethod() == LightingMethod::FFP) return; - mPointLightRadiusMultiplier - = std::clamp(Settings::Manager::getFloat("light bounds multiplier", "Shaders"), 0.f, 5.f); - - mPointLightFadeEnd = std::max(0.f, Settings::Manager::getFloat("maximum light distance", "Shaders")); + mPointLightRadiusMultiplier = lightBoundsMultiplier; + mPointLightFadeEnd = maximumLightDistance; if (mPointLightFadeEnd > 0) - { - mPointLightFadeStart = std::clamp(Settings::Manager::getFloat("light fade start", "Shaders"), 0.f, 1.f); - mPointLightFadeStart = mPointLightFadeEnd * mPointLightFadeStart; - } + mPointLightFadeStart = mPointLightFadeEnd * lightFadeStart; } void LightManager::initFFP(int targetLights) diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 93bddb800b..0b30a77e5c 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -12,7 +12,8 @@ #include #include -#include + +#include "lightingmethod.hpp" namespace SceneUtil { @@ -82,13 +83,6 @@ namespace SceneUtil std::array, 2> mUniformCount; }; - enum class LightingMethod - { - FFP, - PerObjectUniform, - SingleUBO, - }; - /// LightSource managed by a LightManager. /// @par Typically used for point lights. Spot lights are not supported yet. Directional lights affect the whole /// scene @@ -186,6 +180,15 @@ namespace SceneUtil osg::ref_ptr 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 /// subgraph. class LightManager : public osg::Group @@ -212,7 +215,7 @@ namespace SceneUtil META_Node(SceneUtil, LightManager) - LightManager(bool ffp = true); + explicit LightManager(const LightSettings& settings = LightSettings{}); LightManager(const LightManager& copy, const osg::CopyOp& copyop); @@ -264,10 +267,10 @@ namespace SceneUtil std::map 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 - void updateMaxLights(); + void updateMaxLights(int maxLights); osg::ref_ptr generateLightBufferUniform(const osg::Matrixf& sun); @@ -281,7 +284,7 @@ namespace SceneUtil void initPerObjectUniform(int targetLights); void initSingleUBO(int targetLights); - void updateSettings(); + void updateSettings(float lightBoundsMultiplier, float maximumLightDistance, float lightFadeStart); void setLightingMethod(LightingMethod method); void setMaxLights(int value); diff --git a/components/sceneutil/rtt.cpp b/components/sceneutil/rtt.cpp index eec4aaa35d..54d53ddab9 100644 --- a/components/sceneutil/rtt.cpp +++ b/components/sceneutil/rtt.cpp @@ -20,7 +20,7 @@ namespace SceneUtil }; 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) , mTextureHeight(textureHeight) , mSamples(samples) @@ -29,6 +29,7 @@ namespace SceneUtil , mDepthBufferInternalFormat(SceneUtil::AutoDepth::depthInternalFormat()) , mRenderOrderNum(renderOrderNum) , mStereoAwareness(stereoAwareness) + , mAddMSAAIntermediateTarget(addMSAAIntermediateTarget) { addCullCallback(new CullCallback); setCullingActive(false); @@ -206,7 +207,8 @@ namespace SceneUtil camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, Stereo::osgFaceControlledByMultiviewShader(), mGenerateMipmaps, mSamples); 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) @@ -234,8 +236,8 @@ namespace SceneUtil { vdd->mColorTexture = createTexture(mColorBufferInternalFormat); camera->attach(osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, 0, mGenerateMipmaps, mSamples); - SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera( - camera, osg::Camera::COLOR_BUFFER, vdd->mColorTexture, 0, 0, mGenerateMipmaps); + SceneUtil::attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, + vdd->mColorTexture, 0, 0, mGenerateMipmaps, mAddMSAAIntermediateTarget); } if (camera->getBufferAttachmentMap().count(osg::Camera::PACKED_DEPTH_STENCIL_BUFFER) == 0) diff --git a/components/sceneutil/rtt.hpp b/components/sceneutil/rtt.hpp index 5c8183f6c0..d2f43f78ed 100644 --- a/components/sceneutil/rtt.hpp +++ b/components/sceneutil/rtt.hpp @@ -49,7 +49,7 @@ namespace SceneUtil }; RTTNode(uint32_t textureWidth, uint32_t textureHeight, uint32_t samples, bool generateMipmaps, - int renderOrderNum, StereoAwareness stereoAwareness); + int renderOrderNum, StereoAwareness stereoAwareness, bool addMSAAIntermediateTarget); ~RTTNode(); osg::Texture* getColorTexture(osgUtil::CullVisitor* cv); @@ -110,6 +110,7 @@ namespace SceneUtil GLint mDepthBufferInternalFormat; int mRenderOrderNum; StereoAwareness mStereoAwareness; + bool mAddMSAAIntermediateTarget; }; } #endif diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 7b921d15f4..6ff366f76e 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -239,13 +239,12 @@ namespace SceneUtil return glowUpdater; } - bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer, - osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration) + void attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer, + osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration, + bool addMSAAIntermediateTarget) { unsigned int samples = 0; unsigned int colourSamples = 0; - bool addMSAAIntermediateTarget = Settings::Manager::getBool("antialias alpha test", "Shaders") - && Settings::Manager::getInt("antialiasing", "Video") > 1; if (addMSAAIntermediateTarget) { // Alpha-to-coverage requires a multisampled framebuffer. @@ -255,7 +254,6 @@ namespace SceneUtil colourSamples = 1; } camera->attach(buffer, texture, level, face, mipMapGeneration, samples, colourSamples); - return addMSAAIntermediateTarget; } OperationSequence::OperationSequence(bool keep) diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index 0a65a9980f..29fee09176 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -96,8 +96,9 @@ namespace SceneUtil const osg::Vec4f& glowColor, float glowDuration = -1); // 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, - osg::Texture* texture, unsigned int level = 0, unsigned int face = 0, bool mipMapGeneration = false); + void attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer, + osg::Texture* texture, unsigned int level, unsigned int face, bool mipMapGeneration, + bool addMSAAIntermediateTarget); class OperationSequence : public osg::Operation { diff --git a/components/settings/categories/shaders.hpp b/components/settings/categories/shaders.hpp index e7d1e34713..7efb891822 100644 --- a/components/settings/categories/shaders.hpp +++ b/components/settings/categories/shaders.hpp @@ -1,6 +1,7 @@ #ifndef 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/settingvalue.hpp" @@ -30,11 +31,11 @@ namespace Settings SettingValue mSpecularMapPattern{ mIndex, "Shaders", "specular map pattern" }; SettingValue mTerrainSpecularMapPattern{ mIndex, "Shaders", "terrain specular map pattern" }; SettingValue mApplyLightingToEnvironmentMaps{ mIndex, "Shaders", "apply lighting to environment maps" }; - SettingValue mLightingMethod{ mIndex, "Shaders", "lighting method", - makeEnumSanitizerString({ "legacy", "shaders compatibility", "shaders" }) }; + SettingValue mLightingMethod{ mIndex, "Shaders", "lighting method" }; SettingValue mLightBoundsMultiplier{ mIndex, "Shaders", "light bounds multiplier", makeClampSanitizerFloat(0, 5) }; - SettingValue mMaximumLightDistance{ mIndex, "Shaders", "maximum light distance" }; + SettingValue mMaximumLightDistance{ mIndex, "Shaders", "maximum light distance", + makeMaxSanitizerFloat(0) }; SettingValue mLightFadeStart{ mIndex, "Shaders", "light fade start", makeClampSanitizerFloat(0, 1) }; SettingValue mMaxLights{ mIndex, "Shaders", "max lights", makeClampSanitizerInt(2, 64) }; SettingValue mMinimumInteriorBrightness{ mIndex, "Shaders", "minimum interior brightness", diff --git a/components/settings/settings.cpp b/components/settings/settings.cpp index 305d4edc88..bab8f41c1d 100644 --- a/components/settings/settings.cpp +++ b/components/settings/settings.cpp @@ -16,6 +16,7 @@ #endif +#include #include #include #include @@ -87,6 +88,21 @@ namespace Settings stream << value; 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(value))); + } } CategorySettingValueMap Manager::mDefaultSettings = CategorySettingValueMap(); @@ -459,6 +475,11 @@ namespace Settings 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) { sInitialized.emplace(category, setting); @@ -491,4 +512,18 @@ namespace Settings 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; + } } diff --git a/components/settings/settings.hpp b/components/settings/settings.hpp index 784c7c613c..0177b5fbf2 100644 --- a/components/settings/settings.hpp +++ b/components/settings/settings.hpp @@ -5,7 +5,8 @@ #include "gyroscopeaxis.hpp" #include "navmeshrendermode.hpp" -#include "components/detournavigator/collisionshapetype.hpp" +#include +#include #include #include @@ -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, const std::vector& 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: static std::set> sInitialized; @@ -215,6 +217,15 @@ namespace Settings { return parseNavMeshRenderMode(getString(setting, category)); } + + SceneUtil::LightingMethod parseLightingMethod(std::string_view value); + + template <> + inline SceneUtil::LightingMethod Manager::getImpl( + std::string_view setting, std::string_view category) + { + return parseLightingMethod(getString(setting, category)); + } } #endif // COMPONENTS_SETTINGS_H diff --git a/components/settings/settingvalue.hpp b/components/settings/settingvalue.hpp index 407fd15baf..35726cb25b 100644 --- a/components/settings/settingvalue.hpp +++ b/components/settings/settingvalue.hpp @@ -40,6 +40,7 @@ namespace Settings MyGuiColour, GyroscopeAxis, NavMeshRenderMode, + LightingMethod, }; template @@ -147,6 +148,12 @@ namespace Settings return SettingValueType::NavMeshRenderMode; } + template <> + inline constexpr SettingValueType getSettingValueType() + { + return SettingValueType::LightingMethod; + } + inline constexpr std::string_view getSettingValueTypeName(SettingValueType type) { switch (type) @@ -185,6 +192,8 @@ namespace Settings return "gyroscope axis"; case SettingValueType::NavMeshRenderMode: return "navmesh render mode"; + case SettingValueType::LightingMethod: + return "lighting method"; } return "unsupported"; } diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 1aa0f76e17..96e3d42f78 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -680,8 +680,7 @@ namespace Shader bool particleOcclusion = false; node.getUserValue("particleOcclusion", particleOcclusion); - defineMap["particleOcclusion"] - = particleOcclusion && Settings::Manager::getBool("weather particle occlusion", "Shaders") ? "1" : "0"; + defineMap["particleOcclusion"] = particleOcclusion && mWeatherParticleOcclusion ? "1" : "0"; if (reqs.mAlphaBlend && mSupportsNormalsRT) { diff --git a/components/shader/shadervisitor.hpp b/components/shader/shadervisitor.hpp index 0bd8bb9cd7..66bd8c2a9d 100644 --- a/components/shader/shadervisitor.hpp +++ b/components/shader/shadervisitor.hpp @@ -51,6 +51,8 @@ namespace Shader void setSupportsNormalsRT(bool supports) { mSupportsNormalsRT = supports; } + void setWeatherParticleOcclusion(bool value) { mWeatherParticleOcclusion = value; } + void apply(osg::Node& node) override; void apply(osg::Drawable& drawable) override; @@ -78,6 +80,7 @@ namespace Shader bool mAdjustCoverageForAlphaTest; bool mSupportsNormalsRT; + bool mWeatherParticleOcclusion = false; ShaderManager& mShaderManager; Resource::ImageManager& mImageManager;