From 13a1ba0aab499d185b5e275082d6234556bdde4d Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 15 Apr 2015 18:50:50 +0200 Subject: [PATCH] Moon rendering --- apps/openmw/engine.cpp | 6 - apps/openmw/mwrender/sky.cpp | 363 ++++++++++++++++++++++++++++---- apps/openmw/mwrender/sky.hpp | 13 +- apps/openmw/mwworld/weather.cpp | 25 ++- 4 files changed, 342 insertions(+), 65 deletions(-) diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 59504048a..f6f2ba9bb 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -6,8 +6,6 @@ #include #include -#include - #include #include @@ -494,11 +492,7 @@ void OMW::Engine::go() mViewer.addEventHandler(new osgViewer::StatsHandler); osg::Timer timer; - //osgUtil::IncrementalCompileOperation* ico = new osgUtil::IncrementalCompileOperation; - //ico->compileAllForNextFrame(1); - //mViewer.setRealizeOperation(ico); mViewer.realize(); - std::cout << "realize took " << timer.time_m() << std::endl; osg::Timer frameTimer; while (!mViewer.done()) { diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index a4fd17172..1ac7ca10b 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -12,6 +12,9 @@ #include +#include +#include + #include #include @@ -57,7 +60,7 @@ namespace return mat; } - osg::ref_ptr createTexturedQuad() + osg::ref_ptr createTexturedQuad(int numUvSets=1) { osg::ref_ptr geom = new osg::Geometry; @@ -75,7 +78,8 @@ namespace texcoords->push_back(osg::Vec2f(1, 1)); texcoords->push_back(osg::Vec2f(1, 0)); - geom->setTexCoordArray(0, texcoords, osg::Array::BIND_PER_VERTEX); + for (int i=0; isetTexCoordArray(i, texcoords, osg::Array::BIND_PER_VERTEX); geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,4)); @@ -111,6 +115,52 @@ private: osg::Vec4f mEmissionColor; }; +class CloudUpdater : public SceneUtil::StateSetUpdater +{ +public: + void setAnimationTimer(float timer); + + void setTexture(osg::ref_ptr texture) + { + mTexture = texture; + } + void setEmissionColor(osg::Vec4f emissionColor) + { + mEmissionColor = emissionColor; + } + void setOpacity(float opacity) + { + mOpacity = opacity; + } + +protected: + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setTextureAttributeAndModes(0, new osg::TexMat, osg::StateAttribute::ON); + stateset->setAttribute(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor *nv) + { + mAnimationTimer = nv->getFrameStamp()->getSimulationTime()*0.05; + osg::TexMat* texMat = static_cast(stateset->getTextureAttribute(0, osg::StateAttribute::TEXMAT)); + texMat->setMatrix(osg::Matrix::translate(osg::Vec3f(mAnimationTimer, mAnimationTimer, 0.f))); + + stateset->setTextureAttributeAndModes(0, mTexture, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setEmission(osg::Material::FRONT_AND_BACK, mEmissionColor); + + // FIXME: handle opacity, will have to resort to either shaders or multitexturing? diffuse alpha is in use by the vertex colors already + } + +private: + float mAnimationTimer; + osg::ref_ptr mTexture; + osg::Vec4f mEmissionColor; + float mOpacity; +}; + /// Transform that removes the eyepoint of the modelview matrix, /// i.e. its children are positioned relative to the camera. class CameraRelativeTransform : public osg::Transform @@ -118,6 +168,10 @@ class CameraRelativeTransform : public osg::Transform public: CameraRelativeTransform() { + // Culling works in node-local space, not in camera space, so we can't cull this node correctly + // That's not a problem though, children of this node can be culled just fine + // Just make sure you do not place a CameraRelativeTransform deep in the scene graph + setCullingActive(false); } CameraRelativeTransform(const CameraRelativeTransform& copy, const osg::CopyOp& copyop) @@ -211,6 +265,219 @@ private: int mMeshType; }; +class CelestialBody +{ +public: + CelestialBody(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor = 1.f, int numUvSets=1) + : mSceneManager(sceneManager) + { + mGeode = new osg::Geode; + osg::ref_ptr geom = createTexturedQuad(numUvSets); + mGeode->addDrawable(geom); + mTransform = new osg::PositionAttitudeTransform; + mTransform->setScale(osg::Vec3f(450,450,450) * scaleFactor); + mTransform->addChild(mGeode); + + parentNode->addChild(mTransform); + } + + void setDirection(const osg::Vec3f& direction) + { + mTransform->setPosition(direction*1000.f); + + osg::Quat quat; + quat.makeRotate(osg::Vec3f(0,0,1), direction); + mTransform->setAttitude(quat); + } + + void setVisible(bool visible) + { + mTransform->setNodeMask(visible ? ~0 : 0); + } + +protected: + osg::ref_ptr mTransform; + osg::ref_ptr mGeode; + Resource::SceneManager* mSceneManager; + +}; + +class Sun : public CelestialBody +{ +public: + Sun(osg::Group* parentNode, Resource::SceneManager* sceneManager) + : CelestialBody(parentNode, sceneManager, 1.f, 1) + { + osg::ref_ptr tex = mSceneManager->getTextureManager()->getTexture2D("textures/tx_sun_05.dds", + osg::Texture::CLAMP, osg::Texture::CLAMP); + + mTransform->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex, osg::StateAttribute::ON); + mTransform->getOrCreateStateSet()->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON); + } +}; + +class Moon : public CelestialBody +{ +public: + enum Type + { + Type_Masser = 0, + Type_Secunda + }; + + Moon(osg::Group* parentNode, Resource::SceneManager* sceneManager, float scaleFactor, Type type) + : CelestialBody(parentNode, sceneManager, scaleFactor, 2) + , mPhase(Phase_Unspecified) + , mType(type) + { + mUpdater = new MoonUpdater; + mGeode->addUpdateCallback(mUpdater); + + setPhase(Phase_WaxingCrescent); + } + + enum Phase + { + Phase_New = 0, + Phase_WaxingCrescent, + Phase_WaxingHalf, + Phase_WaxingGibbous, + Phase_Full, + Phase_WaningGibbous, + Phase_WaningHalf, + Phase_WaningCrescent, + Phase_Unspecified + }; + + void setTextures(const std::string& phaseTex, const std::string& circleTex) + { + osg::ref_ptr stateset = new osg::StateSet; + + osg::ref_ptr moonTex = mSceneManager->getTextureManager()->getTexture2D(circleTex, + osg::Texture::CLAMP, osg::Texture::CLAMP); + + // stage 0: render the moon circle in atmosphere color + stateset->setTextureAttributeAndModes(0, moonTex, osg::StateAttribute::ON); + + osg::ref_ptr texEnv = new osg::TexEnvCombine; + texEnv->setSource0_RGB(osg::TexEnvCombine::CONSTANT); + texEnv->setConstantColor(osg::Vec4f(0.f, 0.f, 0.f, 1.f)); // atmospherecolor + + stateset->setTextureAttributeAndModes(0, texEnv, osg::StateAttribute::ON); + + // stage 1: render the "lit" side of the moon blended over the circle + osg::ref_ptr moonTex2 = mSceneManager->getTextureManager()->getTexture2D(phaseTex, + osg::Texture::CLAMP, osg::Texture::CLAMP); + + stateset->setTextureAttributeAndModes(1, moonTex2, osg::StateAttribute::ON); + + osg::ref_ptr texEnv2 = new osg::TexEnvCombine; + texEnv2->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv2->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv2->setSource0_Alpha(osg::TexEnvCombine::CONSTANT); + texEnv2->setConstantColor(osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + texEnv2->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + + stateset->setTextureAttributeAndModes(1, texEnv2, osg::StateAttribute::ON); + + mTransform->setStateSet(stateset); + } + + void setPhase(const Phase& phase) + { + if (mPhase == phase) + return; + mPhase = phase; + + std::string textureName = "textures/tx_"; + + if (mType == Moon::Type_Secunda) textureName += "secunda_"; + else textureName += "masser_"; + + if (phase == Moon::Phase_New) textureName += "new"; + else if (phase == Moon::Phase_WaxingCrescent) textureName += "one_wax"; + else if (phase == Moon::Phase_WaxingHalf) textureName += "half_wax"; + else if (phase == Moon::Phase_WaxingGibbous) textureName += "three_wax"; + else if (phase == Moon::Phase_WaningCrescent) textureName += "one_wan"; + else if (phase == Moon::Phase_WaningHalf) textureName += "half_wan"; + else if (phase == Moon::Phase_WaningGibbous) textureName += "three_wan"; + else if (phase == Moon::Phase_Full) textureName += "full"; + + textureName += ".dds"; + + if (mType == Moon::Type_Secunda) + setTextures(textureName, "textures/tx_mooncircle_full_s.dds"); + else + setTextures(textureName, "textures/tx_mooncircle_full_m.dds"); + } + + void setType(const Type& type) + { + mType = type; + } + + class MoonUpdater : public SceneUtil::StateSetUpdater + { + public: + MoonUpdater() + : mAlpha(1.f) + { + } + + virtual void setDefaults(osg::StateSet *stateset) + { + stateset->setAttributeAndModes(createUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + } + + virtual void apply(osg::StateSet *stateset, osg::NodeVisitor*) + { + osg::Material* mat = static_cast(stateset->getAttribute(osg::StateAttribute::MATERIAL)); + mat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, mAlpha)); + } + + void setAlpha(float alpha) + { + mAlpha = alpha; + } + + private: + float mAlpha; + }; + + void setAlpha(float alpha) + { + mUpdater->setAlpha(alpha); + } + + void setAtmosphereColor(const osg::Vec4f& color) + { + // TODO + } + + void setColor(const osg::Vec4f& color) + { + // TODO + } + + unsigned int getPhaseInt() const + { + if (mPhase == Moon::Phase_New) return 0; + else if (mPhase == Moon::Phase_WaxingCrescent) return 1; + else if (mPhase == Moon::Phase_WaningCrescent) return 1; + else if (mPhase == Moon::Phase_WaxingHalf) return 2; + else if (mPhase == Moon::Phase_WaningHalf) return 2; + else if (mPhase == Moon::Phase_WaxingGibbous) return 3; + else if (mPhase == Moon::Phase_WaningGibbous) return 3; + else if (mPhase == Moon::Phase_Full) return 4; + return 0; + } + +private: + Type mType; + Phase mPhase; + osg::ref_ptr mUpdater; +}; + SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneManager) : mSceneManager(sceneManager) , mHour(0.0f) @@ -240,7 +507,6 @@ SkyManager::SkyManager(osg::Group* parentNode, Resource::SceneManager* sceneMana , mIsStorm(false) { osg::ref_ptr skyroot (new CameraRelativeTransform); - skyroot->setCullingActive(false); parentNode->addChild(skyroot); mRootNode = skyroot; @@ -257,8 +523,6 @@ void SkyManager::create() ModVertexAlphaVisitor modAtmosphere(0); mAtmosphereDay->accept(modAtmosphere); - // osg::Node* alphaBlendedRoot = - mAtmosphereUpdater = new AtmosphereUpdater; mAtmosphereDay->addUpdateCallback(mAtmosphereUpdater); @@ -271,27 +535,23 @@ void SkyManager::create() mAtmosphereNight->accept(modStars); mAtmosphereNight->setNodeMask(0); - osg::Geode* geode = new osg::Geode; - osg::ref_ptr sun = createTexturedQuad(); - geode->addDrawable(sun); - osg::PositionAttitudeTransform* trans = new osg::PositionAttitudeTransform; - trans->setScale(osg::Vec3f(450,450,450)); - trans->addChild(geode); - mRootNode->addChild(trans); + mSun.reset(new Sun(mRootNode, mSceneManager)); - mSunTransform = trans; + const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback(); + mMasser.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Masser_Size")/100, Moon::Type_Masser)); + mSecunda.reset(new Moon(mRootNode, mSceneManager, fallback->getFallbackFloat("Moons_Secunda_Size")/100, Moon::Type_Secunda)); mCloudNode = mSceneManager->createInstance("meshes/sky_clouds_01.nif", mRootNode); ModVertexAlphaVisitor modClouds(1); mCloudNode->accept(modClouds); - osg::ref_ptr 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); + mCloudUpdater = new CloudUpdater; + //mCloudNode->addUpdateCallback(mCloudUpdater); mCloudNode->getOrCreateStateSet()->setAttributeAndModes(createAlphaTrackingUnlitMaterial(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + mCloudNode->setNodeMask(0); + osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); @@ -307,16 +567,15 @@ SkyManager::~SkyManager() int SkyManager::getMasserPhase() const { - return 0; if (!mCreated) return 0; + return 0; //return mMasser->getPhaseInt(); } int SkyManager::getSecundaPhase() const { - return 0; if (!mCreated) return 0; - //return mSecunda->getPhaseInt(); + return mSecunda->getPhaseInt(); } void SkyManager::clearRain() @@ -376,9 +635,9 @@ void SkyManager::update(float duration) } //mSunGlare->setVisible(mSunEnabled); - //mSun->setVisible(mSunEnabled); - //mMasser->setVisible(mMasserEnabled); - //mSecunda->setVisible(mSecundaEnabled); + mSun->setVisible(mSunEnabled); + mMasser->setVisible(mMasserEnabled); + mSecunda->setVisible(mSecundaEnabled); // rotate the stars by 360 degrees every 4 days //mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f))); @@ -441,6 +700,11 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mClouds != weather.mCloudTexture) { mClouds = weather.mCloudTexture; + + std::string texture = Misc::ResourceHelpers::correctTexturePath(mClouds, mSceneManager->getVFS()); + + mCloudUpdater->setTexture(mSceneManager->getTextureManager()->getTexture2D(texture, + osg::Texture::REPEAT, osg::Texture::REPEAT)); } if (mNextClouds != weather.mNextCloudTexture) @@ -456,15 +720,18 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) if (mCloudOpacity != weather.mCloudOpacity) { mCloudOpacity = weather.mCloudOpacity; + + mCloudUpdater->setOpacity(0.3); } if (mCloudColour != weather.mSunColor) { - /* + // FIXME: this doesn't look correct 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); - */ + + mCloudUpdater->setEmissionColor(clr); mCloudColour = weather.mSunColor; } @@ -494,7 +761,7 @@ void SkyManager::setWeather(const MWWorld::WeatherResult& weather) } } - mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); + //mAtmosphereNight->setNodeMask((weather.mNight && mEnabled) ? ~0 : 0); /* @@ -524,12 +791,16 @@ void SkyManager::setGlare(const float glare) void SkyManager::sunEnable() { - mSunEnabled = true; + if (!mCreated) return; + + mSun->setVisible(true); } void SkyManager::sunDisable() { - mSunEnabled = false; + if (!mCreated) return; + + mSun->setVisible(false); } void SkyManager::setStormDirection(const Ogre::Vector3 &direction) @@ -541,45 +812,51 @@ void SkyManager::setSunDirection(const osg::Vec3f& direction) { if (!mCreated) return; - mSunTransform->setPosition(direction*1000.f); - - osg::Quat quat; - quat.makeRotate(osg::Vec3f(0,0,1), direction); - mSunTransform->setAttitude(quat); + mSun->setDirection(direction); //mSunGlare->setPosition(direction); } -void SkyManager::setMasserDirection(const Ogre::Vector3& direction) +void SkyManager::setMasserDirection(const osg::Vec3f& direction) { if (!mCreated) return; - //mMasser->setPosition(direction); + + mMasser->setDirection(direction); } -void SkyManager::setSecundaDirection(const Ogre::Vector3& direction) +void SkyManager::setSecundaDirection(const osg::Vec3f& direction) { if (!mCreated) return; - //mSecunda->setPosition(direction); + + mSecunda->setDirection(direction); } void SkyManager::masserEnable() { - mMasserEnabled = true; + if (!mCreated) return; + + mMasser->setVisible(true); } void SkyManager::secundaEnable() { - mSecundaEnabled = true; + if (!mCreated) return; + + mSecunda->setVisible(true); } void SkyManager::masserDisable() { - mMasserEnabled = false; + if (!mCreated) return; + + mMasser->setVisible(false); } void SkyManager::secundaDisable() { - mSecundaEnabled = false; + if (!mCreated) return; + + mSecunda->setVisible(false); } void SkyManager::setLightningStrength(const float factor) @@ -599,13 +876,13 @@ void SkyManager::setLightningStrength(const float factor) void SkyManager::setMasserFade(const float fade) { if (!mCreated) return; - //mMasser->setVisibility(fade); + mMasser->setAlpha(fade); } void SkyManager::setSecundaFade(const float fade) { if (!mCreated) return; - //mSecunda->setVisibility(fade); + mSecunda->setAlpha(fade); } void SkyManager::setHour(double hour) diff --git a/apps/openmw/mwrender/sky.hpp b/apps/openmw/mwrender/sky.hpp index c8403af71..ebf3ee87f 100644 --- a/apps/openmw/mwrender/sky.hpp +++ b/apps/openmw/mwrender/sky.hpp @@ -20,6 +20,9 @@ namespace Resource namespace MWRender { class AtmosphereUpdater; + class CloudUpdater; + class Sun; + class Moon; class SkyManager { @@ -60,9 +63,9 @@ namespace MWRender void setSunDirection(const osg::Vec3f& direction); - void setMasserDirection(const Ogre::Vector3& direction); + void setMasserDirection(const osg::Vec3f& direction); - void setSecundaDirection(const Ogre::Vector3& direction); + void setSecundaDirection(const osg::Vec3f& direction); void setMasserFade(const float fade); @@ -94,13 +97,17 @@ namespace MWRender osg::ref_ptr mCloudNode; + osg::ref_ptr mCloudUpdater; + osg::ref_ptr mAtmosphereDay; osg::ref_ptr mAtmosphereNight; osg::ref_ptr mAtmosphereUpdater; - osg::ref_ptr mSunTransform; + std::auto_ptr mSun; + std::auto_ptr mMasser; + std::auto_ptr mSecunda; bool mCreated; diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index fe4f62953..90aedda1c 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -426,10 +426,10 @@ void WeatherManager::update(float duration, bool paused) mRendering->configureFog(mResult.mFogDepth, mResult.mFogColor); // disable sun during night - //if (mHour >= mNightStart || mHour <= mSunriseTime) - //mRendering->getSkyManager()->sunDisable(); - //else - //mRendering->getSkyManager()->sunEnable(); + if (mHour >= mNightStart || mHour <= mSunriseTime) + mRendering->getSkyManager()->sunDisable(); + else + mRendering->getSkyManager()->sunEnable(); // Update the sun direction. Run it east to west at a fixed angle from overhead. // The sun's speed at day and night may differ, since mSunriseTime and mNightStart @@ -493,10 +493,10 @@ void WeatherManager::update(float duration, bool paused) (1 - moonHeight) * facing * 0.8f, moonHeight); - //mRendering->getSkyManager()->setMasserDirection(masser); - //mRendering->getSkyManager()->setSecundaDirection(secunda); - //mRendering->getSkyManager()->masserEnable(); - //mRendering->getSkyManager()->secundaEnable(); + mRendering->getSkyManager()->setMasserDirection(masser); + mRendering->getSkyManager()->setSecundaDirection(secunda); + mRendering->getSkyManager()->masserEnable(); + mRendering->getSkyManager()->secundaEnable(); float angle = (1-moonHeight) * 90.f * facing; float masserHourFade = calculateHourFade("Masser"); @@ -507,13 +507,13 @@ void WeatherManager::update(float duration, bool paused) masserAngleFade *= masserHourFade; secundaAngleFade *= secundaHourFade; - //mRendering->getSkyManager()->setMasserFade(masserAngleFade); - //mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); + mRendering->getSkyManager()->setMasserFade(masserAngleFade); + mRendering->getSkyManager()->setSecundaFade(secundaAngleFade); } else { - //mRendering->getSkyManager()->masserDisable(); - //mRendering->getSkyManager()->secundaDisable(); + mRendering->getSkyManager()->masserDisable(); + mRendering->getSkyManager()->secundaDisable(); } if (!paused) @@ -568,7 +568,6 @@ void WeatherManager::update(float duration, bool paused) mRendering->setAmbientColour(mResult.mAmbientColor); - //mRendering->sunEnable(false); mRendering->setSunColour(mResult.mSunColor); mRendering->getSkyManager()->setWeather(mResult);