From dbd4abd6fe3ae3b3f1e812c8069b094bad50846e Mon Sep 17 00:00:00 2001 From: scrawl Date: Mon, 9 Feb 2015 19:28:29 +0100 Subject: [PATCH] Fix ripples for D3D - added simpler effect (Fixes #1649) --- apps/openmw/engine.cpp | 1 + apps/openmw/mwrender/renderconst.hpp | 1 + apps/openmw/mwrender/renderingmanager.cpp | 3 +- apps/openmw/mwrender/ripplesimulation.cpp | 275 ++++++------------ apps/openmw/mwrender/ripplesimulation.hpp | 62 ++-- apps/openmw/mwrender/water.cpp | 20 +- apps/openmw/mwrender/water.hpp | 9 +- apps/openmw/mwworld/fallback.cpp | 9 + apps/openmw/mwworld/fallback.hpp | 1 + files/CMakeLists.txt | 7 +- files/materials/ripples.particle | 26 ++ files/materials/water.mat | 24 ++ files/materials/water.shader | 17 +- files/materials/watersim.mat | 59 ---- files/materials/watersim.shaderset | 31 -- files/materials/watersim_addimpulse.shader | 12 - files/materials/watersim_common.h | 25 -- files/materials/watersim_heightmap.shader | 51 ---- .../materials/watersim_heighttonormal.shader | 36 --- 19 files changed, 195 insertions(+), 474 deletions(-) create mode 100644 files/materials/ripples.particle delete mode 100644 files/materials/watersim.mat delete mode 100644 files/materials/watersim.shaderset delete mode 100644 files/materials/watersim_addimpulse.shader delete mode 100644 files/materials/watersim_common.h delete mode 100644 files/materials/watersim_heightmap.shader delete mode 100644 files/materials/watersim_heighttonormal.shader diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 859baebe4ac..9b87c612d4c 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -349,6 +349,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) addResourcesDirectory(mResDir / "mygui"); addResourcesDirectory(mResDir / "water"); addResourcesDirectory(mResDir / "shadows"); + addResourcesDirectory(mResDir / "materials"); OEngine::Render::WindowSettings windowSettings; windowSettings.fullscreen = settings.getBool("fullscreen", "Video"); diff --git a/apps/openmw/mwrender/renderconst.hpp b/apps/openmw/mwrender/renderconst.hpp index 4ac21ad510d..cfd84cb32e8 100644 --- a/apps/openmw/mwrender/renderconst.hpp +++ b/apps/openmw/mwrender/renderconst.hpp @@ -21,6 +21,7 @@ enum RenderQueueGroups RQG_UnderWater = Ogre::RENDER_QUEUE_4, RQG_Water = RQG_Alpha, + RQG_Ripples = RQG_Water+1, // Sky late (sun & sun flare) RQG_SkiesLate = Ogre::RENDER_QUEUE_SKIES_LATE diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 88ede1682c0..8b7f04b19d9 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -175,7 +175,7 @@ RenderingManager::RenderingManager(OEngine::Render::OgreRenderer& _rend, const b mDebugging = new Debugging(mRootNode, engine); mLocalMap = new MWRender::LocalMap(&mRendering, this); - mWater = new MWRender::Water(mRendering.getCamera(), this); + mWater = new MWRender::Water(mRendering.getCamera(), this, mFallback); setMenuTransparency(Settings::Manager::getFloat("menu transparency", "GUI")); } @@ -693,6 +693,7 @@ void RenderingManager::enableLights(bool sun) void RenderingManager::notifyWorldSpaceChanged() { mEffectManager->clear(); + mWater->clearRipples(); } Ogre::Vector4 RenderingManager::boundingBoxToScreen(Ogre::AxisAlignedBox bounds) diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index 64b5e48c383..84794162f3a 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -1,162 +1,72 @@ #include "ripplesimulation.hpp" -#include -#include -#include -#include -#include +#include + #include -#include -#include +#include +#include +#include #include #include "../mwbase/environment.hpp" #include "../mwbase/world.hpp" -namespace MWRender -{ +#include "../mwworld/fallback.hpp" +#include "renderconst.hpp" -RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager) - : mMainSceneMgr(mainSceneManager), - mTime(0), - mCurrentFrameOffset(0,0), - mPreviousFrameOffset(0,0), - mRippleCenter(0,0), - mTextureSize(512), - mRippleAreaLength(1000), - mImpulseSize(20), - mTexelOffset(0,0), - mFirstUpdate(true), - mRectangle(NULL), - mImpulse(NULL) +namespace MWRender { - Ogre::AxisAlignedBox aabInf; - aabInf.setInfinite(); - - mSceneMgr = Ogre::Root::getSingleton().createSceneManager(Ogre::ST_GENERIC); - - mCamera = mSceneMgr->createCamera("RippleCamera"); - - mRectangle = new Ogre::Rectangle2D(true); - mRectangle->setBoundingBox(aabInf); - mRectangle->setCorners(-1.0, 1.0, 1.0, -1.0, false); - Ogre::SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - node->attachObject(mRectangle); - mImpulse = new Ogre::Rectangle2D(true); - mImpulse->setCorners(-0.1, 0.1, 0.1, -0.1, false); - mImpulse->setBoundingBox(aabInf); - mImpulse->setMaterial("AddImpulse"); - Ogre::SceneNode* impulseNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); - impulseNode->attachObject(mImpulse); - - //float w=0.05; - for (int i=0; i<4; ++i) - { - Ogre::TexturePtr texture; - if (i != 3) - texture = Ogre::TextureManager::getSingleton().createManual("RippleHeight" + Ogre::StringConverter::toString(i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - else - texture = Ogre::TextureManager::getSingleton().createManual("RippleNormal", - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, Ogre::TEX_TYPE_2D, mTextureSize, mTextureSize, 1, 0, Ogre::PF_R8G8B8, Ogre::TU_RENDERTARGET); - - - Ogre::RenderTexture* rt = texture->getBuffer()->getRenderTarget(); - rt->removeAllViewports(); - rt->addViewport(mCamera); - rt->setAutoUpdated(false); - rt->getViewport(0)->setClearEveryFrame(false); +RippleSimulation::RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback) + : mSceneMgr(mainSceneManager) + , mParticleSystem(NULL) + , mSceneNode(NULL) +{ + mRippleLifeTime = fallback->getFallbackFloat("Water_RippleLifetime"); + mRippleRotSpeed = fallback->getFallbackFloat("Water_RippleRotSpeed"); - // debug overlay - /* - Ogre::Rectangle2D* debugOverlay = new Ogre::Rectangle2D(true); - debugOverlay->setCorners(w*2-1, 0.9, (w+0.18)*2-1, 0.4, false); - w += 0.2; - debugOverlay->setBoundingBox(aabInf); - Ogre::SceneNode* debugNode = mMainSceneMgr->getRootSceneNode()->createChildSceneNode(); - debugNode->attachObject(debugOverlay); + // Unknown: + // fallback=Water_RippleScale,0.15, 6.5 + // fallback=Water_RippleAlphas,0.7, 0.1, 0.01 - Ogre::MaterialPtr debugMaterial = Ogre::MaterialManager::getSingleton().create("RippleDebug" + Ogre::StringConverter::toString(i), - Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + // Instantiate from ripples.particle file + mParticleSystem = mSceneMgr->createParticleSystem("openmw/Ripples", "openmw/Ripples"); - if (i != 3) - debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleHeight" + Ogre::StringConverter::toString(i)); - else - debugMaterial->getTechnique(0)->getPass(0)->createTextureUnitState("RippleNormal"); - debugMaterial->getTechnique(0)->getPass(0)->setLightingEnabled(false); + mParticleSystem->setRenderQueueGroup(RQG_Ripples); + mParticleSystem->setVisibilityFlags(RV_Effects); - debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i)); - */ + int rippleFrameCount = fallback->getFallbackInt("Water_RippleFrameCount"); + std::string tex = fallback->getFallbackString("Water_RippleTexture"); - mRenderTargets[i] = rt; - mTextures[i] = texture; - } + sh::MaterialInstance* mat = sh::Factory::getInstance().getMaterialInstance("openmw/Ripple"); + mat->setProperty("anim_texture2", sh::makeProperty(new sh::StringValue(std::string("textures\\water\\") + tex + ".dds " + + Ogre::StringConverter::toString(rippleFrameCount) + + " " + + Ogre::StringConverter::toString(0.3)))); - sh::Factory::getInstance().setSharedParameter("rippleTextureSize", sh::makeProperty( - new sh::Vector4(1.0/512, 1.0/512, 512, 512))); - sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( - new sh::Vector3(0, 0, 0))); - sh::Factory::getInstance().setSharedParameter("rippleAreaLength", sh::makeProperty( - new sh::FloatValue(mRippleAreaLength))); + // seems to be required to allocate mFreeParticles. TODO: patch Ogre to handle this better + mParticleSystem->_update(0.f); + mSceneNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); + mSceneNode->attachObject(mParticleSystem); } RippleSimulation::~RippleSimulation() { - delete mRectangle; - delete mImpulse; + if (mParticleSystem) + mSceneMgr->destroyParticleSystem(mParticleSystem); + mParticleSystem = NULL; - Ogre::Root::getSingleton().destroySceneManager(mSceneMgr); + if (mSceneNode) + mSceneMgr->destroySceneNode(mSceneNode); + mSceneNode = NULL; } void RippleSimulation::update(float dt, Ogre::Vector2 position) { - // try to keep 20 fps - mTime += dt; - - while (mTime >= 1/20.0 || mFirstUpdate) - { - mPreviousFrameOffset = mCurrentFrameOffset; - - mCurrentFrameOffset = position - mRippleCenter; - // add texel offsets from previous frame. - mCurrentFrameOffset += mTexelOffset; - - mTexelOffset = Ogre::Vector2(std::fmod(mCurrentFrameOffset.x, 1.0f/mTextureSize), - std::fmod(mCurrentFrameOffset.y, 1.0f/mTextureSize)); - - // now subtract new offset in order to snap to texels - mCurrentFrameOffset -= mTexelOffset; - - // texture coordinate space - mCurrentFrameOffset /= mRippleAreaLength; - - mRippleCenter = position; - - addImpulses(); - waterSimulation(); - heightMapToNormalMap(); - - swapHeightMaps(); - if (!mFirstUpdate) - mTime -= 1/20.0; - else - mFirstUpdate = false; - } - - sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty( - new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0))); -} - -void RippleSimulation::addImpulses() -{ - mRectangle->setVisible(false); - mImpulse->setVisible(true); - - /// \todo it should be more efficient to render all emitters at once + bool newParticle = false; for (std::vector::iterator it=mEmitters.begin(); it !=mEmitters.end(); ++it) { if (it->mPtr == MWBase::Environment::get().getWorld ()->getPlayerPtr()) @@ -165,69 +75,50 @@ void RippleSimulation::addImpulses() // for non-player actors this is done in updateObjectCell it->mPtr = MWBase::Environment::get().getWorld ()->getPlayerPtr(); } - const float* _currentPos = it->mPtr.getRefData().getPosition().pos; - Ogre::Vector3 currentPos (_currentPos[0], _currentPos[1], _currentPos[2]); - - if ( (currentPos - it->mLastEmitPosition).length() > 2 - && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), currentPos)) + Ogre::Vector3 currentPos (it->mPtr.getRefData().getPosition().pos); + currentPos.z = 0; + if ( (currentPos - it->mLastEmitPosition).length() > 10 + // Only emit when close to the water surface, not above it and not too deep in the water + && MWBase::Environment::get().getWorld ()->isUnderwater (it->mPtr.getCell(), + Ogre::Vector3(it->mPtr.getRefData().getPosition().pos)) + && !MWBase::Environment::get().getWorld()->isSubmerged(it->mPtr)) { it->mLastEmitPosition = currentPos; - Ogre::Vector2 pos (currentPos.x, currentPos.y); - pos -= mRippleCenter; - pos /= mRippleAreaLength; - float size = mImpulseSize / mRippleAreaLength; - mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false); - - // don't render if we are offscreen - if (pos.x - size >= 1.0 || pos.y+size <= -1.0 || pos.x+size <= -1.0 || pos.y-size >= 1.0) - continue; - mRenderTargets[1]->update(); + newParticle = true; + Ogre::Particle* created = mParticleSystem->createParticle(); + if (!created) + break; // TODO: cleanup the oldest particle to make room +#if OGRE_VERSION >= (1 << 16 | 10 << 8 | 0) + Ogre::Vector3& position = created->mPosition; + Ogre::Vector3& direction = created->mDirection; + Ogre::ColourValue& colour = created->mColour; + float& totalTimeToLive = created->mTotalTimeToLive; + float& timeToLive = created->mTimeToLive; + Ogre::Radian& rotSpeed = created->mRotationSpeed; + Ogre::Radian& rotation = created->mRotation; +#else + Ogre::Vector3& position = created->position; + Ogre::Vector3& direction = created->direction; + Ogre::ColourValue& colour = created->colour; + float& totalTimeToLive = created->totalTimeToLive; + float& timeToLive = created->timeToLive; + Ogre::Radian& rotSpeed = created->rotationSpeed; + Ogre::Radian& rotation = created->rotation; +#endif + timeToLive = totalTimeToLive = mRippleLifeTime; + colour = Ogre::ColourValue(0.f, 0.f, 0.f, 0.7); // Water_RippleAlphas.x? + direction = Ogre::Vector3(0,0,0); + position = currentPos; + position.z = 0; // Z is set by the Scene Node + rotSpeed = mRippleRotSpeed; + rotation = Ogre::Radian(Ogre::Math::RangeRandom(-Ogre::Math::PI, Ogre::Math::PI)); + created->setDimensions(50,50); } } - mImpulse->setVisible(false); - mRectangle->setVisible(true); -} - -void RippleSimulation::waterSimulation() -{ - mRectangle->setMaterial("HeightmapSimulation"); - - sh::Factory::getInstance().setTextureAlias("Heightmap0", mTextures[0]->getName()); - sh::Factory::getInstance().setTextureAlias("Heightmap1", mTextures[1]->getName()); - - sh::Factory::getInstance().setSharedParameter("currentFrameOffset", sh::makeProperty( - new sh::Vector3(mCurrentFrameOffset.x, mCurrentFrameOffset.y, 0))); - sh::Factory::getInstance().setSharedParameter("previousFrameOffset", sh::makeProperty( - new sh::Vector3(mPreviousFrameOffset.x, mPreviousFrameOffset.y, 0))); - - mRenderTargets[2]->update(); -} - -void RippleSimulation::heightMapToNormalMap() -{ - mRectangle->setMaterial("HeightToNormalMap"); - - sh::Factory::getInstance().setTextureAlias("Heightmap2", mTextures[2]->getName()); - - mRenderTargets[TEX_NORMAL]->update(); -} - -void RippleSimulation::swapHeightMaps() -{ - // 0 -> 1 -> 2 to 2 -> 0 ->1 - Ogre::RenderTexture* tmp = mRenderTargets[0]; - Ogre::TexturePtr tmp2 = mTextures[0]; - - mRenderTargets[0] = mRenderTargets[1]; - mTextures[0] = mTextures[1]; - - mRenderTargets[1] = mRenderTargets[2]; - mTextures[1] = mTextures[2]; - - mRenderTargets[2] = tmp; - mTextures[2] = tmp2; + if (newParticle) // now apparently needs another update, otherwise it won't render in the first frame after a particle is created. TODO: patch Ogre to handle this better + mParticleSystem->_update(0.f); } void RippleSimulation::addEmitter(const MWWorld::Ptr& ptr, float scale, float force) @@ -264,5 +155,15 @@ void RippleSimulation::updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld: } } +void RippleSimulation::setWaterHeight(float height) +{ + mSceneNode->setPosition(0,0,height); +} + +void RippleSimulation::clear() +{ + mParticleSystem->clear(); +} + } diff --git a/apps/openmw/mwrender/ripplesimulation.hpp b/apps/openmw/mwrender/ripplesimulation.hpp index e203212cf0a..4551476a4c1 100644 --- a/apps/openmw/mwrender/ripplesimulation.hpp +++ b/apps/openmw/mwrender/ripplesimulation.hpp @@ -1,19 +1,19 @@ #ifndef RIPPLE_SIMULATION_H #define RIPPLE_SIMULATION_H -#include -#include -#include #include #include "../mwworld/ptr.hpp" namespace Ogre { - class RenderTexture; - class Camera; class SceneManager; - class Rectangle2D; + class ParticleSystem; +} + +namespace MWWorld +{ + class Fallback; } namespace MWRender @@ -30,9 +30,11 @@ struct Emitter class RippleSimulation { public: - RippleSimulation(Ogre::SceneManager* mainSceneManager); + RippleSimulation(Ogre::SceneManager* mainSceneManager, const MWWorld::Fallback* fallback); ~RippleSimulation(); + /// @param dt Time since the last frame + /// @param position Position of the player void update(float dt, Ogre::Vector2 position); /// adds an emitter, position will be tracked automatically @@ -40,47 +42,21 @@ class RippleSimulation void removeEmitter (const MWWorld::Ptr& ptr); void updateEmitterPtr (const MWWorld::Ptr& old, const MWWorld::Ptr& ptr); -private: - RippleSimulation(const RippleSimulation&); - RippleSimulation& operator=(const RippleSimulation&); - - std::vector mEmitters; - - Ogre::RenderTexture* mRenderTargets[4]; - Ogre::TexturePtr mTextures[4]; - - int mTextureSize; - float mRippleAreaLength; - float mImpulseSize; - - bool mFirstUpdate; + /// Change the height of the water surface, thus moving all ripples with it + void setWaterHeight(float height); - Ogre::Camera* mCamera; + /// Remove all active ripples + void clear(); - // own scenemanager to render our simulation +private: Ogre::SceneManager* mSceneMgr; - Ogre::Rectangle2D* mRectangle; - - // scenemanager to create the debug overlays on - Ogre::SceneManager* mMainSceneMgr; - - static const int TEX_NORMAL = 3; - - Ogre::Rectangle2D* mImpulse; + Ogre::ParticleSystem* mParticleSystem; + Ogre::SceneNode* mSceneNode; - void addImpulses(); - void heightMapToNormalMap(); - void waterSimulation(); - void swapHeightMaps(); - - float mTime; - - Ogre::Vector2 mRippleCenter; - - Ogre::Vector2 mTexelOffset; + std::vector mEmitters; - Ogre::Vector2 mCurrentFrameOffset; - Ogre::Vector2 mPreviousFrameOffset; + float mRippleLifeTime; + float mRippleRotSpeed; }; } diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 44e18426965..456fc47e971 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -20,9 +20,6 @@ #include #include -#include "../mwbase/environment.hpp" -#include "../mwbase/world.hpp" - using namespace Ogre; namespace MWRender @@ -187,7 +184,7 @@ void PlaneReflection::setVisibilityMask (int flags) // -------------------------------------------------------------------------------------------------------------------------------- -Water::Water (Ogre::Camera *camera, RenderingManager* rend) : +Water::Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback) : mCamera (camera), mSceneMgr (camera->getSceneManager()), mIsUnderwater(false), mVisibilityFlags(0), mActive(1), mToggled(1), @@ -198,7 +195,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend) : mSimulation(NULL), mPlayer(0,0) { - mSimulation = new RippleSimulation(mSceneMgr); + mSimulation = new RippleSimulation(mSceneMgr, fallback); mSky = rend->getSkyManager(); @@ -313,6 +310,8 @@ void Water::setHeight(const float height) { mTop = height; + mSimulation->setWaterHeight(height); + mWaterPlane = Plane(Vector3::UNIT_Z, -height); if (mReflection) @@ -382,9 +381,13 @@ void Water::update(float dt, Ogre::Vector3 player) void Water::frameStarted(float dt) { + if (!mActive) + return; + + mSimulation->update(dt, mPlayer); + if (mReflection) { - mSimulation->update(dt, mPlayer); mReflection->update(); } } @@ -497,4 +500,9 @@ 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 6a7b05a3aaa..10d0a06ffbf 100644 --- a/apps/openmw/mwrender/water.hpp +++ b/apps/openmw/mwrender/water.hpp @@ -30,6 +30,11 @@ namespace Ogre struct RenderTargetEvent; } +namespace MWWorld +{ + class Fallback; +} + namespace MWRender { class SkyManager; @@ -145,9 +150,11 @@ namespace MWRender { Ogre::Vector2 mPlayer; public: - Water (Ogre::Camera *camera, RenderingManager* rend); + Water (Ogre::Camera *camera, RenderingManager* rend, const MWWorld::Fallback* fallback); ~Water(); + void clearRipples(); + void setActive(bool active); bool toggle(); diff --git a/apps/openmw/mwworld/fallback.cpp b/apps/openmw/mwworld/fallback.cpp index c0b21b2ef25..3a8154ca7cc 100644 --- a/apps/openmw/mwworld/fallback.cpp +++ b/apps/openmw/mwworld/fallback.cpp @@ -22,6 +22,15 @@ namespace MWWorld else return boost::lexical_cast(fallback); } + int Fallback::getFallbackInt(const std::string& fall) const + { + std::string fallback=getFallbackString(fall); + if(fallback.empty()) + return 0; + else + return boost::lexical_cast(fallback); + } + bool Fallback::getFallbackBool(const std::string& fall) const { std::string fallback=getFallbackString(fall); diff --git a/apps/openmw/mwworld/fallback.hpp b/apps/openmw/mwworld/fallback.hpp index 6c5802e0716..f69a5e57bbe 100644 --- a/apps/openmw/mwworld/fallback.hpp +++ b/apps/openmw/mwworld/fallback.hpp @@ -15,6 +15,7 @@ namespace MWWorld Fallback(const std::map& fallback); std::string getFallbackString(const std::string& fall) const; float getFallbackFloat(const std::string& fall) const; + int getFallbackInt(const std::string& fall) const; bool getFallbackBool(const std::string& fall) const; Ogre::ColourValue getFallbackColour(const std::string& fall) const; }; diff --git a/files/CMakeLists.txt b/files/CMakeLists.txt index 9b2325744eb..da3451d93e3 100644 --- a/files/CMakeLists.txt +++ b/files/CMakeLists.txt @@ -38,15 +38,10 @@ set(MATERIAL_FILES selection.mat selection.shader selection.shaderset - watersim_heightmap.shader - watersim_addimpulse.shader - watersim_heighttonormal.shader - watersim_common.h - watersim.mat - watersim.shaderset mygui.mat mygui.shader mygui.shaderset + ripples.particle ) copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}") diff --git a/files/materials/ripples.particle b/files/materials/ripples.particle new file mode 100644 index 00000000000..e8402b6914c --- /dev/null +++ b/files/materials/ripples.particle @@ -0,0 +1,26 @@ +particle_system openmw/Ripples +{ + material openmw/Ripple + particle_width 50 + particle_height 50 + // To make the particles move with the scene node when the waterlevel changes + local_space true + quota 300 + billboard_type perpendicular_common + common_up_vector 0 1 0 + common_direction 0 0 1 + + affector ColourFader + { + alpha -0.33 + } + + affector Scaler + { + rate 100 + } + + affector Rotator + { + } +} diff --git a/files/materials/water.mat b/files/materials/water.mat index ade55f326f0..cf03be39e5a 100644 --- a/files/materials/water.mat +++ b/files/materials/water.mat @@ -75,3 +75,27 @@ material Water } } } + +material openmw/Ripple +{ + // this will be overridden by Water_RippleFrameCount fallback setting + anim_texture2 textures\water\ripple.dds 4 0.25 + pass + { + scene_blend alpha_blend + depth_write off + cull_hardware none + diffuse vertexcolour + emissive 1 1 1 + ambient 0 0 0 + texture_unit diffuseMap + { + create_in_ffp true + anim_texture2 $anim_texture2 + + // to make sure rotating doesn't cause the texture to repeat + tex_address_mode border + tex_border_colour 0 0 0 0 + } + } +} diff --git a/files/materials/water.shader b/files/materials/water.shader index 4dec57276dc..373277d0b40 100644 --- a/files/materials/water.shader +++ b/files/materials/water.shader @@ -64,7 +64,6 @@ #include "shadows.h" #endif -#define RIPPLES 1 #define REFRACTION @shGlobalSettingBool(refraction) #ifdef SH_VERTEX_SHADER @@ -187,11 +186,6 @@ shInput(float3, screenCoordsPassthrough) shInput(float4, position) shInput(float, depthPassthrough) - - #if RIPPLES - shUniform(float3, rippleCenter) @shSharedParameter(rippleCenter, rippleCenter) - shUniform(float, rippleAreaLength) @shSharedParameter(rippleAreaLength, rippleAreaLength) - #endif shUniform(float, far) @shAutoConstant(far, far_clip_distance) @@ -203,10 +197,6 @@ shSampler2D(normalMap) shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix) - - #if RIPPLES - shSampler2D(rippleNormalMap) - #endif shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed) #define WIND_SPEED windDir_windSpeed.z @@ -296,12 +286,7 @@ normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y + normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y); - float4 worldPosition = shMatrixMult(wMat, float4(position.xyz, 1)); - float2 relPos = (worldPosition.xy - rippleCenter.xy) / rippleAreaLength + 0.5; - float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2.0 - 1.0); - - //normal = normalize(normal + normal_ripple); - normal = normalize(float3(normal.x * BUMP + normal_ripple.x, normal.y * BUMP + normal_ripple.y, normal.z)); + normal = normalize(float3(normal.x * BUMP, normal.y * BUMP, normal.z)); normal = float3(normal.x, normal.y, -normal.z); // normal for sunlight scattering diff --git a/files/materials/watersim.mat b/files/materials/watersim.mat deleted file mode 100644 index b58b1a85120..00000000000 --- a/files/materials/watersim.mat +++ /dev/null @@ -1,59 +0,0 @@ -material HeightmapSimulation -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - vertex_program transform_vertex - fragment_program watersim_fragment - - texture_unit heightPrevSampler - { - tex_address_mode border - tex_border_colour 0 0 0 - texture_alias Heightmap0 - } - texture_unit heightCurrentSampler - { - tex_address_mode border - tex_border_colour 0 0 0 - texture_alias Heightmap1 - } - } -} - -material HeightToNormalMap -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - vertex_program transform_vertex - fragment_program height_to_normal_fragment - - texture_unit heightCurrentSampler - { - texture_alias Heightmap2 - } - } -} - -material AddImpulse -{ - allow_fixed_function false - pass - { - depth_check off - depth_write off - scene_blend alpha_blend - vertex_program transform_vertex - fragment_program add_impulse_fragment - - texture_unit alphaMap - { - texture circle.png - } - } -} diff --git a/files/materials/watersim.shaderset b/files/materials/watersim.shaderset deleted file mode 100644 index ea512e25f0d..00000000000 --- a/files/materials/watersim.shaderset +++ /dev/null @@ -1,31 +0,0 @@ -shader_set transform_vertex -{ - source quad.shader - type vertex - profiles_cg vs_2_0 vp40 arbvp1 - profiles_hlsl vs_2_0 -} - -shader_set watersim_fragment -{ - source watersim_heightmap.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} - -shader_set height_to_normal_fragment -{ - source watersim_heighttonormal.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} - -shader_set add_impulse_fragment -{ - source watersim_addimpulse.shader - type fragment - profiles_cg ps_3_0 ps_2_x ps_2_0 fp40 arbfp1 - profiles_hlsl ps_3_0 ps_2_0 -} diff --git a/files/materials/watersim_addimpulse.shader b/files/materials/watersim_addimpulse.shader deleted file mode 100644 index 3ca4192cd7b..00000000000 --- a/files/materials/watersim_addimpulse.shader +++ /dev/null @@ -1,12 +0,0 @@ -#include "core.h" -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(alphaMap) - - SH_START_PROGRAM - { - shOutputColour(0) = EncodeHeightmap(1.0); - shOutputColour(0).a = shSample (alphaMap, UV.xy).a; - } diff --git a/files/materials/watersim_common.h b/files/materials/watersim_common.h deleted file mode 100644 index aa7a636a067..00000000000 --- a/files/materials/watersim_common.h +++ /dev/null @@ -1,25 +0,0 @@ -float DecodeHeightmap(float4 heightmap) -{ - float4 table = float4(1.0, -1.0, 0.0, 0.0); - return dot(heightmap, table); -} - -float DecodeHeightmap(shTexture2D HeightmapSampler, float2 texcoord) -{ - float4 heightmap = shSample(HeightmapSampler, texcoord); - return DecodeHeightmap(heightmap); -} - -float4 EncodeHeightmap(float fHeight) -{ - float h = fHeight; - float positive = fHeight > 0.0 ? fHeight : 0.0; - float negative = fHeight < 0.0 ? -fHeight : 0.0; - - float4 color = float4(0,0,0,0); - - color.r = positive; - color.g = negative; - - return color; -} diff --git a/files/materials/watersim_heightmap.shader b/files/materials/watersim_heightmap.shader deleted file mode 100644 index ec8ae4174ad..00000000000 --- a/files/materials/watersim_heightmap.shader +++ /dev/null @@ -1,51 +0,0 @@ -#include "core.h" - -#define DAMPING 0.95 - -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(heightPrevSampler) - shSampler2D(heightCurrentSampler) - shUniform(float3, previousFrameOffset) @shSharedParameter(previousFrameOffset, previousFrameOffset) - shUniform(float3, currentFrameOffset) @shSharedParameter(currentFrameOffset, currentFrameOffset) - shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) - - SH_START_PROGRAM - { -#if !SH_HLSL - const float3 offset[4] = float3[4]( - float3(-1.0, 0.0, 0.25), - float3( 1.0, 0.0, 0.25), - float3( 0.0,-1.0, 0.25), - float3( 0.0, 1.0, 0.25) - ); -#else - const float3 offset[4] = { - float3(-1.0, 0.0, 0.25), - float3( 1.0, 0.0, 0.25), - float3( 0.0,-1.0, 0.25), - float3( 0.0, 1.0, 0.25) - }; -#endif - - float fHeightPrev = DecodeHeightmap(heightPrevSampler, UV.xy + previousFrameOffset.xy + currentFrameOffset.xy); - - float fNeighCurrent = 0; - for ( int i=0; i<4; i++ ) - { - float2 vTexcoord = UV + currentFrameOffset.xy + offset[i].xy * rippleTextureSize.xy; - fNeighCurrent += (DecodeHeightmap(heightCurrentSampler, vTexcoord) * offset[i].z); - } - - float fHeight = fNeighCurrent * 2.0 - fHeightPrev; - - fHeight *= DAMPING; - - shOutputColour(0) = EncodeHeightmap(fHeight); - } - - - - diff --git a/files/materials/watersim_heighttonormal.shader b/files/materials/watersim_heighttonormal.shader deleted file mode 100644 index eaa4af4983e..00000000000 --- a/files/materials/watersim_heighttonormal.shader +++ /dev/null @@ -1,36 +0,0 @@ -#include "core.h" -#include "watersim_common.h" - - SH_BEGIN_PROGRAM - shInput(float2, UV) - shSampler2D(heightCurrentSampler) - shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize) - - SH_START_PROGRAM - { -#if !SH_HLSL - float2 offset[4] = float2[4] ( - float2(-1.0, 0.0), - float2( 1.0, 0.0), - float2( 0.0,-1.0), - float2( 0.0, 1.0) - ); -#else - float2 offset[4] = { - float2(-1.0, 0.0), - float2( 1.0, 0.0), - float2( 0.0,-1.0), - float2( 0.0, 1.0) - }; -#endif - - float fHeightL = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[0]*rippleTextureSize.xy); - float fHeightR = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[1]*rippleTextureSize.xy); - float fHeightT = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[2]*rippleTextureSize.xy); - float fHeightB = DecodeHeightmap(heightCurrentSampler, UV.xy + offset[3]*rippleTextureSize.xy); - - float3 n = float3(fHeightB - fHeightT, fHeightR - fHeightL, 1.0); - float3 normal = (n + 1.0) * 0.5; - - shOutputColour(0) = float4(normal.rgb, 1.0); - }