From bd1f3493d76cf2ab3b2b5ca2dc1e90c062e6ca38 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 21:35:03 +0100 Subject: [PATCH 01/23] Fix weather particles not being cleared when changing from one particle effect to another --- apps/openmw/mwrender/sky.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index b0af85c0b6..240dff7fd1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1432,6 +1432,14 @@ void SkyManager::setWeather(const WeatherResult& weather) { mCurrentParticleEffect = weather.mParticleEffect; + // cleanup old particles + if (mParticleEffect) + { + mParticleNode->removeChild(mParticleEffect); + mParticleEffect = NULL; + mParticleFader = NULL; + } + if (mCurrentParticleEffect.empty()) { if (mParticleNode) @@ -1439,8 +1447,6 @@ void SkyManager::setWeather(const WeatherResult& weather) mRootNode->removeChild(mParticleNode); mParticleNode = NULL; } - mParticleEffect = NULL; - mParticleFader = NULL; } else { From d6f45c33906072aad42f29a59d835a031ebb14bc Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 21:51:01 +0100 Subject: [PATCH 02/23] Fix the renderbin for weather particles Regression from commit 2ee6b41887b8dff5231f9925c6a0205a75d67159 --- apps/openmw/mwrender/sky.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 240dff7fd1..7d67d38f08 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1453,6 +1453,8 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Default, "RenderBin"); + mParticleNode->getOrCreateStateSet()->setNestRenderBins(false); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); From 5ca0ae52321380e7b5850b9b1ee37dd378fa7ab6 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 23:38:34 +0100 Subject: [PATCH 03/23] Don't add the same AlphaFader to multiple nodes --- apps/openmw/mwrender/sky.cpp | 25 +++++++++++++----------- apps/openmw/mwrender/sky.hpp | 2 +- components/sceneutil/statesetupdater.hpp | 1 + 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 7d67d38f08..a4f3573227 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1196,14 +1196,13 @@ public: mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0,0,0,mAlpha)); } - // Helper for adding AlphaFader to a subgraph + // Helper for adding AlphaFaders to a subgraph class SetupVisitor : public osg::NodeVisitor { public: SetupVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) { - mAlphaFader = new AlphaFader; } virtual void apply(osg::Node &node) @@ -1225,22 +1224,26 @@ public: callback = callback->getNestedCallback(); } + osg::ref_ptr alphaFader (new AlphaFader); + if (composite) - composite->addController(mAlphaFader); + composite->addController(alphaFader); else - node.addUpdateCallback(mAlphaFader); + node.addUpdateCallback(alphaFader); + + mAlphaFaders.push_back(alphaFader); } } traverse(node); } - osg::ref_ptr getAlphaFader() + std::vector > getAlphaFaders() { - return mAlphaFader; + return mAlphaFaders; } private: - osg::ref_ptr mAlphaFader; + std::vector > mAlphaFaders; }; private: @@ -1437,7 +1440,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { mParticleNode->removeChild(mParticleEffect); mParticleEffect = NULL; - mParticleFader = NULL; + mParticleFaders.clear(); } if (mCurrentParticleEffect.empty()) @@ -1464,7 +1467,7 @@ void SkyManager::setWeather(const WeatherResult& weather) AlphaFader::SetupVisitor alphaFaderSetupVisitor; mParticleEffect->accept(alphaFaderSetupVisitor); - mParticleFader = alphaFaderSetupVisitor.getAlphaFader(); + mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); } } @@ -1545,8 +1548,8 @@ void SkyManager::setWeather(const WeatherResult& weather) if (mRainFader) mRainFader->setAlpha(weather.mEffectFade * 0.6); // * Rain_Threshold? - if (mParticleFader) - mParticleFader->setAlpha(weather.mEffectFade); + for (std::vector >::const_iterator it = mParticleFaders.begin(); it != mParticleFaders.end(); ++it) + (*it)->setAlpha(weather.mEffectFade); } void SkyManager::sunEnable() diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 072083d270..a4eeb861c2 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -158,7 +158,7 @@ namespace MWRender osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; - osg::ref_ptr mParticleFader; + std::vector > mParticleFaders; osg::ref_ptr mCloudNode; diff --git a/components/sceneutil/statesetupdater.hpp b/components/sceneutil/statesetupdater.hpp index 37d08e025c..34b8da848a 100644 --- a/components/sceneutil/statesetupdater.hpp +++ b/components/sceneutil/statesetupdater.hpp @@ -15,6 +15,7 @@ namespace SceneUtil /// the first StateSet is the one we can write to, the second is the one currently in use by the draw traversal of the last frame. /// After a frame is completed the places are swapped. /// @par Must be set as UpdateCallback on a Node. + /// @note Do not add the same StateSetUpdater to multiple nodes. /// @note Do not add multiple StateSetControllers on the same Node as they will conflict - instead use the CompositeStateSetUpdater. class StateSetUpdater : public osg::NodeCallback { From fd1ccd21ff587c96cbd5e1cc83a09cb66e871e5a Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 23:49:22 +0100 Subject: [PATCH 04/23] Disable freezeOnCull for weather particles --- apps/openmw/mwrender/animation.cpp | 21 +------------------- apps/openmw/mwrender/sky.cpp | 4 ++++ components/sceneutil/visitor.cpp | 32 ++++++++++++++++++++++++++++++ components/sceneutil/visitor.hpp | 26 ++++++++++++++---------- 4 files changed, 52 insertions(+), 31 deletions(-) create mode 100644 components/sceneutil/visitor.cpp diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index b2fa873102..06065c566d 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1111,25 +1111,6 @@ namespace MWRender attachTo->addChild(lightSource); } - class DisableFreezeOnCullVisitor : public osg::NodeVisitor - { - public: - DisableFreezeOnCullVisitor() - : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) - { - } - - virtual void apply(osg::Geode &geode) - { - for (unsigned int i=0; i(drw)) - partsys->setFreezeOnCull(false); - } - } - }; - void Animation::addEffect (const std::string& model, int effectId, bool loop, const std::string& bonename, std::string texture) { if (!mObjectRoot.get()) @@ -1163,7 +1144,7 @@ namespace MWRender node->accept(findMaxLengthVisitor); // FreezeOnCull doesn't work so well with effect particles, that tend to have moving emitters - DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; node->accept(disableFreezeOnCullVisitor); params.mMaxControllerLength = findMaxLengthVisitor.getMaxLength(); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a4f3573227..0f00b5a4c8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" @@ -1468,6 +1469,9 @@ void SkyManager::setWeather(const WeatherResult& weather) AlphaFader::SetupVisitor alphaFaderSetupVisitor; mParticleEffect->accept(alphaFaderSetupVisitor); mParticleFaders = alphaFaderSetupVisitor.getAlphaFaders(); + + SceneUtil::DisableFreezeOnCullVisitor disableFreezeOnCullVisitor; + mParticleEffect->accept(disableFreezeOnCullVisitor); } } diff --git a/components/sceneutil/visitor.cpp b/components/sceneutil/visitor.cpp new file mode 100644 index 0000000000..3738be08d1 --- /dev/null +++ b/components/sceneutil/visitor.cpp @@ -0,0 +1,32 @@ +#include "visitor.hpp" + +#include + +#include + +#include + +namespace SceneUtil +{ + + void FindByNameVisitor::apply(osg::Group &group) + { + if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind)) + { + mFoundNode = &group; + return; + } + traverse(group); + } + + void DisableFreezeOnCullVisitor::apply(osg::Geode &geode) + { + for (unsigned int i=0; i(drw)) + partsys->setFreezeOnCull(false); + } + } + +} diff --git a/components/sceneutil/visitor.hpp b/components/sceneutil/visitor.hpp index b9342b884e..6560849407 100644 --- a/components/sceneutil/visitor.hpp +++ b/components/sceneutil/visitor.hpp @@ -3,12 +3,12 @@ #include -#include - // Commonly used scene graph visitors namespace SceneUtil { + // Find a Group by name, case-insensitive + // If not found, mFoundNode will be NULL class FindByNameVisitor : public osg::NodeVisitor { public: @@ -19,20 +19,24 @@ namespace SceneUtil { } - virtual void apply(osg::Group& group) - { - if (Misc::StringUtils::ciEqual(group.getName(), mNameToFind)) - { - mFoundNode = &group; - return; - } - traverse(group); - } + virtual void apply(osg::Group& group); std::string mNameToFind; osg::Group* mFoundNode; }; + // Disable freezeOnCull for all visited particlesystems + class DisableFreezeOnCullVisitor : public osg::NodeVisitor + { + public: + DisableFreezeOnCullVisitor() + : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) + { + } + + virtual void apply(osg::Geode &geode); + }; + } #endif From ad016da31d1c36b674262631d406843563a88a83 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:42:37 +0100 Subject: [PATCH 05/23] Enable fog on weather particles --- apps/openmw/mwrender/sky.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 0f00b5a4c8..3adc565eaf 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1457,8 +1457,10 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; - mParticleNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Default, "RenderBin"); - mParticleNode->getOrCreateStateSet()->setNestRenderBins(false); + osg::StateSet* particleStateSet = mParticleNode->getOrCreateStateSet(); + particleStateSet->setRenderBinDetails(RenderBin_Default, "RenderBin"); + particleStateSet->setNestRenderBins(false); + particleStateSet->setMode(GL_FOG, osg::StateAttribute::ON); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); From 9902dfc9ef4be89288c824335629723782a58462 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:53:22 +0100 Subject: [PATCH 06/23] Comment --- apps/openmw/mwrender/water.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index bb6d549e04..84fe4fcc93 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -474,7 +474,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(geode2); + createSimpleWaterStateSet(geode2); // Water_Map_Alpha geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -527,7 +527,7 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr material (new osg::Material); material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); // Water_World_Alpha material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); From 380256977b2d737c33a725141dcb53b7337b21bb Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 01:53:38 +0100 Subject: [PATCH 07/23] Fix another renderBin issue with the weather particles Depth sorting w.r.t. the rest of the scene was broken --- apps/openmw/mwrender/sky.cpp | 32 +++++++++++++++----------------- apps/openmw/mwrender/sky.hpp | 1 + 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 3adc565eaf..a1e5dbba87 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1066,18 +1066,19 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana mRootNode = skyroot; - // By default render before the world is rendered - mRootNode->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); - + mEarlyRenderBinRoot = new osg::Group; + // render before the world is rendered + mEarlyRenderBinRoot->getOrCreateStateSet()->setRenderBinDetails(RenderBin_Sky, "RenderBin"); // Prevent unwanted clipping by water reflection camera's clipping plane - mRootNode->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); + mRootNode->addChild(mEarlyRenderBinRoot); } void SkyManager::create() { assert(!mCreated); - mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode); + mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mEarlyRenderBinRoot); ModVertexAlphaVisitor modAtmosphere(0); mAtmosphereDay->accept(modAtmosphere); @@ -1086,7 +1087,7 @@ void SkyManager::create() mAtmosphereNightNode = new osg::PositionAttitudeTransform; mAtmosphereNightNode->setNodeMask(0); - mRootNode->addChild(mAtmosphereNightNode); + mEarlyRenderBinRoot->addChild(mAtmosphereNightNode); osg::ref_ptr atmosphereNight; if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif")) @@ -1099,14 +1100,14 @@ void SkyManager::create() mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getTextureManager()); atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); - mSun.reset(new Sun(mRootNode, *mSceneManager->getTextureManager())); + mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getTextureManager())); const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); - mMasser.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); - mSecunda.reset(new Moon(mRootNode, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); + mMasser.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Masser_Size")/125, Moon::Type_Masser)); + mSecunda.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getTextureManager(), fallback->getFallbackFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda)); mCloudNode = new osg::PositionAttitudeTransform; - mRootNode->addChild(mCloudNode); + mEarlyRenderBinRoot->addChild(mCloudNode); mCloudMesh = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mCloudNode); ModVertexAlphaVisitor modClouds(1); mCloudMesh->accept(modClouds); @@ -1123,9 +1124,9 @@ void SkyManager::create() osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); - mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); - mRootNode->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); + mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); + mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_FOG, osg::StateAttribute::OFF); mMoonScriptColor = fallback->getFallbackColour("Moons_Script_Color"); @@ -1282,6 +1283,7 @@ void SkyManager::createRain() stateset->setNestRenderBins(false); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); osgParticle::Particle& particleTemplate = mRainParticleSystem->getDefaultParticleTemplate(); particleTemplate.setSizeRange(osgParticle::rangef(5.f, 15.f)); @@ -1457,10 +1459,6 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; - osg::StateSet* particleStateSet = mParticleNode->getOrCreateStateSet(); - particleStateSet->setRenderBinDetails(RenderBin_Default, "RenderBin"); - particleStateSet->setNestRenderBins(false); - particleStateSet->setMode(GL_FOG, osg::StateAttribute::ON); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index a4eeb861c2..573c0ceb61 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -155,6 +155,7 @@ namespace MWRender Resource::SceneManager* mSceneManager; osg::ref_ptr mRootNode; + osg::ref_ptr mEarlyRenderBinRoot; osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; From 8e8f72408d45720891401dc5d021bec52d1fa795 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:12:00 +0100 Subject: [PATCH 08/23] Use diffuse/ambient lighting for the simple water --- apps/openmw/mwrender/water.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 84fe4fcc93..e72fc050cd 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -79,6 +79,10 @@ namespace waterGeom->setVertexArray(verts); waterGeom->setTexCoordArray(0, texcoords); + osg::ref_ptr normal (new osg::Vec3Array); + normal->push_back(osg::Vec3f(0,0,1)); + waterGeom->setNormalArray(normal, osg::Array::BIND_OVERALL); + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); return waterGeom; } @@ -526,9 +530,9 @@ void Water::createSimpleWaterStateSet(osg::Node* node) osg::ref_ptr stateset (new osg::StateSet); osg::ref_ptr material (new osg::Material); - material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); // Water_World_Alpha - material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 0.7f)); // Water_World_Alpha + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); From 30c828dff0642f3e3a3f2181c7473a3931856959 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:17:42 +0100 Subject: [PATCH 09/23] Include cleanup --- apps/openmw/mwrender/renderingmanager.cpp | 1 + apps/openmw/mwrender/water.cpp | 2 ++ apps/openmw/mwrender/water.hpp | 7 +++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e1c0ea666a..4dbfb3072f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -32,6 +32,7 @@ #include #include "../mwworld/fallback.hpp" +#include "../mwworld/cellstore.hpp" #include "sky.hpp" #include "effectmanager.hpp" diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index e72fc050cd..cb03c489d0 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -33,6 +33,8 @@ #include +#include "../mwworld/cellstore.hpp" + #include "vismask.hpp" #include "ripplesimulation.hpp" #include "renderbin.hpp" diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index f77afbfee8..b5eca3f256 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -1,12 +1,13 @@ #ifndef OPENMW_MWRENDER_WATER_H #define OPENMW_MWRENDER_WATER_H +#include + #include +#include #include -#include "../mwworld/cellstore.hpp" - namespace osg { class Group; @@ -28,6 +29,8 @@ namespace Resource namespace MWWorld { class Fallback; + class CellStore; + class Ptr; } namespace MWRender From c0a81030bba44e92e54dcb255c8aed48dadcb763 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 02:24:50 +0100 Subject: [PATCH 10/23] Make use of INI settings for the simple water --- apps/openmw/mwrender/water.cpp | 20 +++++++++++++------- apps/openmw/mwrender/water.hpp | 3 ++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index cb03c489d0..101d9c8220 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -34,6 +34,7 @@ #include #include "../mwworld/cellstore.hpp" +#include "../mwworld/fallback.hpp" #include "vismask.hpp" #include "ripplesimulation.hpp" @@ -457,6 +458,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem : mParent(parent) , mSceneRoot(sceneRoot) , mResourceSystem(resourceSystem) + , mFallback(fallback) , mResourcePath(resourcePath) , mEnabled(true) , mToggled(true) @@ -480,7 +482,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); - createSimpleWaterStateSet(geode2); // Water_Map_Alpha + createSimpleWaterStateSet(geode2, mFallback->getFallbackFloat("Water_Map_Alpha")); geode2->setNodeMask(Mask_SimpleWater); mWaterNode->addChild(geode2); @@ -522,18 +524,18 @@ void Water::updateWaterMaterial() createShaderWaterStateSet(mWaterGeode, mReflection, mRefraction); } else - createSimpleWaterStateSet(mWaterGeode); + createSimpleWaterStateSet(mWaterGeode, mFallback->getFallbackFloat("Water_World_Alpha")); updateVisible(); } -void Water::createSimpleWaterStateSet(osg::Node* node) +void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) { osg::ref_ptr stateset (new osg::StateSet); osg::ref_ptr material (new osg::Material); material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); - material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 0.7f)); // Water_World_Alpha + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, alpha)); material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); material->setColorMode(osg::Material::OFF); stateset->setAttributeAndModes(material, osg::StateAttribute::ON); @@ -548,14 +550,18 @@ void Water::createSimpleWaterStateSet(osg::Node* node) stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); std::vector > textures; - for (int i=0; i<32; ++i) + int frameCount = mFallback->getFallbackInt("Water_SurfaceFrameCount"); + std::string texture = mFallback->getFallbackString("Water_SurfaceTexture"); + for (int i=0; igetTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); } - osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + float fps = mFallback->getFallbackFloat("Water_SurfaceFPS"); + + osg::ref_ptr controller (new NifOsg::FlipController(0, 1.f/fps, textures)); controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); node->setUpdateCallback(controller); node->setStateSet(stateset); diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index b5eca3f256..551184c11c 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -50,6 +50,7 @@ namespace MWRender osg::ref_ptr mWaterNode; osg::ref_ptr mWaterGeode; Resource::ResourceSystem* mResourceSystem; + const MWWorld::Fallback* mFallback; osg::ref_ptr mIncrementalCompileOperation; std::auto_ptr mSimulation; @@ -66,7 +67,7 @@ namespace MWRender osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); - void createSimpleWaterStateSet(osg::Node* node); + void createSimpleWaterStateSet(osg::Node* node, float alpha); /// @param reflection the reflection camera (required) /// @param refraction the refraction camera (optional) From b72d5c5190a9e1ef8756d3c8734a0d011748cb75 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 17:48:35 +0100 Subject: [PATCH 11/23] Don't play idlestorm animation when swimming --- apps/openmw/mwmechanics/character.cpp | 7 +++---- apps/openmw/mwmechanics/character.hpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 36c251053c..de4b449867 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -504,8 +504,6 @@ void CharacterController::refreshCurrentAnims(CharacterState idle, CharacterStat mAnimation->play(mCurrentIdle, idlePriority, MWRender::Animation::BlendMask_All, false, 1.0f, "start", "stop", 0.0f, ~0ul, true); } - - updateIdleStormState(); } @@ -867,7 +865,7 @@ void CharacterController::updatePtr(const MWWorld::Ptr &ptr) mPtr = ptr; } -void CharacterController::updateIdleStormState() +void CharacterController::updateIdleStormState(bool inwater) { bool inStormDirection = false; if (MWBase::Environment::get().getWorld()->isInStorm()) @@ -877,7 +875,7 @@ void CharacterController::updateIdleStormState() inStormDirection = std::acos(stormDirection * characterDirection / (stormDirection.length() * characterDirection.length())) > osg::DegreesToRadians(120.f); } - if (inStormDirection && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) + if (inStormDirection && !inwater && mUpperBodyState == UpperCharState_Nothing && mAnimation->hasAnimation("idlestorm")) { float complete = 0; mAnimation->getInfo("idlestorm", &complete); @@ -1796,6 +1794,7 @@ void CharacterController::update(float duration) forcestateupdate = updateCreatureState() || forcestateupdate; refreshCurrentAnims(idlestate, movestate, jumpstate, forcestateupdate); + updateIdleStormState(inwater); } if (inJump) diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index fee7b959cb..90e285b522 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -196,7 +196,7 @@ class CharacterController : public MWRender::Animation::TextKeyListener bool updateWeaponState(); bool updateCreatureState(); - void updateIdleStormState(); + void updateIdleStormState(bool inwater); void updateHeadTracking(float duration); From de97a8a3dad74b49a72917bb32df80c3be49983b Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 17:53:57 +0100 Subject: [PATCH 12/23] Do not allow disabling the player object --- apps/openmw/mwworld/worldimp.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 17118e169b..45aa310654 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -781,6 +781,9 @@ namespace MWWorld if (reference.getRefData().isEnabled()) { + if (reference == getPlayerPtr()) + throw std::runtime_error("can not disable player object"); + reference.getRefData().disable(); if(mWorldScene->getActiveCells().find (reference.getCell())!=mWorldScene->getActiveCells().end() && reference.getRefData().getCount()) From a5f8ffb83dbbae8cde9dde83e16f98c03ae6fc30 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 18:15:47 +0100 Subject: [PATCH 13/23] aimToTarget: Fix the collision box translation not being taken into account --- apps/openmw/mwphysics/actor.cpp | 5 +++++ apps/openmw/mwphysics/actor.hpp | 6 ++++++ apps/openmw/mwphysics/physicssystem.cpp | 25 +++++++++++++++++++++---- apps/openmw/mwphysics/physicssystem.hpp | 9 +++++++-- apps/openmw/mwworld/worldimp.cpp | 3 +-- 5 files changed, 40 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index a681c79452..98ccefe71c 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -95,6 +95,11 @@ void Actor::updatePosition() mCollisionObject->setWorldTransform(tr); } +osg::Vec3f Actor::getPosition() const +{ + return toOsg(mCollisionObject->getWorldTransform().getOrigin()); +} + void Actor::updateRotation () { btTransform tr = mCollisionObject->getWorldTransform(); diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index a4afa48a11..bcbc256d0e 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -70,6 +70,12 @@ namespace MWPhysics */ osg::Vec3f getHalfExtents() const; + /** + * Returns the position of the collision body + * @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. + */ + osg::Vec3f getPosition() const; + /** * Returns the half extents of the collision body (scaled according to rendering scale) * @note The reason we need this extra method is because of an inconsistency in MW - NPC race scales aren't applied to the collision shape, diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 80a63bf1b5..f4bf7a364b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -869,24 +869,33 @@ namespace MWPhysics } } - osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) + osg::Vec3f PhysicsSystem::getHalfExtents(const MWWorld::Ptr &actor) const { - Actor* physactor = getActor(actor); + const Actor* physactor = getActor(actor); if (physactor) return physactor->getHalfExtents(); else return osg::Vec3f(); } - osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) const { - Actor* physactor = getActor(actor); + const Actor* physactor = getActor(actor); if (physactor) return physactor->getRenderingHalfExtents(); else return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getPosition(const MWWorld::Ptr &actor) const + { + const Actor* physactor = getActor(actor); + if (physactor) + return physactor->getPosition(); + else + return osg::Vec3f(); + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: @@ -1036,6 +1045,14 @@ namespace MWPhysics return NULL; } + const Actor *PhysicsSystem::getActor(const MWWorld::Ptr &ptr) const + { + ActorMap::const_iterator found = mActors.find(ptr); + if (found != mActors.end()) + return found->second; + return NULL; + } + void PhysicsSystem::updateScale(const MWWorld::Ptr &ptr) { ObjectMap::iterator found = mObjects.find(ptr); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 6f38653c89..7c5be0b6e3 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -62,6 +62,7 @@ namespace MWPhysics void updatePtr (const MWWorld::Ptr& old, const MWWorld::Ptr& updated); Actor* getActor(const MWWorld::Ptr& ptr); + const Actor* getActor(const MWWorld::Ptr& ptr) const; // Object or Actor void remove (const MWWorld::Ptr& ptr); @@ -108,10 +109,14 @@ namespace MWPhysics bool isOnGround (const MWWorld::Ptr& actor); /// Get physical half extents (scaled) of the given actor. - osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); + osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor) const; /// @see MWPhysics::Actor::getRenderingHalfExtents - osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor); + osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor) const; + + /// Get the position of the collision shape for the actor. Use together with getHalfExtents() to get the collision bounds in world space. + /// @note The collision shape's origin is in its center, so the position returned can be described as center of the actor collision box in world space. + osg::Vec3f getPosition(const MWWorld::Ptr& actor) const; /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 45aa310654..0f8c5aa327 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -3259,8 +3259,7 @@ namespace MWWorld osg::Vec3f World::aimToTarget(const Ptr &actor, const MWWorld::Ptr& target) { osg::Vec3f weaponPos = getActorHeadPosition(actor, mRendering); - osg::Vec3f targetPos = target.getRefData().getPosition().asVec3(); - targetPos.z() += mPhysics->getHalfExtents(target).z(); + osg::Vec3f targetPos = mPhysics->getPosition(target); return (targetPos - weaponPos); } } From 46e07e4b19e5db9a8860dfbf844ccfa71a407a52 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 18:27:15 +0100 Subject: [PATCH 14/23] Head tracking: fall back to target collision box center if the target has no head node --- apps/openmw/mwmechanics/character.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index de4b449867..f1c3da5ad1 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -2121,7 +2121,7 @@ void CharacterController::updateHeadTracking(float duration) osg::Matrixf mat = mats[0]; osg::Vec3f headPos = mat.getTrans(); - osg::Vec3f targetPos (mHeadTrackTarget.getRefData().getPosition().asVec3()); + osg::Vec3f direction; if (MWRender::Animation* anim = MWBase::Environment::get().getWorld()->getAnimation(mHeadTrackTarget)) { const osg::Node* node = anim->getNode("Head"); @@ -2131,11 +2131,12 @@ void CharacterController::updateHeadTracking(float duration) { osg::MatrixList mats = node->getWorldMatrices(); if (mats.size()) - targetPos = mats[0].getTrans(); + direction = mats[0].getTrans() - headPos; } + else + // no head node to look at, fall back to look at center of collision box + direction = MWBase::Environment::get().getWorld()->aimToTarget(mPtr, mHeadTrackTarget); } - - osg::Vec3f direction = targetPos - headPos; direction.normalize(); if (!mPtr.getRefData().getBaseNode()) From 682f30ef9c7e8edad3e825be6920670ffac3bdce Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 19:05:36 +0100 Subject: [PATCH 15/23] Fix incorrect uses of PhysicsSystem::getHalfExtents Did not account for translation of collision box (mMeshTranslation in actor.cpp) --- apps/openmw/mwphysics/physicssystem.cpp | 19 ++++++++----------- apps/openmw/mwworld/projectilemanager.cpp | 7 +------ 2 files changed, 9 insertions(+), 17 deletions(-) diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index f4bf7a364b..92994d5574 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -240,6 +240,8 @@ namespace MWPhysics const ESM::Position& refpos = ptr.getRefData().getPosition(); osg::Vec3f position(refpos.asVec3()); + float collisionShapeOffset = physicActor->getPosition().z() - position.z(); + // Early-out for totally static creatures // (Not sure if gravity should still apply?) if (!ptr.getClass().isMobile(ptr)) @@ -256,12 +258,11 @@ namespace MWPhysics } btCollisionObject *colobj = physicActor->getCollisionObject(); - osg::Vec3f halfExtents = physicActor->getHalfExtents(); - position.z() += halfExtents.z(); + position.z() += collisionShapeOffset; static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + collisionShapeOffset - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -369,7 +370,7 @@ namespace MWPhysics { // don't let pure water creatures move out of water after stepMove if (ptr.getClass().isPureWaterCreature(ptr) - && newPosition.z() + halfExtents.z() > waterlevel) + && newPosition.z() + physicActor->getHalfExtents().z() > waterlevel) newPosition = oldPosition; } else @@ -450,7 +451,7 @@ namespace MWPhysics } physicActor->setOnGround(isOnGround); - newPosition.z() -= halfExtents.z(); // remove what was added at the beginning + newPosition.z() -= collisionShapeOffset; // remove what was added at the beginning return newPosition; } }; @@ -820,12 +821,8 @@ namespace MWPhysics if (!physactor1 || !physactor2) return false; - osg::Vec3f halfExt1 = physactor1->getHalfExtents(); - osg::Vec3f pos1 (actor1.getRefData().getPosition().asVec3()); - pos1.z() += halfExt1.z()*2*0.9f; // eye level - osg::Vec3f halfExt2 = physactor2->getHalfExtents(); - osg::Vec3f pos2 (actor2.getRefData().getPosition().asVec3()); - pos2.z() += halfExt2.z()*2*0.9f; + osg::Vec3f pos1 (physactor1->getPosition() + osg::Vec3f(0,0,physactor1->getHalfExtents().z() * 0.8)); // eye level + osg::Vec3f pos2 (physactor2->getPosition() + osg::Vec3f(0,0,physactor2->getHalfExtents().z() * 0.8)); RayResult result = castRay(pos1, pos2, MWWorld::Ptr(), CollisionType_World|CollisionType_HeightMap); diff --git a/apps/openmw/mwworld/projectilemanager.cpp b/apps/openmw/mwworld/projectilemanager.cpp index 3e9f172786..d5aca17a63 100644 --- a/apps/openmw/mwworld/projectilemanager.cpp +++ b/apps/openmw/mwworld/projectilemanager.cpp @@ -68,12 +68,7 @@ namespace MWWorld const ESM::EffectList &effects, const Ptr &caster, const std::string &sourceName, const osg::Vec3f& fallbackDirection) { - float height = 0; - - height += mPhysics->getHalfExtents(caster).z() * 2.f * 0.75f; // Spawn at 0.75 * ActorHeight - - osg::Vec3f pos(caster.getRefData().getPosition().asVec3()); - pos.z() += height; + osg::Vec3f pos = mPhysics->getPosition(caster) + osg::Vec3f(0,0,mPhysics->getHalfExtents(caster).z() * 0.5); // Spawn at 0.75 * ActorHeight if (MWBase::Environment::get().getWorld()->isUnderwater(caster.getCell(), pos)) // Underwater casting not possible return; From e3b30baff9733396fbad1fa7f3ff0e51782fd9b8 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:10:52 +0100 Subject: [PATCH 16/23] clipFudge fix --- apps/openmw/mwrender/water.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 101d9c8220..80023ecdaa 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -152,12 +152,9 @@ class ClipCullNode : public osg::Group osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); - // move the plane back along its normal a little bit to prevent bleeding at the water shore - const float clipFudge = -5; - // now apply the height of the plane + // apply the height of the plane // we can't apply this height in the addClipPlane() since the "flip the below graph" function would otherwise flip the height as well - float translate = clipFudge + ((*mCullPlane)[3] * -1); - modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * translate); + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * ((*mCullPlane)[3] * -1)); // flip the below graph if the eye point is above the plane if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0) @@ -165,6 +162,10 @@ class ClipCullNode : public osg::Group modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); } + // move the plane back along its normal a little bit to prevent bleeding at the water shore + const float clipFudge = -5; + modelViewMatrix->preMultTranslate(mCullPlane->getNormal() * clipFudge); + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); traverse(node, nv); cv->popModelViewMatrix(); From 209fa52883aa824baac579074e4568e9993c66a3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:15:43 +0100 Subject: [PATCH 17/23] Hide weather particles underwater (Fixes #2701) --- apps/openmw/mwrender/renderingmanager.cpp | 2 + apps/openmw/mwrender/sky.cpp | 68 ++++++++++++++++++++++- apps/openmw/mwrender/sky.hpp | 10 ++++ 3 files changed, 79 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 4dbfb3072f..5b2aac9e50 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -450,11 +450,13 @@ namespace MWRender void RenderingManager::setWaterEnabled(bool enabled) { mWater->setEnabled(enabled); + mSky->setWaterEnabled(enabled); } void RenderingManager::setWaterHeight(float height) { mWater->setHeight(height); + mSky->setWaterHeight(height); } class NotifyDrawCompletedCallback : public osg::Camera::DrawCallback diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a1e5dbba87..4ff7256ca8 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -262,8 +262,18 @@ public: META_Node(MWRender, CameraRelativeTransform) - virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const + const osg::Vec3f& getLastEyePoint() const { + return mEyePoint; + } + + virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor* nv) const + { + if (nv->getVisitorType() == osg::NodeVisitor::CULL_VISITOR) + { + mEyePoint = static_cast(nv)->getEyePoint(); + } + if (_referenceFrame==RELATIVE_RF) { matrix.setTrans(osg::Vec3f(0.f,0.f,0.f)); @@ -322,6 +332,9 @@ public: cv->getCurrentCullingSet().popCurrentMask(); } }; +private: + // eyePoint for the current frame + mutable osg::Vec3f mEyePoint; }; class ModVertexAlphaVisitor : public osg::NodeVisitor @@ -371,6 +384,45 @@ private: int mMeshType; }; +/// @brief Hides the node subgraph if the eye point is below water. +/// @note Must be added as cull callback. +/// @note Meant to be used on a node that is child of a CameraRelativeTransform. +/// The current eye point must be retrieved by the CameraRelativeTransform since we can't get it anymore once we are in camera-relative space. +class UnderwaterSwitchCallback : public osg::NodeCallback +{ +public: + UnderwaterSwitchCallback(CameraRelativeTransform* cameraRelativeTransform) + : mCameraRelativeTransform(cameraRelativeTransform) + , mEnabled(true) + , mWaterLevel(0.f) + { + } + + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osg::Vec3f eyePoint = mCameraRelativeTransform->getLastEyePoint(); + + if (mEnabled && eyePoint.z() < mWaterLevel) + return; + + traverse(node, nv); + } + + void setEnabled(bool enabled) + { + mEnabled = enabled; + } + void setWaterLevel(float waterLevel) + { + mWaterLevel = waterLevel; + } + +private: + osg::ref_ptr mCameraRelativeTransform; + bool mEnabled; + float mWaterLevel; +}; + /// A base class for the sun and moons. class CelestialBody { @@ -1072,6 +1124,8 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana // Prevent unwanted clipping by water reflection camera's clipping plane mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_CLIP_PLANE0, osg::StateAttribute::OFF); mRootNode->addChild(mEarlyRenderBinRoot); + + mUnderwaterSwitch = new UnderwaterSwitchCallback(skyroot); } void SkyManager::create() @@ -1319,6 +1373,7 @@ void SkyManager::createRain() mRainFader = new RainFader; mRainNode->addUpdateCallback(mRainFader); + mRainNode->addCullCallback(mUnderwaterSwitch); mRootNode->addChild(mRainNode); } @@ -1459,6 +1514,7 @@ void SkyManager::setWeather(const WeatherResult& weather) if (!mParticleNode) { mParticleNode = new osg::PositionAttitudeTransform; + mParticleNode->addCullCallback(mUnderwaterSwitch); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); @@ -1607,4 +1663,14 @@ void SkyManager::setGlareTimeOfDayFade(float val) mSun->setGlareTimeOfDayFade(val); } +void SkyManager::setWaterHeight(float height) +{ + mUnderwaterSwitch->setWaterLevel(height); +} + +void SkyManager::setWaterEnabled(bool enabled) +{ + mUnderwaterSwitch->setEnabled(enabled); +} + } diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index 573c0ceb61..0caadaa073 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -35,6 +35,7 @@ namespace MWRender class RainShooter; class RainFader; class AlphaFader; + class UnderwaterSwitchCallback; struct WeatherResult { @@ -100,6 +101,8 @@ namespace MWRender float mMoonAlpha; }; + ///@brief The SkyManager handles rendering of the sky domes, celestial bodies as well as other objects that need to be rendered + /// relative to the camera (e.g. weather particle effects) class SkyManager { public: @@ -144,6 +147,12 @@ namespace MWRender void setGlareTimeOfDayFade(float val); + /// Enable or disable the water plane (used to remove underwater weather particles) + void setWaterEnabled(bool enabled); + + /// Set height of water plane (used to remove underwater weather particles) + void setWaterHeight(float height); + private: void create(); ///< no need to call this, automatically done on first enable() @@ -160,6 +169,7 @@ namespace MWRender osg::ref_ptr mParticleNode; osg::ref_ptr mParticleEffect; std::vector > mParticleFaders; + osg::ref_ptr mUnderwaterSwitch; osg::ref_ptr mCloudNode; From 1cf1c944b79d3bbd64bbb909614816b08e663cfa Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 3 Nov 2015 23:20:17 +0100 Subject: [PATCH 18/23] Don't attempt to render weather particles on the refraction and reflection textures --- apps/openmw/mwrender/sky.cpp | 2 ++ apps/openmw/mwrender/vismask.hpp | 23 ++++++++++++++--------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index 4ff7256ca8..12708ba481 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -1374,6 +1374,7 @@ void SkyManager::createRain() mRainFader = new RainFader; mRainNode->addUpdateCallback(mRainFader); mRainNode->addCullCallback(mUnderwaterSwitch); + mRainNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mRainNode); } @@ -1515,6 +1516,7 @@ void SkyManager::setWeather(const WeatherResult& weather) { mParticleNode = new osg::PositionAttitudeTransform; mParticleNode->addCullCallback(mUnderwaterSwitch); + mParticleNode->setNodeMask(Mask_WeatherParticles); mRootNode->addChild(mParticleNode); } mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mParticleNode); diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index b1329e9588..a26bde1d13 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,21 +15,26 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), - Mask_Sun = (1<<6), - Mask_Water = (1<<7), - Mask_SimpleWater = (1<<8), - Mask_Terrain = (1<<9), - Mask_FirstPerson = (1<<10), + Mask_Water = (1<<6), + Mask_Terrain = (1<<7), + Mask_FirstPerson = (1<<8), + + // child of Sky + Mask_Sun = (1<<9), + Mask_WeatherParticles = (1<<10), + + // child of Water + Mask_SimpleWater = (1<<11), // top level masks - Mask_Scene = (1<<11), - Mask_GUI = (1<<12), + Mask_Scene = (1<<12), + Mask_GUI = (1<<13), // Set on a Geode - Mask_ParticleSystem = (1<<13), + Mask_ParticleSystem = (1<<14), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<14) + Mask_RenderToTexture = (1<<15) // reserved: (1<<16) for SceneUtil::Mask_Lit }; From c23609e22b1d931274b93c3ce031c682cf6176ff Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 00:19:15 +0100 Subject: [PATCH 19/23] Cache the light list in LightListCallback When multiple cameras are rendering, the later cameras can reuse the light lists from the first camera. --- components/sceneutil/lightmanager.cpp | 37 +++++++++++++++------------ components/sceneutil/lightmanager.hpp | 4 +++ 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/components/sceneutil/lightmanager.cpp b/components/sceneutil/lightmanager.cpp index 18d7ddd46b..1e1d04cf50 100644 --- a/components/sceneutil/lightmanager.cpp +++ b/components/sceneutil/lightmanager.cpp @@ -280,37 +280,40 @@ namespace SceneUtil // - cull list of lights by the camera frustum // - organize lights in a quad tree - // Don't use Camera::getViewMatrix, that one might be relative to another camera! - const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); - const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); - - if (lights.size()) + // update light list if necessary + // makes sure we don't update it more than once per frame when rendering with multiple cameras + if (mLastFrameNumber != nv->getFrameStamp()->getFrameNumber()) { + mLastFrameNumber = nv->getFrameStamp()->getFrameNumber(); + + // Don't use Camera::getViewMatrix, that one might be relative to another camera! + const osg::RefMatrix* viewMatrix = cv->getCurrentRenderStage()->getInitialViewMatrix(); + const std::vector& lights = mLightManager->getLightsInViewSpace(cv->getCurrentCamera(), viewMatrix); + // we do the intersections in view space osg::BoundingSphere nodeBound = node->getBound(); osg::Matrixf mat = *cv->getModelViewMatrix(); transformBoundingSphere(mat, nodeBound); - LightManager::LightList lightList; + mLightList.clear(); for (unsigned int i=0; i (8 - mLightManager->getStartLight()); - if (lightList.size() > maxLights) + osg::StateSet* stateset = NULL; + + if (mLightList.size() > maxLights) { // remove lights culled by this camera + LightManager::LightList lightList = mLightList; for (LightManager::LightList::iterator it = lightList.begin(); it != lightList.end() && lightList.size() > maxLights; ) { osg::CullStack::CullingStack& stack = cv->getModelViewCullingStack(); @@ -334,9 +337,11 @@ namespace SceneUtil while (lightList.size() > maxLights) lightList.pop_back(); } + stateset = mLightManager->getLightListStateSet(lightList); } + else + stateset = mLightManager->getLightListStateSet(mLightList); - osg::StateSet* stateset = mLightManager->getLightListStateSet(lightList); cv->pushStateSet(stateset); diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index c2a1779ede..0783e595dc 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -113,11 +113,13 @@ namespace SceneUtil int mStartLight; }; + /// @note Not thread safe for CullThreadPerCamera threading mode. class LightListCallback : public osg::NodeCallback { public: LightListCallback() : mLightManager(NULL) + , mLastFrameNumber(0) {} LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) @@ -129,6 +131,8 @@ namespace SceneUtil private: LightManager* mLightManager; + unsigned int mLastFrameNumber; + LightManager::LightList mLightList; }; /// @brief Configures a light's attenuation according to vanilla Morrowind attenuation settings. From 6bf393227922926be06e520e46f9c656b4d08b21 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 20:25:03 +0100 Subject: [PATCH 20/23] Fix the check_tabs.sh script choking on QT generated UI files when doing an in-source build --- CI/check_tabs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CI/check_tabs.sh b/CI/check_tabs.sh index 91f81e2a1e..1e88b57fd4 100755 --- a/CI/check_tabs.sh +++ b/CI/check_tabs.sh @@ -1,6 +1,6 @@ #!/bin/bash -OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} apps components) +OUTPUT=$(grep -nRP '\t' --include=\*.{cpp,hpp,c,h} --exclude=ui_\* apps components) if [[ $OUTPUT ]] ; then echo "Error: Tab characters found!" From c996702b56e9525299f90969aecaf84f68badb8d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 20:34:50 +0100 Subject: [PATCH 21/23] Fix some uninitialised variables found by static analysis --- apps/openmw/mwmechanics/character.cpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 8 ++++---- components/sceneutil/lightmanager.hpp | 4 +++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index f1c3da5ad1..c9b2489848 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -654,6 +654,7 @@ CharacterController::CharacterController(const MWWorld::Ptr &ptr, MWRender::Anim , mAnimation(anim) , mIdleState(CharState_None) , mMovementState(CharState_None) + , mAdjustMovementAnimSpeed(false) , mHasMovedInXY(false) , mMovementAnimationControlled(true) , mDeathState(CharState_None) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5b2aac9e50..7b11c9d859 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -131,6 +131,10 @@ namespace MWRender , mRootNode(rootNode) , mResourceSystem(resourceSystem) , mFogDepth(0.f) + , mUnderwaterColor(fallback->getFallbackColour("Water_UnderwaterColor")) + , mUnderwaterWeight(fallback->getFallbackFloat("Water_UnderwaterColorWeight")) + , mUnderwaterFog(0.f) + , mUnderwaterIndoorFog(fallback->getFallbackFloat("Water_UnderwaterIndoorFog")) , mNightEyeFactor(0.f) { osg::ref_ptr lightRoot = new SceneUtil::LightManager; @@ -202,10 +206,6 @@ namespace MWRender updateProjectionMatrix(); mStateUpdater->setFogEnd(mViewDistance); - mUnderwaterColor = fallback->getFallbackColour("Water_UnderwaterColor"); - mUnderwaterWeight = fallback->getFallbackFloat("Water_UnderwaterColorWeight"); - mUnderwaterIndoorFog = fallback->getFallbackFloat("Water_UnderwaterIndoorFog"); - mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); } diff --git a/components/sceneutil/lightmanager.hpp b/components/sceneutil/lightmanager.hpp index 0783e595dc..b652562aa8 100644 --- a/components/sceneutil/lightmanager.hpp +++ b/components/sceneutil/lightmanager.hpp @@ -122,7 +122,9 @@ namespace SceneUtil , mLastFrameNumber(0) {} LightListCallback(const LightListCallback& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) - : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop), mLightManager(copy.mLightManager) + : osg::Object(copy, copyop), osg::NodeCallback(copy, copyop) + , mLightManager(copy.mLightManager) + , mLastFrameNumber(0) {} META_Object(NifOsg, LightListCallback) From 489addf772568d0d67c4387a21b5dc4788ce72d3 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 4 Nov 2015 22:24:25 +0100 Subject: [PATCH 22/23] Don't attempt to run openmw_test_suite on coverity scan branch, since it is not being built --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 69879bd781..22f6164c2f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,8 +40,8 @@ script: - cd ./build - if [ "$COVERITY_SCAN_BRANCH" != 1 ]; then ${ANALYZE}make -j2; fi - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && [ "${TRAVIS_OS_NAME}" = "osx" ]; then make package; fi - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi - - if [ "${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then ./openmw_test_suite; fi + - if [ "$COVERITY_SCAN_BRANCH" != 1 ] && ["${TRAVIS_OS_NAME}" = "linux" ]; then cd .. && ./CI/check_tabs.sh; fi notifications: recipients: - corrmage+travis-ci@gmail.com From 8e4e4e5e38f53974fef9bc3373cd8b9d72c89c8f Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 5 Nov 2015 01:18:01 +0100 Subject: [PATCH 23/23] Fix infinite loop in addToLevList --- apps/openmw/mwscript/miscextensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwscript/miscextensions.cpp b/apps/openmw/mwscript/miscextensions.cpp index 32d86f55ad..5aebbc3a9e 100644 --- a/apps/openmw/mwscript/miscextensions.cpp +++ b/apps/openmw/mwscript/miscextensions.cpp @@ -37,7 +37,7 @@ namespace void addToLevList(ESM::LevelledListBase* list, const std::string& itemId, int level) { - for (std::vector::iterator it = list->mList.begin(); it != list->mList.end();) + for (std::vector::iterator it = list->mList.begin(); it != list->mList.end(); ++it) { if (it->mLevel == level && itemId == it->mId) return;