mirror of
https://github.com/OpenMW/openmw.git
synced 2025-01-21 13:23:53 +00:00
water
This commit is contained in:
parent
9d7470e14c
commit
e077814a8c
27 changed files with 213 additions and 504 deletions
|
@ -261,7 +261,7 @@ int main(int argc, char**argv)
|
|||
boost::filesystem::current_path(bundlePath);
|
||||
#endif
|
||||
|
||||
//try
|
||||
try
|
||||
{
|
||||
Files::ConfigurationManager cfgMgr;
|
||||
OMW::Engine engine(cfgMgr);
|
||||
|
@ -271,11 +271,11 @@ int main(int argc, char**argv)
|
|||
engine.go();
|
||||
}
|
||||
}
|
||||
/*catch (std::exception &e)
|
||||
catch (std::exception &e)
|
||||
{
|
||||
std::cout << "\nERROR: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}*/
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -209,7 +209,7 @@ namespace MWGui
|
|||
mVoiceVolumeSlider->setScrollPosition(Settings::Manager::getFloat("voice volume", "Sound") * (mVoiceVolumeSlider->getScrollRange()-1));
|
||||
|
||||
mWaterShaderButton->setCaptionWithReplacing(Settings::Manager::getBool("shader", "Water") ? "#{sOn}" : "#{sOff}");
|
||||
mReflectObjectsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect objects", "Water") ? "#{sOn}" : "#{sOff}");
|
||||
mReflectObjectsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect statics", "Water") ? "#{sOn}" : "#{sOff}");
|
||||
mReflectActorsButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect actors", "Water") ? "#{sOn}" : "#{sOff}");
|
||||
mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}");
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ enum RenderQueueGroups
|
|||
|
||||
RQG_OcclusionQuery = Ogre::RENDER_QUEUE_6,
|
||||
|
||||
RQG_UnderWater = Ogre::RENDER_QUEUE_7,
|
||||
RQG_UnderWater = Ogre::RENDER_QUEUE_4,
|
||||
|
||||
RQG_Water = Ogre::RENDER_QUEUE_7+1,
|
||||
|
||||
|
@ -49,8 +49,8 @@ enum VisibilityFlags
|
|||
|
||||
RV_Sky = 64,
|
||||
|
||||
// Sun glare (not visible in reflection)
|
||||
RV_Glare = 128,
|
||||
// not visible in reflection
|
||||
RV_NoReflection = 128,
|
||||
|
||||
RV_OcclusionQuery = 256,
|
||||
|
||||
|
|
|
@ -725,14 +725,9 @@ void RenderingManager::applyCompositors()
|
|||
{
|
||||
mCompositors->addCompositor("gbuffer", 0);
|
||||
mCompositors->setCompositorEnabled("gbuffer", true);
|
||||
mCompositors->addCompositor("Underwater", 1);
|
||||
mCompositors->addCompositor("gbufferFinalizer", 2);
|
||||
mCompositors->setCompositorEnabled("gbufferFinalizer", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mCompositors->addCompositor("UnderwaterNoMRT", 0);
|
||||
}
|
||||
|
||||
if (mWater)
|
||||
mWater->assignTextures();
|
||||
|
|
|
@ -307,7 +307,7 @@ void SkyManager::create()
|
|||
mSun->setRenderQueue(RQG_SkiesEarly+4);
|
||||
mSunGlare = new BillboardObject("textures\\tx_sun_flash_grey_05.dds", 3, Vector3(0.4, 0.4, 0.4), mRootNode, "openmw_sun");
|
||||
mSunGlare->setRenderQueue(RQG_SkiesLate);
|
||||
mSunGlare->setVisibilityFlags(RV_Glare);
|
||||
mSunGlare->setVisibilityFlags(RV_NoReflection);
|
||||
|
||||
// Stars
|
||||
MeshPtr mesh = NifOgre::NIFLoader::load("meshes\\sky_night_01.nif");
|
||||
|
@ -389,7 +389,6 @@ void SkyManager::update(float duration)
|
|||
sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer",
|
||||
sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mCloudAnimationTimer)));
|
||||
|
||||
|
||||
/// \todo improve this
|
||||
mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||
mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
|
||||
|
@ -559,6 +558,10 @@ void SkyManager::setSunDirection(const Vector3& direction)
|
|||
if (!mCreated) return;
|
||||
mSun->setPosition(direction);
|
||||
mSunGlare->setPosition(direction);
|
||||
|
||||
float height = direction.z;
|
||||
float fade = ( height > 0.5) ? 1.0 : height * 2;
|
||||
sh::Factory::getInstance ().setSharedParameter ("waterSunFade_sunHeight", sh::makeProperty<sh::Vector2>(new sh::Vector2(fade, height)));
|
||||
}
|
||||
|
||||
void SkyManager::setMasserDirection(const Vector3& direction)
|
||||
|
@ -607,6 +610,7 @@ void SkyManager::setLightningStrength(const float factor)
|
|||
|
||||
void SkyManager::setLightningDirection(const Ogre::Vector3& dir)
|
||||
{
|
||||
if (!mCreated) return;
|
||||
mLightning->setDirection (dir);
|
||||
}
|
||||
|
||||
|
@ -653,3 +657,10 @@ void SkyManager::scaleSky(float scale)
|
|||
{
|
||||
mRootNode->setScale(scale, scale, scale);
|
||||
}
|
||||
|
||||
void SkyManager::setGlareEnabled (bool enabled)
|
||||
{
|
||||
if (!mCreated)
|
||||
return;
|
||||
mSunGlare->setVisible (mSunEnabled && enabled);
|
||||
}
|
||||
|
|
|
@ -164,6 +164,7 @@ namespace MWRender
|
|||
void setLightningDirection(const Ogre::Vector3& dir);
|
||||
|
||||
void setGlare(const float glare);
|
||||
void setGlareEnabled(bool enabled);
|
||||
Ogre::Vector3 getRealSunPos();
|
||||
|
||||
void setSkyPosition(const Ogre::Vector3& position);
|
||||
|
|
|
@ -28,7 +28,7 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel
|
|||
mIsUnderwater(false), mVisibilityFlags(0),
|
||||
mReflectionTarget(0), mActive(1), mToggled(1),
|
||||
mReflectionRenderActive(false), mRendering(rend),
|
||||
mOldFarClip(0),
|
||||
mOldFarClip(0), mOldFarClip2(0),
|
||||
mWaterTimer(0.f)
|
||||
{
|
||||
mSky = rend->getSkyManager();
|
||||
|
@ -73,8 +73,9 @@ Water::Water (Ogre::Camera *camera, RenderingManager* rend, const ESM::Cell* cel
|
|||
underwaterDome->setRenderQueueGroup (RQG_UnderWater);
|
||||
mUnderwaterDome = mSceneManager->getRootSceneNode ()->createChildSceneNode ();
|
||||
mUnderwaterDome->attachObject (underwaterDome);
|
||||
mUnderwaterDome->setScale(100,100,100);
|
||||
mUnderwaterDome->setScale(10000,10000,10000);
|
||||
mUnderwaterDome->setVisible(false);
|
||||
underwaterDome->setMaterialName("Underwater_Dome");
|
||||
|
||||
mSceneManager->addRenderQueueListener(this);
|
||||
|
||||
|
@ -162,7 +163,12 @@ void Water::changeCell(const ESM::Cell* cell)
|
|||
void Water::setHeight(const float height)
|
||||
{
|
||||
mTop = height;
|
||||
|
||||
mWaterPlane = Plane(Vector3::UNIT_Y, height);
|
||||
|
||||
// small error due to reflection texture size & reflection distortion
|
||||
mErrorPlane = Plane(Vector3::UNIT_Y, height - 5);
|
||||
|
||||
mWaterNode->setPosition(0, height, 0);
|
||||
sh::Factory::getInstance ().setSharedParameter ("waterLevel", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(height)));
|
||||
}
|
||||
|
@ -177,39 +183,16 @@ void Water::checkUnderwater(float y)
|
|||
{
|
||||
if (!mActive)
|
||||
{
|
||||
mRendering->getCompositors()->setCompositorEnabled(mCompositorName, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((mIsUnderwater && y > mTop) || !mWater->isVisible() || mCamera->getPolygonMode() != Ogre::PM_SOLID)
|
||||
{
|
||||
//mRendering->getCompositors()->setCompositorEnabled(mCompositorName, false);
|
||||
|
||||
// tell the shader we are not underwater
|
||||
|
||||
/*
|
||||
Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0);
|
||||
if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false))
|
||||
pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(0));
|
||||
*/
|
||||
mWater->setRenderQueueGroup(RQG_Water);
|
||||
|
||||
mIsUnderwater = false;
|
||||
}
|
||||
|
||||
if (!mIsUnderwater && y < mTop && mWater->isVisible() && mCamera->getPolygonMode() == Ogre::PM_SOLID)
|
||||
{
|
||||
//if (mUnderwaterEffect)
|
||||
//mRendering->getCompositors()->setCompositorEnabled(mCompositorName, true);
|
||||
|
||||
// tell the shader we are underwater
|
||||
/*
|
||||
Ogre::Pass* pass = mMaterial->getTechnique(0)->getPass(0);
|
||||
if (pass->hasFragmentProgram() && pass->getFragmentProgramParameters()->_findNamedConstantDefinition("isUnderwater", false))
|
||||
pass->getFragmentProgramParameters()->setNamedConstant("isUnderwater", Real(1));
|
||||
*/
|
||||
//mWater->setRenderQueueGroup(RQG_UnderWater);
|
||||
|
||||
mIsUnderwater = true;
|
||||
}
|
||||
|
||||
|
@ -308,24 +291,36 @@ void Water::updateVisible()
|
|||
void Water::renderQueueStarted (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &skipThisInvocation)
|
||||
{
|
||||
// We don't want the sky to get clipped by custom near clip plane (the water plane)
|
||||
if (queueGroupId < 20 && mReflectionRenderActive)
|
||||
if (((queueGroupId < 20) || queueGroupId == RQG_UnderWater) && mReflectionRenderActive)
|
||||
{
|
||||
mOldFarClip = mReflectionCamera->getFarClipDistance ();
|
||||
mReflectionCamera->disableCustomNearClipPlane();
|
||||
mReflectionCamera->setFarClipDistance (1000000000);
|
||||
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS());
|
||||
}
|
||||
else if (queueGroupId == RQG_UnderWater)
|
||||
{/*
|
||||
mOldFarClip2 = mCamera->getFarClipDistance ();
|
||||
mCamera->setFarClipDistance (1000000000);
|
||||
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS());
|
||||
*/}
|
||||
}
|
||||
|
||||
void Water::renderQueueEnded (Ogre::uint8 queueGroupId, const Ogre::String &invocation, bool &repeatThisInvocation)
|
||||
{
|
||||
if (queueGroupId < 20 && mReflectionRenderActive)
|
||||
if (((queueGroupId < 20) || queueGroupId == RQG_UnderWater) && mReflectionRenderActive)
|
||||
{
|
||||
mReflectionCamera->setFarClipDistance (mOldFarClip);
|
||||
if (!mIsUnderwater)
|
||||
mReflectionCamera->enableCustomNearClipPlane(mWaterPlane);
|
||||
mReflectionCamera->enableCustomNearClipPlane(mErrorPlane);
|
||||
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mReflectionCamera->getProjectionMatrixRS());
|
||||
}
|
||||
if (queueGroupId == RQG_UnderWater)
|
||||
{
|
||||
/*
|
||||
mCamera->setFarClipDistance (mOldFarClip2);
|
||||
Root::getSingleton().getRenderSystem()->_setProjectionMatrix(mCamera->getProjectionMatrixRS());
|
||||
*/}
|
||||
}
|
||||
|
||||
void Water::update(float dt)
|
||||
|
@ -336,6 +331,8 @@ void Water::update(float dt)
|
|||
|
||||
mWaterTimer += dt;
|
||||
sh::Factory::getInstance ().setSharedParameter ("waterTimer", sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mWaterTimer)));
|
||||
|
||||
mRendering->getSkyManager ()->setGlareEnabled (!mIsUnderwater);
|
||||
}
|
||||
|
||||
void Water::applyRTT()
|
||||
|
@ -366,8 +363,6 @@ void Water::applyRTT()
|
|||
|
||||
mReflectionTarget = rtt;
|
||||
}
|
||||
|
||||
mCompositorName = RenderingManager::useMRT() ? "Underwater" : "UnderwaterNoMRT";
|
||||
}
|
||||
|
||||
void Water::applyVisibilityMask()
|
||||
|
|
|
@ -36,6 +36,8 @@ namespace MWRender {
|
|||
Ogre::SceneManager *mSceneManager;
|
||||
|
||||
Ogre::Plane mWaterPlane;
|
||||
Ogre::Plane mErrorPlane;
|
||||
|
||||
Ogre::SceneNode *mWaterNode;
|
||||
Ogre::Entity *mWater;
|
||||
|
||||
|
@ -47,6 +49,7 @@ namespace MWRender {
|
|||
int mTop;
|
||||
|
||||
int mOldFarClip;
|
||||
int mOldFarClip2;
|
||||
|
||||
float mWaterTimer;
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
void RenderScene_vs(in float4 position : POSITION
|
||||
,in float2 uv :TEXCOORD0
|
||||
,uniform float4x4 wvp
|
||||
,out float4 oPosition : POSITION
|
||||
,out float2 oUV :TEXCOORD0)
|
||||
{
|
||||
oPosition = mul(wvp, position);
|
||||
oUV = uv;
|
||||
}
|
||||
|
||||
void RenderScene_ps(in float4 position : POSITION
|
||||
,in float2 uv :TEXCOORD0
|
||||
,uniform sampler2D tex1 : TEXUNIT0
|
||||
,out float4 oColor : COLOR)
|
||||
{
|
||||
float4 scene =tex2D(tex1, uv);
|
||||
oColor= scene;
|
||||
}
|
|
@ -29,7 +29,7 @@ compositor gbuffer
|
|||
|
||||
pass render_quad
|
||||
{
|
||||
material RenderScene
|
||||
material quad
|
||||
input 0 mrt_output 0
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ compositor gbufferFinalizer
|
|||
}
|
||||
pass render_quad
|
||||
{
|
||||
material RenderSceneNoDepth
|
||||
material quad_noDepthWrite
|
||||
input 0 previousscene
|
||||
}
|
||||
pass render_scene
|
||||
|
@ -78,7 +78,7 @@ compositor gbufferFinalizer
|
|||
}
|
||||
pass render_quad
|
||||
{
|
||||
material RenderSceneNoDepth
|
||||
material quad_noDepthWrite
|
||||
input 0 no_mrt_output
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,63 +0,0 @@
|
|||
vertex_program RenderGBuffer_vs cg
|
||||
{
|
||||
source gbuffer.cg
|
||||
profiles vs_4_0 vs_1_1 arbvp1
|
||||
entry_point RenderScene_vs
|
||||
default_params
|
||||
{
|
||||
param_named_auto wvp worldviewproj_matrix
|
||||
}
|
||||
}
|
||||
fragment_program RenderGBuffer_ps cg
|
||||
{
|
||||
source gbuffer.cg
|
||||
entry_point RenderScene_ps
|
||||
profiles ps_4_0 ps_2_x arbfp1
|
||||
default_params
|
||||
{
|
||||
}
|
||||
}
|
||||
material RenderScene
|
||||
{
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
vertex_program_ref RenderGBuffer_vs
|
||||
{
|
||||
}
|
||||
|
||||
fragment_program_ref RenderGBuffer_ps
|
||||
{
|
||||
}
|
||||
|
||||
texture_unit tex1
|
||||
{
|
||||
//scenebuffer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
material RenderSceneNoDepth
|
||||
{
|
||||
technique
|
||||
{
|
||||
pass
|
||||
{
|
||||
depth_write off
|
||||
vertex_program_ref RenderGBuffer_vs
|
||||
{
|
||||
}
|
||||
|
||||
fragment_program_ref RenderGBuffer_ps
|
||||
{
|
||||
}
|
||||
|
||||
texture_unit tex1
|
||||
{
|
||||
//scenebuffer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
#define VISIBILITY 1500.0 // how far you can look through water
|
||||
|
||||
#define BIG_WAVES_X 0.3 // strength of big waves
|
||||
#define BIG_WAVES_Y 0.3
|
||||
|
||||
#define MID_WAVES_X 0.3 // strength of middle sized waves
|
||||
#define MID_WAVES_Y 0.15
|
||||
|
||||
#define SMALL_WAVES_X 0.15 // strength of small waves
|
||||
#define SMALL_WAVES_Y 0.1
|
||||
|
||||
#define WAVE_CHOPPYNESS 0.15 // wave choppyness
|
||||
#define WAVE_SCALE 0.01 // overall wave scale
|
||||
|
||||
#define ABBERATION 0.001 // chromatic abberation amount
|
||||
|
||||
float3 intercept(float3 lineP,
|
||||
float3 lineN,
|
||||
float3 planeN,
|
||||
float planeD)
|
||||
{
|
||||
|
||||
float distance = (planeD - dot(planeN, lineP)) / dot(lineN, planeN);
|
||||
return lineP + lineN * distance;
|
||||
}
|
||||
|
||||
float3 perturb1(shTexture2D tex, float2 coords, float bend, float2 windDir, float windSpeed, float timer)
|
||||
{
|
||||
float2 nCoord = float2(0.0);
|
||||
bend *= WAVE_CHOPPYNESS;
|
||||
nCoord = coords * (WAVE_SCALE * 0.05) + windDir * timer * (windSpeed*0.04);
|
||||
float3 normal0 = 2.0 * shSample(tex, nCoord + float2(-timer*0.015,-timer*0.05)).rgb - 1.0;
|
||||
nCoord = coords * (WAVE_SCALE * 0.1) + windDir * timer * (windSpeed*0.08)-normal0.xy*bend;
|
||||
float3 normal1 = 2.0 * shSample(tex, nCoord + float2(+timer*0.020,+timer*0.015)).rgb - 1.0;
|
||||
|
||||
nCoord = coords * (WAVE_SCALE * 0.25) + windDir * timer * (windSpeed*0.07)-normal1.xy*bend;
|
||||
float3 normal2 = 2.0 * shSample(tex, nCoord + float2(-timer*0.04,-timer*0.03)).rgb - 1.0;
|
||||
nCoord = coords * (WAVE_SCALE * 0.5) + windDir * timer * (windSpeed*0.09)-normal2.xy*bend;
|
||||
float3 normal3 = 2.0 * shSample(tex, nCoord + float2(+timer*0.03,+timer*0.04)).rgb - 1.0;
|
||||
|
||||
nCoord = coords * (WAVE_SCALE* 1.0) + windDir * timer * (windSpeed*0.4)-normal3.xy*bend;
|
||||
float3 normal4 = 2.0 * shSample(tex, nCoord + float2(-timer*0.2,+timer*0.1)).rgb - 1.0;
|
||||
nCoord = coords * (WAVE_SCALE * 2.0) + windDir * timer * (windSpeed*0.7)-normal4.xy*bend;
|
||||
float3 normal5 = 2.0 * shSample(tex, nCoord + float2(+timer*0.1,-timer*0.06)).rgb - 1.0;
|
||||
|
||||
|
||||
float3 normal = normalize(normal0 * BIG_WAVES_X + normal1 * BIG_WAVES_Y +
|
||||
normal2 * MID_WAVES_X + normal3 * MID_WAVES_Y +
|
||||
normal4 * SMALL_WAVES_X + normal5 * SMALL_WAVES_Y);
|
||||
return normal;
|
||||
}
|
||||
|
||||
float3 perturb(shTexture2D tex, float2 coords, float bend, float2 windDir, float windSpeed, float timer)
|
||||
{
|
||||
bend *= WAVE_CHOPPYNESS;
|
||||
float3 col = float3(0.0);
|
||||
float2 nCoord = float2(0.0); //normal coords
|
||||
|
||||
nCoord = coords * (WAVE_SCALE * 0.025) + windDir * timer * (windSpeed*0.03);
|
||||
col += shSample(tex,nCoord + float2(-timer*0.005,-timer*0.01)).rgb*0.20;
|
||||
nCoord = coords * (WAVE_SCALE * 0.1) + windDir * timer * (windSpeed*0.05)-(col.xy/col.zz)*bend;
|
||||
col += shSample(tex,nCoord + float2(+timer*0.01,+timer*0.005)).rgb*0.20;
|
||||
|
||||
nCoord = coords * (WAVE_SCALE * 0.2) + windDir * timer * (windSpeed*0.1)-(col.xy/col.zz)*bend;
|
||||
col += shSample(tex,nCoord + float2(-timer*0.02,-timer*0.03)).rgb*0.20;
|
||||
nCoord = coords * (WAVE_SCALE * 0.5) + windDir * timer * (windSpeed*0.2)-(col.xy/col.zz)*bend;
|
||||
col += shSample(tex,nCoord + float2(+timer*0.03,+timer*0.02)).rgb*0.15;
|
||||
|
||||
nCoord = coords * (WAVE_SCALE* 0.8) + windDir * timer * (windSpeed*1.0)-(col.xy/col.zz)*bend;
|
||||
col += shSample(tex, nCoord + float2(-timer*0.06,+timer*0.08)).rgb*0.15;
|
||||
nCoord = coords * (WAVE_SCALE * 1.0) + windDir * timer * (windSpeed*1.3)-(col.xy/col.zz)*bend;
|
||||
col += shSample(tex,nCoord + float2(+timer*0.08,-timer*0.06)).rgb*0.10;
|
||||
|
||||
return col;
|
||||
}
|
||||
|
||||
|
||||
float3 getCaustics (shTexture2D causticMap, float3 worldPos, float3 eyePosWS, float3 worldNormal, float3 lightDirectionWS0, float waterLevel, float waterTimer, float3 windDir_windSpeed)
|
||||
{
|
||||
float3 waterEyePos = intercept(worldPos.xyz, eyePosWS - worldPos, float3(0,1,0), waterLevel);
|
||||
float waterDepth = shSaturate((waterEyePos.y - worldPos.y) / 50.0);
|
||||
|
||||
float3 causticPos = intercept(worldPos.xyz, lightDirectionWS0.xyz, float3(0,1,0), waterLevel);
|
||||
|
||||
///\ todo clean this up
|
||||
float causticdepth = length(causticPos-worldPos.xyz);
|
||||
causticdepth = 1.0-shSaturate(causticdepth / VISIBILITY);
|
||||
causticdepth = shSaturate(causticdepth);
|
||||
|
||||
// NOTE: the original shader calculated a tangent space basis here,
|
||||
// but using only the world normal is cheaper and i couldn't see a visual difference
|
||||
// also, if this effect gets moved to screen-space some day, it's unlikely to have tangent information
|
||||
float3 causticNorm = worldNormal.xyz * perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).xzy * 2 - 1;
|
||||
|
||||
//float fresnel = pow(clamp(dot(LV,causticnorm),0.0,1.0),2.0);
|
||||
|
||||
float NdotL = max(dot(worldNormal.xyz, lightDirectionWS0.xyz),0.0);
|
||||
|
||||
float causticR = 1.0-perturb(causticMap, causticPos.xz, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z;
|
||||
|
||||
/// \todo sunFade
|
||||
|
||||
// float3 caustics = clamp(pow(float3(causticR)*5.5,float3(5.5*causticdepth)),0.0,1.0)*NdotL*sunFade*causticdepth;
|
||||
float3 caustics = clamp(pow(float3(causticR)*5.5,float3(5.5*causticdepth)),0.0,1.0)*NdotL*causticdepth;
|
||||
float causticG = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z;
|
||||
float causticB = 1.0-perturb(causticMap,causticPos.xz+(1.0-causticdepth)*ABBERATION*2.0, causticdepth, windDir_windSpeed.xy, windDir_windSpeed.z, waterTimer).z;
|
||||
//caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*sunFade*causticdepth;
|
||||
caustics = shSaturate(pow(float3(causticR,causticG,causticB)*5.5,float3(5.5*causticdepth)))*NdotL*causticdepth;
|
||||
|
||||
caustics *= 3;
|
||||
|
||||
// shore transition
|
||||
caustics = shLerp (float3(1,1,1), caustics, waterDepth);
|
||||
|
||||
return caustics;
|
||||
}
|
||||
|
|
@ -11,9 +11,6 @@ material openmw_objects_base
|
|||
scene_blend default
|
||||
depth_write default
|
||||
alpha_rejection default
|
||||
shadow_transparency true // use diffuse alpha as mask for shadow
|
||||
|
||||
shadow_caster_material openmw_shadowcaster
|
||||
|
||||
pass
|
||||
{
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
// ----------------------------------- FRAGMENT ------------------------------------------
|
||||
|
||||
#if UNDERWATER
|
||||
#include "caustics.h"
|
||||
#include "underwater.h"
|
||||
#endif
|
||||
|
||||
SH_BEGIN_PROGRAM
|
||||
|
@ -163,6 +163,7 @@
|
|||
shSampler2D(causticMap)
|
||||
|
||||
shUniform(float, waterTimer) @shSharedParameter(waterTimer)
|
||||
shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight)
|
||||
|
||||
shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed)
|
||||
#endif
|
||||
|
@ -262,22 +263,30 @@
|
|||
shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0));
|
||||
|
||||
#if UNDERWATER
|
||||
float fogAmount = (worldPos.y > waterLevel)
|
||||
float fogAmount = (cameraPos.y > waterLevel)
|
||||
? shSaturate(length(waterEyePos-worldPos) / VISIBILITY)
|
||||
: shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY);
|
||||
|
||||
float3 eyeVec = normalize(cameraPos.xyz-worldPos);
|
||||
|
||||
float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz));
|
||||
waterSunGradient = clamp(pow(waterSunGradient*0.7+0.3,2.0),0.0,1.0);
|
||||
waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0));
|
||||
float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5;
|
||||
|
||||
float waterGradient = dot(eyeVec, vec3(0.0,-1.0,0.0));
|
||||
float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0));
|
||||
waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0);
|
||||
float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0;
|
||||
float3 waterext = float3(0.6, 0.9, 1.0);//water extinction
|
||||
watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT)));
|
||||
watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3;
|
||||
|
||||
float3 waterSunColour = vec3(0.0,1.0,0.85)*waterSunGradient;
|
||||
waterSunColour = (cameraPos.z < waterLevel) ? waterSunColour*0.5:waterSunColour*0.25;//below or above water?
|
||||
|
||||
float3 waterColour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0;
|
||||
shOutputColour(0).xyz = waterColour;
|
||||
float darkness = VISIBILITY*2.0;
|
||||
darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0);
|
||||
watercolour *= darkness;
|
||||
|
||||
float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0;
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater);
|
||||
#endif
|
||||
|
||||
#if MRT
|
||||
|
|
22
files/materials/quad.mat
Normal file
22
files/materials/quad.mat
Normal file
|
@ -0,0 +1,22 @@
|
|||
material quad
|
||||
{
|
||||
depth_write on
|
||||
|
||||
pass
|
||||
{
|
||||
vertex_program quad_vertex
|
||||
fragment_program quad_fragment
|
||||
|
||||
depth_write $depth_write
|
||||
|
||||
texture_unit SceneBuffer
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
material quad_noDepthWrite
|
||||
{
|
||||
parent quad
|
||||
depth_write off
|
||||
}
|
25
files/materials/quad.shader
Normal file
25
files/materials/quad.shader
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "core.h"
|
||||
|
||||
#ifdef SH_VERTEX_SHADER
|
||||
|
||||
SH_BEGIN_PROGRAM
|
||||
shInput(float2, uv0)
|
||||
shOutput(float2, UV)
|
||||
shUniform(float4x4, wvp) @shAutoConstant(wvp, worldviewproj_matrix)
|
||||
SH_START_PROGRAM
|
||||
{
|
||||
shOutputPosition = shMatrixMult(wvp, shInputPosition);
|
||||
UV = uv0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
SH_BEGIN_PROGRAM
|
||||
shInput(float2, UV)
|
||||
shSampler2D(SceneBuffer)
|
||||
SH_START_PROGRAM
|
||||
{
|
||||
shOutputColour(0) = shSample(SceneBuffer, UV);
|
||||
}
|
||||
|
||||
#endif
|
15
files/materials/quad.shaderset
Normal file
15
files/materials/quad.shaderset
Normal file
|
@ -0,0 +1,15 @@
|
|||
shader_set quad_vertex
|
||||
{
|
||||
source quad.shader
|
||||
type vertex
|
||||
profiles_cg vs_2_0 vp40 arbvp1
|
||||
profiles_hlsl vs_2_0
|
||||
}
|
||||
|
||||
shader_set quad_fragment
|
||||
{
|
||||
source quad.shader
|
||||
type fragment
|
||||
profiles_cg ps_2_x ps_2_0 ps fp40 arbfp1
|
||||
profiles_hlsl ps_2_0
|
||||
}
|
|
@ -125,7 +125,7 @@
|
|||
// ----------------------------------- FRAGMENT ------------------------------------------
|
||||
|
||||
#if UNDERWATER
|
||||
#include "caustics.h"
|
||||
#include "underwater.h"
|
||||
#endif
|
||||
|
||||
SH_BEGIN_PROGRAM
|
||||
|
@ -195,6 +195,7 @@
|
|||
shSampler2D(causticMap)
|
||||
|
||||
shUniform(float, waterTimer) @shSharedParameter(waterTimer)
|
||||
shUniform(float2, waterSunFade_sunHeight) @shSharedParameter(waterSunFade_sunHeight)
|
||||
|
||||
shUniform(float3, windDir_windSpeed) @shSharedParameter(windDir_windSpeed)
|
||||
#endif
|
||||
|
@ -226,7 +227,7 @@
|
|||
if (worldPos.y < waterLevel)
|
||||
{
|
||||
float4 worldNormal = shMatrixMult(worldMatrix, float4(normal.xyz, 0));
|
||||
waterEyePos = intercept(worldPos, eyePosWS - worldPos, float3(0,1,0), waterLevel);
|
||||
waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,1,0), waterLevel);
|
||||
caustics = getCaustics(causticMap, worldPos, waterEyePos.xyz, worldNormal.xyz, lightDirectionWS0.xyz, waterLevel, waterTimer, windDir_windSpeed);
|
||||
}
|
||||
|
||||
|
@ -331,9 +332,44 @@
|
|||
|
||||
#if FOG
|
||||
float fogValue = shSaturate((depth - fogParams.y) * fogParams.w);
|
||||
|
||||
#if UNDERWATER
|
||||
// regular fog only if fragment is above water
|
||||
if (worldPos.y > waterLevel)
|
||||
#endif
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue);
|
||||
#endif
|
||||
|
||||
// prevent negative colour output (for example with negative lights)
|
||||
shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0));
|
||||
|
||||
#if UNDERWATER
|
||||
float fogAmount = (cameraPos.y > waterLevel)
|
||||
? shSaturate(length(waterEyePos-worldPos) / VISIBILITY)
|
||||
: shSaturate(length(cameraPos.xyz-worldPos)/ VISIBILITY);
|
||||
|
||||
float3 eyeVec = normalize(cameraPos.xyz-worldPos);
|
||||
|
||||
float waterSunGradient = dot(eyeVec, -normalize(lightDirectionWS0.xyz));
|
||||
waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0));
|
||||
float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5;
|
||||
|
||||
float waterGradient = dot(eyeVec, float3(0.0,-1.0,0.0));
|
||||
waterGradient = clamp((waterGradient*0.5+0.5),0.2,1.0);
|
||||
float3 watercolour = (float3(0.0078, 0.5176, 0.700)+waterSunColour)*waterGradient*2.0;
|
||||
float3 waterext = float3(0.6, 0.9, 1.0);//water extinction
|
||||
watercolour = shLerp(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT)));
|
||||
watercolour = (cameraPos.y <= waterLevel) ? watercolour : watercolour*0.3;
|
||||
|
||||
|
||||
float darkness = VISIBILITY*2.0;
|
||||
darkness = clamp((waterEyePos.y - waterLevel + darkness)/darkness,0.2,1.0);
|
||||
watercolour *= darkness;
|
||||
|
||||
float isUnderwater = (worldPos.y < waterLevel) ? 1.0 : 0.0;
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, watercolour, fogAmount * isUnderwater);
|
||||
#endif
|
||||
|
||||
|
||||
#if MRT
|
||||
shOutputColour(1) = float4(depth / far,1,1,1);
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#define ABBERATION 0.001 // chromatic abberation amount
|
||||
|
||||
#define SUN_EXT float3(0.45, 0.55, 0.68) //sunlight extinction
|
||||
|
||||
float3 intercept(float3 lineP,
|
||||
float3 lineN,
|
||||
float3 planeN,
|
||||
|
|
|
@ -31,3 +31,11 @@ material Water
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
material Underwater_Dome
|
||||
{
|
||||
parent openmw_objects_base
|
||||
|
||||
depth_write off
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
|
||||
// tweakables ----------------------------------------------------
|
||||
|
||||
#define VISIBILITY 1500.0 // how far you can look through water
|
||||
|
||||
#define BIG_WAVES_X 0.3 // strength of big waves
|
||||
#define BIG_WAVES_Y 0.3
|
||||
|
||||
|
@ -57,8 +59,8 @@
|
|||
|
||||
#define ABBERATION 0.001 // chromatic abberation amount
|
||||
#define BUMP 1.5 // overall water surface bumpiness
|
||||
#define REFL_BUMP 0.11 // reflection distortion amount
|
||||
#define REFR_BUMP 0.08 // refraction distortion amount
|
||||
#define REFL_BUMP 0.08 // reflection distortion amount
|
||||
#define REFR_BUMP 0.06 // refraction distortion amount
|
||||
|
||||
#define SCATTER_AMOUNT 3.0 // amount of sunlight scattering
|
||||
#define SCATTER_COLOUR float3(0.0,1.0,0.95) // colour of sunlight scattering
|
||||
|
@ -202,6 +204,17 @@
|
|||
// brighten up the refraction underwater
|
||||
refraction = (cameraPos.y < 0) ? shSaturate(refraction * 1.5) : refraction;
|
||||
|
||||
// specular
|
||||
float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS);
|
||||
|
||||
shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz;
|
||||
|
||||
// smooth transition to shore (above water only)
|
||||
shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, refraction, (1-shoreFade) * (1-isUnderwater));
|
||||
|
||||
// fog
|
||||
if (isUnderwater == 1)
|
||||
{
|
||||
float waterSunGradient = dot(-vVec, -lVec);
|
||||
waterSunGradient = shSaturate(pow(waterSunGradient*0.7+0.3,2.0));
|
||||
float3 waterSunColour = float3(0.0,1.0,0.85)*waterSunGradient * 0.5;
|
||||
|
@ -212,17 +225,19 @@
|
|||
float3 waterext = float3(0.6, 0.9, 1.0);//water extinction
|
||||
watercolour = mix(watercolour*0.3*waterSunFade_sunHeight.x, watercolour, shSaturate(1.0-exp(-waterSunFade_sunHeight.y*SUN_EXT)));
|
||||
|
||||
// specular
|
||||
float specular = pow(max(dot(R, lVec), 0.0),SPEC_HARDNESS);
|
||||
float darkness = VISIBILITY*2.0;
|
||||
darkness = clamp((cameraPos.y+darkness)/darkness,0.2,1.0);
|
||||
|
||||
shOutputColour(0).xyz = shLerp( shLerp(refraction, scatterColour, lightScatter), reflection, fresnel) + specular * sunSpecular.xyz;
|
||||
|
||||
// smooth transition to shore (above water only)
|
||||
shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, refraction, (1-shoreFade) * (1-isUnderwater));
|
||||
|
||||
// fog
|
||||
float fog = shSaturate(length(cameraPos.xyz-position.xyz) / VISIBILITY);
|
||||
shOutputColour(0).xyz = shLerp(shOutputColour(0).xyz, watercolour * darkness, shSaturate(fog / waterext));
|
||||
}
|
||||
else
|
||||
{
|
||||
float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w);
|
||||
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColor, fogValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 192 KiB |
Binary file not shown.
Before Width: | Height: | Size: 34 KiB |
Binary file not shown.
|
@ -1,61 +0,0 @@
|
|||
void main_vp
|
||||
(
|
||||
in float4 inPos : POSITION,
|
||||
|
||||
out float4 pos : POSITION,
|
||||
out float2 uv0 : TEXCOORD0,
|
||||
out float4 noiseCoord : TEXCOORD1,
|
||||
|
||||
uniform float4x4 worldViewProj,
|
||||
uniform float timeVal,
|
||||
uniform float scale
|
||||
)
|
||||
{
|
||||
// Use standardise transform, so work accord with render system specific (RS depth, requires texture flipping, etc)
|
||||
pos = mul(worldViewProj, inPos);
|
||||
|
||||
// The input positions adjusted by texel offsets, so clean up inaccuracies
|
||||
inPos.xy = sign(inPos.xy);
|
||||
|
||||
// Convert to image-space
|
||||
uv0 = (float2(inPos.x, -inPos.y) + 1.0f) * 0.5f;
|
||||
noiseCoord = (pos + timeVal) * scale;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float4 main_fp_nomrt (float2 iTexCoord : TEXCOORD0,
|
||||
float3 noiseCoord : TEXCOORD1,
|
||||
uniform sampler2D RT : register(s0),
|
||||
uniform sampler2D NormalMap : register(s1),
|
||||
uniform sampler2D CausticMap : register(s2)) : COLOR
|
||||
{
|
||||
float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1;
|
||||
|
||||
float4 col = tex2D(RT, iTexCoord + normal.xy * 0.015) +
|
||||
(tex2D(CausticMap, noiseCoord) / 5);
|
||||
col.xyz = lerp(col.xyz, float3(0.15, 0.40, 0.40), 0.4);
|
||||
return col;
|
||||
|
||||
}
|
||||
|
||||
|
||||
float4 main_fp (float2 iTexCoord : TEXCOORD0,
|
||||
float3 noiseCoord : TEXCOORD1,
|
||||
uniform float far,
|
||||
uniform sampler2D RT : register(s0),
|
||||
uniform sampler2D NormalMap : register(s1),
|
||||
uniform sampler2D CausticMap : register(s2),
|
||||
uniform sampler2D DepthMap : register(s3)) : COLOR
|
||||
{
|
||||
float4 normal = tex2D(NormalMap, noiseCoord) * 2 - 1;
|
||||
|
||||
float depth = tex2D(DepthMap, iTexCoord + normal.xy * 0.015).r * far;
|
||||
depth = saturate(depth / 2000.f);
|
||||
|
||||
float4 color = tex2D(RT, iTexCoord + normal.xy * 0.015) +
|
||||
(tex2D(CausticMap, noiseCoord) / 5);
|
||||
color.xyz = lerp(color.xyz, float3(0.15, 0.40, 0.40), 0.4);
|
||||
|
||||
return lerp(color, float4(0.15, 0.40, 0.40, 1), depth);
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
void main_vp
|
||||
(
|
||||
in float4 iPos : POSITION
|
||||
, in float2 iUv : TEXCOORD0
|
||||
|
||||
, out float4 oPos : POSITION
|
||||
, out float3 oScreenCoords : TEXCOORD0
|
||||
, out float2 oUv : TEXCOORD1
|
||||
, out float oDepth : TEXCOORD2
|
||||
, out float4 oEyeVector : TEXCOORD3
|
||||
|
||||
, uniform float4x4 wvpMat
|
||||
, uniform float4 camPosObjSpace
|
||||
)
|
||||
{
|
||||
oPos = mul(wvpMat, iPos);
|
||||
|
||||
oUv = iUv * 10; // uv scale
|
||||
oDepth = oPos.z;
|
||||
|
||||
float4x4 scalemat = float4x4( 0.5, 0, 0, 0.5,
|
||||
0, -0.5, 0, 0.5,
|
||||
0, 0, 0.5, 0.5,
|
||||
0, 0, 0, 1 );
|
||||
float4 texcoordProj = mul(scalemat, oPos);
|
||||
oScreenCoords = float3(texcoordProj.x, texcoordProj.y, texcoordProj.w);
|
||||
|
||||
oEyeVector = camPosObjSpace - iPos;
|
||||
}
|
||||
|
||||
void main_fp
|
||||
(
|
||||
out float4 oColor : COLOR
|
||||
|
||||
, in float3 iScreenCoords : TEXCOORD0
|
||||
, in float2 iUv : TEXCOORD1
|
||||
, in float iDepth : TEXCOORD2
|
||||
, in float4 iEyeVector : TEXCOORD3
|
||||
, uniform float renderTargetFlipping
|
||||
, uniform float4 lightPosObjSpace0
|
||||
, uniform float4 lightSpecularColour0
|
||||
|
||||
, uniform sampler2D reflectionMap : register(s0)
|
||||
, uniform sampler2D refractionMap : register(s1)
|
||||
, uniform sampler2D depthMap : register(s2)
|
||||
, uniform sampler2D normalMap : register(s3)
|
||||
, uniform float time
|
||||
, uniform float far
|
||||
, uniform float4 fogParams
|
||||
, uniform float4 fogColour
|
||||
, uniform float isUnderwater
|
||||
)
|
||||
{
|
||||
|
||||
float2 screenCoords = iScreenCoords.xy / iScreenCoords.z;
|
||||
screenCoords.y = (1-saturate(renderTargetFlipping))+renderTargetFlipping*screenCoords.y;
|
||||
|
||||
// No need for transparency since we are using a refraction map
|
||||
oColor.a = 1;
|
||||
|
||||
// Sample screen-space depth map and subtract pixel depth to get the real water depth
|
||||
float depthTex = tex2D(depthMap, screenCoords).r;
|
||||
float depth1 = depthTex * far - iDepth;
|
||||
depth1 = saturate(depth1 / 500.f);
|
||||
|
||||
// Simple wave effect. to be replaced by something better
|
||||
float2 uv1 = iUv + time * float2(0.5, 0);
|
||||
float2 uv2 = iUv + time * float2(0, 0.5);
|
||||
float2 uv3 = iUv + time * float2(-0.5, 0);
|
||||
float2 uv4 = iUv + time * float2(0, -0.5);
|
||||
float4 normal = tex2D(normalMap, uv1) + tex2D(normalMap, uv2) + tex2D(normalMap, uv3) + tex2D(normalMap, uv4);
|
||||
normal = normal / 4.f;
|
||||
normal = 2*normal - 1;
|
||||
|
||||
float2 screenCoords_reflect = screenCoords + normal.yx * 0.05;
|
||||
float2 screenCoords_refract = screenCoords + normal.yx * 0.05 * depth1;
|
||||
|
||||
// Sample depth again with the refracted coordinates
|
||||
depthTex = tex2D(depthMap, screenCoords_refract).r;
|
||||
float depth2 = (depthTex * far - iDepth) / 500.f;
|
||||
depth2 = (depthTex == 0 ? 1 : depth2);
|
||||
// if depth2 is less than 0, this means we would refract something which is above water,
|
||||
// which we don't want to - so in that case, don't refract
|
||||
if (depth2 < 0.25) // delta due to inaccuracies
|
||||
{
|
||||
screenCoords_refract = screenCoords;
|
||||
depth2 = depth1;
|
||||
}
|
||||
depth2 = saturate(depth2);
|
||||
|
||||
float4 reflection = tex2D(reflectionMap, screenCoords_reflect);
|
||||
float4 refraction = tex2D(refractionMap, screenCoords_refract);
|
||||
|
||||
// tangent to object space
|
||||
normal.xyz = normal.xzy;
|
||||
|
||||
iEyeVector.xyz = normalize(iEyeVector.xyz);
|
||||
|
||||
// fresnel
|
||||
float facing = 1.0 - max(abs(dot(iEyeVector.xyz, normal.xyz)), 0);
|
||||
float reflectionFactor = saturate(0.35 + 0.65 * pow(facing, 2));
|
||||
|
||||
// specular
|
||||
float3 lightDir = normalize(lightPosObjSpace0.xyz); // assumes that light 0 is a directional light
|
||||
float3 halfVector = normalize(iEyeVector + lightDir);
|
||||
float specular = pow(max(dot(normal.xyz, halfVector.xyz), 0), 64);
|
||||
|
||||
float opacity = depth2 * saturate(reflectionFactor + specular);
|
||||
opacity *= (1-isUnderwater);
|
||||
|
||||
reflection.xyz += lightSpecularColour0.xyz * specular;
|
||||
|
||||
oColor.xyz = lerp(refraction.xyz, reflection.xyz, opacity);
|
||||
|
||||
oColor.xyz = lerp(oColor.xyz, float3(0.15, 0.40, 0.40), isUnderwater*0.6); // underwater tint color
|
||||
oColor.xyz = lerp(oColor.xyz, float3(0.15, 0.40, 0.40), saturate(isUnderwater * (iDepth / 2000.f))); // underwater fog
|
||||
|
||||
// add fog
|
||||
//float fogValue = saturate((iDepth - fogParams.y) * fogParams.w);
|
||||
//oColor.xyz = lerp(oColor.xyz, fogColour, fogValue);
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
compositor UnderwaterNoMRT
|
||||
{
|
||||
technique
|
||||
{
|
||||
texture rt0 target_width target_height PF_R8G8B8
|
||||
|
||||
target rt0 { input previous }
|
||||
|
||||
target_output
|
||||
{
|
||||
// Start with clear output
|
||||
input none
|
||||
|
||||
pass render_quad
|
||||
{
|
||||
material Water/CompositorNoMRT
|
||||
input 0 rt0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
compositor Underwater
|
||||
{
|
||||
technique
|
||||
{
|
||||
texture_ref scene gbuffer mrt_output
|
||||
texture rt0 target_width target_height PF_R8G8B8
|
||||
|
||||
target rt0 { input previous }
|
||||
|
||||
target_output
|
||||
{
|
||||
// Start with clear output
|
||||
input none
|
||||
|
||||
pass render_quad
|
||||
{
|
||||
material Water/Compositor
|
||||
input 0 rt0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue