From bd9dc5856030763aa49a412fc5942288d2e5a2af Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 21:45:58 +0100 Subject: [PATCH 1/9] Use the correct scale for actor swim height (Fixes #2833) --- apps/openmw/mwclass/creature.cpp | 2 +- apps/openmw/mwclass/creature.hpp | 3 ++- apps/openmw/mwclass/npc.cpp | 6 +++++- apps/openmw/mwclass/npc.hpp | 3 ++- apps/openmw/mwphysics/actor.cpp | 13 ++++++++++--- apps/openmw/mwphysics/actor.hpp | 10 +++++++++- apps/openmw/mwphysics/physicssystem.cpp | 11 ++++++++++- apps/openmw/mwphysics/physicssystem.hpp | 3 +++ apps/openmw/mwrender/characterpreview.cpp | 2 +- apps/openmw/mwworld/class.cpp | 2 +- apps/openmw/mwworld/class.hpp | 3 ++- apps/openmw/mwworld/scene.cpp | 2 +- apps/openmw/mwworld/worldimp.cpp | 2 +- 13 files changed, 48 insertions(+), 14 deletions(-) diff --git a/apps/openmw/mwclass/creature.cpp b/apps/openmw/mwclass/creature.cpp index 450889eb2..95bc429e3 100644 --- a/apps/openmw/mwclass/creature.cpp +++ b/apps/openmw/mwclass/creature.cpp @@ -774,7 +774,7 @@ namespace MWClass return ref->mBase->mAiData.mFight; } - void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale) const + void Creature::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool /* rendering */) const { MWWorld::LiveCellRef *ref = ptr.get(); scale *= ref->mBase->mScale; diff --git a/apps/openmw/mwclass/creature.hpp b/apps/openmw/mwclass/creature.hpp index c4ea09255..55127eefc 100644 --- a/apps/openmw/mwclass/creature.hpp +++ b/apps/openmw/mwclass/creature.hpp @@ -133,7 +133,8 @@ namespace MWClass virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh }; } diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index 9fa2cc603..5679dc3e9 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -1012,8 +1012,12 @@ namespace MWClass + shield; } - void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale) const + void Npc::adjustScale(const MWWorld::Ptr &ptr, osg::Vec3f&scale, bool rendering) const { + if (!rendering) + return; // collision meshes are not scaled based on race height + // having the same collision extents for all races makes the environments easier to test + MWWorld::LiveCellRef *ref = ptr.get(); diff --git a/apps/openmw/mwclass/npc.hpp b/apps/openmw/mwclass/npc.hpp index d919131db..c2d2ca8fa 100644 --- a/apps/openmw/mwclass/npc.hpp +++ b/apps/openmw/mwclass/npc.hpp @@ -109,7 +109,8 @@ namespace MWClass /// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \return Any effect? - virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale) const; + virtual void adjustScale (const MWWorld::Ptr &ptr, osg::Vec3f &scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual void skillUsageSucceeded (const MWWorld::Ptr& ptr, int skill, int usageType, float extraFactor=1.f) const; ///< Inform actor \a ptr that a skill use has succeeded. diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp index 94d93e7d7..a681c7945 100644 --- a/apps/openmw/mwphysics/actor.cpp +++ b/apps/openmw/mwphysics/actor.cpp @@ -110,12 +110,14 @@ void Actor::updateScale() float scale = mPtr.getCellRef().getScale(); osg::Vec3f scaleVec(scale,scale,scale); - if (!mPtr.getClass().isNpc()) - mPtr.getClass().adjustScale(mPtr, scaleVec); - + mPtr.getClass().adjustScale(mPtr, scaleVec, false); mScale = scaleVec; mShape->setLocalScaling(toBullet(mScale)); + scaleVec = osg::Vec3f(scale,scale,scale); + mPtr.getClass().adjustScale(mPtr, scaleVec, true); + mRenderingScale = scaleVec; + updatePosition(); } @@ -124,6 +126,11 @@ osg::Vec3f Actor::getHalfExtents() const return osg::componentMultiply(mHalfExtents, mScale); } +osg::Vec3f Actor::getRenderingHalfExtents() const +{ + return osg::componentMultiply(mHalfExtents, mRenderingScale); +} + void Actor::setInertialForce(const osg::Vec3f &force) { mForce = force; diff --git a/apps/openmw/mwphysics/actor.hpp b/apps/openmw/mwphysics/actor.hpp index 7a12f549d..a4afa48a1 100644 --- a/apps/openmw/mwphysics/actor.hpp +++ b/apps/openmw/mwphysics/actor.hpp @@ -66,10 +66,17 @@ namespace MWPhysics void updatePosition(); /** - * Returns the (scaled) half extents + * Returns the half extents of the collision body (scaled according to collision scale) */ osg::Vec3f getHalfExtents() 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, + * most likely to make environment collision testing easier. However in some cases (swimming level) we want the actual scale. + */ + osg::Vec3f getRenderingHalfExtents() const; + /** * Sets the current amount of inertial force (incl. gravity) affecting this physic actor */ @@ -118,6 +125,7 @@ namespace MWPhysics osg::Quat mRotation; osg::Vec3f mScale; + osg::Vec3f mRenderingScale; osg::Vec3f mPosition; osg::Vec3f mForce; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index e666161da..80a63bf1b 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -261,7 +261,7 @@ namespace MWPhysics static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get() .find("fSwimHeightScale")->getFloat(); - float swimlevel = waterlevel + halfExtents.z() - (halfExtents.z() * 2 * fSwimHeightScale); + float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale); ActorTracer tracer; osg::Vec3f inertia = physicActor->getInertialForce(); @@ -878,6 +878,15 @@ namespace MWPhysics return osg::Vec3f(); } + osg::Vec3f PhysicsSystem::getRenderingHalfExtents(const MWWorld::Ptr &actor) + { + Actor* physactor = getActor(actor); + if (physactor) + return physactor->getRenderingHalfExtents(); + else + return osg::Vec3f(); + } + class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback { public: diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index db8da2886..6f38653c8 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -110,6 +110,9 @@ namespace MWPhysics /// Get physical half extents (scaled) of the given actor. osg::Vec3f getHalfExtents(const MWWorld::Ptr& actor); + /// @see MWPhysics::Actor::getRenderingHalfExtents + osg::Vec3f getRenderingHalfExtents(const MWWorld::Ptr& actor); + /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will /// be overwritten. Valid until the next call to applyQueuedMovement. void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index 93afeda25..eb950ea79 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -287,7 +287,7 @@ namespace MWRender void InventoryPreview::onSetup() { osg::Vec3f scale (1.f, 1.f, 1.f); - mCharacter.getClass().adjustScale(mCharacter, scale); + mCharacter.getClass().adjustScale(mCharacter, scale, true); mNode->setScale(scale); diff --git a/apps/openmw/mwworld/class.cpp b/apps/openmw/mwworld/class.cpp index 4c73c603b..30fd42527 100644 --- a/apps/openmw/mwworld/class.cpp +++ b/apps/openmw/mwworld/class.cpp @@ -287,7 +287,7 @@ namespace MWWorld return ""; } - void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const + void Class::adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const { } diff --git a/apps/openmw/mwworld/class.hpp b/apps/openmw/mwworld/class.hpp index 1157db670..b2d3453af 100644 --- a/apps/openmw/mwworld/class.hpp +++ b/apps/openmw/mwworld/class.hpp @@ -258,7 +258,8 @@ namespace MWWorld virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; ///< @return the number of enchantment points available for possible enchanting - virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale) const; + virtual void adjustScale(const MWWorld::Ptr& ptr, osg::Vec3f& scale, bool rendering) const; + /// @param rendering Indicates if the scale to adjust is for the rendering mesh, or for the collision mesh virtual bool canSell (const MWWorld::Ptr& item, int npcServices) const; ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 459b3b6ca..33e2ba17c 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -72,7 +72,7 @@ namespace { float scale = ptr.getCellRef().getScale(); osg::Vec3f scaleVec (scale, scale, scale); - ptr.getClass().adjustScale(ptr, scaleVec); + ptr.getClass().adjustScale(ptr, scaleVec, true); rendering.scaleObject(ptr, scaleVec); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index be86987e8..17118e169 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1969,7 +1969,7 @@ namespace MWWorld { osg::Vec3f pos (object.getRefData().getPosition().asVec3()); - pos.z() += heightRatio*2*mPhysics->getHalfExtents(object).z(); + pos.z() += heightRatio*2*mPhysics->getRenderingHalfExtents(object).z(); return isUnderwater(object.getCell(), pos); } From 8da4530957f1e64b031c513486cceeba311a8044 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 22:09:02 +0100 Subject: [PATCH 2/9] Use INI-imported underwater fog settings (Fixes #2907, Fixes #1511) --- apps/openmw/mwrender/renderingmanager.cpp | 17 +++++--- apps/openmw/mwrender/renderingmanager.hpp | 6 ++- apps/openmw/mwworld/weather.cpp | 53 ++++++++++++++++++++++- apps/openmw/mwworld/weather.hpp | 7 +++ 4 files changed, 76 insertions(+), 7 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index da81b23b1..e1c0ea666 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -31,6 +31,8 @@ #include +#include "../mwworld/fallback.hpp" + #include "sky.hpp" #include "effectmanager.hpp" #include "npcanimation.hpp" @@ -199,6 +201,10 @@ 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)); } @@ -349,13 +355,14 @@ namespace MWRender { osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); - configureFog (cell->mAmbi.mFogDensity, color); + configureFog (cell->mAmbi.mFogDensity, mUnderwaterIndoorFog, color); } - void RenderingManager::configureFog(float fogDepth, const osg::Vec4f &color) + void RenderingManager::configureFog(float fogDepth, float underwaterFog, const osg::Vec4f &color) { mFogDepth = fogDepth; mFogColor = color; + mUnderwaterFog = underwaterFog; } SkyManager* RenderingManager::getSkyManager() @@ -378,9 +385,9 @@ namespace MWRender mCamera->getPosition(focal, cameraPos); if (mWater->isUnderwater(cameraPos)) { - setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); - mStateUpdater->setFogStart(0.f); - mStateUpdater->setFogEnd(1000); + setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight)); + mStateUpdater->setFogStart(mViewDistance * (1 - mUnderwaterFog)); + mStateUpdater->setFogEnd(mViewDistance); } else { diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 1ddab7338..3e17ef413 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -79,7 +79,7 @@ namespace MWRender void configureAmbient(const ESM::Cell* cell); void configureFog(const ESM::Cell* cell); - void configureFog(float fogDepth, const osg::Vec4f& colour); + void configureFog(float fogDepth, float underwaterFog, const osg::Vec4f& colour); void addCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store); @@ -192,6 +192,10 @@ namespace MWRender osg::ref_ptr mStateUpdater; float mFogDepth; + osg::Vec4f mUnderwaterColor; + float mUnderwaterWeight; + float mUnderwaterFog; + float mUnderwaterIndoorFog; osg::Vec4f mFogColor; osg::Vec4f mAmbientColor; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 5008d8fbf..8920c17b4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -438,6 +438,10 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mDayEnd(mSunsetTime) , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) + , mUnderwaterSunriseFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog")) + , mUnderwaterDayFog(fallback.getFallbackFloat("Water_UnderwaterDayFog")) + , mUnderwaterSunsetFog(fallback.getFallbackFloat("Water_UnderwaterSunsetFog")) + , mUnderwaterNightFog(fallback.getFallbackFloat("Water_UnderwaterNightFog")) , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) @@ -624,6 +628,53 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } + // TODO: use pre/post sunset/sunrise time values in [Weather] section + // TODO: factor out the time of day interpolation code to reuse for calculateWeatherResult() + float gameHour = time.getHour(); + float underwaterFog; + // night + if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) + underwaterFog = mUnderwaterNightFog; + // sunrise + else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) + { + if (gameHour <= mSunriseTime) + { + // fade in + float advance = mSunriseTime - gameHour; + float factor = advance / 0.5f; + underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterNightFog, factor); + } + else //if (gameHour >= 6) + { + // fade out + float advance = gameHour - mSunriseTime; + float factor = advance / 3.f; + underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterDayFog, factor); + } + } + // day + else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) + underwaterFog = mUnderwaterDayFog; + // sunset + else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) + { + if (gameHour <= mDayEnd + 1) + { + // fade in + float advance = (mDayEnd + 1) - gameHour; + float factor = (advance / 2); + underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterDayFog, factor); + } + else //if (gameHour >= 19) + { + // fade out + float advance = gameHour - (mDayEnd + 1); + float factor = advance / 2.f; + underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterNightFog, factor); + } + } + float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) mRendering.getSkyManager()->setGlareTimeOfDayFade(0); @@ -635,7 +686,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setSecundaState(mSecunda.calculateState(time)); - mRendering.configureFog(mResult.mFogDepth, mResult.mFogColor); + mRendering.configureFog(mResult.mFogDepth, underwaterFog, mResult.mFogColor); mRendering.setAmbientColour(mResult.mAmbientColor); mRendering.setSunColour(mResult.mSunColor); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 7ce7c1bf8..a1a7d3077 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -249,6 +249,13 @@ namespace MWWorld float mDayEnd; float mHoursBetweenWeatherChanges; float mRainSpeed; + + // underwater fog not really related to weather, but we handle it here because it's convenient + float mUnderwaterSunriseFog; + float mUnderwaterDayFog; + float mUnderwaterSunsetFog; + float mUnderwaterNightFog; + std::vector mWeatherSettings; MoonModel mMasser; MoonModel mSecunda; From 45bf3e6788a8d6649c0bb5e7771bcbe8abc6f8d0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 22:47:40 +0100 Subject: [PATCH 3/9] Create TimeOfDayInterpolator class to refactor time handling in WeatherManager --- apps/openmw/mwworld/weather.cpp | 243 +++++++++++++------------------- apps/openmw/mwworld/weather.hpp | 73 ++++++---- 2 files changed, 138 insertions(+), 178 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 8920c17b4..ed43059f4 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -31,17 +31,74 @@ namespace { static const int invalidWeatherID = -1; + // linear interpolate between x and y based on factor. float lerp (float x, float y, float factor) { return x * (1-factor) + y * factor; } - + // linear interpolate between x and y based on factor. osg::Vec4f lerp (const osg::Vec4f& x, const osg::Vec4f& y, float factor) { return x * (1-factor) + y * factor; } } +template +T TimeOfDayInterpolator::getValue(const float gameHour, const TimeOfDaySettings& timeSettings) const +{ + // TODO: use pre/post sunset/sunrise time values in [Weather] section + + // night + if (gameHour <= timeSettings.mNightEnd || gameHour >= timeSettings.mNightStart + 1) + return mNightValue; + // sunrise + else if (gameHour >= timeSettings.mNightEnd && gameHour <= timeSettings.mDayStart + 1) + { + if (gameHour <= timeSettings.mSunriseTime) + { + // fade in + float advance = timeSettings.mSunriseTime - gameHour; + float factor = advance / 0.5f; + return lerp(mSunriseValue, mNightValue, factor); + } + else + { + // fade out + float advance = gameHour - timeSettings.mSunriseTime; + float factor = advance / 3.f; + return lerp(mSunriseValue, mDayValue, factor); + } + } + // day + else if (gameHour >= timeSettings.mDayStart + 1 && gameHour <= timeSettings.mDayEnd - 1) + return mDayValue; + // sunset + else if (gameHour >= timeSettings.mDayEnd - 1 && gameHour <= timeSettings.mNightStart + 1) + { + if (gameHour <= timeSettings.mDayEnd + 1) + { + // fade in + float advance = (timeSettings.mDayEnd + 1) - gameHour; + float factor = (advance / 2); + return lerp(mSunsetValue, mDayValue, factor); + } + else + { + // fade out + float advance = gameHour - (timeSettings.mDayEnd + 1); + float factor = advance / 2.f; + return lerp(mSunsetValue, mNightValue, factor); + } + } + // shut up compiler + return T(); +} + + + +template class TimeOfDayInterpolator; +template class TimeOfDayInterpolator; + Weather::Weather(const std::string& name, const MWWorld::Fallback& fallback, float stormWindSpeed, @@ -49,22 +106,22 @@ Weather::Weather(const std::string& name, const std::string& ambientLoopSoundID, const std::string& particleEffect) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) - , mSkySunriseColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color")) - , mSkyDayColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color")) - , mSkySunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color")) - , mSkyNightColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) - , mFogSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color")) - , mFogDayColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color")) - , mFogSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color")) - , mFogNightColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) - , mAmbientSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color")) - , mAmbientDayColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color")) - , mAmbientSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color")) - , mAmbientNightColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) - , mSunSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color")) - , mSunDayColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color")) - , mSunSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color")) - , mSunNightColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) + , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) + , mFogColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) + , mAmbientColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) + , mSunColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color"), + fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) @@ -432,16 +489,13 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) , mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time")) - , mNightStart(mSunsetTime + mSunsetDuration) - , mNightEnd(mSunriseTime - 0.5f) - , mDayStart(mSunriseTime + mSunriseDuration) - , mDayEnd(mSunsetTime) + , mNightFade(0, 0, 0, 1) , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) - , mUnderwaterSunriseFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog")) - , mUnderwaterDayFog(fallback.getFallbackFloat("Water_UnderwaterDayFog")) - , mUnderwaterSunsetFog(fallback.getFallbackFloat("Water_UnderwaterSunsetFog")) - , mUnderwaterNightFog(fallback.getFallbackFloat("Water_UnderwaterNightFog")) + , mUnderwaterFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog"), + fallback.getFallbackFloat("Water_UnderwaterDayFog"), + fallback.getFallbackFloat("Water_UnderwaterSunsetFog"), + fallback.getFallbackFloat("Water_UnderwaterNightFog")) , mWeatherSettings() , mMasser("Masser", fallback) , mSecunda("Secunda", fallback) @@ -461,6 +515,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo , mAmbientSound() , mPlayingSoundID() { + mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration; + mTimeSettings.mNightEnd = mSunriseTime - 0.5f; + mTimeSettings.mDayStart = mSunriseTime + mSunriseDuration; + mTimeSettings.mDayEnd = mSunsetTime; + mTimeSettings.mSunriseTime = mSunriseTime; + mWeatherSettings.reserve(10); addWeather("Clear", fallback); // 0 addWeather("Cloudy", fallback); // 1 @@ -593,7 +653,7 @@ void WeatherManager::update(float duration, bool paused) } // disable sun during night - if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) + if (time.getHour() >= mTimeSettings.mNightStart || time.getHour() <= mSunriseTime) mRendering.getSkyManager()->sunDisable(); else mRendering.getSkyManager()->sunEnable(); @@ -604,10 +664,10 @@ void WeatherManager::update(float duration, bool paused) { // Shift times into a 24-hour window beginning at mSunriseTime... float adjustedHour = time.getHour(); - float adjustedNightStart = mNightStart; + float adjustedNightStart = mTimeSettings.mNightStart; if ( time.getHour() < mSunriseTime ) adjustedHour += 24.f; - if ( mNightStart < mSunriseTime ) + if ( mTimeSettings.mNightStart < mSunriseTime ) adjustedNightStart += 24.f; const bool is_night = adjustedHour >= adjustedNightStart; @@ -628,52 +688,7 @@ void WeatherManager::update(float duration, bool paused) mRendering.setSunDirection( final * -1 ); } - // TODO: use pre/post sunset/sunrise time values in [Weather] section - // TODO: factor out the time of day interpolation code to reuse for calculateWeatherResult() - float gameHour = time.getHour(); - float underwaterFog; - // night - if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) - underwaterFog = mUnderwaterNightFog; - // sunrise - else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) - { - if (gameHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - gameHour; - float factor = advance / 0.5f; - underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterNightFog, factor); - } - else //if (gameHour >= 6) - { - // fade out - float advance = gameHour - mSunriseTime; - float factor = advance / 3.f; - underwaterFog = lerp(mUnderwaterSunriseFog, mUnderwaterDayFog, factor); - } - } - // day - else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) - underwaterFog = mUnderwaterDayFog; - // sunset - else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) - { - if (gameHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - gameHour; - float factor = (advance / 2); - underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterDayFog, factor); - } - else //if (gameHour >= 19) - { - // fade out - float advance = gameHour - (mDayEnd + 1); - float factor = advance / 2.f; - underwaterFog = lerp(mUnderwaterSunsetFog, mUnderwaterNightFog, factor); - } - } + float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings); float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) @@ -748,7 +763,7 @@ bool WeatherManager::isDark() const TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() || MWBase::Environment::get().getWorld()->isCellQuasiExterior()); - return exterior && (time.getHour() < mSunriseTime || time.getHour() > mNightStart - 1); + return exterior && (time.getHour() < mSunriseTime || time.getHour() > mTimeSettings.mNightStart - 1); } void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress) @@ -1026,81 +1041,15 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mParticleEffect = current.mParticleEffect; mResult.mRainEffect = current.mRainEffect; - mResult.mNight = (gameHour < mSunriseTime || gameHour > mNightStart - 1); + mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - // TODO: use pre/post sunset/sunrise time values in [Weather] section - // night - if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) - { - mResult.mFogColor = current.mFogNightColor; - mResult.mAmbientColor = current.mAmbientNightColor; - mResult.mSunColor = current.mSunNightColor; - mResult.mSkyColor = current.mSkyNightColor; - mResult.mNightFade = 1.f; - } - - // sunrise - else if (gameHour >= mNightEnd && gameHour <= mDayStart + 1) - { - if (gameHour <= mSunriseTime) - { - // fade in - float advance = mSunriseTime - gameHour; - float factor = advance / 0.5f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - else //if (gameHour >= 6) - { - // fade out - float advance = gameHour - mSunriseTime; - float factor = advance / 3.f; - mResult.mFogColor = lerp(current.mFogSunriseColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunriseColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunriseColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunriseColor, current.mSkyDayColor, factor); - } - } - - // day - else if (gameHour >= mDayStart + 1 && gameHour <= mDayEnd - 1) - { - mResult.mFogColor = current.mFogDayColor; - mResult.mAmbientColor = current.mAmbientDayColor; - mResult.mSunColor = current.mSunDayColor; - mResult.mSkyColor = current.mSkyDayColor; - } - - // sunset - else if (gameHour >= mDayEnd - 1 && gameHour <= mNightStart + 1) - { - if (gameHour <= mDayEnd + 1) - { - // fade in - float advance = (mDayEnd + 1) - gameHour; - float factor = (advance / 2); - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogDayColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientDayColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunDayColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyDayColor, factor); - } - else //if (gameHour >= 19) - { - // fade out - float advance = gameHour - (mDayEnd + 1); - float factor = advance / 2.f; - mResult.mFogColor = lerp(current.mFogSunsetColor, current.mFogNightColor, factor); - mResult.mAmbientColor = lerp(current.mAmbientSunsetColor, current.mAmbientNightColor, factor); - mResult.mSunColor = lerp(current.mSunSunsetColor, current.mSunNightColor, factor); - mResult.mSkyColor = lerp(current.mSkySunsetColor, current.mSkyNightColor, factor); - mResult.mNightFade = factor; - } - } + mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); + mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); + mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); + mResult.mSkyColor = current.mSkyColor.getValue(gameHour, mTimeSettings); + mResult.mNightFade = mNightFade.getValue(gameHour, mTimeSettings); if (gameHour >= mSunsetTime - mSunPreSunsetTime) { diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a1a7d3077..86d1898fa 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -34,6 +34,33 @@ namespace MWWorld class Fallback; class TimeStamp; + + struct TimeOfDaySettings + { + float mNightStart; + float mNightEnd; + float mDayStart; + float mDayEnd; + float mSunriseTime; + }; + + /// Interpolates between 4 data points (sunrise, day, sunset, night) based on the time of day. + /// The template value could be a floating point number, or a color. + template + class TimeOfDayInterpolator + { + public: + TimeOfDayInterpolator(const T& sunrise, const T& day, const T& sunset, const T& night) + : mSunriseValue(sunrise), mDayValue(day), mSunsetValue(sunset), mNightValue(night) + { + } + + T getValue (const float gameHour, const TimeOfDaySettings& timeSettings) const; + + private: + T mSunriseValue, mDayValue, mSunsetValue, mNightValue; + }; + /// Defines a single weather setting (according to INI) class Weather { @@ -47,29 +74,14 @@ namespace MWWorld std::string mCloudTexture; - // Sky (atmosphere) colors - osg::Vec4f mSkySunriseColor; - osg::Vec4f mSkyDayColor; - osg::Vec4f mSkySunsetColor; - osg::Vec4f mSkyNightColor; - - // Fog colors - osg::Vec4f mFogSunriseColor; - osg::Vec4f mFogDayColor; - osg::Vec4f mFogSunsetColor; - osg::Vec4f mFogNightColor; - - // Ambient lighting colors - osg::Vec4f mAmbientSunriseColor; - osg::Vec4f mAmbientDayColor; - osg::Vec4f mAmbientSunsetColor; - osg::Vec4f mAmbientNightColor; - - // Sun (directional) lighting colors - osg::Vec4f mSunSunriseColor; - osg::Vec4f mSunDayColor; - osg::Vec4f mSunSunsetColor; - osg::Vec4f mSunNightColor; + // Sky (atmosphere) color + TimeOfDayInterpolator mSkyColor; + // Fog color + TimeOfDayInterpolator mFogColor; + // Ambient lighting color + TimeOfDayInterpolator mAmbientColor; + // Sun (directional) lighting color + TimeOfDayInterpolator mSunColor; // Fog depth/density float mLandFogDayDepth; @@ -243,18 +255,17 @@ namespace MWWorld float mSunriseDuration; float mSunsetDuration; float mSunPreSunsetTime; - float mNightStart; - float mNightEnd; - float mDayStart; - float mDayEnd; + + TimeOfDaySettings mTimeSettings; + + // fading of night skydome + TimeOfDayInterpolator mNightFade; + float mHoursBetweenWeatherChanges; float mRainSpeed; // underwater fog not really related to weather, but we handle it here because it's convenient - float mUnderwaterSunriseFog; - float mUnderwaterDayFog; - float mUnderwaterSunsetFog; - float mUnderwaterNightFog; + TimeOfDayInterpolator mUnderwaterFog; std::vector mWeatherSettings; MoonModel mMasser; From 802620a86b08850f07a88b1eea1120d0b5ac1ea0 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 1 Nov 2015 23:03:16 +0100 Subject: [PATCH 4/9] Use TimeOfDayInterpolator for Land Fog Depth Fixes the sudden fog jump at nightfall. --- apps/openmw/mwworld/weather.cpp | 9 +++++---- apps/openmw/mwworld/weather.hpp | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index ed43059f4..24b45fcea 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -122,8 +122,10 @@ Weather::Weather(const std::string& name, fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color"), fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color"), fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) - , mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) - , mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) + , mLandFogDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"), + fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_Depth")) , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color")) , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) @@ -1043,8 +1045,7 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam mResult.mNight = (gameHour < mSunriseTime || gameHour > mTimeSettings.mNightStart - 1); - mResult.mFogDepth = mResult.mNight ? current.mLandFogNightDepth : current.mLandFogDayDepth; - + mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings); mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings); mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings); mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings); diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index 86d1898fa..4a78350fe 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -84,8 +84,7 @@ namespace MWWorld TimeOfDayInterpolator mSunColor; // Fog depth/density - float mLandFogDayDepth; - float mLandFogNightDepth; + TimeOfDayInterpolator mLandFogDepth; // Color modulation for the sun itself during sunset osg::Vec4f mSunDiscSunsetColor; From 4690ec12cc80cada2d026caa6b1c6c560d8a7689 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:29:09 +0100 Subject: [PATCH 5/9] Render the water plane with GL_DEPTH_CLAMP if supported (Fixes #996) --- apps/openmw/mwrender/water.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 251a1232c..20710ab7e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -389,6 +390,24 @@ private: osg::ref_ptr mScene; }; +/// DepthClampCallback enables GL_DEPTH_CLAMP for the current draw, if supported. +class DepthClampCallback : public osg::Drawable::DrawCallback +{ +public: + virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const + { + if (!osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3)) + drawable->drawImplementation(renderInfo); + + glEnable(GL_DEPTH_CLAMP); + + drawable->drawImplementation(renderInfo); + + // restore default + glDisable(GL_DEPTH_CLAMP); + } +}; + Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico, const MWWorld::Fallback* fallback, const std::string& resourcePath) : mParent(parent) @@ -402,6 +421,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); + waterGeom->setDrawCallback(new DepthClampCallback); mWaterGeode = new osg::Geode; mWaterGeode->addDrawable(waterGeom); From c60388afb68afa22d433f7d9dfaa4ea3e0a95a0f Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:30:18 +0100 Subject: [PATCH 6/9] Add fudge factor to move the water mesh away from camera when the camera gets too close --- apps/openmw/mwrender/water.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 20710ab7e..c44f480f8 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -205,6 +205,36 @@ public: } }; +/// Moves water mesh away from the camera slightly if the camera gets to close on the Z axis. +/// The offset works around graphics artifacts that occured with the GL_DEPTH_CLAMP when the camera gets extremely close to the mesh (seen on NVIDIA at least). +/// Must be added as a Cull callback. +class FudgeCallback : public osg::NodeCallback +{ +public: + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) + { + osgUtil::CullVisitor* cv = static_cast(nv); + + const float fudge = 0.1; + if (std::abs(cv->getEyeLocal().z()) < fudge) + { + float diff = fudge - cv->getEyeLocal().z(); + osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); + + if (cv->getEyeLocal().z() > 0) + modelViewMatrix->preMultTranslate(osg::Vec3f(0,0,-diff)); + else + modelViewMatrix->preMultTranslate(osg::Vec3f(0,0,diff)); + + cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF); + traverse(node, nv); + cv->popModelViewMatrix(); + } + else + traverse(node, nv); + } +}; + osg::ref_ptr readShader (osg::Shader::Type type, const std::string& file, const std::map& defineMap = std::map()) { osg::ref_ptr shader (new osg::Shader(type)); @@ -432,6 +462,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem mWaterNode = new osg::PositionAttitudeTransform; mWaterNode->addChild(mWaterGeode); + mWaterNode->addCullCallback(new FudgeCallback); // simple water fallback for the local map osg::ref_ptr geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); From 913bbe347b0b0704800d61b3470d11fc69e36ab7 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:52:20 +0100 Subject: [PATCH 7/9] Don't check the extension string every frame --- apps/openmw/mwrender/water.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c44f480f8..c6061b40a 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -426,8 +426,12 @@ class DepthClampCallback : public osg::Drawable::DrawCallback public: virtual void drawImplementation(osg::RenderInfo& renderInfo,const osg::Drawable* drawable) const { - if (!osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3)) + static bool supported = osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3); + if (!supported) + { drawable->drawImplementation(renderInfo); + return; + } glEnable(GL_DEPTH_CLAMP); From 3f988327c7178d3c6a106c1366e9a23bd0084104 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 00:57:59 +0100 Subject: [PATCH 8/9] Destructor fix --- apps/openmw/mwrender/water.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index c6061b40a..046164698 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -613,6 +613,17 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin Water::~Water() { mParent->removeChild(mWaterNode); + + if (mReflection) + { + mParent->removeChild(mReflection); + mReflection = NULL; + } + if (mRefraction) + { + mParent->removeChild(mRefraction); + mRefraction = NULL; + } } void Water::setEnabled(bool enabled) From 0348b8df1c25b5134ee28c0f6c25d1682fd03000 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 2 Nov 2015 01:23:21 +0100 Subject: [PATCH 9/9] Fix applying of plane height in ClipCullNode (Fixes #2985) --- apps/openmw/mwrender/water.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 046164698..bb6d549e0 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -145,14 +145,18 @@ 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 + // 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); + // 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) { 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); @@ -168,7 +172,7 @@ public: { addCullCallback (new PlaneCullCallback(&mPlane)); - mClipNodeTransform = new osg::PositionAttitudeTransform; + mClipNodeTransform = new osg::Group; mClipNodeTransform->addCullCallback(new FlipCallback(&mPlane)); addChild(mClipNodeTransform); @@ -184,12 +188,12 @@ public: mPlane = plane; mClipNode->getClipPlaneList().clear(); - mClipNode->addClipPlane(new osg::ClipPlane(0, mPlane)); + mClipNode->addClipPlane(new osg::ClipPlane(0, osg::Plane(mPlane.getNormal(), 0))); // mPlane.d() applied in FlipCallback mClipNode->setStateSetModes(*getOrCreateStateSet(), osg::StateAttribute::ON); } private: - osg::ref_ptr mClipNodeTransform; + osg::ref_ptr mClipNodeTransform; osg::ref_ptr mClipNode; osg::Plane mPlane; @@ -205,7 +209,7 @@ public: } }; -/// Moves water mesh away from the camera slightly if the camera gets to close on the Z axis. +/// Moves water mesh away from the camera slightly if the camera gets too close on the Z axis. /// The offset works around graphics artifacts that occured with the GL_DEPTH_CLAMP when the camera gets extremely close to the mesh (seen on NVIDIA at least). /// Must be added as a Cull callback. class FudgeCallback : public osg::NodeCallback @@ -215,7 +219,7 @@ public: { osgUtil::CullVisitor* cv = static_cast(nv); - const float fudge = 0.1; + const float fudge = 0.2; if (std::abs(cv->getEyeLocal().z()) < fudge) { float diff = fudge - cv->getEyeLocal().z();