water ripples (experimental)

actorid
scrawl 12 years ago
parent 3ec703e6af
commit a461b282c1

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

@ -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;
}
}

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

@ -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}")

@ -29,6 +29,8 @@
#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
#define shOutputPosition oPosition #define shOutputPosition oPosition
@ -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

@ -35,6 +35,12 @@ 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
@ -160,6 +160,11 @@
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)
shSampler2D(reflectionMap) shSampler2D(reflectionMap)
@ -167,6 +172,11 @@
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
#define WIND_DIR windDir_windSpeed.xy #define WIND_DIR windDir_windSpeed.xy
@ -221,7 +231,13 @@
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;
} }

@ -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
}
}
}

@ -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
}

@ -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;
}

@ -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;
}

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

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 753 B

Loading…
Cancel
Save