Fix ripples for D3D - added simpler effect (Fixes #1649)

openmw-35
scrawl 10 years ago
parent 9dbd9af31c
commit dbd4abd6fe

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

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

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

@ -1,162 +1,72 @@
#include "ripplesimulation.hpp"
#include <OgreTextureManager.h>
#include <OgreStringConverter.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreRoot.h>
#include <OgreRectangle2D.h>
#include <stdexcept>
#include <OgreSceneNode.h>
#include <OgreRenderTexture.h>
#include <OgreViewport.h>
#include <OgreSceneManager.h>
#include <OgreParticleSystem.h>
#include <OgreParticle.h>
#include <extern/shiny/Main/Factory.hpp>
#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<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)));
// 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<sh::Vector3>(
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<Emitter>::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<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;
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();
}
}

@ -1,19 +1,19 @@
#ifndef RIPPLE_SIMULATION_H
#define RIPPLE_SIMULATION_H
#include <OgreTexture.h>
#include <OgreMaterial.h>
#include <OgreVector2.h>
#include <OgreVector3.h>
#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 @@ public:
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<Emitter> 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<Emitter> mEmitters;
Ogre::Vector2 mCurrentFrameOffset;
Ogre::Vector2 mPreviousFrameOffset;
float mRippleLifeTime;
float mRippleRotSpeed;
};
}

@ -20,9 +20,6 @@
#include <extern/shiny/Main/Factory.hpp>
#include <extern/shiny/Platforms/Ogre/OgreMaterial.hpp>
#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

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

@ -22,6 +22,15 @@ namespace MWWorld
else
return boost::lexical_cast<float>(fallback);
}
int Fallback::getFallbackInt(const std::string& fall) const
{
std::string fallback=getFallbackString(fall);
if(fallback.empty())
return 0;
else
return boost::lexical_cast<int>(fallback);
}
bool Fallback::getFallbackBool(const std::string& fall) const
{
std::string fallback=getFallbackString(fall);

@ -15,6 +15,7 @@ namespace MWWorld
Fallback(const std::map<std::string,std::string>& 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;
};

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

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

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

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

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

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

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

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

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

@ -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);
}
Loading…
Cancel
Save