From 10398723d877b6ce1b6469fc470dbd96b9a1b236 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 15 Apr 2012 22:44:38 +0200 Subject: [PATCH 01/13] use different image pixel format --- libs/openengine/ogre/imagerotate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/openengine/ogre/imagerotate.cpp b/libs/openengine/ogre/imagerotate.cpp index 1147559d6..11fd5eea6 100644 --- a/libs/openengine/ogre/imagerotate.cpp +++ b/libs/openengine/ogre/imagerotate.cpp @@ -54,7 +54,7 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest TEX_TYPE_2D, width, height, 0, - PF_A8R8G8B8, + PF_FLOAT16_RGBA, TU_RENDERTARGET); RenderTarget* rtt = destTexture->getBuffer()->getRenderTarget(); @@ -63,7 +63,6 @@ void ImageRotate::rotate(const std::string& sourceImage, const std::string& dest vp->setOverlaysEnabled(false); vp->setShadowsEnabled(false); vp->setBackgroundColour(ColourValue(0,0,0,0)); - vp->setClearEveryFrame(true, FBT_DEPTH); rtt->update(); From 13b67faf2f38c3692db617c4d31d6f1c33ed3d74 Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 16 Apr 2012 20:39:41 +0200 Subject: [PATCH 02/13] adding more safety checks --- apps/openmw/mwrender/renderingmanager.cpp | 5 +++-- files/settings-default.cfg | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c1462807f..a35560848 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -54,9 +54,10 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // disable unsupported effects const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); - if (caps->getNumMultiRenderTargets() < 2) + if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("shader", "Water", false); - if (!caps->isShaderProfileSupported("fp40") && !caps->isShaderProfileSupported("ps_4_0")) + if ( !(caps->isShaderProfileSupported("fp40") || caps->isShaderProfileSupported("ps_4_0")) + || !Settings::Manager::getBool("shaders", "Objects")) Settings::Manager::setBool("enabled", "Shadows", false); // note that the order is important here diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 553a82e49..e4a0c020a 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -86,6 +86,7 @@ num lights = 8 [Water] # Enable this to get fancy-looking water with reflections and refractions +# Only available if object shaders are on # All the settings below have no effect if this is false shader = true From a11c4da16c3688d8a4760c7f866e8edc518614f2 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 17 Apr 2012 14:22:03 +0200 Subject: [PATCH 03/13] vertex colour tweak --- apps/openmw/mwrender/shaderhelper.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/openmw/mwrender/shaderhelper.cpp b/apps/openmw/mwrender/shaderhelper.cpp index 5354251f8..1d29be2b8 100644 --- a/apps/openmw/mwrender/shaderhelper.cpp +++ b/apps/openmw/mwrender/shaderhelper.cpp @@ -256,9 +256,9 @@ void ShaderHelper::createShader(const bool mrt, const bool shadows, const bool s } outStream << - " float3 lightingFinal = lightColour.xyz * diffuse.xyz * vertexColour.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n" + " float3 lightingFinal = lightColour.xyz * diffuse.xyz + ambient.xyz * lightAmbient.xyz + emissive.xyz; \n" " float fogValue = saturate((iDepth - fogParams.y) * fogParams.w); \n" - " oColor.xyz = lerp(lightingFinal * tex.xyz, fogColour.xyz, fogValue); \n" + " oColor.xyz = lerp(lightingFinal * tex.xyz * vertexColour.xyz, fogColour.xyz, fogValue); \n" " oColor.a = tex.a * diffuse.a * vertexColour.a; \n"; if (mrt) outStream << From 046ef39c4a6f756f167147d34f112057c6c9914f Mon Sep 17 00:00:00 2001 From: scrawl Date: Wed, 18 Apr 2012 01:10:00 +0200 Subject: [PATCH 04/13] use camera-relative rendering to prevent precision artifacts when moving far from (0,0,0) --- apps/openmw/mwrender/renderingmanager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a35560848..3082cf0d7 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -52,6 +52,10 @@ RenderingManager::RenderingManager (OEngine::Render::OgreRenderer& _rend, const // Load resources ResourceGroupManager::getSingleton().initialiseAllResourceGroups(); + // Due to the huge world size of MW, we'll want camera-relative rendering. + // This prevents precision artifacts when moving very far from the origin. + mRendering.getScene()->setCameraRelativeRendering(true); + // disable unsupported effects const RenderSystemCapabilities* caps = Root::getSingleton().getRenderSystem()->getCapabilities(); if (caps->getNumMultiRenderTargets() < 2 || !Settings::Manager::getBool("shaders", "Objects")) From aa4a1b675fcc138c5b15f7d031846f2253b62f89 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 01:08:26 +0200 Subject: [PATCH 05/13] fixed the sky reflection issue --- apps/openmw/mwrender/renderconst.hpp | 2 ++ apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 44 ++++++++++++++++++----- apps/openmw/mwrender/water.hpp | 9 ++++- 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 2c7f9e9ac..c4aa093c0 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -52,6 +52,8 @@ enum VisibilityFlags // Sun glare (not visible in reflection) RV_Glare = 128, + RV_OcclusionQuery = 256, + RV_Map = RV_Terrain + RV_Statics + RV_StaticsSmall + RV_Misc + RV_Water, /// \todo markers (normally hidden) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 3082cf0d7..581973811 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -225,6 +225,8 @@ void RenderingManager::update (float duration){ mLocalMap->updatePlayer( mRendering.getCamera()->getRealPosition(), mRendering.getCamera()->getRealOrientation() ); checkUnderwater(); + + mWater->update(); } void RenderingManager::waterAdded (MWWorld::Ptr::CellStore *store){ if(store->cell->data.flags & store->cell->HasWater){ diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 71cf56dfd..445677808 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -11,7 +11,8 @@ namespace MWRender Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mCamera (camera), mViewport (camera->getViewport()), mSceneManager (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), - mReflectionTarget(0), mActive(1), mToggled(1) + mReflectionTarget(0), mActive(1), mToggled(1), + mReflectionRenderActive(false) { mSky = sky; @@ -81,6 +82,8 @@ Water::Water (Ogre::Camera *camera, SkyManager* sky, const ESM::Cell* cell) : mUnderwaterEffect = Settings::Manager::getBool("underwater effect", "Water"); + mSceneManager->addRenderQueueListener(this); + // ---------------------------------------------------------------------------------------------- // ---------------------------------- reflection debug overlay ---------------------------------- @@ -161,6 +164,7 @@ void Water::changeCell(const ESM::Cell* cell) void Water::setHeight(const float height) { mTop = height; + mWaterPlane = Plane(Vector3::UNIT_Y, height); mWaterNode->setPosition(0, height, 0); } @@ -220,17 +224,15 @@ void Water::preRenderTargetUpdate(const RenderTargetEvent& evt) mReflectionCamera->setFarClipDistance(mCamera->getFarClipDistance()); mReflectionCamera->setAspectRatio(mCamera->getAspectRatio()); mReflectionCamera->setFOVy(mCamera->getFOVy()); + mReflectionRenderActive = true; - // Some messy code to get the skybox to show up at all - // The problem here is that it gets clipped by the water plane - // Therefore scale it up a bit + /// \todo For some reason this camera is delayed for 1 frame, which causes ugly sky reflection behaviour.. + /// to circumvent this we just scale the sky up, so it's not that noticable Vector3 pos = mCamera->getRealPosition(); pos.y = mTop*2 - pos.y; mSky->setSkyPosition(pos); - mSky->scaleSky(mCamera->getFarClipDistance() / 1000.f); - - mReflectionCamera->enableCustomNearClipPlane(Plane(Vector3::UNIT_Y, mTop)); - mReflectionCamera->enableReflection(Plane(Vector3::UNIT_Y, mTop)); + mSky->scaleSky(mCamera->getFarClipDistance() / 5000.f); + mReflectionCamera->enableReflection(mWaterPlane); } } @@ -240,8 +242,9 @@ void Water::postRenderTargetUpdate(const RenderTargetEvent& evt) { mSky->resetSkyPosition(); mSky->scaleSky(1); - mReflectionCamera->disableCustomNearClipPlane(); mReflectionCamera->disableReflection(); + mReflectionCamera->disableCustomNearClipPlane(); + mReflectionRenderActive = false; } } @@ -290,4 +293,27 @@ void Water::updateVisible() mReflectionTarget->setActive(mToggled && mActive && !mIsUnderwater); } +void Water::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation) +{ + // We don't want the sky to get clipped by custom near clip plane (the water plane) + if (queueGroupId < 20 && mReflectionRenderActive) + { + mReflectionCamera->disableCustomNearClipPlane(); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); + } +} + +void Water::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) +{ + if (queueGroupId < 20 && mReflectionRenderActive) + { + mReflectionCamera->enableCustomNearClipPlane(mWaterPlane); + Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS()); + } +} + +void Water::update() +{ +} + } // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index f14482e2b..c8b8d311e 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -11,7 +11,7 @@ namespace MWRender { class SkyManager; /// Water rendering - class Water : public Ogre::RenderTargetListener + class Water : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener { static const int CELL_SIZE = 8192; Ogre::Camera *mCamera; @@ -27,11 +27,17 @@ namespace MWRender { bool mToggled; int mTop; + bool mReflectionRenderActive; + Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); protected: void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); + + void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); + void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); + void updateVisible(); SkyManager* mSky; @@ -55,6 +61,7 @@ namespace MWRender { void setActive(bool active); void toggle(); + void update(); void setViewportBackground(const Ogre::ColourValue& bg); From fb0e649191270e9c4f4720c2a4983520cf01a632 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 01:10:55 +0200 Subject: [PATCH 06/13] minor fix --- apps/openmw/mwrender/occlusionquery.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/apps/openmw/mwrender/occlusionquery.cpp b/apps/openmw/mwrender/occlusionquery.cpp index 80b804dce..6d3f67de9 100644 --- a/apps/openmw/mwrender/occlusionquery.cpp +++ b/apps/openmw/mwrender/occlusionquery.cpp @@ -65,6 +65,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQueryTotal->createBillboard(Vector3::ZERO); mBBQueryTotal->setMaterialName("QueryTotalPixels"); mBBQueryTotal->setRenderQueueGroup(RQG_OcclusionQuery+1); + mBBQueryTotal->setVisibilityFlags(RV_OcclusionQuery); mBBNodeReal->attachObject(mBBQueryTotal); mBBQueryVisible = mRendering->getScene()->createBillboardSet(1); @@ -73,6 +74,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQueryVisible->createBillboard(Vector3::ZERO); mBBQueryVisible->setMaterialName("QueryVisiblePixels"); mBBQueryVisible->setRenderQueueGroup(RQG_OcclusionQuery+1); + mBBQueryVisible->setVisibilityFlags(RV_OcclusionQuery); mBBNodeReal->attachObject(mBBQueryVisible); mBBQuerySingleObject = mRendering->getScene()->createBillboardSet(1); @@ -82,6 +84,7 @@ OcclusionQuery::OcclusionQuery(OEngine::Render::OgreRenderer* renderer, SceneNod mBBQuerySingleObject->createBillboard(Vector3::ZERO); mBBQuerySingleObject->setMaterialName("QueryVisiblePixels"); mBBQuerySingleObject->setRenderQueueGroup(RQG_OcclusionQuery); + mBBQuerySingleObject->setVisibilityFlags(RV_OcclusionQuery); mObjectNode->attachObject(mBBQuerySingleObject); mRendering->getScene()->addRenderObjectListener(this); From c6da3872b443572b5c686eae15d14f4ac35ab8c1 Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 20:59:57 +0200 Subject: [PATCH 07/13] light improvements --- apps/openmw/mwrender/objects.cpp | 132 ++++++++++++---------- apps/openmw/mwrender/objects.hpp | 26 +++-- apps/openmw/mwrender/renderingmanager.cpp | 11 ++ apps/openmw/mwrender/renderingmanager.hpp | 3 + apps/openmw/mwrender/terrainmaterial.cpp | 4 +- apps/openmw/mwworld/scene.cpp | 5 +- 6 files changed, 113 insertions(+), 68 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index eb7e440cb..a79d72989 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -8,20 +8,15 @@ using namespace MWRender; -bool Objects::lightConst = false; -float Objects::lightConstValue = 0.0f; - -bool Objects::lightLinear = true; -int Objects::lightLinearMethod = 1; +// These are the Morrowind.ini defaults float Objects::lightLinearValue = 3; float Objects::lightLinearRadiusMult = 1; -bool Objects::lightQuadratic = false; -int Objects::lightQuadraticMethod = 2; float Objects::lightQuadraticValue = 16; float Objects::lightQuadraticRadiusMult = 1; -bool Objects::lightOutQuadInLin = false; +bool Objects::lightOutQuadInLin = true; +bool Objects::lightQuadratic = false; int Objects::uniqueID = 0; @@ -132,7 +127,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) } } - if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects")) + if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) { insert->attachObject(ent); @@ -144,18 +139,7 @@ void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) { Ogre::StaticGeometry* sg = 0; -/* if (transparent) - { - if( mStaticGeometryAlpha.find(ptr.getCell()) == mStaticGeometryAlpha.end()) - { - uniqueID = uniqueID +1; - sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); - mStaticGeometryAlpha[ptr.getCell()] = sg; - } - else - sg = mStaticGeometryAlpha[ptr.getCell()]; - } - else*/ if (small) + if (small) { if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) { @@ -207,34 +191,35 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f assert(insert); Ogre::Light *light = mRenderer.getScene()->createLight(); light->setDiffuseColour (r, g, b); - mLights.push_back(light->getName()); - float cval=0.0f, lval=0.0f, qval=0.0f; + LightInfo info; + info.name = light->getName(); + info.radius = radius; + info.colour = Ogre::ColourValue(r, g, b); + mLights.push_back(info); - if(lightConst) - cval = lightConstValue; - if(!lightOutQuadInLin) + bool quadratic = false; + if (!lightOutQuadInLin) + quadratic = lightQuadratic; + else { - if(lightLinear) - radius *= lightLinearRadiusMult; - if(lightQuadratic) - radius *= lightQuadraticRadiusMult; + quadratic = !mInterior; + } - if(lightLinear) - lval = lightLinearValue / pow(radius, lightLinearMethod); - if(lightQuadratic) - qval = lightQuadraticValue / pow(radius, lightQuadraticMethod); + if (!quadratic) + { + float r = radius * lightLinearRadiusMult; + float attenuation = lightLinearValue / r; + light->setAttenuation(r*10, 0, attenuation, 0); } else { - // FIXME: - // Do quadratic or linear, depending if we're in an exterior or interior - // cell, respectively. Ignore lightLinear and lightQuadratic. + float r = radius * lightQuadraticRadiusMult; + float attenuation = lightQuadraticValue / pow(r, 2); + light->setAttenuation(r*10, 0, 0, attenuation); } - light->setAttenuation(10*radius, cval, lval, qval); - insert->attachObject(light); } @@ -290,13 +275,6 @@ void Objects::removeCell(MWWorld::Ptr::CellStore* store) mRenderer.getScene()->destroyStaticGeometry (sg); sg = 0; } - /*if(mStaticGeometryAlpha.find(store) != mStaticGeometryAlpha.end()) - { - Ogre::StaticGeometry* sg = mStaticGeometryAlpha[store]; - mStaticGeometryAlpha.erase(store); - mRenderer.getScene()->destroyStaticGeometry (sg); - sg = 0; - }*/ if(mBounds.find(store) != mBounds.end()) mBounds.erase(store); @@ -314,11 +292,6 @@ void Objects::buildStaticGeometry(ESMS::CellStore& cell) Ogre::StaticGeometry* sg = mStaticGeometrySmall[&cell]; sg->build(); } - /*if(mStaticGeometryAlpha.find(&cell) != mStaticGeometryAlpha.end()) - { - Ogre::StaticGeometry* sg = mStaticGeometryAlpha[&cell]; - sg->build(); - }*/ } Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) @@ -328,12 +301,12 @@ Ogre::AxisAlignedBox Objects::getDimensions(MWWorld::Ptr::CellStore* cell) void Objects::enableLights() { - std::vector::iterator it = mLights.begin(); + std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(*it)) + if (mMwRoot->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(*it)->setVisible(true); + mMwRoot->getCreator()->getLight(it->name)->setVisible(true); ++it; } else @@ -343,12 +316,12 @@ void Objects::enableLights() void Objects::disableLights() { - std::vector::iterator it = mLights.begin(); + std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { - if (mMwRoot->getCreator()->hasLight(*it)) + if (mMwRoot->getCreator()->hasLight(it->name)) { - mMwRoot->getCreator()->getLight(*it)->setVisible(false); + mMwRoot->getCreator()->getLight(it->name)->setVisible(false); ++it; } else @@ -356,3 +329,48 @@ void Objects::disableLights() } } +void Objects::setInterior(const bool interior) +{ + mInterior = interior; +} + +void Objects::update(const float dt) +{ + // adjust the lights depending if we're in an interior or exterior cell + // quadratic means the light intensity falls off quite fast, resulting in a + // dark, atmospheric environment (perfect for exteriors) + // for interiors, we want more "warm" lights, so use linear attenuation. + std::vector::iterator it = mLights.begin(); + while (it != mLights.end()) + { + if (mMwRoot->getCreator()->hasLight(it->name)) + { + Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); + + bool quadratic = false; + if (!lightOutQuadInLin) + quadratic = lightQuadratic; + else + { + quadratic = !mInterior; + } + + if (!quadratic) + { + float radius = it->radius * lightLinearRadiusMult; + float attenuation = lightLinearValue / it->radius; + light->setAttenuation(radius*10, 0, attenuation, 0); + } + else + { + float radius = it->radius * lightQuadraticRadiusMult; + float attenuation = lightQuadraticValue / pow(it->radius, 2); + light->setAttenuation(radius*10, 0, 0, attenuation); + } + + ++it; + } + else + it = mLights.erase(it); + } +} diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 0c19f9f33..63e639ef7 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -10,37 +10,41 @@ namespace MWRender{ +/// information about light needed for rendering +struct LightInfo +{ + std::string name; // ogre handle + Ogre::ColourValue colour; + float radius; +}; + class Objects{ OEngine::Render::OgreRenderer &mRenderer; std::map mCellSceneNodes; std::map mStaticGeometry; std::map mStaticGeometrySmall; - //std::map mStaticGeometryAlpha; std::map mBounds; - std::vector mLights; + std::vector mLights; Ogre::SceneNode* mMwRoot; bool mIsStatic; static int uniqueID; - static bool lightConst; - static float lightConstValue; - static bool lightLinear; - static int lightLinearMethod; static float lightLinearValue; static float lightLinearRadiusMult; static bool lightQuadratic; - static int lightQuadraticMethod; static float lightQuadraticValue; static float lightQuadraticRadiusMult; static bool lightOutQuadInLin; + bool mInterior; + void clearSceneNode (Ogre::SceneNode *node); ///< Remove all movable objects from \a node. public: - Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer){} + Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mInterior(true) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); @@ -49,6 +53,12 @@ public: void enableLights(); void disableLights(); + void update (const float dt); + ///< per-frame update + + void setInterior(const bool interior); + ///< call this to switch from interior to exterior or vice versa + Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*); ///< get a bounding box that encloses all objects in the specified cell diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 581973811..5232c5140 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -213,6 +213,7 @@ void RenderingManager::moveObjectToCell (const MWWorld::Ptr& ptr, const Ogre::Ve void RenderingManager::update (float duration){ mActors.update (duration); + mObjects.update (duration); mOcclusionQuery->update(duration); @@ -508,4 +509,14 @@ Shadows* RenderingManager::getShadows() return mShadows; } +void RenderingManager::switchToInterior() +{ + mObjects.setInterior(true); +} + +void RenderingManager::switchToExterior() +{ + mObjects.setInterior(false); +} + } // namespace diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index a563d78c6..cc3bc62b5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -117,6 +117,9 @@ class RenderingManager: private RenderingInterface { Shadows* getShadows(); + void switchToInterior(); + void switchToExterior(); + void setGlare(bool glare); void skyEnable (); void skyDisable (); diff --git a/apps/openmw/mwrender/terrainmaterial.cpp b/apps/openmw/mwrender/terrainmaterial.cpp index 9785ec903..a3265b2a5 100644 --- a/apps/openmw/mwrender/terrainmaterial.cpp +++ b/apps/openmw/mwrender/terrainmaterial.cpp @@ -1149,8 +1149,8 @@ namespace Ogre // simple per-pixel lighting with no normal mapping for (int i=0; igetNumberOfLightsSupported(); ++i) { - outStream << " float3 halfAngle"< 0) outStream << diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index 2123b4799..c8b20b8b1 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -203,6 +203,8 @@ namespace MWWorld // Sky system mWorld->adjustSky(); + mRendering.switchToExterior(); + mCellChanged = true; } @@ -248,8 +250,9 @@ namespace MWWorld // adjust player mCurrentCell = cell; playerCellChange (cell, position); - + // adjust fog + mRendering.switchToInterior(); mRendering.configureFog(*cell); // Sky system From 7400b7f313d8cbc7141ca89d926be3dc42dca9be Mon Sep 17 00:00:00 2001 From: scrawl Date: Thu, 19 Apr 2012 23:25:58 +0200 Subject: [PATCH 08/13] fix underwater effect staying active when teleporting from underwater to a cell that doesn't have water --- apps/openmw/mwrender/renderingmanager.cpp | 2 ++ apps/openmw/mwrender/water.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 5232c5140..3f1bb924f 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -512,11 +512,13 @@ Shadows* RenderingManager::getShadows() void RenderingManager::switchToInterior() { mObjects.setInterior(true); + mRendering.getScene()->setCameraRelativeRendering(false); } void RenderingManager::switchToExterior() { mObjects.setInterior(false); + mRendering.getScene()->setCameraRelativeRendering(true); } } // namespace diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 445677808..c81f23f54 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -176,7 +176,12 @@ void Water::toggle() void Water::checkUnderwater(float y) { - if (!mActive) return; + if (!mActive) + { + CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); + return; + } + if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID) { CompositorManager::getSingleton().setCompositorEnabled(mViewport, mCompositorName, false); From f4428097f951d0c021bb46753e78cf8700c5aa27 Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Mon, 23 Apr 2012 15:37:38 +0200 Subject: [PATCH 09/13] removing more cout spam --- apps/openmw/mwclass/npc.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/openmw/mwclass/npc.cpp b/apps/openmw/mwclass/npc.cpp index c053ad130..afb904f51 100644 --- a/apps/openmw/mwclass/npc.cpp +++ b/apps/openmw/mwclass/npc.cpp @@ -105,10 +105,10 @@ namespace MWClass void Npc::insertObjectRendering (const MWWorld::Ptr& ptr, MWRender::RenderingInterface& renderingInterface) const { - - + + renderingInterface.getActors().insertNPC(ptr, getInventoryStore(ptr)); - + } void Npc::insertObject(const MWWorld::Ptr& ptr, MWWorld::PhysicsSystem& physics, MWWorld::Environment& environment) const @@ -296,7 +296,6 @@ namespace MWClass void Npc::registerSelf() { boost::shared_ptr instance (new Npc); - std::cout << "class npc:" << typeid (ESM::NPC).name(); registerClass (typeid (ESM::NPC).name(), instance); } } From d5e52e46ea58fb10bbe1cc9171f9aef428947b3f Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Tue, 24 Apr 2012 09:19:41 +0200 Subject: [PATCH 10/13] removing even more cout spam (thanks to scrawl for finding this one) --- apps/openmw/mwworld/player.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/openmw/mwworld/player.cpp b/apps/openmw/mwworld/player.cpp index d24780ec1..5ed9aeaff 100644 --- a/apps/openmw/mwworld/player.cpp +++ b/apps/openmw/mwworld/player.cpp @@ -24,8 +24,6 @@ namespace MWWorld float* playerPos = mPlayer.mData.getPosition().pos; playerPos[0] = playerPos[1] = playerPos[2] = 0; - std::cout << renderer->getHandle(); - mPlayer.mData.setBaseNode(renderer->getNode()); /// \todo Do not make a copy of classes defined in esm/p records. mClass = new ESM::Class (*world.getStore().classes.find (player->cls)); From 4ce83badc9860cc965cbdf79c7d859517d16cc96 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Apr 2012 20:42:53 +0200 Subject: [PATCH 11/13] flickering lights --- apps/openmw/mwrender/objects.cpp | 121 +++++++++++++++++----- apps/openmw/mwrender/objects.hpp | 33 ++++-- apps/openmw/mwrender/renderingmanager.cpp | 2 - apps/openmw/mwworld/weather.cpp | 1 - components/esm/loadligh.hpp | 2 +- 5 files changed, 122 insertions(+), 37 deletions(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index a79d72989..86a845a27 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -192,19 +192,43 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f Ogre::Light *light = mRenderer.getScene()->createLight(); light->setDiffuseColour (r, g, b); + ESMS::LiveCellRef *ref = + ptr.get(); + LightInfo info; info.name = light->getName(); info.radius = radius; info.colour = Ogre::ColourValue(r, g, b); - mLights.push_back(info); + if (ref->base->data.flags & ESM::Light::Negative) + info.colour *= -1; + info.interior = (ptr.getCell()->cell->data.flags & ESM::Cell::Interior); + + if (ref->base->data.flags & ESM::Light::Flicker) + info.type = LT_Flicker; + else if (ref->base->data.flags & ESM::Light::FlickerSlow) + info.type = LT_FlickerSlow; + else if (ref->base->data.flags & ESM::Light::Pulse) + info.type = LT_Pulse; + else if (ref->base->data.flags & ESM::Light::PulseSlow) + info.type = LT_PulseSlow; + else + info.type = LT_Normal; + + // random starting phase for the animation + info.time = Ogre::Math::RangeRandom(0, 2 * M_PI); + + // adjust the lights depending if we're in an interior or exterior cell + // quadratic means the light intensity falls off quite fast, resulting in a + // dark, atmospheric environment (perfect for exteriors) + // for interiors, we want more "warm" lights, so use linear attenuation. bool quadratic = false; if (!lightOutQuadInLin) quadratic = lightQuadratic; else { - quadratic = !mInterior; + quadratic = !info.interior; } if (!quadratic) @@ -221,6 +245,7 @@ void Objects::insertLight (const MWWorld::Ptr& ptr, float r, float g, float b, f } insert->attachObject(light); + mLights.push_back(info); } bool Objects::deleteObject (const MWWorld::Ptr& ptr) @@ -329,17 +354,8 @@ void Objects::disableLights() } } -void Objects::setInterior(const bool interior) -{ - mInterior = interior; -} - void Objects::update(const float dt) { - // adjust the lights depending if we're in an interior or exterior cell - // quadratic means the light intensity falls off quite fast, resulting in a - // dark, atmospheric environment (perfect for exteriors) - // for interiors, we want more "warm" lights, so use linear attenuation. std::vector::iterator it = mLights.begin(); while (it != mLights.end()) { @@ -347,26 +363,77 @@ void Objects::update(const float dt) { Ogre::Light* light = mMwRoot->getCreator()->getLight(it->name); - bool quadratic = false; - if (!lightOutQuadInLin) - quadratic = lightQuadratic; - else - { - quadratic = !mInterior; - } + // Light animation (pulse & flicker) + it->time += dt; + const float phase = std::fmod(it->time, (32 * 2 * M_PI)) * 20; + float pulseConstant; - if (!quadratic) + // These formulas are just guesswork, but they work pretty well + if (it->type == LT_Normal) { - float radius = it->radius * lightLinearRadiusMult; - float attenuation = lightLinearValue / it->radius; - light->setAttenuation(radius*10, 0, attenuation, 0); + // Less than 1/255 light modifier for a constant light: + pulseConstant = (const float)(1.0 + sin(phase) / 255.0 ); + } + else if (it->type == LT_Flicker) + { + // Let's do a 50% -> 100% sine wave pulse over 1 second: + // This is 75% +/- 25% + pulseConstant = (const float)(0.75 + sin(phase) * 0.25); + + // Then add a 25% flicker variation: + it->resetTime -= dt; + if (it->resetTime < 0) + { + it->flickerVariation = (rand() % 1000) / 1000 * 0.25; + it->resetTime = 0.5; + } + if (it->resetTime > 0.25) + { + pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime * 2.0f) + pulseConstant * it->resetTime * 2.0f; + } + else + { + pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime * 2.0f) + pulseConstant * (1-it->resetTime * 2.0f); + } + } + else if (it->type == LT_FlickerSlow) + { + // Let's do a 50% -> 100% sine wave pulse over 1 second: + // This is 75% +/- 25% + pulseConstant = (const float)(0.75 + sin(phase / 4.0) * 0.25); + + // Then add a 25% flicker variation: + it->resetTime -= dt; + if (it->resetTime < 0) + { + it->flickerVariation = (rand() % 1000) / 1000 * 0.25; + it->resetTime = 0.5; + } + if (it->resetTime > 0.5) + { + pulseConstant = (pulseConstant+it->flickerVariation) * (1-it->resetTime) + pulseConstant * it->resetTime; + } + else + { + pulseConstant = (pulseConstant+it->flickerVariation) * (it->resetTime) + pulseConstant * (1-it->resetTime); + } + } + else if (it->type == LT_Pulse) + { + // Let's do a 75% -> 125% sine wave pulse over 1 second: + // This is 100% +/- 25% + pulseConstant = (const float)(1.0 + sin(phase) * 0.25); + } + else if (it->type == LT_PulseSlow) + { + // Let's do a 75% -> 125% sine wave pulse over 1 second: + // This is 100% +/- 25% + pulseConstant = (const float)(1.0 + sin(phase / 4.0) * 0.25); } else - { - float radius = it->radius * lightQuadraticRadiusMult; - float attenuation = lightQuadraticValue / pow(it->radius, 2); - light->setAttenuation(radius*10, 0, 0, attenuation); - } + assert(0 && "Invalid light type"); + + light->setDiffuseColour( it->colour * pulseConstant ); ++it; } diff --git a/apps/openmw/mwrender/objects.hpp b/apps/openmw/mwrender/objects.hpp index 63e639ef7..fb26808b9 100644 --- a/apps/openmw/mwrender/objects.hpp +++ b/apps/openmw/mwrender/objects.hpp @@ -11,11 +11,37 @@ namespace MWRender{ /// information about light needed for rendering +enum LightType +{ + // These are all mutually exclusive + LT_Normal=0, + LT_Flicker=1, + LT_FlickerSlow=2, + LT_Pulse=3, + LT_PulseSlow=4 +}; + struct LightInfo { + // Constants std::string name; // ogre handle Ogre::ColourValue colour; float radius; + bool interior; // Does this light belong to an interior or exterior cell + LightType type; + + // Runtime variables + float flickerVariation; // 25% flicker variation, reset once every 0.5 seconds + float flickerSlowVariation; // 25% flicker variation, reset once every 1.0 seconds + float resetTime; + long double time; + + + LightInfo() : + flickerVariation(0), resetTime(0.5), + flickerSlowVariation(0), time(0), interior(true) + { + } }; class Objects{ @@ -38,13 +64,11 @@ class Objects{ static bool lightOutQuadInLin; - bool mInterior; - void clearSceneNode (Ogre::SceneNode *node); ///< Remove all movable objects from \a node. public: - Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer), mInterior(true) {} + Objects(OEngine::Render::OgreRenderer& renderer): mRenderer (renderer) {} ~Objects(){} void insertBegin (const MWWorld::Ptr& ptr, bool enabled, bool static_); void insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh); @@ -56,9 +80,6 @@ public: void update (const float dt); ///< per-frame update - void setInterior(const bool interior); - ///< call this to switch from interior to exterior or vice versa - Ogre::AxisAlignedBox getDimensions(MWWorld::Ptr::CellStore*); ///< get a bounding box that encloses all objects in the specified cell diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 6f6503a2e..a95a179c6 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -510,13 +510,11 @@ Shadows* RenderingManager::getShadows() void RenderingManager::switchToInterior() { - mObjects.setInterior(true); mRendering.getScene()->setCameraRelativeRendering(false); } void RenderingManager::switchToExterior() { - mObjects.setInterior(false); mRendering.getScene()->setCameraRelativeRendering(true); } diff --git a/apps/openmw/mwworld/weather.cpp b/apps/openmw/mwworld/weather.cpp index 803fce1e1..bcbb96eec 100644 --- a/apps/openmw/mwworld/weather.cpp +++ b/apps/openmw/mwworld/weather.cpp @@ -522,7 +522,6 @@ void WeatherManager::update(float duration) // re-scale to 100 percent const float total = clear+cloudy+foggy+overcast+rain+thunder+ash+blight;//+snow+blizzard; - srand(time(NULL)); float random = ((rand()%100)/100.f) * total; //if (random >= snow+blight+ash+thunder+rain+overcast+foggy+cloudy+clear) diff --git a/components/esm/loadligh.hpp b/components/esm/loadligh.hpp index 178258a05..9e7934b15 100644 --- a/components/esm/loadligh.hpp +++ b/components/esm/loadligh.hpp @@ -17,7 +17,7 @@ struct Light { Dynamic = 0x001, Carry = 0x002, // Can be carried - Negative = 0x004, // Negative light? + Negative = 0x004, // Negative light - i.e. darkness Flicker = 0x008, Fire = 0x010, OffDefault = 0x020, // Off by default From d1d21c8a0e48ac393883376d166cf6a5f190bb6c Mon Sep 17 00:00:00 2001 From: Marc Zinnschlag Date: Sat, 28 Apr 2012 21:21:40 +0200 Subject: [PATCH 12/13] compile fix --- apps/openmw/mwrender/objects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/openmw/mwrender/objects.cpp b/apps/openmw/mwrender/objects.cpp index 86a845a27..5922086a0 100644 --- a/apps/openmw/mwrender/objects.cpp +++ b/apps/openmw/mwrender/objects.cpp @@ -365,7 +365,7 @@ void Objects::update(const float dt) // Light animation (pulse & flicker) it->time += dt; - const float phase = std::fmod(it->time, (32 * 2 * M_PI)) * 20; + const float phase = std::fmod(static_cast (it->time), (32 * 2 * M_PI)) * 20; float pulseConstant; // These formulas are just guesswork, but they work pretty well From af3ccd85e313d3d5e26b50a3ce9b745df6c3d894 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sat, 28 Apr 2012 21:23:24 +0200 Subject: [PATCH 13/13] determine shield weight (tested with some light/medium/heavy shields) --- apps/openmw/mwclass/armor.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/openmw/mwclass/armor.cpp b/apps/openmw/mwclass/armor.cpp index 3a3403261..d4dab13d4 100644 --- a/apps/openmw/mwclass/armor.cpp +++ b/apps/openmw/mwclass/armor.cpp @@ -138,8 +138,7 @@ namespace MWClass case ESM::Armor::Boots: typeGmst = "iBootsWeight"; break; case ESM::Armor::LGauntlet: case ESM::Armor::RGauntlet: typeGmst = "iGauntletWeight"; break; -/// \todo how to determine if shield light, medium or heavy? -// case ESM::Armor::Shield: + case ESM::Armor::Shield: typeGmst = "iShieldWeight"; break; case ESM::Armor::LBracer: case ESM::Armor::RBracer: typeGmst = "iGauntletWeight"; break; }