From 41a8b22ebda40390f57d4812b51edea50a0ea8e2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 22 Feb 2012 19:17:37 +0100 Subject: [PATCH] implemented weather transitions (currently only blends the clouds) --- apps/openmw/mwrender/renderingmanager.cpp | 4 + apps/openmw/mwrender/renderingmanager.hpp | 4 + apps/openmw/mwrender/sky.cpp | 54 ++++++++++--- apps/openmw/mwrender/sky.hpp | 18 ++++- apps/openmw/mwworld/weather.cpp | 92 ++++++++++++++++++++++- apps/openmw/mwworld/weather.hpp | 41 +++++++++- apps/openmw/mwworld/world.cpp | 2 + 7 files changed, 199 insertions(+), 16 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 1d136b703..1e2a8383a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -64,6 +64,10 @@ RenderingManager::~RenderingManager () delete mSkyManager; } +MWRender::SkyManager* RenderingManager::getSkyManager() +{ + return mSkyManager; +} MWRender::Objects& RenderingManager::getObjects(){ return mObjects; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 0a84aea66..3ca677eac 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -62,6 +62,8 @@ class RenderingManager: private RenderingInterface { /// MWWorld::Player has been rewritten to not need access /// to internal details of the rendering system anymore + SkyManager* getSkyManager(); + void toggleLight(); bool toggleRenderMode(int mode); @@ -111,7 +113,9 @@ class RenderingManager: private RenderingInterface { private: void setAmbientMode(); + SkyManager* mSkyManager; + OEngine::Render::OgreRenderer &mRendering; MWRender::Objects mObjects; diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index f1d310088..0961875da 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -44,6 +44,11 @@ void CelestialBody::setPosition(const Vector3& pPosition) mNode->setPosition(finalPosition); } +void CelestialBody::setColour(const ColourValue& pColour) +{ + mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour); +} + void CelestialBody::init(const String& textureName, const unsigned int initialSize, const Vector3& pInitialPosition, @@ -68,7 +73,7 @@ void CelestialBody::init(const String& textureName, mNode->attachObject(bbSet); bbSet->createBillboard(0,0,0); - mMaterial = MaterialManager::getSingleton().create("CelestialBody"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + mMaterial = MaterialManager::getSingleton().create("BillboardMaterial"+StringConverter::toString(bodyCount), ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); mMaterial->removeAllTechniques(); Pass* p = mMaterial->createTechnique()->createPass(); p->setSceneBlending(SBT_TRANSPARENT_ALPHA); @@ -78,7 +83,7 @@ void CelestialBody::init(const String& textureName, p->setDiffuse(0.0,0.0,0.0,1.0); p->setAmbient(0.0,0.0,0.0); p->createTextureUnitState(textureName); - bbSet->setMaterialName("CelestialBody"+StringConverter::toString(bodyCount)); + bbSet->setMaterialName("BillboardMaterial"+StringConverter::toString(bodyCount)); bodyCount++; } @@ -152,6 +157,8 @@ void Moon::setType(const Moon::Type& type) mType = type; } + +/// \todo the moon phase rendering is not correct - the dark part of the moon does not occlude the stars void Moon::setPhase(const Moon::Phase& phase) { Ogre::String textureName = "textures\\tx_"; @@ -199,12 +206,6 @@ void Moon::setVisibility(const float pVisibility) mMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("visibilityFactor", Real(pVisibility)); } -void Moon::setColour(const ColourValue& pColour) -{ - mMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(pColour); -} - - void SkyManager::ModVertexAlpha(Entity* ent, unsigned int meshType) { // Get the vertex colour buffer of this mesh @@ -367,14 +368,16 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) " out float4 oColor : COLOR, \n" " in float4 color : TEXCOORD1, \n" " uniform sampler2D texture : TEXUNIT0, \n" + " uniform sampler2D secondTexture : TEXUNIT1, \n" + " uniform float transitionFactor, \n" " uniform float time, \n" " uniform float opacity, \n" " uniform float4 emissive \n" ") \n" "{ \n" " uv += float2(1,1) * time * "<setSource(outStream2.str()); mCloudFragmentShader->load(); @@ -400,6 +403,8 @@ SkyManager::SkyManager (SceneNode* pMwRoot, Camera* pCamera) mAtmosphereMaterial->getTechnique(0)->getPass(0)->setDepthWriteEnabled(false); mAtmosphereMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); mCloudMaterial->getTechnique(0)->getPass(0)->setSceneBlending(SBT_TRANSPARENT_ALPHA); + + mCloudMaterial->getTechnique(0)->getPass(0)->createTextureUnitState(""); } SkyManager::~SkyManager() @@ -437,6 +442,7 @@ void SkyManager::disable() void SkyManager::setMoonColour (bool red) { + /// \todo tweak these colors mSecunda->setColour( red ? ColourValue(1.0, 0.0, 0.0) : ColourValue(1.0, 1.0, 1.0)); } @@ -445,3 +451,31 @@ void SkyManager::setCloudsOpacity(float opacity) { mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(opacity)); } + +void SkyManager::setWeather(const MWWorld::WeatherResult& weather) +{ + if (mClouds != weather.mCloudTexture) + { + mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName("textures\\"+weather.mCloudTexture); + mClouds = weather.mCloudTexture; + } + + if (mNextClouds != weather.mNextCloudTexture) + { + mCloudMaterial->getTechnique(0)->getPass(0)->getTextureUnitState(1)->setTextureName("textures\\"+weather.mNextCloudTexture); + mNextClouds = weather.mNextCloudTexture; + } + + if (mCloudBlendFactor != weather.mCloudBlendFactor) + { + mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("transitionFactor", Real(weather.mCloudBlendFactor)); + mCloudBlendFactor = weather.mCloudBlendFactor; + } + + if (mCloudOpacity != weather.mCloudOpacity) + { + mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstant("opacity", Real(weather.mCloudOpacity)); + mCloudOpacity = weather.mCloudOpacity; + } + +} diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index f4f44570d..59206f0c0 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -8,6 +8,7 @@ #include #include "sky.hpp" +#include "../mwworld/weather.hpp" namespace Ogre { @@ -30,7 +31,8 @@ namespace MWRender Ogre::SceneNode* pRootNode ); CelestialBody(); - + + void setColour(const Ogre::ColourValue& pColour); void setPosition(const Ogre::Vector3& pPosition); void setVisible(const bool visible); @@ -59,9 +61,7 @@ namespace MWRender void setVisibility(const float pVisibility); ///< set the transparency factor for this moon - - void setColour(const Ogre::ColourValue& pColour); - + enum Phase { Phase_New = 0, @@ -123,6 +123,8 @@ namespace MWRender void setCloudsOpacity(float opacity); ///< change opacity of the clouds + void setWeather(const MWWorld::WeatherResult& weather); + private: CelestialBody* mSun; Moon* mMasser; @@ -137,6 +139,14 @@ namespace MWRender Ogre::HighLevelGpuProgramPtr mCloudFragmentShader; + // remember the cloud texture names used right now, so we don't have to set the texture names if they didnt change + Ogre::String mClouds; + Ogre::String mNextClouds; + float mCloudBlendFactor; + float mCloudOpacity; + + float mRemainingTransitionTime; + void ModVertexAlpha(Ogre::Entity* ent, unsigned int meshType); }; } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 7be8f2328..84ab3a0d2 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -2,9 +2,99 @@ #include "../mwrender/renderingmanager.hpp" +using namespace Ogre; using namespace MWWorld; -WeatherManager::WeatherManager(MWRender::RenderingManager* rendering) +#define TRANSITION_TIME 10 + +WeatherManager::WeatherManager(MWRender::RenderingManager* rendering) : + mCurrentWeather("clear") { mRendering = rendering; + + /// \todo read these from Morrowind.ini + Weather clear; + clear.mCloudTexture = "tx_sky_clear.dds"; + clear.mCloudsMaximumPercent = 0.75; + mWeatherSettings["clear"] = clear; + + Weather cloudy; + cloudy.mCloudTexture = "tx_sky_cloudy.dds"; + cloudy.mCloudsMaximumPercent = 0.9; + mWeatherSettings["cloudy"] = cloudy; + + Weather overcast; + overcast.mCloudTexture = "tx_sky_overcast.dds"; + overcast.mCloudsMaximumPercent = 1.0; + mWeatherSettings["overcast"] = overcast; + + setWeather("clear", true); + setWeather("cloudy", false); +} + +void WeatherManager::setWeather(const String& weather, bool instant) +{ + if (instant) + { + mNextWeather = ""; + mCurrentWeather = weather; + } + else if (weather != mCurrentWeather) + { + mNextWeather = weather; + mRemainingTransitionTime = TRANSITION_TIME; + } +} + +WeatherResult WeatherManager::getResult() +{ + const Weather& current = mWeatherSettings[mCurrentWeather]; + WeatherResult result; + + result.mCloudTexture = current.mCloudTexture; + result.mCloudBlendFactor = 0; + result.mCloudOpacity = current.mCloudsMaximumPercent; + /// \todo + + return result; +} + +WeatherResult WeatherManager::transition(const Weather& other, float factor) +{ + const Weather& current = mWeatherSettings[mCurrentWeather]; + WeatherResult result; + + result.mCloudTexture = current.mCloudTexture; + result.mNextCloudTexture = other.mCloudTexture; + result.mCloudBlendFactor = factor; + + #define lerp(x, y) (x * (1-factor) + y * factor) + + result.mCloudOpacity = lerp(current.mCloudsMaximumPercent, other.mCloudsMaximumPercent); + + /// \todo + + return result; +} + +void WeatherManager::update(float duration) +{ + WeatherResult result; + + if (mNextWeather != "") + { + mRemainingTransitionTime -= duration; + if (mRemainingTransitionTime < 0) + { + mCurrentWeather = mNextWeather; + mNextWeather = ""; + } + } + + if (mNextWeather != "") + result = transition(mWeatherSettings[mNextWeather], 1-(mRemainingTransitionTime/TRANSITION_TIME)); + else + result = getResult(); + + mRendering->getSkyManager()->setWeather(result); } diff --git a/apps/openmw/mwworld/weather.hpp b/apps/openmw/mwworld/weather.hpp index a91ed8b8e..14e75a463 100644 --- a/apps/openmw/mwworld/weather.hpp +++ b/apps/openmw/mwworld/weather.hpp @@ -11,6 +11,35 @@ namespace MWRender namespace MWWorld { + /// Defines the actual weather that results from weather setting (see below), time of day and weather transition + struct WeatherResult + { + Ogre::String mCloudTexture; + Ogre::String mNextCloudTexture; + float mCloudBlendFactor; + + Ogre::ColourValue mFogColor; + + Ogre::ColourValue mAmbientColor; + + Ogre::ColourValue mSunColor; + + Ogre::ColourValue mSunDiscColor; + + float mFogDepth; + + float mWindSpeed; + + float mCloudSpeed; + + float mCloudOpacity; + + float mGlareView; + + Ogre::String mAmbientLoopSoundID; + }; + + /// Defines a single weather setting struct Weather { @@ -83,7 +112,7 @@ namespace MWWorld * @param instant * if true, the weather changes instantly. if false, it slowly starts transitioning. */ - void setWeather(const Weather& weather, bool instant=false); + void setWeather(const Ogre::String& weather, bool instant=false); /** * Per-frame update @@ -93,6 +122,16 @@ namespace MWWorld private: MWRender::RenderingManager* mRendering; + + std::map mWeatherSettings; + + Ogre::String mCurrentWeather; + Ogre::String mNextWeather; + + float mRemainingTransitionTime; + + WeatherResult transition(const Weather& other, const float factor); + WeatherResult getResult(); }; } diff --git a/apps/openmw/mwworld/world.cpp b/apps/openmw/mwworld/world.cpp index b4f16898e..9d874b06f 100644 --- a/apps/openmw/mwworld/world.cpp +++ b/apps/openmw/mwworld/world.cpp @@ -693,6 +693,8 @@ namespace MWWorld void World::update (float duration) { mWorldScene->update (duration); + + mWeatherManager->update (duration); } OEngine::Render::Fader* World::getFader()