1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-29 03:45:32 +00:00
openmw-tes3mp/apps/openmw/mwrender/sky.cpp

638 lines
18 KiB
C++
Raw Normal View History

#include "sky.hpp"
#include <osg/Transform>
#include <osg/Geode>
#include <osg/Depth>
#include <osg/Geometry>
#include <osg/Material>
#include <osg/Geometry>
#include <osg/PositionAttitudeTransform>
#include <osg/io_utils>
#include <osgUtil/CullVisitor>
2012-07-11 07:08:55 +00:00
#include <boost/lexical_cast.hpp>
#include <openengine/misc/rng.hpp>
#include <components/misc/resourcehelpers.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/resource/texturemanager.hpp>
#include <components/vfs/manager.hpp>
#include <components/sceneutil/util.hpp>
#include <components/sceneutil/statesetcontroller.hpp>
2012-07-13 07:13:12 +00:00
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
2013-03-17 13:22:30 +00:00
#include "../mwworld/fallback.hpp"
2012-04-03 13:13:47 +00:00
#include "renderconst.hpp"
2012-04-06 15:21:56 +00:00
#include "renderingmanager.hpp"
2012-03-16 18:02:33 +00:00
namespace
{
osg::StateSet* getWritableStateSet(osg::Node* node)
{
osg::StateSet* stateset = node->getOrCreateStateSet();
osg::ref_ptr<osg::StateSet> cloned = static_cast<osg::StateSet*>(stateset->clone(osg::CopyOp::SHALLOW_COPY));
node->setStateSet(cloned);
return cloned;
}
osg::ref_ptr<osg::Material> createAlphaTrackingUnlitMaterial()
{
osg::ref_ptr<osg::Material> mat = new osg::Material;
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f));
mat->setColorMode(osg::Material::DIFFUSE);
return mat;
}
2012-07-13 07:13:12 +00:00
osg::ref_ptr<osg::Material> createUnlitMaterial()
{
osg::ref_ptr<osg::Material> mat = new osg::Material;
mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
mat->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f));
mat->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f));
mat->setColorMode(osg::Material::OFF);
return mat;
}
2012-07-13 07:13:12 +00:00
osg::ref_ptr<osg::Geometry> createTexturedQuad()
{
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
2012-07-13 07:13:12 +00:00
osg::ref_ptr<osg::Vec3Array> verts = new osg::Vec3Array;
verts->push_back(osg::Vec3f(-0.5, -0.5, 0));
verts->push_back(osg::Vec3f(-0.5, 0.5, 0));
verts->push_back(osg::Vec3f(0.5, 0.5, 0));
verts->push_back(osg::Vec3f(0.5, -0.5, 0));
geom->setVertexArray(verts);
osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array;
texcoords->push_back(osg::Vec2f(0, 0));
texcoords->push_back(osg::Vec2f(0, 1));
texcoords->push_back(osg::Vec2f(1, 1));
texcoords->push_back(osg::Vec2f(1, 0));
2012-07-13 07:13:12 +00:00
geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX);
2012-07-20 15:08:15 +00:00
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4));
return geom;
}
2012-07-20 15:08:15 +00:00
}
namespace MWRender
{
class AtmosphereUpdater : public SceneUtil::StateSetController
2012-02-26 19:46:09 +00:00
{
public:
void setEmissionColor(osg::Vec4f emissionColor)
{
mEmissionColor = emissionColor;
}
2012-02-26 19:46:09 +00:00
protected:
virtual void setDefaults(osg::StateSet* stateset)
2012-07-13 07:13:12 +00:00
{
stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
2012-07-13 07:13:12 +00:00
}
2012-02-26 19:46:09 +00:00
virtual void apply(osg::StateSet* stateset, osg::NodeVisitor* /*nv*/)
{
osg::Material* mat = static_cast<osg::Material*>(stateset->getAttribute(osg::StateAttribute::MATERIAL));
mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor);
}
private:
osg::Vec4f mEmissionColor;
};
2012-02-26 19:46:09 +00:00
/// Transform that removes the eyepoint of the modelview matrix,
/// i.e. its children are positioned relative to the camera.
class CameraRelativeTransform : public osg::Transform
2012-04-06 13:17:54 +00:00
{
public:
CameraRelativeTransform()
{
}
2012-04-06 13:17:54 +00:00
CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop)
: osg::Transform(copy, copyop)
2012-07-13 07:13:12 +00:00
{
}
META_Node(MWRender, CameraRelativeTransform)
virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix, osg::NodeVisitor*) const
{
if (_referenceFrame==RELATIVE_RF)
{
matrix.setTrans(osg::Vec3f(0.f,0.f,0.f));
return false;
}
else // absolute
{
matrix.makeIdentity();
return true;
}
}
osg::BoundingSphere computeBound() const
{
return osg::BoundingSphere(osg::Vec3f(0,0,0), 0);
}
};
2012-02-29 09:13:25 +00:00
class DisableCullingVisitor : public osg::NodeVisitor
{
public:
DisableCullingVisitor()
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
{
}
void apply(osg::Geode &geode)
{
geode.setCullingActive(false);
}
};
2012-02-21 16:38:15 +00:00
class ModVertexAlphaVisitor : public osg::NodeVisitor
2012-02-21 16:38:15 +00:00
{
public:
ModVertexAlphaVisitor(int meshType)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mMeshType(meshType)
{
}
2012-02-21 16:38:15 +00:00
void apply(osg::Geode &geode)
{
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
{
osg::Drawable* drw = geode.getDrawable(i);
osg::Geometry* geom = drw->asGeometry();
if (!geom)
continue;
// might want to use fog coordinates instead of vertex colors so we can apply a separate fade to the diffuse alpha
// (that isn't possible now, with the diffuse tracking the vertex colors)
osg::ref_ptr<osg::Vec4Array> colors = new osg::Vec4Array(geom->getVertexArray()->getNumElements());
for (unsigned int i=0; i<colors->size(); ++i)
{
float alpha = 1.f;
if (mMeshType == 0) alpha = i%2 ? 0.f : 1.f; // this is a cylinder, so every second vertex belongs to the bottom-most row
else if (mMeshType == 1)
{
if (i>= 49 && i <= 64) alpha = 0.f; // bottom-most row
else if (i>= 33 && i <= 48) alpha = 0.25098; // second row
else alpha = 1.f;
}
else if (mMeshType == 2)
{
osg::Vec4Array* origColors = static_cast<osg::Vec4Array*>(geom->getColorArray());
alpha = ((*origColors)[i].x() == 1.f) ? 1.f : 0.f;
}
(*colors)[i] = osg::Vec4f(alpha, alpha, alpha, alpha);
}
geom->setColorArray(colors, osg::Array::BIND_PER_VERTEX);
}
}
2012-02-29 09:13:25 +00:00
private:
int mMeshType;
};
SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager)
: mSceneManager(sceneManager)
, mHour(0.0f)
, mDay(0)
, mMonth(0)
, mClouds()
, mNextClouds()
, mCloudBlendFactor(0.0f)
, mCloudOpacity(0.0f)
, mCloudSpeed(0.0f)
, mStarsOpacity(0.0f)
, mRemainingTransitionTime(0.0f)
, mGlareFade(0.0f)
, mGlare(0.0f)
, mEnabled(true)
, mSunEnabled(true)
, mMasserEnabled(true)
, mSecundaEnabled(true)
, mCreated(false)
2012-07-11 07:08:55 +00:00
, mCloudAnimationTimer(0.f)
2012-07-13 07:13:12 +00:00
, mMoonRed(false)
2014-06-25 16:20:21 +00:00
, mRainEnabled(false)
, mRainTimer(0)
, mRainSpeed(0)
, mRainFrequency(1)
, mStormDirection(0,-1,0)
, mIsStorm(false)
{
osg::ref_ptr<CameraRelativeTransform> skyroot (new CameraRelativeTransform);
skyroot->setCullingActive(false);
parentNode->addChild(skyroot);
mRootNode = skyroot;
// By default render before the world is rendered
mRootNode->getOrCreateStateSet()->setRenderBinDetails(-1, "RenderBin");
}
2012-02-29 09:13:25 +00:00
void SkyManager::create()
{
2012-07-23 16:19:34 +00:00
assert(!mCreated);
mAtmosphereDay = mSceneManager->createInstance("meshes/sky_atmosphere.nif", mRootNode);
ModVertexAlphaVisitor modAtmosphere(0);
mAtmosphereDay->accept(modAtmosphere);
2012-02-29 09:13:25 +00:00
// osg::Node* alphaBlendedRoot =
mAtmosphereUpdater = new AtmosphereUpdater;
mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater);
if (mSceneManager->getVFS()->exists("meshes/sky_night_02.nif"))
mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_02.nif", mRootNode);
else
mAtmosphereNight = mSceneManager->createInstance("meshes/sky_night_01.nif", mRootNode);
mAtmosphereNight->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
ModVertexAlphaVisitor modStars(2);
mAtmosphereNight->accept(modStars);
mAtmosphereNight->setNodeMask(0);
osg::Geode* geode = new osg::Geode;
osg::ref_ptr<osg::Geometry> sun = createTexturedQuad();
geode->addDrawable(sun);
osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform;
trans->setScale(osg::Vec3f(450,450,450));
trans->addChild(geode);
mRootNode->addChild(trans);
mSunTransform = trans;
mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode);
ModVertexAlphaVisitor modClouds(1);
mCloudNode->accept(modClouds);
osg::ref_ptr<osg::Texture2D> sunTex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds",
osg::Texture::CLAMP, osg::Texture::CLAMP);
trans->getOrCreateStateSet()->setTextureAttributeAndModes(0, sunTex, osg::StateAttribute::ON);
trans->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON);
mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
depth->setWriteMask(false);
mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON);
mRootNode->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
mCreated = true;
}
SkyManager::~SkyManager()
{
2014-06-25 16:20:21 +00:00
clearRain();
}
2012-02-21 16:38:15 +00:00
int SkyManager::getMasserPhase() const
{
return 0;
if (!mCreated) return 0;
//return mMasser->getPhaseInt();
2012-02-21 16:38:15 +00:00
}
int SkyManager::getSecundaPhase() const
{
return 0;
if (!mCreated) return 0;
//return mSecunda->getPhaseInt();
2012-02-21 16:38:15 +00:00
}
2014-06-25 16:20:21 +00:00
void SkyManager::clearRain()
{
}
void SkyManager::updateRain(float dt)
{
}
void SkyManager::update(float duration)
2012-02-26 17:21:11 +00:00
{
if (!mEnabled) return;
//const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback();
2012-08-15 11:17:35 +00:00
//if (mIsStorm)
// mCloudNode->setOrientation(Ogre::Vector3::UNIT_Y.getRotationTo(mStormDirection));
//else
// mCloudNode->setOrientation(Ogre::Quaternion::IDENTITY);
2014-06-25 16:20:21 +00:00
updateRain(duration);
// UV Scroll the clouds
mCloudAnimationTimer += duration * mCloudSpeed;
2012-02-29 09:13:25 +00:00
2012-02-26 19:46:09 +00:00
/// \todo improve this
//mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
//mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
2012-02-29 09:13:25 +00:00
//mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1));
//mMasser->setColour (ColourValue(1,1,1,1));
2012-02-26 19:46:09 +00:00
if (mSunEnabled)
{
2012-07-11 07:08:55 +00:00
// take 1/10 sec for fading the glare effect from invisible to full
if (mGlareFade > mGlare)
{
2012-07-11 07:08:55 +00:00
mGlareFade -= duration*10;
if (mGlareFade < mGlare) mGlareFade = mGlare;
}
else if (mGlareFade < mGlare)
{
2012-07-11 07:08:55 +00:00
mGlareFade += duration*10;
if (mGlareFade > mGlare) mGlareFade = mGlare;
}
// increase the strength of the sun glare effect depending
// on how directly the player is looking at the sun
/*
2012-02-26 19:46:09 +00:00
Vector3 sun = mSunGlare->getPosition();
Vector3 cam = mCamera->getRealDirection();
2012-02-26 19:46:09 +00:00
const Degree angle = sun.angleBetween( cam );
float val = 1- (angle.valueDegrees() / 180.f);
val = (val*val*val*val)*6;
mSunGlare->setSize(val * mGlareFade);
*/
2012-02-26 19:46:09 +00:00
}
2012-02-29 09:13:25 +00:00
//mSunGlare->setVisible(mSunEnabled);
//mSun->setVisible(mSunEnabled);
//mMasser->setVisible(mMasserEnabled);
//mSecunda->setVisible(mSecundaEnabled);
2012-03-15 18:49:15 +00:00
2012-03-16 18:02:33 +00:00
// rotate the stars by 360 degrees every 4 days
//mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f)));
}
void SkyManager::setEnabled(bool enabled)
{
if (enabled && !mCreated)
create();
if (!enabled)
clearRain();
2014-06-25 16:20:21 +00:00
mRootNode->setNodeMask(enabled ? ~((unsigned int)(0)) : 0);
mEnabled = enabled;
}
void SkyManager::setMoonColour (bool red)
{
2012-07-13 07:13:12 +00:00
mMoonRed = red;
2012-02-21 21:11:41 +00:00
}
void SkyManager::setWeather(const MWWorld::WeatherResult& weather)
{
if (!mCreated) return;
2012-07-06 08:31:48 +00:00
2014-06-25 16:20:21 +00:00
mRainEffect = weather.mRainEffect;
mRainEnabled = !mRainEffect.empty();
mRainFrequency = weather.mRainFrequency;
mRainSpeed = weather.mRainSpeed;
mIsStorm = weather.mIsStorm;
2014-06-25 16:20:21 +00:00
if (mCurrentParticleEffect != weather.mParticleEffect)
{
mCurrentParticleEffect = weather.mParticleEffect;
if (mCurrentParticleEffect.empty())
{
if (mParticleEffect)
mRootNode->removeChild(mParticleEffect);
mParticleEffect = NULL;
}
else
{
mParticleEffect = mSceneManager->createInstance(mCurrentParticleEffect, mRootNode);
DisableCullingVisitor visitor;
mParticleEffect->accept(visitor);
/*
for (size_t i = 0; i < mParticle->mControllers.size(); ++i)
{
if (mParticle->mControllers[i].getSource().isNull())
mParticle->mControllers[i].setSource(Ogre::ControllerManager::getSingleton().getFrameTimeSource());
}
*/
}
}
if (mClouds != weather.mCloudTexture)
{
mClouds = weather.mCloudTexture;
}
2012-02-29 09:13:25 +00:00
if (mNextClouds != weather.mNextCloudTexture)
{
mNextClouds = weather.mNextCloudTexture;
}
2012-02-29 09:13:25 +00:00
if (mCloudBlendFactor != weather.mCloudBlendFactor)
{
mCloudBlendFactor = weather.mCloudBlendFactor;
}
2012-02-29 09:13:25 +00:00
if (mCloudOpacity != weather.mCloudOpacity)
{
mCloudOpacity = weather.mCloudOpacity;
}
2012-02-29 09:13:25 +00:00
if (mCloudColour != weather.mSunColor)
{
/*
osg::Vec4f clr( weather.mSunColor.r()*0.7f + weather.mAmbientColor.r()*0.7f,
weather.mSunColor.g()*0.7f + weather.mAmbientColor.g()*0.7f,
weather.mSunColor.b()*0.7f + weather.mAmbientColor.b()*0.7f, 1.f);
*/
2012-07-11 07:08:55 +00:00
mCloudColour = weather.mSunColor;
}
2012-02-29 09:13:25 +00:00
if (mSkyColour != weather.mSkyColor)
2012-02-29 09:13:25 +00:00
{
mSkyColour = weather.mSkyColor;
mAtmosphereUpdater->setEmissionColor(mSkyColour);
}
2012-02-29 09:13:25 +00:00
if (mFogColour != weather.mFogColor)
{
mFogColour = weather.mFogColor;
}
2012-07-11 07:08:55 +00:00
mCloudSpeed = weather.mCloudSpeed;
2012-02-29 09:13:25 +00:00
if (weather.mNight && mStarsOpacity != weather.mNightFade)
{
if (weather.mNightFade != 0)
2012-03-03 11:26:08 +00:00
{
//sh::Factory::getInstance().setSharedParameter ("nightFade",
// sh::makeProperty<sh::FloatValue>(new sh::FloatValue(weather.mNightFade)));
2012-07-11 07:08:55 +00:00
//mStarsOpacity = weather.mNightFade;
2012-03-03 11:26:08 +00:00
}
}
2012-02-26 19:46:09 +00:00
mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0);
2012-02-26 19:46:09 +00:00
/*
2012-02-26 19:46:09 +00:00
float strength;
float timeofday_angle = std::abs(mSunGlare->getPosition().z/mSunGlare->getPosition().length());
if (timeofday_angle <= 0.44)
strength = timeofday_angle/0.44f;
else
strength = 1.f;
2012-02-29 09:13:25 +00:00
mSunGlare->setVisibility(weather.mGlareView * mGlareFade * strength);
mSun->setVisibility(weather.mGlareView * strength);
2012-02-29 09:13:25 +00:00
if (mParticle.get())
setAlpha(mParticle, weather.mEffectFade);
for (std::map<Ogre::SceneNode*, NifOgre::ObjectScenePtr>::iterator it = mRainModels.begin(); it != mRainModels.end(); ++it)
setAlpha(it->second, weather.mEffectFade);
*/
}
void SkyManager::setGlare(const float glare)
{
mGlare = glare;
}
void SkyManager::sunEnable()
{
mSunEnabled = true;
}
void SkyManager::sunDisable()
{
mSunEnabled = false;
}
void SkyManager::setStormDirection(const Ogre::Vector3 &direction)
{
mStormDirection = direction;
}
void SkyManager::setSunDirection(const osg::Vec3f& direction)
{
if (!mCreated) return;
2012-07-19 20:23:07 +00:00
mSunTransform->setPosition(direction*1000.f);
osg::Quat quat;
quat.makeRotate(osg::Vec3f(0,0,1), direction);
mSunTransform->setAttitude(quat);
//mSunGlare->setPosition(direction);
}
2012-02-25 12:46:17 +00:00
void SkyManager::setMasserDirection(const Ogre::Vector3& direction)
2012-02-25 15:36:45 +00:00
{
if (!mCreated) return;
//mMasser->setPosition(direction);
2012-02-25 15:36:45 +00:00
}
void SkyManager::setSecundaDirection(const Ogre::Vector3& direction)
2012-02-25 15:36:45 +00:00
{
if (!mCreated) return;
//mSecunda->setPosition(direction);
2012-02-25 15:36:45 +00:00
}
void SkyManager::masserEnable()
{
mMasserEnabled = true;
}
void SkyManager::secundaEnable()
{
mSecundaEnabled = true;
}
void SkyManager::masserDisable()
{
mMasserEnabled = false;
}
void SkyManager::secundaDisable()
{
mSecundaEnabled = false;
}
2012-07-13 07:13:12 +00:00
void SkyManager::setLightningStrength(const float factor)
2012-02-25 12:46:17 +00:00
{
if (!mCreated) return;
/*
2012-02-25 12:46:17 +00:00
if (factor > 0.f)
{
2012-07-13 07:13:12 +00:00
mLightning->setDiffuseColour (ColourValue(2*factor, 2*factor, 2*factor));
mLightning->setVisible(true);
2012-02-25 12:46:17 +00:00
}
else
2012-07-13 07:13:12 +00:00
mLightning->setVisible(false);
*/
2012-07-13 07:13:12 +00:00
}
2012-02-25 15:36:45 +00:00
void SkyManager::setMasserFade(const float fade)
{
2012-04-11 16:53:13 +00:00
if (!mCreated) return;
//mMasser->setVisibility(fade);
2012-02-25 15:36:45 +00:00
}
void SkyManager::setSecundaFade(const float fade)
{
2012-04-11 16:53:13 +00:00
if (!mCreated) return;
//mSecunda->setVisibility(fade);
2012-02-25 15:36:45 +00:00
}
void SkyManager::setHour(double hour)
{
mHour = static_cast<float>(hour);
}
void SkyManager::setDate(int day, int month)
{
mDay = day;
mMonth = month;
}
2012-07-19 20:23:07 +00:00
void SkyManager::setGlareEnabled (bool enabled)
{
if (!mCreated || !mEnabled)
2012-07-19 20:23:07 +00:00
return;
//mSunGlare->setVisible (mSunEnabled && enabled);
2012-07-19 20:23:07 +00:00
}
}