diff --git a/CHANGELOG.md b/CHANGELOG.md index fad734ec04..beef1c79fe 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 ab38515c27..eabac16447 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 78aadb05ba..c47399fe7e 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 40a6b998cf..a6e4fe5e79 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 7a46f31899..68e606ee74 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 c6e48819c0..37d671a5aa 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 a7f9247f71..1060a5c0b2 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 1bbed37404..038438f326 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 1d94b4bf9d..f9f9dc74ca 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 376924d82d..e5c2be95d9 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 32a7977d2a..1ad16ca24c 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 bd0741da92..b00c3cb9b8 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 -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. +Controls what kinds of things are rendered in water reflections. -This setting can be toggled with the 'Reflect actors' button in the Water tab of the Video panel of the Options menu. +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 + +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 2d9c13bc92..cc24adbe35 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 d3f5c6a2e8..cddf94af95 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