1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 21:23:52 +00:00

Implement rain (Feature #41)

This commit is contained in:
scrawl 2014-06-25 18:20:21 +02:00
parent 4a6dbe6f89
commit f6a568c995
4 changed files with 139 additions and 4 deletions

View file

@ -236,6 +236,10 @@ SkyManager::SkyManager(Ogre::SceneNode *root, Ogre::Camera *pCamera)
, mCloudAnimationTimer(0.f)
, mMoonRed(false)
, mParticleNode(NULL)
, mRainEnabled(false)
, mRainTimer(0)
, mRainSpeed(0)
, mRainFrequency(1)
{
mSceneMgr = root->getCreator();
mRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
@ -351,6 +355,7 @@ void SkyManager::create()
SkyManager::~SkyManager()
{
clearRain();
delete mSun;
delete mSunGlare;
delete mMasser;
@ -369,6 +374,66 @@ int SkyManager::getSecundaPhase() const
return mSecunda->getPhaseInt();
}
void SkyManager::clearRain()
{
for (std::map<Ogre::SceneNode*, NifOgre::ObjectScenePtr>::iterator it = mRainModels.begin(); it != mRainModels.end();)
{
it->second.setNull();
Ogre::SceneNode* parent = it->first->getParentSceneNode();
mSceneMgr->destroySceneNode(it->first);
mSceneMgr->destroySceneNode(parent);
mRainModels.erase(it++);
}
}
void SkyManager::updateRain(float dt)
{
// Move existing rain
// Note: if rain gets disabled, we let the existing rain drops finish falling down.
float minHeight = 200;
for (std::map<Ogre::SceneNode*, NifOgre::ObjectScenePtr>::iterator it = mRainModels.begin(); it != mRainModels.end();)
{
Ogre::Vector3 pos = it->first->getPosition();
pos.z -= mRainSpeed * dt;
it->first->setPosition(pos);
if (pos.z < -minHeight)
{
it->second.setNull();
Ogre::SceneNode* parent = it->first->getParentSceneNode();
mSceneMgr->destroySceneNode(it->first);
mSceneMgr->destroySceneNode(parent);
mRainModels.erase(it++);
}
else
++it;
}
// Spawn new rain
float rainFrequency = mRainFrequency;
float startHeight = 700;
if (mRainEnabled)
{
mRainTimer += dt;
if (mRainTimer >= 1.f/rainFrequency)
{
mRainTimer = 0;
const float rangeRandom = 100;
float xOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2);
float yOffs = (std::rand()/(RAND_MAX+1.0)) * rangeRandom - (rangeRandom/2);
Ogre::SceneNode* sceneNode = mCamera->getParentSceneNode()->createChildSceneNode();
sceneNode->setInheritOrientation(false);
// Create a separate node to control the offset, since a node with setInheritOrientation(false) will still
// consider the orientation of the parent node for its position, just not for its orientation
Ogre::SceneNode* offsetNode = sceneNode->createChildSceneNode(Ogre::Vector3(xOffs,yOffs,startHeight));
NifOgre::ObjectScenePtr objects = NifOgre::Loader::createObjects(offsetNode, mRainEffect);
mRainModels[offsetNode] = objects;
}
}
}
void SkyManager::update(float duration)
{
if (!mEnabled) return;
@ -380,6 +445,8 @@ void SkyManager::update(float duration)
mParticle->mControllers[i].update();
}
updateRain(duration);
// UV Scroll the clouds
mCloudAnimationTimer += duration * mCloudSpeed;
sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer",
@ -430,13 +497,22 @@ void SkyManager::enable()
if (!mCreated)
create();
if (mParticleNode)
mParticleNode->setVisible(true);
mRootNode->setVisible(true);
mEnabled = true;
}
void SkyManager::disable()
{
if (mParticleNode)
mParticleNode->setVisible(false);
clearRain();
mRootNode->setVisible(false);
mEnabled = false;
}
@ -449,6 +525,11 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
{
if (!mCreated) return;
mRainEffect = weather.mRainEffect;
mRainEnabled = !mRainEffect.empty();
mRainFrequency = weather.mRainFrequency;
mRainSpeed = weather.mRainSpeed;
if (mCurrentParticleEffect != weather.mParticleEffect)
{
mCurrentParticleEffect = weather.mParticleEffect;
@ -461,7 +542,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
{
if (!mParticleNode)
{
mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode(Ogre::Vector3(0,0,100));
mParticleNode = mCamera->getParentSceneNode()->createChildSceneNode();
mParticleNode->setInheritOrientation(false);
}

View file

@ -148,6 +148,8 @@ namespace MWRender
void sunDisable();
void setRainSpeed(float speed);
void setSunDirection(const Ogre::Vector3& direction);
void setMasserDirection(const Ogre::Vector3& direction);
@ -176,6 +178,9 @@ namespace MWRender
void create();
///< no need to call this, automatically done on first enable()
void updateRain(float dt);
void clearRain();
bool mCreated;
bool mMoonRed;
@ -203,6 +208,9 @@ namespace MWRender
Ogre::SceneNode* mParticleNode;
NifOgre::ObjectScenePtr mParticle;
std::map<Ogre::SceneNode*, NifOgre::ObjectScenePtr> mRainModels;
float mRainTimer;
// remember some settings so we don't have to apply them again if they didnt change
Ogre::String mClouds;
Ogre::String mNextClouds;
@ -223,6 +231,11 @@ namespace MWRender
float mGlare; // target
float mGlareFade; // actual
bool mRainEnabled;
std::string mRainEffect;
float mRainSpeed;
float mRainFrequency;
bool mEnabled;
bool mSunEnabled;
bool mMasserEnabled;

View file

@ -59,6 +59,21 @@ void WeatherManager::setFallbackWeather(Weather& weather,const std::string& name
weather.mCloudSpeed = mFallback->getFallbackFloat("Weather_"+upper+"_Cloud_Speed");
weather.mGlareView = mFallback->getFallbackFloat("Weather_"+upper+"_Glare_View");
weather.mCloudTexture = mFallback->getFallbackString("Weather_"+upper+"_Cloud_Texture");
bool usesPrecip = mFallback->getFallbackBool("Weather_"+upper+"_Using_Precip");
if (usesPrecip)
weather.mRainEffect = "meshes\\raindrop.nif";
weather.mRainSpeed = mRainSpeed;
weather.mRainFrequency = mFallback->getFallbackFloat("Weather_"+upper+"_Rain_Entrance_Speed");
/*
Unhandled:
Rain Diameter=600 ?
Rain Height Min=200 ?
Rain Height Max=700 ?
Rain Threshold=0.6 ?
Max Raindrops=650 ?
*/
size_t offset = weather.mCloudTexture.find(".tga");
if (offset != std::string::npos)
weather.mCloudTexture.replace(offset, weather.mCloudTexture.length() - offset, ".dds");
@ -100,7 +115,7 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa
mHour(14), mCurrentWeather("clear"), mNextWeather(""), mFirstUpdate(true),
mWeatherUpdateTime(0), mThunderFlash(0), mThunderChance(0),
mThunderChanceNeeded(50), mThunderSoundDelay(0), mRemainingTransitionTime(0),
mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), mRendering(rendering)
mTimePassed(0), mFallback(fallback), mWindSpeed(0.f), mRendering(rendering), mIsStorm(false)
{
//Globals
mThunderSoundID0 = mFallback->getFallbackString("Weather_Thunderstorm_Thunder_Sound_ID_0");
@ -117,6 +132,8 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa
mThunderThreshold = mFallback->getFallbackFloat("Weather_Thunderstorm_Thunder_Threshold");
mThunderSoundDelay = 0.25;
mRainSpeed = mFallback->getFallbackFloat("Weather_Precip_Gravity");
//Some useful values
/* TODO: Use pre-sunrise_time, pre-sunset_time,
* post-sunrise_time, and post-sunset_time to better
@ -140,10 +157,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager* rendering,MWWorld::Fa
Weather thunderstorm;
thunderstorm.mRainLoopSoundID = "rain heavy";
thunderstorm.mRainEffect = "meshes\\raindrop.nif";
setFallbackWeather(thunderstorm,"thunderstorm");
Weather rain;
rain.mRainLoopSoundID = "rain";
rain.mRainEffect = "meshes\\raindrop.nif";
setFallbackWeather(rain,"rain");
Weather overcast;
@ -217,7 +236,11 @@ void WeatherManager::setResult(const String& weatherType)
mResult.mIsStorm = current.mIsStorm;
mResult.mRainSpeed = current.mRainSpeed;
mResult.mRainFrequency = current.mRainFrequency;
mResult.mParticleEffect = current.mParticleEffect;
mResult.mRainEffect = current.mRainEffect;
mResult.mNight = (mHour < mSunriseTime || mHour > mNightStart - 1);
@ -324,6 +347,9 @@ void WeatherManager::transition(float factor)
mResult.mIsStorm = current.mIsStorm;
mResult.mParticleEffect = current.mParticleEffect;
mResult.mRainEffect = current.mRainEffect;
mResult.mRainSpeed = current.mRainSpeed;
mResult.mRainFrequency = current.mRainFrequency;
}
void WeatherManager::update(float duration)
@ -361,6 +387,7 @@ void WeatherManager::update(float duration)
setResult(mCurrentWeather);
mWindSpeed = mResult.mWindSpeed;
mIsStorm = mResult.mIsStorm;
mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor);
@ -499,7 +526,6 @@ void WeatherManager::update(float duration)
mRendering->getSkyManager()->setWeather(mResult);
// Play sounds
if (mNextWeather == "")
{
@ -779,7 +805,7 @@ void WeatherManager::switchToNextWeather(bool instantly)
bool WeatherManager::isInStorm() const
{
return mResult.mIsStorm;
return mIsStorm;
}
Ogre::Vector3 WeatherManager::getStormDirection() const

View file

@ -62,6 +62,10 @@ namespace MWWorld
std::string mAmbientLoopSoundID;
std::string mParticleEffect;
std::string mRainEffect;
float mRainSpeed;
float mRainFrequency;
};
@ -129,8 +133,17 @@ namespace MWWorld
// Possible effect on movement speed?
bool mIsStorm;
// How fast does rain travel down?
// In Morrowind.ini this is set globally, but we may want to change it per weather later.
float mRainSpeed;
// How often does a new rain mesh spawn?
float mRainFrequency;
std::string mParticleEffect;
std::string mRainEffect;
// Note: For Weather Blight, there is a "Disease Chance" (=0.1) setting. But according to MWSFD this feature
// is broken in the vanilla game and was disabled.
};
@ -188,6 +201,7 @@ namespace MWWorld
private:
float mHour;
float mWindSpeed;
bool mIsStorm;
MWWorld::Fallback* mFallback;
void setFallbackWeather(Weather& weather,const std::string& name);
MWRender::RenderingManager* mRendering;
@ -226,6 +240,7 @@ namespace MWWorld
typedef std::map<std::string,std::vector<char> > RegionModMap;
RegionModMap mRegionMods;
float mRainSpeed;
float mSunriseTime;
float mSunsetTime;
float mSunriseDuration;