Merge remote-tracking branch 'origin/master'

openmw-37
Marc Zinnschlag 9 years ago
commit ab2df963e9

@ -774,7 +774,7 @@ namespace MWClass
return ref->mBase->mAiData.mFight; 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<ESM::Creature> *ref = ptr.get<ESM::Creature>(); MWWorld::LiveCellRef<ESM::Creature> *ref = ptr.get<ESM::Creature>();
scale *= ref->mBase->mScale; scale *= ref->mBase->mScale;

@ -133,7 +133,8 @@ namespace MWClass
virtual int getBaseFightRating(const MWWorld::Ptr &ptr) const; 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
}; };
} }

@ -1012,8 +1012,12 @@ namespace MWClass
+ shield; + 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<ESM::NPC> *ref = MWWorld::LiveCellRef<ESM::NPC> *ref =
ptr.get<ESM::NPC>(); ptr.get<ESM::NPC>();

@ -109,7 +109,8 @@ namespace MWClass
/// \param actor Actor that is resposible for the ID being applied to \a ptr. /// \param actor Actor that is resposible for the ID being applied to \a ptr.
/// \return Any effect? /// \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; 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. ///< Inform actor \a ptr that a skill use has succeeded.

@ -110,12 +110,14 @@ void Actor::updateScale()
float scale = mPtr.getCellRef().getScale(); float scale = mPtr.getCellRef().getScale();
osg::Vec3f scaleVec(scale,scale,scale); osg::Vec3f scaleVec(scale,scale,scale);
if (!mPtr.getClass().isNpc()) mPtr.getClass().adjustScale(mPtr, scaleVec, false);
mPtr.getClass().adjustScale(mPtr, scaleVec);
mScale = scaleVec; mScale = scaleVec;
mShape->setLocalScaling(toBullet(mScale)); mShape->setLocalScaling(toBullet(mScale));
scaleVec = osg::Vec3f(scale,scale,scale);
mPtr.getClass().adjustScale(mPtr, scaleVec, true);
mRenderingScale = scaleVec;
updatePosition(); updatePosition();
} }
@ -124,6 +126,11 @@ osg::Vec3f Actor::getHalfExtents() const
return osg::componentMultiply(mHalfExtents, mScale); return osg::componentMultiply(mHalfExtents, mScale);
} }
osg::Vec3f Actor::getRenderingHalfExtents() const
{
return osg::componentMultiply(mHalfExtents, mRenderingScale);
}
void Actor::setInertialForce(const osg::Vec3f &force) void Actor::setInertialForce(const osg::Vec3f &force)
{ {
mForce = force; mForce = force;

@ -66,10 +66,17 @@ namespace MWPhysics
void updatePosition(); void updatePosition();
/** /**
* Returns the (scaled) half extents * Returns the half extents of the collision body (scaled according to collision scale)
*/ */
osg::Vec3f getHalfExtents() const; 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 * Sets the current amount of inertial force (incl. gravity) affecting this physic actor
*/ */
@ -118,6 +125,7 @@ namespace MWPhysics
osg::Quat mRotation; osg::Quat mRotation;
osg::Vec3f mScale; osg::Vec3f mScale;
osg::Vec3f mRenderingScale;
osg::Vec3f mPosition; osg::Vec3f mPosition;
osg::Vec3f mForce; osg::Vec3f mForce;

@ -261,7 +261,7 @@ namespace MWPhysics
static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>() static const float fSwimHeightScale = MWBase::Environment::get().getWorld()->getStore().get<ESM::GameSetting>()
.find("fSwimHeightScale")->getFloat(); .find("fSwimHeightScale")->getFloat();
float swimlevel = waterlevel + halfExtents.z() - (halfExtents.z() * 2 * fSwimHeightScale); float swimlevel = waterlevel + halfExtents.z() - (physicActor->getRenderingHalfExtents().z() * 2 * fSwimHeightScale);
ActorTracer tracer; ActorTracer tracer;
osg::Vec3f inertia = physicActor->getInertialForce(); osg::Vec3f inertia = physicActor->getInertialForce();
@ -878,6 +878,15 @@ namespace MWPhysics
return osg::Vec3f(); 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 class ContactTestResultCallback : public btCollisionWorld::ContactResultCallback
{ {
public: public:

@ -110,6 +110,9 @@ namespace MWPhysics
/// Get physical half extents (scaled) of the given actor. /// Get physical half extents (scaled) of the given actor.
osg::Vec3f getHalfExtents(const MWWorld::Ptr& 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 /// Queues velocity movement for a Ptr. If a Ptr is already queued, its velocity will
/// be overwritten. Valid until the next call to applyQueuedMovement. /// be overwritten. Valid until the next call to applyQueuedMovement.
void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity); void queueObjectMovement(const MWWorld::Ptr &ptr, const osg::Vec3f &velocity);

@ -287,7 +287,7 @@ namespace MWRender
void InventoryPreview::onSetup() void InventoryPreview::onSetup()
{ {
osg::Vec3f scale (1.f, 1.f, 1.f); osg::Vec3f scale (1.f, 1.f, 1.f);
mCharacter.getClass().adjustScale(mCharacter, scale); mCharacter.getClass().adjustScale(mCharacter, scale, true);
mNode->setScale(scale); mNode->setScale(scale);

@ -31,6 +31,8 @@
#include <components/esm/loadcell.hpp> #include <components/esm/loadcell.hpp>
#include "../mwworld/fallback.hpp"
#include "sky.hpp" #include "sky.hpp"
#include "effectmanager.hpp" #include "effectmanager.hpp"
#include "npcanimation.hpp" #include "npcanimation.hpp"
@ -199,6 +201,10 @@ namespace MWRender
updateProjectionMatrix(); updateProjectionMatrix();
mStateUpdater->setFogEnd(mViewDistance); 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("near", mNearClip));
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance));
} }
@ -349,13 +355,14 @@ namespace MWRender
{ {
osg::Vec4f color = SceneUtil::colourFromRGB(cell->mAmbi.mFog); 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; mFogDepth = fogDepth;
mFogColor = color; mFogColor = color;
mUnderwaterFog = underwaterFog;
} }
SkyManager* RenderingManager::getSkyManager() SkyManager* RenderingManager::getSkyManager()
@ -378,9 +385,9 @@ namespace MWRender
mCamera->getPosition(focal, cameraPos); mCamera->getPosition(focal, cameraPos);
if (mWater->isUnderwater(cameraPos)) if (mWater->isUnderwater(cameraPos))
{ {
setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); setFogColor(mUnderwaterColor * mUnderwaterWeight + mFogColor * (1.f-mUnderwaterWeight));
mStateUpdater->setFogStart(0.f); mStateUpdater->setFogStart(mViewDistance * (1 - mUnderwaterFog));
mStateUpdater->setFogEnd(1000); mStateUpdater->setFogEnd(mViewDistance);
} }
else else
{ {

@ -79,7 +79,7 @@ namespace MWRender
void configureAmbient(const ESM::Cell* cell); void configureAmbient(const ESM::Cell* cell);
void configureFog(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 addCell(const MWWorld::CellStore* store);
void removeCell(const MWWorld::CellStore* store); void removeCell(const MWWorld::CellStore* store);
@ -192,6 +192,10 @@ namespace MWRender
osg::ref_ptr<StateUpdater> mStateUpdater; osg::ref_ptr<StateUpdater> mStateUpdater;
float mFogDepth; float mFogDepth;
osg::Vec4f mUnderwaterColor;
float mUnderwaterWeight;
float mUnderwaterFog;
float mUnderwaterIndoorFog;
osg::Vec4f mFogColor; osg::Vec4f mFogColor;
osg::Vec4f mAmbientColor; osg::Vec4f mAmbientColor;

@ -13,6 +13,7 @@
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <osg/FrontFace> #include <osg/FrontFace>
#include <osg/Shader> #include <osg/Shader>
#include <osg/GLExtensions>
#include <osgDB/ReadFile> #include <osgDB/ReadFile>
@ -144,14 +145,18 @@ class ClipCullNode : public osg::Group
osg::RefMatrix* modelViewMatrix = new osg::RefMatrix(*cv->getModelViewMatrix()); 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 // 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) if (mCullPlane->intersect(osg::BoundingSphere(osg::Vec3d(0,0,eyePoint.z()), 0)) > 0)
{ {
modelViewMatrix->preMultScale(osg::Vec3(1,1,-1)); 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); cv->pushModelViewMatrix(modelViewMatrix, osg::Transform::RELATIVE_RF);
traverse(node, nv); traverse(node, nv);
@ -167,7 +172,7 @@ public:
{ {
addCullCallback (new PlaneCullCallback(&mPlane)); addCullCallback (new PlaneCullCallback(&mPlane));
mClipNodeTransform = new osg::PositionAttitudeTransform; mClipNodeTransform = new osg::Group;
mClipNodeTransform->addCullCallback(new FlipCallback(&mPlane)); mClipNodeTransform->addCullCallback(new FlipCallback(&mPlane));
addChild(mClipNodeTransform); addChild(mClipNodeTransform);
@ -183,12 +188,12 @@ public:
mPlane = plane; mPlane = plane;
mClipNode->getClipPlaneList().clear(); 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); mClipNode->setStateSetModes(*getOrCreateStateSet(), osg::StateAttribute::ON);
} }
private: private:
osg::ref_ptr<osg::PositionAttitudeTransform> mClipNodeTransform; osg::ref_ptr<osg::Group> mClipNodeTransform;
osg::ref_ptr<osg::ClipNode> mClipNode; osg::ref_ptr<osg::ClipNode> mClipNode;
osg::Plane mPlane; osg::Plane mPlane;
@ -204,6 +209,36 @@ public:
} }
}; };
/// 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
{
public:
virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
{
osgUtil::CullVisitor* cv = static_cast<osgUtil::CullVisitor*>(nv);
const float fudge = 0.2;
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<osg::Shader> readShader (osg::Shader::Type type, const std::string& file, const std::map<std::string, std::string>& defineMap = std::map<std::string, std::string>()) osg::ref_ptr<osg::Shader> readShader (osg::Shader::Type type, const std::string& file, const std::map<std::string, std::string>& defineMap = std::map<std::string, std::string>())
{ {
osg::ref_ptr<osg::Shader> shader (new osg::Shader(type)); osg::ref_ptr<osg::Shader> shader (new osg::Shader(type));
@ -389,6 +424,28 @@ private:
osg::ref_ptr<osg::Node> mScene; osg::ref_ptr<osg::Node> 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
{
static bool supported = osg::isGLExtensionOrVersionSupported(renderInfo.getState()->getContextID(), "GL_ARB_depth_clamp", 3.3);
if (!supported)
{
drawable->drawImplementation(renderInfo);
return;
}
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, Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem *resourceSystem, osgUtil::IncrementalCompileOperation *ico,
const MWWorld::Fallback* fallback, const std::string& resourcePath) const MWWorld::Fallback* fallback, const std::string& resourcePath)
: mParent(parent) : mParent(parent)
@ -402,6 +459,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback)); mSimulation.reset(new RippleSimulation(parent, resourceSystem, fallback));
osg::ref_ptr<osg::Geometry> waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); osg::ref_ptr<osg::Geometry> waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900);
waterGeom->setDrawCallback(new DepthClampCallback);
mWaterGeode = new osg::Geode; mWaterGeode = new osg::Geode;
mWaterGeode->addDrawable(waterGeom); mWaterGeode->addDrawable(waterGeom);
@ -412,6 +470,7 @@ Water::Water(osg::Group *parent, osg::Group* sceneRoot, Resource::ResourceSystem
mWaterNode = new osg::PositionAttitudeTransform; mWaterNode = new osg::PositionAttitudeTransform;
mWaterNode->addChild(mWaterGeode); mWaterNode->addChild(mWaterGeode);
mWaterNode->addCullCallback(new FudgeCallback);
// simple water fallback for the local map // simple water fallback for the local map
osg::ref_ptr<osg::Geode> geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES)); osg::ref_ptr<osg::Geode> geode2 (osg::clone(mWaterGeode.get(), osg::CopyOp::DEEP_COPY_NODES));
@ -558,6 +617,17 @@ void Water::processChangedSettings(const Settings::CategorySettingVector& settin
Water::~Water() Water::~Water()
{ {
mParent->removeChild(mWaterNode); mParent->removeChild(mWaterNode);
if (mReflection)
{
mParent->removeChild(mReflection);
mReflection = NULL;
}
if (mRefraction)
{
mParent->removeChild(mRefraction);
mRefraction = NULL;
}
} }
void Water::setEnabled(bool enabled) void Water::setEnabled(bool enabled)

@ -287,7 +287,7 @@ namespace MWWorld
return ""; 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
{ {
} }

@ -258,7 +258,8 @@ namespace MWWorld
virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const; virtual int getEnchantmentPoints (const MWWorld::Ptr& ptr) const;
///< @return the number of enchantment points available for possible enchanting ///< @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; 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 ///< Determine whether or not \a item can be sold to an npc with the given \a npcServices

@ -72,7 +72,7 @@ namespace
{ {
float scale = ptr.getCellRef().getScale(); float scale = ptr.getCellRef().getScale();
osg::Vec3f scaleVec (scale, scale, scale); osg::Vec3f scaleVec (scale, scale, scale);
ptr.getClass().adjustScale(ptr, scaleVec); ptr.getClass().adjustScale(ptr, scaleVec, true);
rendering.scaleObject(ptr, scaleVec); rendering.scaleObject(ptr, scaleVec);
} }
} }

@ -31,17 +31,74 @@ namespace
{ {
static const int invalidWeatherID = -1; static const int invalidWeatherID = -1;
// linear interpolate between x and y based on factor.
float lerp (float x, float y, float factor) float lerp (float x, float y, float factor)
{ {
return x * (1-factor) + y * 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) osg::Vec4f lerp (const osg::Vec4f& x, const osg::Vec4f& y, float factor)
{ {
return x * (1-factor) + y * factor; return x * (1-factor) + y * factor;
} }
} }
template <typename T>
T TimeOfDayInterpolator<T>::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<float>;
template class TimeOfDayInterpolator<osg::Vec4f>;
Weather::Weather(const std::string& name, Weather::Weather(const std::string& name,
const MWWorld::Fallback& fallback, const MWWorld::Fallback& fallback,
float stormWindSpeed, float stormWindSpeed,
@ -49,24 +106,26 @@ Weather::Weather(const std::string& name,
const std::string& ambientLoopSoundID, const std::string& ambientLoopSoundID,
const std::string& particleEffect) const std::string& particleEffect)
: mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture")) : mCloudTexture(fallback.getFallbackString("Weather_" + name + "_Cloud_Texture"))
, mSkySunriseColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color")) , mSkyColor(fallback.getFallbackColour("Weather_" + name +"_Sky_Sunrise_Color"),
, mSkyDayColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color")) fallback.getFallbackColour("Weather_" + name + "_Sky_Day_Color"),
, mSkySunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color")) fallback.getFallbackColour("Weather_" + name + "_Sky_Sunset_Color"),
, mSkyNightColor(fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color")) fallback.getFallbackColour("Weather_" + name + "_Sky_Night_Color"))
, mFogSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color")) , mFogColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunrise_Color"),
, mFogDayColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color")) fallback.getFallbackColour("Weather_" + name + "_Fog_Day_Color"),
, mFogSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color")) fallback.getFallbackColour("Weather_" + name + "_Fog_Sunset_Color"),
, mFogNightColor(fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color")) fallback.getFallbackColour("Weather_" + name + "_Fog_Night_Color"))
, mAmbientSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color")) , mAmbientColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunrise_Color"),
, mAmbientDayColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color")) fallback.getFallbackColour("Weather_" + name + "_Ambient_Day_Color"),
, mAmbientSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color")) fallback.getFallbackColour("Weather_" + name + "_Ambient_Sunset_Color"),
, mAmbientNightColor(fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color")) fallback.getFallbackColour("Weather_" + name + "_Ambient_Night_Color"))
, mSunSunriseColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color")) , mSunColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunrise_Color"),
, mSunDayColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color")) fallback.getFallbackColour("Weather_" + name + "_Sun_Day_Color"),
, mSunSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color")) fallback.getFallbackColour("Weather_" + name + "_Sun_Sunset_Color"),
, mSunNightColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color")) fallback.getFallbackColour("Weather_" + name + "_Sun_Night_Color"))
, mLandFogDayDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth")) , mLandFogDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Day_Depth"),
, mLandFogNightDepth(fallback.getFallbackFloat("Weather_" + name + "_Land_Fog_Night_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")) , mSunDiscSunsetColor(fallback.getFallbackColour("Weather_" + name + "_Sun_Disc_Sunset_Color"))
, mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed")) , mWindSpeed(fallback.getFallbackFloat("Weather_" + name + "_Wind_Speed"))
, mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed")) , mCloudSpeed(fallback.getFallbackFloat("Weather_" + name + "_Cloud_Speed"))
@ -432,12 +491,13 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo
, mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration")) , mSunriseDuration(fallback.getFallbackFloat("Weather_Sunrise_Duration"))
, mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration")) , mSunsetDuration(fallback.getFallbackFloat("Weather_Sunset_Duration"))
, mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time")) , mSunPreSunsetTime(fallback.getFallbackFloat("Weather_Sun_Pre-Sunset_Time"))
, mNightStart(mSunsetTime + mSunsetDuration) , mNightFade(0, 0, 0, 1)
, mNightEnd(mSunriseTime - 0.5f)
, mDayStart(mSunriseTime + mSunriseDuration)
, mDayEnd(mSunsetTime)
, mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes")) , mHoursBetweenWeatherChanges(fallback.getFallbackFloat("Weather_Hours_Between_Weather_Changes"))
, mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity")) , mRainSpeed(fallback.getFallbackFloat("Weather_Precip_Gravity"))
, mUnderwaterFog(fallback.getFallbackFloat("Water_UnderwaterSunriseFog"),
fallback.getFallbackFloat("Water_UnderwaterDayFog"),
fallback.getFallbackFloat("Water_UnderwaterSunsetFog"),
fallback.getFallbackFloat("Water_UnderwaterNightFog"))
, mWeatherSettings() , mWeatherSettings()
, mMasser("Masser", fallback) , mMasser("Masser", fallback)
, mSecunda("Secunda", fallback) , mSecunda("Secunda", fallback)
@ -457,6 +517,12 @@ WeatherManager::WeatherManager(MWRender::RenderingManager& rendering, const MWWo
, mAmbientSound() , mAmbientSound()
, mPlayingSoundID() , mPlayingSoundID()
{ {
mTimeSettings.mNightStart = mSunsetTime + mSunsetDuration;
mTimeSettings.mNightEnd = mSunriseTime - 0.5f;
mTimeSettings.mDayStart = mSunriseTime + mSunriseDuration;
mTimeSettings.mDayEnd = mSunsetTime;
mTimeSettings.mSunriseTime = mSunriseTime;
mWeatherSettings.reserve(10); mWeatherSettings.reserve(10);
addWeather("Clear", fallback); // 0 addWeather("Clear", fallback); // 0
addWeather("Cloudy", fallback); // 1 addWeather("Cloudy", fallback); // 1
@ -589,7 +655,7 @@ void WeatherManager::update(float duration, bool paused)
} }
// disable sun during night // disable sun during night
if (time.getHour() >= mNightStart || time.getHour() <= mSunriseTime) if (time.getHour() >= mTimeSettings.mNightStart || time.getHour() <= mSunriseTime)
mRendering.getSkyManager()->sunDisable(); mRendering.getSkyManager()->sunDisable();
else else
mRendering.getSkyManager()->sunEnable(); mRendering.getSkyManager()->sunEnable();
@ -600,10 +666,10 @@ void WeatherManager::update(float duration, bool paused)
{ {
// Shift times into a 24-hour window beginning at mSunriseTime... // Shift times into a 24-hour window beginning at mSunriseTime...
float adjustedHour = time.getHour(); float adjustedHour = time.getHour();
float adjustedNightStart = mNightStart; float adjustedNightStart = mTimeSettings.mNightStart;
if ( time.getHour() < mSunriseTime ) if ( time.getHour() < mSunriseTime )
adjustedHour += 24.f; adjustedHour += 24.f;
if ( mNightStart < mSunriseTime ) if ( mTimeSettings.mNightStart < mSunriseTime )
adjustedNightStart += 24.f; adjustedNightStart += 24.f;
const bool is_night = adjustedHour >= adjustedNightStart; const bool is_night = adjustedHour >= adjustedNightStart;
@ -624,6 +690,8 @@ void WeatherManager::update(float duration, bool paused)
mRendering.setSunDirection( final * -1 ); mRendering.setSunDirection( final * -1 );
} }
float underwaterFog = mUnderwaterFog.getValue(time.getHour(), mTimeSettings);
float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2; float peakHour = mSunriseTime + (mSunsetTime - mSunriseTime) / 2;
if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime) if (time.getHour() < mSunriseTime || time.getHour() > mSunsetTime)
mRendering.getSkyManager()->setGlareTimeOfDayFade(0); mRendering.getSkyManager()->setGlareTimeOfDayFade(0);
@ -635,7 +703,7 @@ void WeatherManager::update(float duration, bool paused)
mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time)); mRendering.getSkyManager()->setMasserState(mMasser.calculateState(time));
mRendering.getSkyManager()->setSecundaState(mSecunda.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.setAmbientColour(mResult.mAmbientColor);
mRendering.setSunColour(mResult.mSunColor); mRendering.setSunColour(mResult.mSunColor);
@ -697,7 +765,7 @@ bool WeatherManager::isDark() const
TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp(); TimeStamp time = MWBase::Environment::get().getWorld()->getTimeStamp();
bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior() bool exterior = (MWBase::Environment::get().getWorld()->isCellExterior()
|| MWBase::Environment::get().getWorld()->isCellQuasiExterior()); || 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) void WeatherManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
@ -975,81 +1043,14 @@ inline void WeatherManager::calculateResult(const int weatherID, const float gam
mResult.mParticleEffect = current.mParticleEffect; mResult.mParticleEffect = current.mParticleEffect;
mResult.mRainEffect = current.mRainEffect; 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 mResult.mFogDepth = current.mLandFogDepth.getValue(gameHour, mTimeSettings);
// night mResult.mFogColor = current.mFogColor.getValue(gameHour, mTimeSettings);
if (gameHour <= mNightEnd || gameHour >= mNightStart + 1) mResult.mAmbientColor = current.mAmbientColor.getValue(gameHour, mTimeSettings);
{ mResult.mSunColor = current.mSunColor.getValue(gameHour, mTimeSettings);
mResult.mFogColor = current.mFogNightColor; mResult.mSkyColor = current.mSkyColor.getValue(gameHour, mTimeSettings);
mResult.mAmbientColor = current.mAmbientNightColor; mResult.mNightFade = mNightFade.getValue(gameHour, mTimeSettings);
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;
}
}
if (gameHour >= mSunsetTime - mSunPreSunsetTime) if (gameHour >= mSunsetTime - mSunPreSunsetTime)
{ {

@ -34,6 +34,33 @@ namespace MWWorld
class Fallback; class Fallback;
class TimeStamp; 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 <typename T>
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) /// Defines a single weather setting (according to INI)
class Weather class Weather
{ {
@ -47,33 +74,17 @@ namespace MWWorld
std::string mCloudTexture; std::string mCloudTexture;
// Sky (atmosphere) colors // Sky (atmosphere) color
osg::Vec4f mSkySunriseColor; TimeOfDayInterpolator<osg::Vec4f> mSkyColor;
osg::Vec4f mSkyDayColor; // Fog color
osg::Vec4f mSkySunsetColor; TimeOfDayInterpolator<osg::Vec4f> mFogColor;
osg::Vec4f mSkyNightColor; // Ambient lighting color
TimeOfDayInterpolator<osg::Vec4f> mAmbientColor;
// Fog colors // Sun (directional) lighting color
osg::Vec4f mFogSunriseColor; TimeOfDayInterpolator<osg::Vec4f> mSunColor;
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;
// Fog depth/density // Fog depth/density
float mLandFogDayDepth; TimeOfDayInterpolator<float> mLandFogDepth;
float mLandFogNightDepth;
// Color modulation for the sun itself during sunset // Color modulation for the sun itself during sunset
osg::Vec4f mSunDiscSunsetColor; osg::Vec4f mSunDiscSunsetColor;
@ -243,12 +254,18 @@ namespace MWWorld
float mSunriseDuration; float mSunriseDuration;
float mSunsetDuration; float mSunsetDuration;
float mSunPreSunsetTime; float mSunPreSunsetTime;
float mNightStart;
float mNightEnd; TimeOfDaySettings mTimeSettings;
float mDayStart;
float mDayEnd; // fading of night skydome
TimeOfDayInterpolator<float> mNightFade;
float mHoursBetweenWeatherChanges; float mHoursBetweenWeatherChanges;
float mRainSpeed; float mRainSpeed;
// underwater fog not really related to weather, but we handle it here because it's convenient
TimeOfDayInterpolator<float> mUnderwaterFog;
std::vector<Weather> mWeatherSettings; std::vector<Weather> mWeatherSettings;
MoonModel mMasser; MoonModel mMasser;
MoonModel mSecunda; MoonModel mSecunda;

@ -1969,7 +1969,7 @@ namespace MWWorld
{ {
osg::Vec3f pos (object.getRefData().getPosition().asVec3()); 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); return isUnderwater(object.getCell(), pos);
} }

Loading…
Cancel
Save