forked from teamnwah/openmw-tes3coop
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
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
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 "renderingmanager.hpp"
|
||||
#include "compositors.hpp"
|
||||
#include "ripplesimulation.hpp"
|
||||
|
||||
#include <extern/shiny/Main/Factory.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),
|
||||
mRendering(rend),
|
||||
mWaterTimer(0.f),
|
||||
mReflection(NULL)
|
||||
mReflection(NULL),
|
||||
mSimulation(NULL)
|
||||
{
|
||||
mSimulation = new RippleSimulation(mSceneMgr);
|
||||
|
||||
mSky = rend->getSkyManager();
|
||||
|
||||
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 ();
|
||||
|
@ -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()
|
||||
|
|
|
@ -29,6 +29,7 @@ namespace MWRender {
|
|||
|
||||
class SkyManager;
|
||||
class RenderingManager;
|
||||
class RippleSimulation;
|
||||
|
||||
class Reflection
|
||||
{
|
||||
|
@ -110,6 +111,8 @@ namespace MWRender {
|
|||
|
||||
float mWaterTimer;
|
||||
|
||||
RippleSimulation* mSimulation;
|
||||
|
||||
Ogre::Vector3 getSceneNodeCoordinates(int gridX, int gridY);
|
||||
|
||||
protected:
|
||||
|
@ -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();
|
||||
|
||||
|
|
2
extern/shiny/Main/Factory.cpp
vendored
2
extern/shiny/Main/Factory.cpp
vendored
|
@ -219,6 +219,8 @@ namespace sh
|
|||
break;
|
||||
}
|
||||
|
||||
std::cout << "loading " << it->first << std::endl;
|
||||
|
||||
MaterialInstance newInstance(it->first, this);
|
||||
newInstance.create(mPlatform);
|
||||
if (!mShadersEnabled)
|
||||
|
|
|
@ -3,6 +3,7 @@ project(resources)
|
|||
set(WATER_FILES
|
||||
underwater_dome.mesh
|
||||
water_nm.png
|
||||
circle.png
|
||||
)
|
||||
|
||||
set(GBUFFER_FILES
|
||||
|
@ -43,6 +44,12 @@ 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
|
||||
)
|
||||
|
||||
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 shFract(val) frac(val)
|
||||
|
||||
#ifdef SH_VERTEX_SHADER
|
||||
|
||||
#define shOutputPosition oPosition
|
||||
|
@ -64,6 +66,8 @@
|
|||
|
||||
#if SH_GLSL == 1
|
||||
|
||||
#define shFract(val) fract(val)
|
||||
|
||||
@version 120
|
||||
|
||||
#define float2 vec2
|
||||
|
|
|
@ -4,7 +4,7 @@ material quad
|
|||
|
||||
pass
|
||||
{
|
||||
vertex_program quad_vertex
|
||||
vertex_program transform_vertex
|
||||
fragment_program quad_fragment
|
||||
|
||||
depth_write $depth_write
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
shader_set quad_vertex
|
||||
shader_set transform_vertex
|
||||
{
|
||||
source quad.shader
|
||||
type vertex
|
||||
|
|
|
@ -35,6 +35,12 @@ material Water
|
|||
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
|
||||
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 )
|
||||
|
||||
|
||||
#define RIPPLES 1
|
||||
|
||||
#ifdef SH_VERTEX_SHADER
|
||||
|
||||
|
@ -119,8 +119,8 @@
|
|||
#define WAVE_SCALE 75 // overall wave scale
|
||||
|
||||
#define BUMP 1.5 // overall water surface bumpiness
|
||||
#define REFL_BUMP 0.08 // reflection distortion amount
|
||||
#define REFR_BUMP 0.06 // refraction distortion amount
|
||||
#define REFL_BUMP 0.16 // reflection distortion amount
|
||||
#define REFR_BUMP 0.12 // refraction distortion amount
|
||||
|
||||
#define SCATTER_AMOUNT 3.0 // amount 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(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)
|
||||
|
||||
shSampler2D(reflectionMap)
|
||||
|
@ -167,6 +172,11 @@
|
|||
shSampler2D(depthMap)
|
||||
shSampler2D(normalMap)
|
||||
|
||||
#if RIPPLES
|
||||
shSampler2D(rippleNormalMap)
|
||||
shUniform(float4x4, wMat) @shAutoConstant(wMat, world_matrix)
|
||||
#endif
|
||||
|
||||
shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed)
|
||||
#define WIND_SPEED windDir_windSpeed.z
|
||||
#define WIND_DIR windDir_windSpeed.xy
|
||||
|
@ -221,7 +231,13 @@
|
|||
normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y +
|
||||
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
|
||||
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 = float3(relPos.x, relPos.y, 0);
|
||||
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