Skip to content

Commit

Permalink
water ripples (experimental)
Browse files Browse the repository at this point in the history
  • Loading branch information
scrawl committed Feb 1, 2013
1 parent 3ec703e commit a461b28
Show file tree
Hide file tree
Showing 20 changed files with 545 additions and 14 deletions.
2 changes: 1 addition & 1 deletion apps/openmw/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
compositors characterpreview externalrendering globalmap videoplayer
compositors characterpreview externalrendering globalmap videoplayer ripplesimulation
)

add_openmw_dir (mwinput
Expand Down
5 changes: 4 additions & 1 deletion apps/openmw/mwrender/renderingmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,10 @@ void RenderingManager::update (float duration, bool paused)
*world->getPlayer().getPlayer().getCell()->mCell,
Ogre::Vector3(cam.x, -cam.z, cam.y))
);
mWater->update(duration);

// MW to ogre coordinates
orig = Ogre::Vector3(orig.x, orig.z, -orig.y);
mWater->update(duration, orig);
}
}

Expand Down
212 changes: 212 additions & 0 deletions apps/openmw/mwrender/ripplesimulation.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
#include "ripplesimulation.hpp"

#include <OgreTextureManager.h>
#include <OgreStringConverter.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreRoot.h>

#include <extern/shiny/Main/Factory.hpp>

namespace MWRender
{


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)
{
Ogre::AxisAlignedBox aabInf;
aabInf.setInfinite();


mHeightToNormalMapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightToNormalMap");
mHeightmapMaterial = Ogre::MaterialManager::getSingleton().getByName("HeightmapSimulation");

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);

// 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);

Ogre::MaterialPtr debugMaterial = Ogre::MaterialManager::getSingleton().create("RippleDebug" + Ogre::StringConverter::toString(i),
Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);

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);

debugOverlay->setMaterial("RippleDebug" + Ogre::StringConverter::toString(i));

mRenderTargets[i] = rt;
mTextures[i] = texture;
}

sh::Factory::getInstance().setSharedParameter("rippleTextureSize", sh::makeProperty<sh::Vector4>(
new sh::Vector4(1.0/512, 1.0/512, 512, 512)));
sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty<sh::Vector3>(
new sh::Vector3(0, 0, 0)));
sh::Factory::getInstance().setSharedParameter("rippleAreaLength", sh::makeProperty<sh::FloatValue>(
new sh::FloatValue(mRippleAreaLength)));

}

RippleSimulation::~RippleSimulation()
{
delete mRectangle;

Ogre::Root::getSingleton().destroySceneManager(mSceneMgr);
}

void RippleSimulation::update(float dt, Ogre::Vector2 position)
{
// try to keep 20 fps
mTime += dt;

while (mTime >= 1/20.0)
{
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;

std::cout << "Offset " << mCurrentFrameOffset << std::endl;

mRippleCenter = position;

addImpulses();
waterSimulation();
heightMapToNormalMap();

swapHeightMaps();
mTime -= 1/20.0;
}

sh::Factory::getInstance().setSharedParameter("rippleCenter", sh::makeProperty<sh::Vector3>(
new sh::Vector3(mRippleCenter.x + mTexelOffset.x, mRippleCenter.y + mTexelOffset.y, 0)));
}

void RippleSimulation::addImpulse(Ogre::Vector2 position)
{
mImpulses.push(position);
}

void RippleSimulation::addImpulses()
{
mRectangle->setVisible(false);
mImpulse->setVisible(true);

while (mImpulses.size())
{
Ogre::Vector2 pos = mImpulses.front();
pos -= mRippleCenter;
pos /= mRippleAreaLength;
float size = mImpulseSize / mRippleAreaLength;
mImpulse->setCorners(pos.x-size, pos.y+size, pos.x+size, pos.y-size, false);
mImpulses.pop();

mRenderTargets[1]->update();
}

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<sh::Vector3>(
new sh::Vector3(mCurrentFrameOffset.x, mCurrentFrameOffset.y, 0)));
sh::Factory::getInstance().setSharedParameter("previousFrameOffset", sh::makeProperty<sh::Vector3>(
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;
}


}
72 changes: 72 additions & 0 deletions apps/openmw/mwrender/ripplesimulation.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#ifndef RIPPLE_SIMULATION_H
#define RIPPLE_SIMULATION_H

#include <OgreTexture.h>
#include <OgreMaterial.h>
#include <OgreVector2.h>

namespace Ogre
{
class RenderTexture;
class Camera;
class SceneManager;
class Rectangle2D;
}

namespace MWRender
{

class RippleSimulation
{
public:
RippleSimulation(Ogre::SceneManager* mainSceneManager);
~RippleSimulation();

void update(float dt, Ogre::Vector2 position);

void addImpulse (Ogre::Vector2 position);

private:
Ogre::RenderTexture* mRenderTargets[4];
Ogre::TexturePtr mTextures[4];

int mTextureSize;
float mRippleAreaLength;
float mImpulseSize;

Ogre::Camera* mCamera;

// own scenemanager to render our simulation
Ogre::SceneManager* mSceneMgr;
Ogre::Rectangle2D* mRectangle;

// scenemanager to create the debug overlays on
Ogre::SceneManager* mMainSceneMgr;

Ogre::MaterialPtr mHeightmapMaterial;
Ogre::MaterialPtr mHeightToNormalMapMaterial;

static const int TEX_NORMAL = 3;

Ogre::Rectangle2D* mImpulse;

std::queue <Ogre::Vector2> mImpulses;

void addImpulses();
void heightMapToNormalMap();
void waterSimulation();
void swapHeightMaps();

float mTime;

Ogre::Vector2 mRippleCenter;

Ogre::Vector2 mTexelOffset;

Ogre::Vector2 mCurrentFrameOffset;
Ogre::Vector2 mPreviousFrameOffset;
};

}

#endif
14 changes: 12 additions & 2 deletions apps/openmw/mwrender/water.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "sky.hpp"
#include "renderingmanager.hpp"
#include "compositors.hpp"
#include "ripplesimulation.hpp"

#include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgreMaterial.hpp>
Expand Down Expand Up @@ -180,8 +181,11 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel
mActive(1), mToggled(1),
mRendering(rend),
mWaterTimer(0.f),
mReflection(NULL)
mReflection(NULL),
mSimulation(NULL)
{
mSimulation = new RippleSimulation(mSceneMgr);

mSky = rend->getSkyManager();

mMaterial = MaterialManager::getSingleton().getByName("Water");
Expand Down Expand Up @@ -375,7 +379,7 @@ void Water::updateVisible()
}
}

void Water::update(float dt)
void Water::update(float dt, Ogre::Vector3 player)
{
/*
Ogre::Vector3 pos = mCamera->getDerivedPosition ();
Expand All @@ -387,6 +391,12 @@ void Water::update(float dt)
sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mWaterTimer)));

mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater);

//if (player.y <= mTop)
{
mSimulation->addImpulse(Ogre::Vector2(player.x, player.z));
}
mSimulation->update(dt, Ogre::Vector2(player.x, player.z));
}

void Water::applyRTT()
Expand Down
5 changes: 4 additions & 1 deletion apps/openmw/mwrender/water.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ namespace MWRender {

class SkyManager;
class RenderingManager;
class RippleSimulation;

class Reflection
{
Expand Down Expand Up @@ -110,6 +111,8 @@ namespace MWRender {

float mWaterTimer;

RippleSimulation* mSimulation;

Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);

protected:
Expand Down Expand Up @@ -137,7 +140,7 @@ namespace MWRender {
void setActive(bool active);

void toggle();
void update(float dt);
void update(float dt, Ogre::Vector3 player);

void assignTextures();

Expand Down
2 changes: 2 additions & 0 deletions extern/shiny/Main/Factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ namespace sh
break;
}

std::cout << "loading " << it->first << std::endl;

MaterialInstance newInstance(it->first, this);
newInstance.create(mPlatform);
if (!mShadersEnabled)
Expand Down
Loading

0 comments on commit a461b28

Please sign in to comment.