From 00ab552184432536ad6514ff9968d4ea61a7e88e Mon Sep 17 00:00:00 2001 From: Andrei Kortunov Date: Thu, 21 Feb 2019 20:14:18 +0400 Subject: [PATCH] Add more settings to water reflections in exteriors (feature #4859) --- CHANGELOG.md | 1 + apps/openmw/mwclass/activator.cpp | 6 +++- apps/openmw/mwclass/door.cpp | 6 +++- apps/openmw/mwclass/static.cpp | 6 +++- apps/openmw/mwgui/settingswindow.cpp | 15 +++++++++- apps/openmw/mwgui/settingswindow.hpp | 2 ++ apps/openmw/mwrender/localmap.cpp | 4 +-- apps/openmw/mwrender/renderingmanager.cpp | 2 +- apps/openmw/mwrender/vismask.hpp | 17 ++++++----- apps/openmw/mwrender/water.cpp | 29 ++++++++++++++----- apps/openmw/mwrender/water.hpp | 1 + .../reference/modding/settings/water.rst | 19 +++++++----- files/mygui/openmw_settings_window.layout | 13 +++++---- files/settings-default.cfg | 4 +-- 14 files changed, 88 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fad734ec0..beef1c79f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -46,6 +46,7 @@ Feature #4730: Native animated containers support Feature #4812: Support NiSwitchNode Feature #4836: Daytime node switch + Feature #4859: Make water reflections more configurable Feature #4887: Add openmw command option to set initial random seed Feature #4890: Make Distant Terrain configurable Task #4686: Upgrade media decoder to a more current FFmpeg API diff --git a/apps/openmw/mwclass/activator.cpp b/apps/openmw/mwclass/activator.cpp index ab38515c2..eabac1644 100644 --- a/apps/openmw/mwclass/activator.cpp +++ b/apps/openmw/mwclass/activator.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -18,6 +19,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/vismask.hpp" #include "../mwgui/tooltips.hpp" @@ -29,8 +31,10 @@ namespace MWClass void Activator::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model, true); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwclass/door.cpp b/apps/openmw/mwclass/door.cpp index 78aadb05b..c47399fe7 100644 --- a/apps/openmw/mwclass/door.cpp +++ b/apps/openmw/mwclass/door.cpp @@ -2,6 +2,7 @@ #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -24,6 +25,7 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" #include "../mwrender/animation.hpp" +#include "../mwrender/vismask.hpp" #include "../mwmechanics/actorutil.hpp" @@ -53,8 +55,10 @@ namespace MWClass void Door::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model, true); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwclass/static.cpp b/apps/openmw/mwclass/static.cpp index 40a6b998c..a6e4fe5e7 100644 --- a/apps/openmw/mwclass/static.cpp +++ b/apps/openmw/mwclass/static.cpp @@ -1,6 +1,7 @@ #include "static.hpp" #include +#include #include "../mwworld/ptr.hpp" #include "../mwphysics/physicssystem.hpp" @@ -8,14 +9,17 @@ #include "../mwrender/objects.hpp" #include "../mwrender/renderinginterface.hpp" +#include "../mwrender/vismask.hpp" namespace MWClass { void Static::insertObjectRendering (const MWWorld::Ptr& ptr, const std::string& model, MWRender::RenderingInterface& renderingInterface) const { - if (!model.empty()) { + if (!model.empty()) + { renderingInterface.getObjects().insertModel(ptr, model); + ptr.getRefData().getBaseNode()->setNodeMask(MWRender::Mask_Static); } } diff --git a/apps/openmw/mwgui/settingswindow.cpp b/apps/openmw/mwgui/settingswindow.cpp index 7a46f3189..68e606ee7 100644 --- a/apps/openmw/mwgui/settingswindow.cpp +++ b/apps/openmw/mwgui/settingswindow.cpp @@ -193,6 +193,7 @@ namespace MWGui getWidget(mKeyboardSwitch, "KeyboardButton"); getWidget(mControllerSwitch, "ControllerButton"); getWidget(mWaterTextureSize, "WaterTextureSize"); + getWidget(mWaterReflectionDetail, "WaterReflectionDetail"); #ifndef WIN32 // hide gamma controls since it currently does not work under Linux @@ -216,6 +217,7 @@ namespace MWGui mResolutionList->eventListChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onResolutionSelected); mWaterTextureSize->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterTextureSizeChanged); + mWaterReflectionDetail->eventComboChangePosition += MyGUI::newDelegate(this, &SettingsWindow::onWaterReflectionDetailChanged); mKeyboardSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onKeyboardSwitchClicked); mControllerSwitch->eventMouseButtonClick += MyGUI::newDelegate(this, &SettingsWindow::onControllerSwitchClicked); @@ -249,7 +251,7 @@ namespace MWGui std::string tmip = Settings::Manager::getString("texture mipmap", "General"); mTextureFilteringButton->setCaption(textureMipmappingToStr(tmip)); - int waterTextureSize = Settings::Manager::getInt ("rtt size", "Water"); + int waterTextureSize = Settings::Manager::getInt("rtt size", "Water"); if (waterTextureSize >= 512) mWaterTextureSize->setIndexSelected(0); if (waterTextureSize >= 1024) @@ -257,6 +259,10 @@ namespace MWGui if (waterTextureSize >= 2048) mWaterTextureSize->setIndexSelected(2); + int waterReflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); + waterReflectionDetail = std::min(3, std::max(0, waterReflectionDetail)); + mWaterReflectionDetail->setIndexSelected(waterReflectionDetail); + mWindowBorderButton->setEnabled(!Settings::Manager::getBool("fullscreen", "Video")); mKeyboardSwitch->setStateSelected(true); @@ -336,6 +342,13 @@ namespace MWGui apply(); } + void SettingsWindow::onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos) + { + unsigned int level = std::min((unsigned int)3, (unsigned int)pos); + Settings::Manager::setInt("reflection detail", "Water", level); + apply(); + } + void SettingsWindow::onButtonToggled(MyGUI::Widget* _sender) { std::string on = MWBase::Environment::get().getWindowManager()->getGameSettingString("sOn", "On"); diff --git a/apps/openmw/mwgui/settingswindow.hpp b/apps/openmw/mwgui/settingswindow.hpp index c6e48819c..37d671a5a 100644 --- a/apps/openmw/mwgui/settingswindow.hpp +++ b/apps/openmw/mwgui/settingswindow.hpp @@ -33,6 +33,7 @@ namespace MWGui MyGUI::Widget* mAnisotropyBox; MyGUI::ComboBox* mWaterTextureSize; + MyGUI::ComboBox* mWaterReflectionDetail; // controls MyGUI::ScrollView* mControlsBox; @@ -52,6 +53,7 @@ namespace MWGui void highlightCurrentResolution(); void onWaterTextureSizeChanged(MyGUI::ComboBox* _sender, size_t pos); + void onWaterReflectionDetailChanged(MyGUI::ComboBox* _sender, size_t pos); void onRebindAction(MyGUI::Widget* _sender); void onInputTabMouseWheel(MyGUI::Widget* _sender, int _rel); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index a7f9247f7..1060a5c0b 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -178,7 +178,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object); + camera->setCullMask(Mask_Scene | Mask_SimpleWater | Mask_Terrain | Mask_Object | Mask_Static); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; @@ -380,7 +380,7 @@ void LocalMap::requestExteriorMap(const MWWorld::CellStore* cell) void LocalMap::requestInteriorMap(const MWWorld::CellStore* cell) { osg::ComputeBoundsVisitor computeBoundsVisitor; - computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object); + computeBoundsVisitor.setTraversalMask(Mask_Scene | Mask_Terrain | Mask_Object | Mask_Static); mSceneRoot->accept(computeBoundsVisitor); osg::BoundingBox bounds = computeBoundsVisitor.getBoundingBox(); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1bbed3740..038438f32 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -243,7 +243,7 @@ namespace MWRender int indoorShadowCastingTraversalMask = shadowCastingTraversalMask; if (Settings::Manager::getBool("object shadows", "Shadows")) - shadowCastingTraversalMask |= Mask_Object; + shadowCastingTraversalMask |= (Mask_Object|Mask_Static); mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index 1d94b4bf9..f9f9dc74c 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -34,25 +34,26 @@ namespace MWRender Mask_Terrain = (1<<8), Mask_FirstPerson = (1<<9), Mask_Object = (1<<10), + Mask_Static = (1<<11), // child of Sky - Mask_Sun = (1<<11), - Mask_WeatherParticles = (1<<12), + Mask_Sun = (1<<12), + Mask_WeatherParticles = (1<<13), // top level masks - Mask_Scene = (1<<13), - Mask_GUI = (1<<14), + Mask_Scene = (1<<14), + Mask_GUI = (1<<15), // Set on a ParticleSystem Drawable - Mask_ParticleSystem = (1<<15), + Mask_ParticleSystem = (1<<16), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<16), + Mask_RenderToTexture = (1<<17), - Mask_PreCompile = (1<<17), + Mask_PreCompile = (1<<18), // Set on a camera's cull mask to enable the LightManager - Mask_Lighting = (1<<18) + Mask_Lighting = (1<<19) }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 376924d82..e5c2be95d 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -225,7 +225,7 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("RefractionCamera"); - setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); + setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Static|Mask_Terrain|Mask_Actor|Mask_ParticleSystem|Mask_Sky|Mask_Sun|Mask_Player|Mask_Lighting); setNodeMask(Mask_RenderToTexture); setViewport(0, 0, rttSize, rttSize); @@ -307,7 +307,7 @@ private: class Reflection : public osg::Camera { public: - Reflection() + Reflection(bool isInterior) { setRenderOrder(osg::Camera::PRE_RENDER); setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -316,9 +316,13 @@ public: setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); setName("ReflectionCamera"); - bool reflectActors = Settings::Manager::getBool("reflect actors", "Water"); - - setCullMask(Mask_Effect|Mask_Scene|Mask_Object|Mask_Terrain|Mask_ParticleSystem|Mask_Sky|Mask_Player|Mask_Lighting|(reflectActors ? Mask_Actor : 0)); + unsigned int reflectionDetail = Settings::Manager::getInt("reflection detail", "Water"); + reflectionDetail = std::max((unsigned int)isInterior, reflectionDetail); + unsigned int extraMask = 0; + if(reflectionDetail >= 1) extraMask |= Mask_Static; + if(reflectionDetail >= 2) extraMask |= Mask_Effect|Mask_ParticleSystem|Mask_Object; + if(reflectionDetail >= 3) extraMask |= Mask_Actor; + setCullMask(Mask_Scene|Mask_Terrain|Mask_Sky|Mask_Player|Mask_Lighting|extraMask); setNodeMask(Mask_RenderToTexture); unsigned int rttSize = Settings::Manager::getInt("rtt size", "Water"); @@ -405,6 +409,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem , mEnabled(true) , mToggled(true) , mTop(0) + , mInterior(false) { mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); @@ -457,7 +462,7 @@ void Water::updateWaterMaterial() if (Settings::Manager::getBool("shader", "Water")) { - mReflection = new Reflection; + mReflection = new Reflection(mInterior); mReflection->setWaterLevel(mTop); mReflection->setScene(mSceneRoot); mParent->addChild(mReflection); @@ -630,10 +635,20 @@ void Water::setEnabled(bool enabled) void Water::changeCell(const MWWorld::CellStore* store) { - if (store->getCell()->isExterior()) + bool isInterior = !store->getCell()->isExterior(); + bool wasInterior = mInterior; + if (!isInterior) + { mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); + mInterior = false; + } else + { mWaterNode->setPosition(osg::Vec3f(0,0,mTop)); + mInterior = true; + } + if(mInterior != wasInterior) + updateWaterMaterial(); // create a new StateSet to prevent threading issues osg::ref_ptr nodeStateSet (new osg::StateSet); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 32a7977d2..1ad16ca24 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -70,6 +70,7 @@ namespace MWRender bool mEnabled; bool mToggled; float mTop; + bool mInterior; osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); diff --git a/docs/source/reference/modding/settings/water.rst b/docs/source/reference/modding/settings/water.rst index bd0741da9..b00c3cb9b 100644 --- a/docs/source/reference/modding/settings/water.rst +++ b/docs/source/reference/modding/settings/water.rst @@ -58,17 +58,22 @@ This setting has no effect if the shader setting is false. This setting can be toggled with the 'Refraction' button in the Water tab of the Video panel of the Options menu. -reflect actors +reflection detail -------------- -:Type: boolean -:Range: True/False -:Default: False +:Type: integer +:Range: 0, 1, 2, 3 +:Default: 1 + +Controls what kinds of things are rendered in water reflections. -This setting controls whether or not NPCs and creatures are drawn in water reflections. -Setting this to true will enable actors in reflections and increase realism with a likely decrease in performance. +0: only terrain and the sky are reflected (acts like level 1 in interiors) +1: statics, activators, and doors are also reflected +2: items, containers, and particles are also reflected +3: actors are also reflected -This setting can be toggled with the 'Reflect actors' button in the Water tab of the Video panel of the Options menu. +The player is always reflected in third-person mode. +This setting can be changed ingame with the "Reflection shader detail" dropdown under the Water tab of the Video panel in the Options menu. small feature culling pixel size -------------------------------- diff --git a/files/mygui/openmw_settings_window.layout b/files/mygui/openmw_settings_window.layout index 2d9c13bc9..cc24adbe3 100644 --- a/files/mygui/openmw_settings_window.layout +++ b/files/mygui/openmw_settings_window.layout @@ -428,13 +428,14 @@ - - - - + + + + + - - + + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index d3f5c6a2e..cddf94af9 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -462,8 +462,8 @@ rtt size = 512 # Enable refraction which affects visibility through water plane. refraction = false -# Draw NPCs and creatures on water reflections. -reflect actors = false +# Draw objects on water reflections. +reflection detail = 1 # Overrides the value in '[Camera] small feature culling pixel size' specifically for water reflection/refraction textures. small feature culling pixel size = 20.0