Torque3D/Templates/Empty/game/shaders/common/water/waterP.hlsl

384 lines
14 KiB
HLSL

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "../shaderModelAutoGen.hlsl"
#include "../torque.hlsl"
//-----------------------------------------------------------------------------
// Defines
//-----------------------------------------------------------------------------
#define PIXEL_DIST IN.rippleTexCoord2.z
// miscParams
#define FRESNEL_BIAS miscParams[0]
#define FRESNEL_POWER miscParams[1]
// miscParams[2] is unused
#define ISRIVER miscParams[3]
// reflectParams
#define REFLECT_PLANE_Z reflectParams[0]
#define REFLECT_MIN_DIST reflectParams[1]
#define REFLECT_MAX_DIST reflectParams[2]
#define NO_REFLECT reflectParams[3]
// fogParams
#define FOG_DENSITY fogParams[0]
#define FOG_DENSITY_OFFSET fogParams[1]
// wetnessParams
#define WET_DEPTH wetnessParams[0]
#define WET_COLOR_FACTOR wetnessParams[1]
// distortionParams
#define DISTORT_START_DIST distortionParams[0]
#define DISTORT_END_DIST distortionParams[1]
#define DISTORT_FULL_DEPTH distortionParams[2]
// foamParams
#define FOAM_OPACITY foamParams[0]
#define FOAM_MAX_DEPTH foamParams[1]
#define FOAM_AMBIENT_LERP foamParams[2]
#define FOAM_RIPPLE_INFLUENCE foamParams[3]
// specularParams
#define SPEC_POWER specularParams[3]
#define SPEC_COLOR specularParams.xyz
//-----------------------------------------------------------------------------
// Structures
//-----------------------------------------------------------------------------
struct ConnectData
{
float4 hpos : TORQUE_POSITION;
// TexCoord 0 and 1 (xy,zw) for ripple texture lookup
float4 rippleTexCoord01 : TEXCOORD0;
// xy is TexCoord 2 for ripple texture lookup
// z is the Worldspace unit distance/depth of this vertex/pixel
// w is amount of the crestFoam ( more at crest of waves ).
float4 rippleTexCoord2 : TEXCOORD1;
// Screenspace vert position BEFORE wave transformation
float4 posPreWave : TEXCOORD2;
// Screenspace vert position AFTER wave transformation
float4 posPostWave : TEXCOORD3;
// Objectspace vert position BEFORE wave transformation
// w coord is world space z position.
float4 objPos : TEXCOORD4;
float4 foamTexCoords : TEXCOORD5;
float3x3 tangentMat : TEXCOORD6;
};
//-----------------------------------------------------------------------------
// approximate Fresnel function
//-----------------------------------------------------------------------------
float fresnel(float NdotV, float bias, float power)
{
return bias + (1.0-bias)*pow(abs(1.0 - max(NdotV, 0)), power);
}
//-----------------------------------------------------------------------------
// Uniforms
//-----------------------------------------------------------------------------
TORQUE_UNIFORM_SAMPLER2D(bumpMap,0);
TORQUE_UNIFORM_SAMPLER2D(prepassTex, 1);
TORQUE_UNIFORM_SAMPLER2D(reflectMap, 2);
TORQUE_UNIFORM_SAMPLER2D(refractBuff, 3);
TORQUE_UNIFORM_SAMPLERCUBE(skyMap, 4);
TORQUE_UNIFORM_SAMPLER2D(foamMap, 5);
TORQUE_UNIFORM_SAMPLER1D(depthGradMap, 6);
uniform float4 specularParams;
uniform float4 baseColor;
uniform float4 miscParams;
uniform float2 fogParams;
uniform float4 reflectParams;
uniform float3 reflectNormal;
uniform float2 wetnessParams;
uniform float farPlaneDist;
uniform float3 distortionParams;
uniform float4 foamParams;
uniform float3 ambientColor;
uniform float3 eyePos; // This is in object space!
uniform float3 fogData;
uniform float4 fogColor;
uniform float4 rippleMagnitude;
uniform float4 rtParams1;
uniform float depthGradMax;
uniform float3 inLightVec;
uniform float4x4 modelMat;
uniform float4 sunColor;
uniform float sunBrightness;
uniform float reflectivity;
//-----------------------------------------------------------------------------
// Main
//-----------------------------------------------------------------------------
float4 main( ConnectData IN ) : TORQUE_TARGET0
{
// Get the bumpNorm...
float3 bumpNorm = ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord01.xy ).rgb * 2.0 - 1.0 ) * rippleMagnitude.x;
bumpNorm += ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord01.zw ).rgb * 2.0 - 1.0 ) * rippleMagnitude.y;
bumpNorm += ( TORQUE_TEX2D( bumpMap, IN.rippleTexCoord2.xy ).rgb * 2.0 - 1.0 ) * rippleMagnitude.z;
bumpNorm = normalize( bumpNorm );
bumpNorm = lerp( bumpNorm, float3(0,0,1), 1.0 - rippleMagnitude.w );
bumpNorm = mul( bumpNorm, IN.tangentMat );
// Get depth of the water surface (this pixel).
// Convert from WorldSpace to EyeSpace.
float pixelDepth = PIXEL_DIST / farPlaneDist;
float2 prepassCoord = viewportCoordToRenderTarget( IN.posPostWave, rtParams1 );
float startDepth = TORQUE_PREPASS_UNCONDITION( prepassTex, prepassCoord ).w;
// The water depth in world units of the undistorted pixel.
float startDelta = ( startDepth - pixelDepth );
startDelta = max( startDelta, 0.0 );
startDelta *= farPlaneDist;
// Calculate the distortion amount for the water surface.
//
// We subtract a little from it so that we don't
// distort where the water surface intersects the
// camera near plane.
float distortAmt = saturate( ( PIXEL_DIST - DISTORT_START_DIST ) / DISTORT_END_DIST );
// Scale down distortion in shallow water.
distortAmt *= saturate( startDelta / DISTORT_FULL_DEPTH );
// Do the intial distortion... we might remove it below.
float2 distortDelta = bumpNorm.xy * distortAmt;
float4 distortPos = IN.posPostWave;
distortPos.xy += distortDelta;
prepassCoord = viewportCoordToRenderTarget( distortPos, rtParams1 );
// Get prepass depth at the position of this distorted pixel.
float prepassDepth = TORQUE_PREPASS_UNCONDITION( prepassTex, prepassCoord ).w;
if ( prepassDepth > 0.99 )
prepassDepth = 5.0;
float delta = ( prepassDepth - pixelDepth ) * farPlaneDist;
if ( delta < 0.0 )
{
// If we got a negative delta then the distorted
// sample is above the water surface. Mask it out
// by removing the distortion.
distortPos = IN.posPostWave;
delta = startDelta;
distortAmt = 0;
}
else
{
float diff = ( prepassDepth - startDepth ) * farPlaneDist;
if ( diff < 0 )
{
distortAmt = saturate( ( PIXEL_DIST - DISTORT_START_DIST ) / DISTORT_END_DIST );
distortAmt *= saturate( delta / DISTORT_FULL_DEPTH );
distortDelta = bumpNorm.xy * distortAmt;
distortPos = IN.posPostWave;
distortPos.xy += distortDelta;
prepassCoord = viewportCoordToRenderTarget( distortPos, rtParams1 );
// Get prepass depth at the position of this distorted pixel.
prepassDepth = TORQUE_PREPASS_UNCONDITION( prepassTex, prepassCoord ).w;
if ( prepassDepth > 0.99 )
prepassDepth = 5.0;
delta = ( prepassDepth - pixelDepth ) * farPlaneDist;
}
if ( delta < 0.1 )
{
// If we got a negative delta then the distorted
// sample is above the water surface. Mask it out
// by removing the distortion.
distortPos = IN.posPostWave;
delta = startDelta;
distortAmt = 0;
}
}
float4 temp = IN.posPreWave;
temp.xy += bumpNorm.xy * distortAmt;
float2 reflectCoord = viewportCoordToRenderTarget( temp, rtParams1 );
float2 refractCoord = viewportCoordToRenderTarget( distortPos, rtParams1 );
float4 fakeColor = float4(ambientColor,1);
float3 eyeVec = IN.objPos.xyz - eyePos;
eyeVec = mul( (float3x3)modelMat, eyeVec );
eyeVec = mul( IN.tangentMat, eyeVec );
float3 reflectionVec = reflect( eyeVec, bumpNorm );
// Use fakeColor for ripple-normals that are angled towards the camera
eyeVec = -eyeVec;
eyeVec = normalize( eyeVec );
float ang = saturate( dot( eyeVec, bumpNorm ) );
float fakeColorAmt = ang;
// for verts far from the reflect plane z position
float rplaneDist = abs( REFLECT_PLANE_Z - IN.objPos.w );
rplaneDist = saturate( ( rplaneDist - 1.0 ) / 2.0 );
rplaneDist *= ISRIVER;
fakeColorAmt = max( fakeColorAmt, rplaneDist );
#ifndef UNDERWATER
// Get foam color and amount
float2 foamRippleOffset = bumpNorm.xy * FOAM_RIPPLE_INFLUENCE;
IN.foamTexCoords.xy += foamRippleOffset;
IN.foamTexCoords.zw += foamRippleOffset;
float4 foamColor = TORQUE_TEX2D( foamMap, IN.foamTexCoords.xy );
foamColor += TORQUE_TEX2D( foamMap, IN.foamTexCoords.zw );
foamColor = saturate( foamColor );
// Modulate foam color by ambient color
// so we don't have glowing white foam at night.
foamColor.rgb = lerp( foamColor.rgb, ambientColor.rgb, FOAM_AMBIENT_LERP );
float foamDelta = saturate( delta / FOAM_MAX_DEPTH );
float foamAmt = 1 - pow( foamDelta, 2 );
// Fade out the foam in very very low depth,
// this improves the shoreline a lot.
float diff = 0.8 - foamAmt;
if ( diff < 0.0 )
foamAmt -= foamAmt * abs( diff ) / 0.2;
foamAmt *= FOAM_OPACITY * foamColor.a;
foamColor.rgb *= FOAM_OPACITY * foamAmt * foamColor.a;
// Get reflection map color.
float4 refMapColor = TORQUE_TEX2D( reflectMap, reflectCoord );
// If we do not have a reflection texture then we use the cubemap.
refMapColor = lerp( refMapColor, TORQUE_TEXCUBE( skyMap, reflectionVec ), NO_REFLECT );
fakeColor = ( TORQUE_TEXCUBE( skyMap, reflectionVec ) );
fakeColor.a = 1;
// Combine reflection color and fakeColor.
float4 reflectColor = lerp( refMapColor, fakeColor, fakeColorAmt );
// Get refract color
float4 refractColor = hdrDecode( TORQUE_TEX2D( refractBuff, refractCoord ) );
// We darken the refraction color a bit to make underwater
// elements look wet. We fade out this darkening near the
// surface in order to not have hard water edges.
// @param WET_DEPTH The depth in world units at which full darkening will be recieved.
// @param WET_COLOR_FACTOR The refract color is scaled down by this amount when at WET_DEPTH
refractColor.rgb *= 1.0f - ( saturate( delta / WET_DEPTH ) * WET_COLOR_FACTOR );
// Add Water fog/haze.
float fogDelta = delta - FOG_DENSITY_OFFSET;
if ( fogDelta < 0.0 )
fogDelta = 0.0;
float fogAmt = 1.0 - saturate( exp( -FOG_DENSITY * fogDelta ) );
// Calculate the water "base" color based on depth.
float4 waterBaseColor = baseColor * TORQUE_TEX1D( depthGradMap, saturate( delta / depthGradMax ) );
waterBaseColor = toLinear(waterBaseColor);
// Modulate baseColor by the ambientColor.
waterBaseColor *= float4( ambientColor.rgb, 1 );
// calc "diffuse" color by lerping from the water color
// to refraction image based on the water clarity.
float4 diffuseColor = lerp( refractColor, waterBaseColor, fogAmt );
// fresnel calculation
float fresnelTerm = fresnel( ang, FRESNEL_BIAS, FRESNEL_POWER );
// Scale the frensel strength by fog amount
// so that parts that are very clear get very little reflection.
fresnelTerm *= fogAmt;
// Also scale the frensel by our distance to the
// water surface. This removes the hard reflection
// when really close to the water surface.
fresnelTerm *= saturate( PIXEL_DIST - 0.1 );
fresnelTerm *= reflectivity;
// Combine the diffuse color and reflection image via the
// fresnel term and set out output color.
float4 OUT = lerp( diffuseColor, reflectColor, fresnelTerm );
float3 lightVec = inLightVec;
// Get some specular reflection.
float3 newbump = bumpNorm;
newbump.xy *= 3.5;
newbump = normalize( newbump );
float3 halfAng = normalize( eyeVec + -lightVec );
float specular = saturate( dot( newbump, halfAng ) );
specular = pow( specular, SPEC_POWER );
// Scale down specularity in very shallow water to improve the transparency of the shoreline.
specular *= saturate( delta / 2 );
OUT.rgb = OUT.rgb + ( SPEC_COLOR * specular.xxx );
#else
float4 refractColor = hdrDecode( TORQUE_TEX2D( refractBuff, refractCoord ) );
float4 OUT = refractColor;
#endif
#ifndef UNDERWATER
OUT.rgb = OUT.rgb + foamColor.rgb;
float factor = computeSceneFog( eyePos,
IN.objPos.xyz,
IN.objPos.w,
fogData.x,
fogData.y,
fogData.z );
OUT.rgb = lerp( OUT.rgb, fogColor.rgb, 1.0 - saturate( factor ) );
//OUT.rgb = fogColor.rgb;
#endif
OUT.a = 1.0;
//return OUT;
return hdrEncode( OUT );
}