forked from mirror/openmw-tes3mp
water ripples (experimental)
This commit is contained in:
parent
3ec703e6af
commit
a461b282c1
20 changed files with 545 additions and 14 deletions
|
@ -16,7 +16,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
|
||||||
add_openmw_dir (mwrender
|
add_openmw_dir (mwrender
|
||||||
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
renderingmanager debugging sky player animation npcanimation creatureanimation actors objects
|
||||||
renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
|
renderinginterface localmap occlusionquery terrain terrainmaterial water shadows
|
||||||
compositors characterpreview externalrendering globalmap videoplayer
|
compositors characterpreview externalrendering globalmap videoplayer ripplesimulation
|
||||||
)
|
)
|
||||||
|
|
||||||
add_openmw_dir (mwinput
|
add_openmw_dir (mwinput
|
||||||
|
|
|
@ -386,7 +386,10 @@ void RenderingManager::update (float duration, bool paused)
|
||||||
*world->getPlayer().getPlayer().getCell()->mCell,
|
*world->getPlayer().getPlayer().getCell()->mCell,
|
||||||
Ogre::Vector3(cam.x, -cam.z, cam.y))
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
212
apps/openmw/mwrender/ripplesimulation.cpp
Normal file
212
apps/openmw/mwrender/ripplesimulation.cpp
Normal file
|
@ -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
apps/openmw/mwrender/ripplesimulation.hpp
Normal file
72
apps/openmw/mwrender/ripplesimulation.hpp
Normal file
|
@ -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
|
|
@ -12,6 +12,7 @@
|
||||||
#include "sky.hpp"
|
#include "sky.hpp"
|
||||||
#include "renderingmanager.hpp"
|
#include "renderingmanager.hpp"
|
||||||
#include "compositors.hpp"
|
#include "compositors.hpp"
|
||||||
|
#include "ripplesimulation.hpp"
|
||||||
|
|
||||||
#include <extern/shiny/Main/Factory.hpp>
|
#include <extern/shiny/Main/Factory.hpp>
|
||||||
#include <extern/shiny/Platforms/Ogre/OgreMaterial.hpp>
|
#include <extern/shiny/Platforms/Ogre/OgreMaterial.hpp>
|
||||||
|
@ -180,8 +181,11 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel
|
||||||
mActive(1), mToggled(1),
|
mActive(1), mToggled(1),
|
||||||
mRendering(rend),
|
mRendering(rend),
|
||||||
mWaterTimer(0.f),
|
mWaterTimer(0.f),
|
||||||
mReflection(NULL)
|
mReflection(NULL),
|
||||||
|
mSimulation(NULL)
|
||||||
{
|
{
|
||||||
|
mSimulation = new RippleSimulation(mSceneMgr);
|
||||||
|
|
||||||
mSky = rend->getSkyManager();
|
mSky = rend->getSkyManager();
|
||||||
|
|
||||||
mMaterial = MaterialManager::getSingleton().getByName("Water");
|
mMaterial = MaterialManager::getSingleton().getByName("Water");
|
||||||
|
@ -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 ();
|
Ogre::Vector3 pos = mCamera->getDerivedPosition ();
|
||||||
|
@ -387,6 +391,12 @@ void Water::update(float dt)
|
||||||
sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mWaterTimer)));
|
sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mWaterTimer)));
|
||||||
|
|
||||||
mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater);
|
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()
|
void Water::applyRTT()
|
||||||
|
|
|
@ -29,6 +29,7 @@ namespace MWRender {
|
||||||
|
|
||||||
class SkyManager;
|
class SkyManager;
|
||||||
class RenderingManager;
|
class RenderingManager;
|
||||||
|
class RippleSimulation;
|
||||||
|
|
||||||
class Reflection
|
class Reflection
|
||||||
{
|
{
|
||||||
|
@ -110,6 +111,8 @@ namespace MWRender {
|
||||||
|
|
||||||
float mWaterTimer;
|
float mWaterTimer;
|
||||||
|
|
||||||
|
RippleSimulation* mSimulation;
|
||||||
|
|
||||||
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
|
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -137,7 +140,7 @@ namespace MWRender {
|
||||||
void setActive(bool active);
|
void setActive(bool active);
|
||||||
|
|
||||||
void toggle();
|
void toggle();
|
||||||
void update(float dt);
|
void update(float dt, Ogre::Vector3 player);
|
||||||
|
|
||||||
void assignTextures();
|
void assignTextures();
|
||||||
|
|
||||||
|
|
2
extern/shiny/Main/Factory.cpp
vendored
2
extern/shiny/Main/Factory.cpp
vendored
|
@ -219,6 +219,8 @@ namespace sh
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::cout << "loading " << it->first << std::endl;
|
||||||
|
|
||||||
MaterialInstance newInstance(it->first, this);
|
MaterialInstance newInstance(it->first, this);
|
||||||
newInstance.create(mPlatform);
|
newInstance.create(mPlatform);
|
||||||
if (!mShadersEnabled)
|
if (!mShadersEnabled)
|
||||||
|
|
|
@ -3,6 +3,7 @@ project(resources)
|
||||||
set(WATER_FILES
|
set(WATER_FILES
|
||||||
underwater_dome.mesh
|
underwater_dome.mesh
|
||||||
water_nm.png
|
water_nm.png
|
||||||
|
circle.png
|
||||||
)
|
)
|
||||||
|
|
||||||
set(GBUFFER_FILES
|
set(GBUFFER_FILES
|
||||||
|
@ -43,6 +44,12 @@ set(MATERIAL_FILES
|
||||||
selection.mat
|
selection.mat
|
||||||
selection.shader
|
selection.shader
|
||||||
selection.shaderset
|
selection.shaderset
|
||||||
|
watersim_heightmap.shader
|
||||||
|
watersim_addimpulse.shader
|
||||||
|
watersim_heighttonormal.shader
|
||||||
|
watersim_common.h
|
||||||
|
watersim.mat
|
||||||
|
watersim.shaderset
|
||||||
)
|
)
|
||||||
|
|
||||||
copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}")
|
copy_all_files(${CMAKE_CURRENT_SOURCE_DIR}/water "${OpenMW_BINARY_DIR}/resources/water/" "${WATER_FILES}")
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#define shNormalInput(type) , in type normal : NORMAL
|
#define shNormalInput(type) , in type normal : NORMAL
|
||||||
|
|
||||||
#define shColourInput(type) , in type colour : COLOR
|
#define shColourInput(type) , in type colour : COLOR
|
||||||
|
|
||||||
|
#define shFract(val) frac(val)
|
||||||
|
|
||||||
#ifdef SH_VERTEX_SHADER
|
#ifdef SH_VERTEX_SHADER
|
||||||
|
|
||||||
|
@ -64,6 +66,8 @@
|
||||||
|
|
||||||
#if SH_GLSL == 1
|
#if SH_GLSL == 1
|
||||||
|
|
||||||
|
#define shFract(val) fract(val)
|
||||||
|
|
||||||
@version 120
|
@version 120
|
||||||
|
|
||||||
#define float2 vec2
|
#define float2 vec2
|
||||||
|
|
|
@ -4,7 +4,7 @@ material quad
|
||||||
|
|
||||||
pass
|
pass
|
||||||
{
|
{
|
||||||
vertex_program quad_vertex
|
vertex_program transform_vertex
|
||||||
fragment_program quad_fragment
|
fragment_program quad_fragment
|
||||||
|
|
||||||
depth_write $depth_write
|
depth_write $depth_write
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
shader_set quad_vertex
|
shader_set transform_vertex
|
||||||
{
|
{
|
||||||
source quad.shader
|
source quad.shader
|
||||||
type vertex
|
type vertex
|
||||||
|
|
|
@ -34,7 +34,13 @@ material Water
|
||||||
{
|
{
|
||||||
direct_texture water_nm.png
|
direct_texture water_nm.png
|
||||||
}
|
}
|
||||||
|
|
||||||
|
texture_unit rippleNormalMap
|
||||||
|
{
|
||||||
|
direct_texture RippleNormal
|
||||||
|
tex_address_mode border
|
||||||
|
tex_border_colour 0.5 0.5 1.0
|
||||||
|
}
|
||||||
|
|
||||||
// for simple_water
|
// for simple_water
|
||||||
texture_unit animatedTexture
|
texture_unit animatedTexture
|
||||||
|
|
|
@ -61,7 +61,7 @@
|
||||||
|
|
||||||
// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html )
|
// Inspired by Blender GLSL Water by martinsh ( http://devlog-martinsh.blogspot.de/2012/07/waterundewater-shader-wip.html )
|
||||||
|
|
||||||
|
#define RIPPLES 1
|
||||||
|
|
||||||
#ifdef SH_VERTEX_SHADER
|
#ifdef SH_VERTEX_SHADER
|
||||||
|
|
||||||
|
@ -119,8 +119,8 @@
|
||||||
#define WAVE_SCALE 75 // overall wave scale
|
#define WAVE_SCALE 75 // overall wave scale
|
||||||
|
|
||||||
#define BUMP 1.5 // overall water surface bumpiness
|
#define BUMP 1.5 // overall water surface bumpiness
|
||||||
#define REFL_BUMP 0.08 // reflection distortion amount
|
#define REFL_BUMP 0.16 // reflection distortion amount
|
||||||
#define REFR_BUMP 0.06 // refraction distortion amount
|
#define REFR_BUMP 0.12 // refraction distortion amount
|
||||||
|
|
||||||
#define SCATTER_AMOUNT 3.0 // amount of sunlight scattering
|
#define SCATTER_AMOUNT 3.0 // amount of sunlight scattering
|
||||||
#define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering
|
#define SCATTER_COLOUR gammaCorrectRead(float3(0.0,1.0,0.95)) // colour of sunlight scattering
|
||||||
|
@ -159,6 +159,11 @@
|
||||||
shInput(float3, screenCoordsPassthrough)
|
shInput(float3, screenCoordsPassthrough)
|
||||||
shInput(float4, position)
|
shInput(float4, position)
|
||||||
shInput(float, depthPassthrough)
|
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)
|
shUniform(float, far) @shAutoConstant(far, far_clip_distance)
|
||||||
|
|
||||||
|
@ -166,6 +171,11 @@
|
||||||
shSampler2D(refractionMap)
|
shSampler2D(refractionMap)
|
||||||
shSampler2D(depthMap)
|
shSampler2D(depthMap)
|
||||||
shSampler2D(normalMap)
|
shSampler2D(normalMap)
|
||||||
|
|
||||||
|
#if RIPPLES
|
||||||
|
shSampler2D(rippleNormalMap)
|
||||||
|
shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix)
|
||||||
|
#endif
|
||||||
|
|
||||||
shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed)
|
shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed)
|
||||||
#define WIND_SPEED windDir_windSpeed.z
|
#define WIND_SPEED windDir_windSpeed.z
|
||||||
|
@ -220,8 +230,14 @@
|
||||||
float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y +
|
float3 normal = (normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y +
|
||||||
normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y +
|
normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y +
|
||||||
normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xzy;
|
normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y).xzy;
|
||||||
|
|
||||||
normal = normalize(float3(normal.x * BUMP, normal.y, normal.z * BUMP));
|
float4 worldPosition = shMatrixMult(wMat, float4(position.xyz, 1));
|
||||||
|
float2 relPos = (worldPosition.xz - rippleCenter.xy) / rippleAreaLength + 0.5;
|
||||||
|
float3 normal_ripple = normalize(shSample(rippleNormalMap, relPos.xy).xyz * 2 - 1);
|
||||||
|
normal_ripple = normal_ripple.xzy;
|
||||||
|
|
||||||
|
normal = normalize(normal + normal_ripple);
|
||||||
|
|
||||||
|
|
||||||
// normal for sunlight scattering
|
// normal for sunlight scattering
|
||||||
float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 +
|
float3 lNormal = (normal0 * BIG_WAVES_X*0.5 + normal1 * BIG_WAVES_Y*0.5 +
|
||||||
|
@ -303,7 +319,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz);
|
shOutputColour(0).xyz = gammaCorrectOutput(shOutputColour(0).xyz);
|
||||||
|
//shOutputColour(0).xyz = float3(relPos.x, relPos.y, 0);
|
||||||
shOutputColour(0).w = 1;
|
shOutputColour(0).w = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
59
files/materials/watersim.mat
Normal file
59
files/materials/watersim.mat
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
files/materials/watersim.shaderset
Normal file
31
files/materials/watersim.shaderset
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
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
|
||||||
|
}
|
12
files/materials/watersim_addimpulse.shader
Normal file
12
files/materials/watersim_addimpulse.shader
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#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;
|
||||||
|
}
|
25
files/materials/watersim_common.h
Normal file
25
files/materials/watersim_common.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
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;
|
||||||
|
}
|
42
files/materials/watersim_heightmap.shader
Normal file
42
files/materials/watersim_heightmap.shader
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
#define DAMPING 0.92
|
||||||
|
|
||||||
|
#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
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
27
files/materials/watersim_heighttonormal.shader
Normal file
27
files/materials/watersim_heighttonormal.shader
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "core.h"
|
||||||
|
#include "watersim_common.h"
|
||||||
|
|
||||||
|
SH_BEGIN_PROGRAM
|
||||||
|
shInput(float2, UV)
|
||||||
|
shSampler2D(heightCurrentSampler)
|
||||||
|
shUniform(float4, rippleTextureSize) @shSharedParameter(rippleTextureSize, rippleTextureSize)
|
||||||
|
|
||||||
|
SH_START_PROGRAM
|
||||||
|
{
|
||||||
|
float2 offset[4] = float2[4] (
|
||||||
|
vec2(-1.0, 0.0),
|
||||||
|
vec2( 1.0, 0.0),
|
||||||
|
vec2( 0.0,-1.0),
|
||||||
|
vec2( 0.0, 1.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
BIN
files/water/circle.png
Normal file
BIN
files/water/circle.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 753 B |
Loading…
Reference in a new issue