From 01944c33f5a28eb2c64188f9e9259c0cf3b9b780 Mon Sep 17 00:00:00 2001 From: scrawl Date: Tue, 2 Jun 2015 16:35:35 +0200 Subject: [PATCH] Basic water rendering --- apps/openmw/CMakeLists.txt | 4 +- apps/openmw/mwrender/localmap.cpp | 2 +- apps/openmw/mwrender/refraction.cpp | 110 ----- apps/openmw/mwrender/refraction.hpp | 45 -- apps/openmw/mwrender/renderingmanager.cpp | 63 ++- apps/openmw/mwrender/renderingmanager.hpp | 8 + apps/openmw/mwrender/rendermode.hpp | 4 +- apps/openmw/mwrender/vismask.hpp | 7 +- apps/openmw/mwrender/water.cpp | 549 +++++----------------- apps/openmw/mwrender/water.hpp | 171 +------ apps/openmw/mwworld/scene.cpp | 4 +- apps/openmw/mwworld/worldimp.cpp | 6 +- components/nifosg/controller.cpp | 7 + components/nifosg/controller.hpp | 1 + components/sceneutil/controller.cpp | 5 +- 15 files changed, 234 insertions(+), 752 deletions(-) delete mode 100644 apps/openmw/mwrender/refraction.cpp delete mode 100644 apps/openmw/mwrender/refraction.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index c46a83183..015d0db9a 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -22,8 +22,8 @@ source_group(game FILES ${GAME} ${GAME_HEADER}) add_openmw_dir (mwrender actors objects renderingmanager animation rotatecontroller sky npcanimation vismask creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation - bulletdebugdraw globalmap characterpreview camera localmap -# occlusionquery water shadows ripplesimulation refraction terrainstorage + bulletdebugdraw globalmap characterpreview camera localmap water +# occlusionquery shadows ripplesimulation refraction terrainstorage ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index edc88ac55..3003e4736 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -157,7 +157,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); camera->setRenderOrder(osg::Camera::PRE_RENDER); - camera->setCullMask(MWRender::Mask_Scene); + camera->setCullMask(MWRender::Mask_Scene|MWRender::Mask_Water); camera->setNodeMask(Mask_RenderToTexture); osg::ref_ptr stateset = new osg::StateSet; diff --git a/apps/openmw/mwrender/refraction.cpp b/apps/openmw/mwrender/refraction.cpp deleted file mode 100644 index 739ed24d9..000000000 --- a/apps/openmw/mwrender/refraction.cpp +++ /dev/null @@ -1,110 +0,0 @@ -#include "refraction.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "renderconst.hpp" - -namespace MWRender -{ - - Refraction::Refraction(Ogre::Camera *parentCamera) - : mParentCamera(parentCamera) - , mRenderActive(false) - , mIsUnderwater(false) - { - mCamera = mParentCamera->getSceneManager()->createCamera("RefractionCamera"); - - mParentCamera->getSceneManager()->addRenderQueueListener(this); - - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().createManual("WaterRefraction", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, 512, 512, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - - mRenderTarget = texture->getBuffer()->getRenderTarget(); - Ogre::Viewport* vp = mRenderTarget->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setVisibilityMask(RV_Refraction); - vp->setMaterialScheme("water_refraction"); - vp->setBackgroundColour (Ogre::ColourValue(0.090195f, 0.115685f, 0.12745f)); - mRenderTarget->setAutoUpdated(true); - mRenderTarget->addListener(this); - } - - Refraction::~Refraction() - { - mRenderTarget->removeListener(this); - Ogre::TextureManager::getSingleton().remove("WaterRefraction"); - mParentCamera->getSceneManager()->destroyCamera(mCamera); - mParentCamera->getSceneManager()->removeRenderQueueListener(this); - } - - void Refraction::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) - { - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setOrientation(mParentCamera->getDerivedOrientation()); - mCamera->setPosition(mParentCamera->getDerivedPosition()); - mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); - mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); - mCamera->setAspectRatio(mParentCamera->getAspectRatio()); - mCamera->setFOVy(mParentCamera->getFOVy()); - - // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. - // since all we are interested in is depth, we only need the third row of the matrix. - Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); - sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); - sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); - - // enable clip plane here to take advantage of CPU culling for overwater or underwater objects - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); - - mRenderActive = true; - } - - void Refraction::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) - { - mCamera->disableCustomNearClipPlane (); - mRenderActive = false; - } - - void Refraction::setHeight(float height) - { - mNearClipPlane = Ogre::Plane( -Ogre::Vector3(0,0,1), -(height + 5)); - mNearClipPlaneUnderwater = Ogre::Plane( Ogre::Vector3(0,0,1), height - 5); - } - - void Refraction::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 && mRenderActive) - { - mCamera->disableCustomNearClipPlane(); - Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } - } - - void Refraction::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) - { - if (queueGroupId < 20 && mRenderActive) - { - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mNearClipPlaneUnderwater : mNearClipPlane); - Ogre::Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } - } - - void Refraction::setActive(bool active) - { - mRenderTarget->setActive(active); - } - -} diff --git a/apps/openmw/mwrender/refraction.hpp b/apps/openmw/mwrender/refraction.hpp deleted file mode 100644 index b9ab8deac..000000000 --- a/apps/openmw/mwrender/refraction.hpp +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef MWRENDER_REFRACTION_H -#define MWRENDER_REFRACTION_H - -#include -#include -#include - -namespace Ogre -{ - class Camera; - class RenderTarget; -} - -namespace MWRender -{ - - class Refraction : public Ogre::RenderTargetListener, public Ogre::RenderQueueListener - { - - public: - Refraction(Ogre::Camera* parentCamera); - ~Refraction(); - - void setHeight (float height); - void preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt); - void setUnderwater(bool underwater) {mIsUnderwater = underwater;} - void setActive (bool active); - - void renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation); - void renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation); - - private: - Ogre::Camera* mParentCamera; - Ogre::Camera* mCamera; - Ogre::RenderTarget* mRenderTarget; - Ogre::Plane mNearClipPlane; - Ogre::Plane mNearClipPlaneUnderwater; - bool mRenderActive; - bool mIsUnderwater; - }; - -} - -#endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 31ff9b02b..a708bbe88 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -34,6 +34,7 @@ #include "vismask.hpp" #include "pathgrid.hpp" #include "camera.hpp" +#include "water.hpp" namespace MWRender { @@ -129,7 +130,9 @@ namespace MWRender mResourceSystem->getSceneManager()->setIncrementalCompileOperation(mViewer->getIncrementalCompileOperation()); - mEffectManager.reset(new EffectManager(mRootNode, mResourceSystem)); + mEffectManager.reset(new EffectManager(lightRoot, mResourceSystem)); + + mWater.reset(new Water(lightRoot, mResourceSystem)); mCamera.reset(new Camera(mViewer->getCamera())); @@ -177,6 +180,7 @@ namespace MWRender mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); mFieldOfView = Settings::Manager::getFloat("field of view", "General"); updateProjectionMatrix(); + mStateUpdater->setFogEnd(mViewDistance); } RenderingManager::~RenderingManager() @@ -230,6 +234,8 @@ namespace MWRender void RenderingManager::addCell(const MWWorld::CellStore *store) { mPathgrid->addCell(store); + + mWater->changeCell(store); } void RenderingManager::removeCell(const MWWorld::CellStore *store) @@ -253,6 +259,22 @@ namespace MWRender mStateUpdater->setWireframe(wireframe); return wireframe; } + else if (mode == Render_Water) + { + return mWater->toggle(); + } + else if (mode == Render_Scene) + { + int mask = mViewer->getCamera()->getCullMask(); + bool enabled = mask&Mask_Scene; + enabled = !enabled; + if (enabled) + mask |= Mask_Scene; + else + mask &= ~Mask_Scene; + mViewer->getCamera()->setCullMask(mask); + return enabled; + } /* else //if (mode == Render_BoundingBoxes) { @@ -271,12 +293,9 @@ namespace MWRender configureFog (cell->mAmbi.mFogDensity, color); } - void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &colour) + void RenderingManager::configureFog(float /* fogDepth */, const osg::Vec4f &color) { - mViewer->getCamera()->setClearColor(colour); - - mStateUpdater->setFogColor(colour); - mStateUpdater->setFogEnd(mViewDistance); + mFogColor = color; } SkyManager* RenderingManager::getSkyManager() @@ -289,6 +308,19 @@ namespace MWRender mEffectManager->update(dt); mSky->update(dt); mCamera->update(dt, paused); + + osg::Vec3f focal, cameraPos; + mCamera->getPosition(focal, cameraPos); + if (mWater->isUnderwater(cameraPos)) + { + setFogColor(osg::Vec4f(0.090195f, 0.115685f, 0.12745f, 1.f)); + mStateUpdater->setFogEnd(1000); + } + else + { + setFogColor(mFogColor); + mStateUpdater->setFogEnd(mViewDistance); + } } void RenderingManager::updatePlayerPtr(const MWWorld::Ptr &ptr) @@ -325,6 +357,16 @@ namespace MWRender mObjects->removeObject(ptr); } + void RenderingManager::setWaterEnabled(bool enabled) + { + mWater->setEnabled(enabled); + } + + void RenderingManager::setWaterHeight(float height) + { + mWater->setHeight(height); + } + void RenderingManager::getCameraToViewportRay(float nX, float nY, osg::Vec3f &origin, osg::Vec3f &dest) { osg::Matrix viewProj = mViewer->getCamera()->getViewMatrix() * mViewer->getCamera()->getProjectionMatrix(); @@ -390,7 +432,7 @@ namespace MWRender osgUtil::IntersectionVisitor intersectionVisitor(intersector); int mask = intersectionVisitor.getTraversalMask(); - mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect); + mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water); if (ignorePlayer) mask &= ~(Mask_Player); @@ -521,6 +563,13 @@ namespace MWRender mViewer->startThreading(); } + void RenderingManager::setFogColor(const osg::Vec4f &color) + { + mViewer->getCamera()->setClearColor(color); + + mStateUpdater->setFogColor(color); + } + void RenderingManager::processChangedSettings(const Settings::CategorySettingVector &changed) { for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 57a2df60e..d90a75c86 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -42,6 +42,7 @@ namespace MWRender class NpcAnimation; class Pathgrid; class Camera; + class Water; class RenderingManager : public MWRender::RenderingInterface { @@ -73,6 +74,9 @@ namespace MWRender void removeObject(const MWWorld::Ptr& ptr); + void setWaterEnabled(bool enabled); + void setWaterHeight(float level); + /// Return the object under the mouse cursor / crosshair position, given by nX and nY normalized screen coordinates, /// where (0,0) is the top left corner. MWWorld::Ptr getFacedObject(const float nX, const float nY, float maxDistance, bool ignorePlayer); @@ -131,6 +135,7 @@ namespace MWRender private: void updateProjectionMatrix(); void updateTextureFiltering(); + void setFogColor(const osg::Vec4f& color); osg::ref_ptr mViewer; osg::ref_ptr mRootNode; @@ -141,6 +146,7 @@ namespace MWRender std::auto_ptr mPathgrid; std::auto_ptr mObjects; + std::auto_ptr mWater; std::auto_ptr mSky; std::auto_ptr mEffectManager; std::auto_ptr mPlayerAnimation; @@ -149,6 +155,8 @@ namespace MWRender osg::ref_ptr mStateUpdater; + osg::Vec4f mFogColor; + float mNearClip; float mViewDistance; float mFieldOfView; diff --git a/apps/openmw/mwrender/rendermode.hpp b/apps/openmw/mwrender/rendermode.hpp index a74d9bd52..ba767bc55 100644 --- a/apps/openmw/mwrender/rendermode.hpp +++ b/apps/openmw/mwrender/rendermode.hpp @@ -9,7 +9,9 @@ namespace MWRender Render_CollisionDebug, Render_Wireframe, Render_Pathgrid, - Render_BoundingBoxes + Render_BoundingBoxes, + Render_Water, + Render_Scene }; } diff --git a/apps/openmw/mwrender/vismask.hpp b/apps/openmw/mwrender/vismask.hpp index c9ac35c67..3a0336f82 100644 --- a/apps/openmw/mwrender/vismask.hpp +++ b/apps/openmw/mwrender/vismask.hpp @@ -15,13 +15,14 @@ namespace MWRender Mask_Actor = (1<<3), Mask_Player = (1<<4), Mask_Sky = (1<<5), + Mask_Water = (1<<6), // top level masks - Mask_Scene = (1<<6), - Mask_GUI = (1<<7), + Mask_Scene = (1<<7), + Mask_GUI = (1<<8), // Set on cameras within the main scene graph - Mask_RenderToTexture = (1<<8) + Mask_RenderToTexture = (1<<9) // reserved: (1<<16) for SceneUtil::Mask_Lit }; diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index f2175ced5..2dd843e4e 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -1,491 +1,184 @@ #include "water.hpp" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "sky.hpp" -#include "renderingmanager.hpp" -#include "ripplesimulation.hpp" -#include "refraction.hpp" - -#include -#include - -using namespace Ogre; +#include -namespace MWRender -{ - -CubeReflection::CubeReflection(Ogre::SceneManager* sceneManager) - : Reflection(sceneManager) -{ - Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton ().createManual("CubeReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_CUBE_MAP, - 512,512, 0, PF_R8G8B8, TU_RENDERTARGET); - - mCamera = mSceneMgr->createCamera ("CubeCamera"); - mCamera->setNearClipDistance (5); - mCamera->setFarClipDistance (1000); - - for (int face = 0; face < 6; ++face) - { - mRenderTargets[face] = texture->getBuffer (face)->getRenderTarget(); - mRenderTargets[face]->removeAllViewports (); - Viewport* vp = mRenderTargets[face]->addViewport (mCamera); - vp->setOverlaysEnabled(false); - vp->setShadowsEnabled(false); - vp->setMaterialScheme ("water_reflection"); - mRenderTargets[face]->setAutoUpdated(false); - - /* - Vector3 lookAt(0,0,0), up(0,0,0), right(0,0,0); - switch(face) - { - case 0: lookAt.x =-1; up.y = 1; right.z = 1; break; // +X - case 1: lookAt.x = 1; up.y = 1; right.z =-1; break; // -X - case 2: lookAt.y =-1; up.z = 1; right.x = 1; break; // +Y - case 3: lookAt.y = 1; up.z =-1; right.x = 1; break; // -Y - case 4: lookAt.z = 1; up.y = 1; right.x =-1; break; // +Z - case 5: lookAt.z =-1; up.y = 1; right.x =-1; break; // -Z - } - Quaternion orient(right, up, lookAt); - mCamera->setOrientation(orient); - */ - } -} +#include +#include +#include +#include +#include +#include -CubeReflection::~CubeReflection () -{ - Ogre::TextureManager::getSingleton ().remove("CubeReflection"); - mSceneMgr->destroyCamera (mCamera); -} +#include +#include -void CubeReflection::update () -{ - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setPosition(mParentCamera->getDerivedPosition()); -} +#include +#include -// -------------------------------------------------------------------------------------------------------------------------------- +#include "vismask.hpp" -PlaneReflection::PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky) - : Reflection(sceneManager) - , mSky(sky) - , mRenderActive(false) +namespace { - mCamera = mSceneMgr->createCamera ("PlaneReflectionCamera"); - mSceneMgr->addRenderQueueListener(this); - - mTexture = TextureManager::getSingleton().createManual("WaterReflection", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, TEX_TYPE_2D, 512, 512, 0, PF_R8G8B8, TU_RENDERTARGET); - - mRenderTarget = mTexture->getBuffer()->getRenderTarget(); - Viewport* vp = mRenderTarget->addViewport(mCamera); - vp->setOverlaysEnabled(false); - vp->setBackgroundColour(ColourValue(0.8f, 0.9f, 1.0f)); - vp->setShadowsEnabled(false); - vp->setMaterialScheme("water_reflection"); - mRenderTarget->addListener(this); - mRenderTarget->setActive(true); - mRenderTarget->setAutoUpdated(true); - - sh::Factory::getInstance ().setTextureAlias ("WaterReflection", mTexture->getName()); -} -PlaneReflection::~PlaneReflection () -{ - mRenderTarget->removeListener (this); - mSceneMgr->destroyCamera (mCamera); - mSceneMgr->removeRenderQueueListener(this); - TextureManager::getSingleton ().remove("WaterReflection"); -} - -void PlaneReflection::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 && mRenderActive) + osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats) { - mCamera->disableCustomNearClipPlane(); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } -} - -void PlaneReflection::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation) -{ - if (queueGroupId < 20 && mRenderActive) - { - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); - Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS()); - } -} - -void PlaneReflection::preRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ - if (mParentCamera->isAttached()) - mParentCamera->getParentSceneNode ()->needUpdate (); - mCamera->setOrientation(mParentCamera->getDerivedOrientation()); - mCamera->setPosition(mParentCamera->getDerivedPosition()); - mCamera->setNearClipDistance(mParentCamera->getNearClipDistance()); - mCamera->setFarClipDistance(mParentCamera->getFarClipDistance()); - mCamera->setAspectRatio(mParentCamera->getAspectRatio()); - mCamera->setFOVy(mParentCamera->getFOVy()); - mRenderActive = true; - - mCamera->enableReflection(mWaterPlane); - - // for depth calculation, we want the original viewproj matrix _without_ the custom near clip plane. - // since all we are interested in is depth, we only need the third row of the matrix. - Ogre::Matrix4 projMatrix = mCamera->getProjectionMatrixWithRSDepth () * mCamera->getViewMatrix (); - sh::Vector4* row3 = new sh::Vector4(projMatrix[2][0], projMatrix[2][1], projMatrix[2][2], projMatrix[2][3]); - sh::Factory::getInstance ().setSharedParameter ("vpRow2Fix", sh::makeProperty (row3)); - - // enable clip plane here to take advantage of CPU culling for overwater or underwater objects - mCamera->enableCustomNearClipPlane(mIsUnderwater ? mErrorPlaneUnderwater : mErrorPlane); -} - -void PlaneReflection::postRenderTargetUpdate(const Ogre::RenderTargetEvent& evt) -{ - mCamera->disableReflection(); - mCamera->disableCustomNearClipPlane(); - mRenderActive = false; -} - -void PlaneReflection::setHeight (float height) -{ - mWaterPlane = Plane(Ogre::Vector3(0,0,1), height); - mErrorPlane = Plane(Ogre::Vector3(0,0,1), height - 5); - mErrorPlaneUnderwater = Plane(Ogre::Vector3(0,0,-1), -height - 5); -} - -void PlaneReflection::setActive (bool active) -{ - mRenderTarget->setActive(active); -} - -void PlaneReflection::setViewportBackground(Ogre::ColourValue colour) -{ - mRenderTarget->getViewport (0)->setBackgroundColour (colour); -} - -void PlaneReflection::setVisibilityMask (int flags) -{ - mRenderTarget->getViewport (0)->setVisibilityMask (flags); -} - -// -------------------------------------------------------------------------------------------------------------------------------- - -Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) : - mCamera (camera), mSceneMgr (camera->getSceneManager()), - mIsUnderwater(false), mActive(1), - mToggled(1), mWaterTimer(0.f), - mRendering(rend), - mVisibilityFlags(0), - mReflection(NULL), - mRefraction(NULL), - mSimulation(NULL), - mPlayer(0,0) -{ - mSimulation = new RippleSimulation(mSceneMgr, fallback); - - mSky = rend->getSkyManager(); - - mMaterial = MaterialManager::getSingleton().getByName("Water"); - - mTop = 0; - - mIsUnderwater = false; - - mWaterPlane = Plane(Vector3::UNIT_Z, 0); - - int waterScale = 30; - - MeshManager::getSingleton().createPlane("water", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mWaterPlane, - static_cast(CELL_SIZE*5*waterScale), static_cast(CELL_SIZE*5*waterScale), - 40, 40, true, 1, static_cast(3 * waterScale), static_cast(3 * waterScale), Vector3::UNIT_Y); - - mWater = mSceneMgr->createEntity("water"); - mWater->setVisibilityFlags(RV_Water); - mWater->setCastShadows(false); - mWater->setRenderQueueGroup(RQG_Alpha); - - mWaterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - - mWaterNode->attachObject(mWater); - - applyRTT(); - applyVisibilityMask(); - - mWater->setMaterial(mMaterial); + osg::ref_ptr verts (new osg::Vec3Array); + osg::ref_ptr texcoords (new osg::Vec2Array); + + // some drivers don't like huge triangles, so we do some subdivisons + // a paged solution would be even better + const float step = size/segments; + const float texCoordStep = textureRepeats / segments; + for (int x=0; xpush_back(osg::Vec3f(x1, y2, 0.f)); + verts->push_back(osg::Vec3f(x1, y1, 0.f)); + verts->push_back(osg::Vec3f(x2, y1, 0.f)); + verts->push_back(osg::Vec3f(x2, y2, 0.f)); + + float u1 = x*texCoordStep; + float v1 = y*texCoordStep; + float u2 = u1 + texCoordStep; + float v2 = v1 + texCoordStep; + + texcoords->push_back(osg::Vec2f(u1, v2)); + texcoords->push_back(osg::Vec2f(u1, v1)); + texcoords->push_back(osg::Vec2f(u2, v1)); + texcoords->push_back(osg::Vec2f(u2, v2)); + } + } - setHeight(mTop); + osg::ref_ptr waterGeom (new osg::Geometry); + waterGeom->setVertexArray(verts); + waterGeom->setTexCoordArray(0, texcoords); - sh::MaterialInstance* m = sh::Factory::getInstance ().getMaterialInstance ("Water"); - m->setListener (this); + waterGeom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,verts->size())); + return waterGeom; + } - // ---------------------------------------------------------------------------------------------- - // ---------------------------------- reflection debug overlay ---------------------------------- - // ---------------------------------------------------------------------------------------------- -/* - if (Settings::Manager::getBool("shader", "Water")) + void createWaterStateSet(Resource::ResourceSystem* resourceSystem, osg::ref_ptr node) { - OverlayManager& mgr = OverlayManager::getSingleton(); - Overlay* overlay; - // destroy if already exists - if ((overlay = mgr.getByName("ReflectionDebugOverlay"))) - mgr.destroy(overlay); + osg::ref_ptr stateset (new osg::StateSet); - overlay = mgr.create("ReflectionDebugOverlay"); + osg::ref_ptr material (new osg::Material); + material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4f(1.f, 1.f, 1.f, 1.f)); + material->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.7f)); + material->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 1.f)); + material->setColorMode(osg::Material::OFF); + stateset->setAttributeAndModes(material, osg::StateAttribute::ON); - if (MaterialManager::getSingleton().resourceExists("Ogre/ReflectionDebugTexture")) - MaterialManager::getSingleton().remove("Ogre/ReflectionDebugTexture"); - MaterialPtr debugMat = MaterialManager::getSingleton().create( - "Ogre/ReflectionDebugTexture", - ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + stateset->setMode(GL_BLEND, osg::StateAttribute::ON); + stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - debugMat->getTechnique(0)->getPass(0)->setLightingEnabled(false); - debugMat->getTechnique(0)->getPass(0)->createTextureUnitState(mReflectionTexture->getName()); + osg::ref_ptr depth (new osg::Depth); + depth->setWriteMask(false); + stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); - OverlayContainer* debugPanel; + stateset->setRenderBinDetails(9, "RenderBin"); - // destroy container if exists - try + std::vector > textures; + for (int i=0; i<32; ++i) { - if ((debugPanel = - static_cast( - mgr.getOverlayElement("Ogre/ReflectionDebugTexPanel" - )))) - mgr.destroyOverlayElement(debugPanel); + std::ostringstream texname; + texname << "textures/water/water" << std::setw(2) << std::setfill('0') << i << ".dds"; + textures.push_back(resourceSystem->getTextureManager()->getTexture2D(texname.str(), osg::Texture::REPEAT, osg::Texture::REPEAT)); } - catch (Ogre::Exception&) {} - - debugPanel = (OverlayContainer*) - (OverlayManager::getSingleton().createOverlayElement("Panel", "Ogre/ReflectionDebugTexPanel")); - debugPanel->_setPosition(0, 0.55); - debugPanel->_setDimensions(0.3, 0.3); - debugPanel->setMaterialName(debugMat->getName()); - debugPanel->show(); - overlay->add2D(debugPanel); - overlay->show(); - } -*/ -} -void Water::setActive(bool active) -{ - mActive = active; - updateVisible(); + osg::ref_ptr controller (new NifOsg::FlipController(0, 2/32.f, textures)); + controller->setSource(boost::shared_ptr(new SceneUtil::FrameTimeSource)); + node->addUpdateCallback(controller); + node->setStateSet(stateset); + stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); + } - sh::Factory::getInstance ().setSharedParameter ("waterEnabled", sh::makeProperty (new sh::FloatValue(active ? 1.0f : 0.0f))); } -Water::~Water() +namespace MWRender { - MeshManager::getSingleton().remove("water"); - - mWaterNode->detachObject(mWater); - mSceneMgr->destroyEntity(mWater); - mSceneMgr->destroySceneNode(mWaterNode); - delete mReflection; - delete mRefraction; - delete mSimulation; -} +// -------------------------------------------------------------------------------------------------------------------------------- -void Water::changeCell(const ESM::Cell* cell) +Water::Water(osg::Group *parent, Resource::ResourceSystem *resourceSystem) + : mParent(parent) + , mResourceSystem(resourceSystem) + , mEnabled(true) + , mToggled(true) + , mTop(0) { - if(cell->isExterior()) - mWaterNode->setPosition(getSceneNodeCoordinates(cell->mData.mX, cell->mData.mY)); -} + osg::ref_ptr waterGeom = createWaterGeometry(CELL_SIZE*150, 40, 900); -void Water::setHeight(const float height) -{ - mTop = height; + osg::ref_ptr geode (new osg::Geode); + geode->addDrawable(waterGeom); + geode->setNodeMask(Mask_Water); - mSimulation->setWaterHeight(height); + createWaterStateSet(mResourceSystem, geode); - mWaterPlane = Plane(Vector3::UNIT_Z, -height); + mWaterNode = new osg::PositionAttitudeTransform; + mWaterNode->addChild(geode); - if (mReflection) - mReflection->setHeight(height); - if (mRefraction) - mRefraction->setHeight(height); + mParent->addChild(mWaterNode); - mWaterNode->setPosition(0, 0, height); - sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty(new sh::FloatValue(height))); + setHeight(mTop); } -bool Water::toggle() +Water::~Water() { - mToggled = !mToggled; - updateVisible(); - return mToggled; + mParent->removeChild(mWaterNode); } -void -Water::updateUnderwater(bool underwater) +void Water::setEnabled(bool enabled) { - if (!mActive) { - return; - } - mIsUnderwater = - underwater && - mWater->isVisible() && - mCamera->getPolygonMode() == Ogre::PM_SOLID; - - if (mReflection) - mReflection->setUnderwater (mIsUnderwater); - if (mRefraction) - mRefraction->setUnderwater (mIsUnderwater); - + mEnabled = enabled; updateVisible(); } -Vector3 Water::getSceneNodeCoordinates(int gridX, int gridY) +void Water::changeCell(const MWWorld::CellStore* store) { - return Vector3(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); + if (store->getCell()->isExterior()) + mWaterNode->setPosition(getSceneNodeCoordinates(store->getCell()->mData.mX, store->getCell()->mData.mY)); + else + mWaterNode->setPosition(osg::Vec3f(0,0,mTop)); } -void Water::setViewportBackground(const ColourValue& bg) +void Water::setHeight(const float height) { - if (mReflection) - mReflection->setViewportBackground(bg); -} + mTop = height; -void Water::updateVisible() -{ - mWater->setVisible(mToggled && mActive); - if (mReflection) - mReflection->setActive(mToggled && mActive); - if (mRefraction) - mRefraction->setActive(mToggled && mActive); + osg::Vec3f pos = mWaterNode->getPosition(); + pos.z() = height; + mWaterNode->setPosition(pos); } -void Water::update(float dt, Ogre::Vector3 player) +void Water::updateVisible() { - mWaterTimer += dt; - sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty(new sh::FloatValue(mWaterTimer))); - - mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater); - - mPlayer = Ogre::Vector2(player.x, player.y); + mWaterNode->setNodeMask(mEnabled && mToggled ? ~0 : 0); } -void Water::frameStarted(float dt) -{ - if (!mActive) - return; - - mSimulation->update(dt, mPlayer); - - if (mReflection) - { - mReflection->update(); - } -} - -void Water::applyRTT() +bool Water::toggle() { - delete mReflection; - mReflection = NULL; - delete mRefraction; - mRefraction = NULL; - - // Create rendertarget for reflection - //int rttsize = Settings::Manager::getInt("rtt size", "Water"); - - if (Settings::Manager::getBool("shader", "Water")) - { - mReflection = new PlaneReflection(mSceneMgr, mSky); - mReflection->setParentCamera (mCamera); - mReflection->setHeight(mTop); - - if (Settings::Manager::getBool("refraction", "Water")) - { - mRefraction = new Refraction(mCamera); - mRefraction->setHeight(mTop); - } - } - + mToggled = !mToggled; updateVisible(); + return mToggled; } -void Water::applyVisibilityMask() -{ - mVisibilityFlags = RV_Terrain * Settings::Manager::getBool("reflect terrain", "Water") - + (RV_Statics + RV_StaticsSmall + RV_Misc) * Settings::Manager::getBool("reflect statics", "Water") - + RV_Actors * Settings::Manager::getBool("reflect actors", "Water") - + RV_Effects - + RV_Sky; - - if (mReflection) - mReflection->setVisibilityMask(mVisibilityFlags); -} - -void Water::processChangedSettings(const Settings::CategorySettingVector& settings) -{ - bool applyRT = false; - bool applyVisMask = false; - for (Settings::CategorySettingVector::const_iterator it=settings.begin(); - it != settings.end(); ++it) - { - if ( it->first == "Water" && ( - it->second == "shader" - || it->second == "refraction" - || it->second == "rtt size")) - applyRT = true; - - if ( it->first == "Water" && ( - it->second == "reflect actors" - || it->second == "reflect terrain" - || it->second == "reflect statics")) - applyVisMask = true; - } - - if(applyRT) - { - applyRTT(); - applyVisibilityMask(); - mWater->setMaterial(mMaterial); - } - if (applyVisMask) - applyVisibilityMask(); -} - -void Water::requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration) +bool Water::isUnderwater(const osg::Vec3f &pos) const { + return pos.z() < mTop && mToggled && mEnabled; } -void Water::createdConfiguration (sh::MaterialInstance* m, const std::string& configuration) +osg::Vec3f Water::getSceneNodeCoordinates(int gridX, int gridY) { - if (configuration == "local_map" || !Settings::Manager::getBool("shader", "Water")) - { - // for simple water, set animated texture names - // these have to be set in code - std::string textureNames[32]; - for (int i=0; i<32; ++i) - { - textureNames[i] = "textures\\water\\water" + StringConverter::toString(i, 2, '0') + ".dds"; - } - - Ogre::Technique* t = static_cast(m->getMaterial())->getOgreTechniqueForConfiguration(configuration); - if (t->getPass(0)->getNumTextureUnitStates () == 0) - return; - t->getPass(0)->getTextureUnitState(0)->setAnimatedTextureName(textureNames, 32, 2); - t->getPass(0)->setDepthWriteEnabled (false); - t->getPass(0)->setSceneBlending (Ogre::SBT_TRANSPARENT_ALPHA); - } + return osg::Vec3f(static_cast(gridX * CELL_SIZE + (CELL_SIZE / 2)), static_cast(gridY * CELL_SIZE + (CELL_SIZE / 2)), mTop); } +/* void Water::addEmitter (const MWWorld::Ptr& ptr, float scale, float force) { mSimulation->addEmitter (ptr, scale, force); @@ -500,10 +193,6 @@ void Water::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr) { mSimulation->updateEmitterPtr(old, ptr); } +*/ -void Water::clearRipples() -{ - mSimulation->clear(); } - -} // namespace diff --git a/apps/openmw/mwrender/water.hpp b/apps/openmw/mwrender/water.hpp index 53d54cdc9..45b4b38a6 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -1,183 +1,60 @@ -#ifndef GAME_MWRENDER_WATER_H -#define GAME_MWRENDER_WATER_H +#ifndef OPENMW_MWRENDER_WATER_H +#define OPENMW_MWRENDER_WATER_H -#include -#include -#include -#include -#include -#include -#include +#include -#include -#include +#include "../mwworld/cellstore.hpp" -#include - - -#include "renderconst.hpp" - -#include "../mwworld/ptr.hpp" - -namespace Ogre +namespace osg { - class Camera; - class SceneManager; - class SceneNode; - class Entity; - class Vector3; - class Rectangle2D; - struct RenderTargetEvent; + class Group; + class PositionAttitudeTransform; } -namespace MWWorld +namespace Resource { - class Fallback; + class ResourceSystem; } -namespace MWRender { - - class SkyManager; - class RenderingManager; - class RippleSimulation; - class Refraction; - - class Reflection - { - public: - Reflection(Ogre::SceneManager* sceneManager) - : mCamera(NULL) - , mParentCamera(NULL) - , mSceneMgr(sceneManager) - , mIsUnderwater(false) - {} - virtual ~Reflection() {} - - virtual void setHeight (float height) {} - virtual void setParentCamera (Ogre::Camera* parent) { mParentCamera = parent; } - void setUnderwater(bool underwater) { mIsUnderwater = underwater; } - virtual void setActive (bool active) {} - virtual void setViewportBackground(Ogre::ColourValue colour) {} - virtual void update() {} - virtual void setVisibilityMask (int flags) {} - - protected: - Ogre::Camera* mCamera; - Ogre::Camera* mParentCamera; - Ogre::TexturePtr mTexture; - Ogre::SceneManager* mSceneMgr; - bool mIsUnderwater; - }; - - class CubeReflection : public Reflection - { - public: - CubeReflection(Ogre::SceneManager* sceneManager); - virtual ~CubeReflection(); - - virtual void update(); - protected: - Ogre::RenderTarget* mRenderTargets[6]; - }; - - class PlaneReflection : public Reflection, public Ogre::RenderQueueListener, public Ogre::RenderTargetListener - { - public: - PlaneReflection(Ogre::SceneManager* sceneManager, SkyManager* sky); - virtual ~PlaneReflection(); - - virtual void setHeight (float height); - virtual void setActive (bool active); - virtual void setVisibilityMask (int flags); - - 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); - - virtual void setViewportBackground(Ogre::ColourValue colour); - - protected: - Ogre::RenderTarget* mRenderTarget; - SkyManager* mSky; - Ogre::Plane mWaterPlane; - Ogre::Plane mErrorPlane; - Ogre::Plane mErrorPlaneUnderwater; - bool mRenderActive; - }; +namespace MWRender +{ /// Water rendering - class Water : public sh::MaterialInstanceListener + class Water { static const int CELL_SIZE = 8192; - Ogre::Camera *mCamera; - Ogre::SceneManager *mSceneMgr; - - Ogre::Plane mWaterPlane; - Ogre::SceneNode *mWaterNode; - Ogre::Entity *mWater; + osg::ref_ptr mParent; + osg::ref_ptr mWaterNode; + Resource::ResourceSystem* mResourceSystem; - bool mIsUnderwater; - bool mActive; + bool mEnabled; bool mToggled; float mTop; - float mWaterTimer; - - - Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY); - - protected: - void applyRTT(); - void applyVisibilityMask(); - + osg::Vec3f getSceneNodeCoordinates(int gridX, int gridY); void updateVisible(); - RenderingManager* mRendering; - SkyManager* mSky; - - Ogre::MaterialPtr mMaterial; - - bool mUnderwaterEffect; - int mVisibilityFlags; - - Reflection* mReflection; - Refraction* mRefraction; - RippleSimulation* mSimulation; - - Ogre::Vector2 mPlayer; - public: - Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback); + Water(osg::Group* parent, Resource::ResourceSystem* resourceSystem); ~Water(); - void clearRipples(); - - void setActive(bool active); + void setEnabled(bool enabled); bool toggle(); - void update(float dt, Ogre::Vector3 player); - void frameStarted(float dt); + bool isUnderwater(const osg::Vec3f& pos) const; + + /* /// adds an emitter, position will be tracked automatically using its scene node void addEmitter (const MWWorld::Ptr& ptr, float scale = 1.f, float force = 1.f); void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); + */ - void setViewportBackground(const Ogre::ColourValue& bg); - - void processChangedSettings(const Settings::CategorySettingVector& settings); - - /// Updates underwater state accordingly - void updateUnderwater(bool underwater); - void changeCell(const ESM::Cell* cell); + void changeCell(const MWWorld::CellStore* store); void setHeight(const float height); - virtual void requestedConfiguration (sh::MaterialInstance* m, const std::string& configuration); - virtual void createdConfiguration (sh::MaterialInstance* m, const std::string& configuration); - }; } diff --git a/apps/openmw/mwworld/scene.cpp b/apps/openmw/mwworld/scene.cpp index db1f9714a..1a9ae3494 100644 --- a/apps/openmw/mwworld/scene.cpp +++ b/apps/openmw/mwworld/scene.cpp @@ -265,11 +265,11 @@ namespace MWWorld mRendering.addCell(cell); bool waterEnabled = cell->getCell()->hasWater() || cell->isExterior(); float waterLevel = cell->isExterior() ? -1.f : cell->getWaterLevel(); - //mRendering.setWaterEnabled(waterEnabled); + mRendering.setWaterEnabled(waterEnabled); if (waterEnabled) { mPhysics->enableWater(waterLevel); - //mRendering.setWaterHeight(waterLevel); + mRendering.setWaterHeight(waterLevel); } else mPhysics->disableWater(); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 126267fd4..799f82015 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1763,17 +1763,17 @@ namespace MWWorld void World::setWaterHeight(const float height) { mPhysics->setWaterHeight(height); - //mRendering->setWaterHeight(height); + mRendering->setWaterHeight(height); } bool World::toggleWater() { - return 0;//mRendering->toggleWater(); + return mRendering->toggleRenderMode(MWRender::Render_Water); } bool World::toggleWorld() { - return 0;//mRendering->toggleWorld(); + return mRendering->toggleRenderMode(MWRender::Render_Scene); } void World::PCDropped (const Ptr& item) diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 06d5d8792..a314910c5 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -399,6 +399,13 @@ FlipController::FlipController(const Nif::NiFlipController *ctrl, std::vector > textures) + : mTexSlot(texSlot) + , mDelta(delta) + , mTextures(textures) +{ +} + FlipController::FlipController() { } diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 4ebd4f41d..4877c83db 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -218,6 +218,7 @@ namespace NifOsg public: FlipController(const Nif::NiFlipController* ctrl, std::vector > textures); + FlipController(int texSlot, float delta, std::vector > textures); FlipController(); FlipController(const FlipController& copy, const osg::CopyOp& copyop); diff --git a/components/sceneutil/controller.cpp b/components/sceneutil/controller.cpp index 4b51485f2..b8b452dc3 100644 --- a/components/sceneutil/controller.cpp +++ b/components/sceneutil/controller.cpp @@ -20,7 +20,10 @@ namespace SceneUtil float Controller::getInputValue(osg::NodeVisitor* nv) { - return mFunction->calculate(mSource->getValue(nv)); + if (mFunction) + return mFunction->calculate(mSource->getValue(nv)); + else + return mSource->getValue(nv); } void Controller::setSource(boost::shared_ptr source)