298 lines
11 KiB
Plaintext
298 lines
11 KiB
Plaintext
float3 lightDir : register(c1);
|
|
float3 viewPos : register(c2);
|
|
float3 viewDir : register(c4);
|
|
float3 passID2expIsLast : register(c23);
|
|
|
|
float4 g_fGlow : register(c61);
|
|
|
|
sampler2D colorSampler : register(s0);
|
|
sampler2D depthSampler : register(s1);
|
|
sampler2D waveSampler : register(s3);
|
|
sampler2D shadowSampler : register(s4);
|
|
|
|
// Tweakables
|
|
static float4 g_fRayColor = float4(1.75f * 0.45f, 1.75f * 0.4f, 1.75f * 0.35f, 1.0f);
|
|
static float g_fRayNearPlane = 10.0f;
|
|
static float g_fRayFarPlane = 500.0f;
|
|
static float g_fRayDensity = 0.25f;
|
|
static float g_fRayDecay = 0.9125f;
|
|
static float g_fRayAnglePersistence = 4.f;
|
|
|
|
float4 ps_ray_mask(float2 TexCoord : TEXCOORD0, float2 LightPos : TEXCOORD2) : COLOR0
|
|
{
|
|
float2 d = LightPos - TexCoord;
|
|
float r = saturate( 1.f - dot(d, d) );
|
|
r *= saturate( g_fRayAnglePersistence * dot(-lightDir, viewDir) );
|
|
|
|
float m = tex2D(depthSampler, TexCoord).x;
|
|
m = saturate( (m - g_fRayNearPlane) / (g_fRayFarPlane - g_fRayNearPlane) );
|
|
// m = saturate(1.f - m);
|
|
|
|
// float2 p = TexCoord * 2.0f - 1.0f;
|
|
// float b = saturate( 1.0f - 0.7071f * dot(p, p) );
|
|
|
|
return /* b */ m * r * g_fRayColor;
|
|
}
|
|
|
|
// Pixel shader
|
|
float4 ps_ray_extrude(float2 TexCoord : TEXCOORD0, float2 LightPos : TEXCOORD2) : COLOR0
|
|
{
|
|
float2 s = g_fRayDensity / (passID2expIsLast.y) * (LightPos - TexCoord) / 8.f;
|
|
|
|
float4 r = 0.f, ro = 0.f, rm = 0.f, rd = .125f;
|
|
float2 c = TexCoord;
|
|
|
|
for(int i = 0; i < 8; i++)
|
|
{
|
|
float4 rs = tex2D(colorSampler, c);
|
|
ro = (i == 0) ? rs : ro;
|
|
|
|
rm = max(rs, rm);
|
|
rs.xyz = rm.xyz;
|
|
r += rs * rd;
|
|
|
|
rd.xyz *= (float3)g_fRayDecay;
|
|
c += s;
|
|
}
|
|
|
|
r.xyz *= 1.0f + 0.25f * g_fGlow.z;
|
|
r.a = min(ro.a, r.a);
|
|
|
|
return r * saturate(1.f - passID2expIsLast.z * r.a);
|
|
}
|
|
|
|
float3 g_fTime : register(c3);
|
|
|
|
// Tweakables
|
|
static float g_fWaterLevel = 5.0f;
|
|
|
|
static float4 g_fLightFilterColor = float4(0.4f, 0.75f, 0.8f, 0.99f); // float4(0.8f, 0.85f, 0.9f, 0.8f);
|
|
static float g_fFilterOffset = 0.0f;
|
|
static float g_fLightFilterDensity = 0.02f;
|
|
|
|
static float g_fCausticScaling = 0.004f;
|
|
static float g_fCausticDistortion = 0.1f;
|
|
static float4 g_fCausticPatternScaling = 0.25f;
|
|
static float2 g_vCausticSpeed = float2(0.05f, 0.1f);
|
|
static float g_fCausticBrightness = 0.35f;
|
|
|
|
float4 ps_underwater_filter(float2 TexCoord : TEXCOORD0, float3 EyeDir : TEXCOORD1,
|
|
float2 LightPos : TEXCOORD2) : COLOR0
|
|
{
|
|
// Compute eye space position
|
|
float fEyeDepth = tex2D(depthSampler, TexCoord).x;
|
|
float3 vEyePoint = viewPos + fEyeDepth * EyeDir;
|
|
float3 vEyeNormal = normalize( cross( ddx(vEyePoint), ddy(vEyePoint) ) );
|
|
|
|
// Compute distance to water level
|
|
float fUnderWater = g_fWaterLevel - vEyePoint.y;
|
|
float fLightTravel = max( fUnderWater / max(-lightDir.y, 0.0001f), 0.0f );
|
|
|
|
// Intersect water plane
|
|
float3 vSubmerged = vEyePoint - viewPos;
|
|
float fSubmergedBelow = (fUnderWater >= 0.0f)
|
|
? abs(vSubmerged.y)
|
|
: (g_fWaterLevel - viewPos.y);
|
|
float fSubmerged = (viewPos.y > g_fWaterLevel)
|
|
? max(fUnderWater, 0.0f)
|
|
: fSubmergedBelow;
|
|
vSubmerged *= fSubmerged / max( abs(vSubmerged.y), 0.0001f );
|
|
|
|
// Compute submerged length
|
|
fSubmerged = length(vSubmerged);
|
|
|
|
// Compute light color
|
|
float4 fFilterDist= fLightTravel + float2(fSubmerged, 0.0f).xxxy;
|
|
float4 fLightColor = pow(g_fLightFilterColor, g_fLightFilterDensity * fFilterDist );
|
|
|
|
// Color hack
|
|
fLightColor.xyz *= pow(g_fLightFilterColor.xyz, max(fLightTravel - 30, 0) * 0.08f);
|
|
|
|
// Compute light coordinate space
|
|
float3 vLightU = normalize( cross( lightDir, float3(1.0f, 0.0f, 0.0f) ) );
|
|
float3 vLightV = normalize( cross( vLightU, lightDir ) );
|
|
|
|
// Scale time
|
|
float fTime = g_fTime.z * 0.000095f;
|
|
|
|
// Animate caustics
|
|
float2 fCausticCoord = float2( dot(vLightU, vEyePoint), dot(vLightV, vEyePoint) ) * g_fCausticScaling;
|
|
float2 fCausticCoordDelta = fTime * g_vCausticSpeed * g_fCausticScaling;
|
|
|
|
float3 bx = float3(2.0f, 1.0f, 0.0f);
|
|
|
|
// Get caustic normal
|
|
float3 vCausticNormal1 = normalize( tex2D(waveSampler, fCausticCoord - fCausticCoordDelta).xzy * bx.xyx - bx.yzy );
|
|
float3 vCausticNormal2 = normalize( tex2D(waveSampler, fCausticCoord.yx + fCausticCoordDelta).xzy * bx.xyx - bx.yzy );
|
|
float3 vCausticNormal3 = normalize( tex2D(waveSampler, 5 * (fCausticCoord - 2 * fCausticCoordDelta)).xzy * bx.xyx - bx.yzy );
|
|
float3 vCausticNormal4 = normalize( tex2D(waveSampler, 5 * (fCausticCoord.yx + 2 * fCausticCoordDelta)).xzy * bx.xyx - bx.yzy );
|
|
|
|
// Compute normals used for distortion & lighting
|
|
float3 vCausticNormalX1 = vCausticNormal1 + vCausticNormal4 / 3.0f;
|
|
float3 vCausticNormalX2 = vCausticNormal2 + vCausticNormal3 / 3.0f;
|
|
float3 vCausticNormal = vCausticNormalX1 + vCausticNormalX2;
|
|
vCausticNormal = normalize(vCausticNormal);
|
|
|
|
// Compute caustic pattern
|
|
float4 fCausticPattern = float2( dot(vEyePoint, vLightU), dot(vEyePoint, vLightV) ).xyxy;
|
|
fCausticPattern.xy += g_fCausticDistortion * vCausticNormalX1.xz * (1.0f + fEyeDepth); // + 1000 * dc.yx;
|
|
fCausticPattern.zw += g_fCausticDistortion * vCausticNormalX2.xz * (1.0f + fEyeDepth); // - 1000 * dc.xy;
|
|
fCausticPattern *= g_fCausticPatternScaling;
|
|
fCausticPattern = 2.0f * (fCausticPattern - round(fCausticPattern));
|
|
float fCaustics = dot(fCausticPattern, fCausticPattern) * g_fCausticBrightness;
|
|
|
|
// Sharpen
|
|
fCaustics *= fCaustics;
|
|
fCaustics *= fCaustics;
|
|
|
|
// Cut at surface
|
|
fCaustics *= saturate(fUnderWater);
|
|
|
|
// Remove underside lighting
|
|
fCaustics *= saturate( dot(vEyeNormal, -lightDir) ) * tex2D(shadowSampler, TexCoord).x;
|
|
|
|
float3 vSurfacePoint = vEyePoint - vSubmerged;
|
|
vSurfacePoint.y = 0.0f;
|
|
float fFadeOut = saturate( max(dot(vSurfacePoint, vSurfacePoint) - 2000000.0f, 0.0f) / 10000000.0f )
|
|
* saturate(fUnderWater);
|
|
|
|
// Filter light
|
|
return lerp(float4(fLightColor.xyz, fLightColor.w * fCaustics), float2(1, 0).xxxy, fFadeOut);
|
|
}
|
|
|
|
// Tweakables
|
|
static float4 g_fFogColor = float4(0.1f, 0.18f, 0.17f, 0.0f); // float4(0.6f, 0.7f, 0.9f, 0.25f);
|
|
static float g_fFogDensity = 0.7f;
|
|
static float g_fSceneFog = 0.6f;
|
|
static float g_fRayScaling = 0.024f;
|
|
static float2 g_vRaySpeed = float2(0.03f, 0.02f);
|
|
|
|
float4 ps_underwater(float2 TexCoord : TEXCOORD0, float3 EyeDir : TEXCOORD1,
|
|
float2 LightPos : TEXCOORD2) : COLOR0
|
|
{
|
|
// Compute eye space position
|
|
float fEyeDepth = tex2D(depthSampler, TexCoord).x;
|
|
float3 vEyePoint = viewPos + fEyeDepth * EyeDir;
|
|
|
|
// Compute distance to water level
|
|
float fUnderWater = g_fWaterLevel - vEyePoint.y;
|
|
|
|
// Intersect water plane
|
|
float3 vSubmerged = vEyePoint - viewPos;
|
|
float fSubmergedBelow = (fUnderWater >= 0.0f)
|
|
? abs(vSubmerged.y)
|
|
: (g_fWaterLevel - viewPos.y);
|
|
float fSubmerged = (viewPos.y > g_fWaterLevel)
|
|
? max(fUnderWater, 0.0f)
|
|
: fSubmergedBelow;
|
|
vSubmerged *= fSubmerged / max( abs(vSubmerged.y), 0.0001f );
|
|
|
|
// Compute submerged length & normalize
|
|
fSubmerged = length(vSubmerged);
|
|
float3 vSubmergedDir = vSubmerged / max(fSubmerged, 0.0001f);
|
|
|
|
// Pre-compute light travel quantities
|
|
float fEyeLightTravel = max( (g_fWaterLevel - viewPos.y) / max(-lightDir.y, 0.0001f), 0.0f );
|
|
float fDeltaLightTravel = vSubmergedDir.y / min(lightDir.y, -0.0001f);
|
|
float fSubmergedLightTravel = fEyeLightTravel + fDeltaLightTravel * fSubmerged;
|
|
|
|
float4 fLogLightFilterColor = log(g_fLightFilterColor);
|
|
float4 fFog = g_fFogColor / (fLogLightFilterColor * g_fLightFilterDensity * fDeltaLightTravel - g_fFogDensity);
|
|
fFog *= exp(fLogLightFilterColor * (g_fFilterOffset + g_fLightFilterDensity * fSubmergedLightTravel) - g_fFogDensity * fSubmerged)
|
|
- exp(fLogLightFilterColor * (g_fFilterOffset + g_fLightFilterDensity) * fEyeLightTravel);
|
|
|
|
// "Absorb" more scene light
|
|
fFog.w = g_fSceneFog * (1.0f - exp(-g_fFogDensity * fSubmerged));
|
|
// fFog.w = dot(fFog.xyz, 0.1f);
|
|
// fFog.w = 1.0f - fFog.w;
|
|
// fFog.w = 0;
|
|
|
|
// Compute light coordinate space
|
|
float3 vLightU = normalize( cross( lightDir, float3(1.0f, 0.0f, 0.0f) ) );
|
|
float3 vLightV = normalize( cross( vLightU, lightDir ) );
|
|
|
|
// Parallel ray direction vector
|
|
float3 vRayDir = EyeDir - lightDir * dot(lightDir, EyeDir);
|
|
vRayDir = normalize(vRayDir);
|
|
float3 vFullRayDir = EyeDir / dot(EyeDir, vRayDir);
|
|
|
|
// 1 / submerged flat
|
|
float3 vSubmergedFlatInvScale = vSubmerged - lightDir * dot(lightDir, vSubmerged);
|
|
vSubmergedFlatInvScale /= max( dot(vSubmergedFlatInvScale, vSubmergedFlatInvScale), 0.0001f );
|
|
|
|
// 4 ray Planes
|
|
float4 fPlanes = float4(5.0f, 10.0f, 20.0f, 40.0f);
|
|
float4 fPlaneIntersect = fPlanes * dot(vRayDir, vSubmergedFlatInvScale);
|
|
float4 fPlaneSubmerged = vSubmerged.y * fPlaneIntersect;
|
|
// float fWeightScaling = saturate( 1.0f - 0.1f * dot(viewDir, -lightDir) ); // polar
|
|
float4 fPlaneWeight = 1.0f - saturate( 0.5f * (fPlaneIntersect - 1.0f) );
|
|
|
|
// Compute light travel
|
|
float4 fPlanesY = g_fWaterLevel - (viewPos.y + vFullRayDir.y * fPlanes);
|
|
float4 fPlanesLightTravel = max( fPlanesY / max(-lightDir.y, 0.0001f), 0.0f );
|
|
float4 fPlanesLightInt = 1.0f / (1.0f + 0.01f * fPlanesLightTravel * fPlanesLightTravel);
|
|
|
|
// return float4(fPlanesLightInt.yyy, 1.0f);
|
|
|
|
// Snap view pos
|
|
// float3 vSnappedViewPos = vLightU * floor( dot(vLightU, viewPos) / 25.0f ) * 25.0f
|
|
// + vLightV * floor( dot(vLightV, viewPos) / 25.0f ) * 25.0f;
|
|
// fPlanes += dot(viewPos - vSnappedViewPos, vRayDir);
|
|
|
|
// Scale time
|
|
float fTime = g_fTime.z * 0.000075f;
|
|
|
|
// Animate rays
|
|
float4 fRayCoordsX = dot(vLightU, viewPos) + dot(vLightU, vRayDir) * fPlanes;
|
|
float4 fRayCoordsY = dot(vLightV, viewPos) + dot(vLightV, vRayDir) * fPlanes;
|
|
// fPlanes = dot(vLightU, vRayDir) * tx - dot(vLightV, vRayDir) * ty - 2.0f * dot(viewPos, vRayDir);
|
|
fRayCoordsX *= g_fRayScaling; fRayCoordsY *= g_fRayScaling;
|
|
float2 fRayCoordDelta = fTime * g_vRaySpeed * g_fRayScaling;
|
|
|
|
// Sample rays
|
|
float4 fRay1 = tex2D(waveSampler, float2(fRayCoordsX.x, fRayCoordsY.x) + fPlanes.x * fRayCoordDelta).xzyw;
|
|
float4 fRay2 = tex2D(waveSampler, float2(fRayCoordsX.y, fRayCoordsY.y) - fPlanes.y * fRayCoordDelta).xzyw;
|
|
float4 fRay3 = tex2D(waveSampler, float2(fRayCoordsX.z, fRayCoordsY.z) + fPlanes.z * fRayCoordDelta).xzyw;
|
|
float4 fRay4 = tex2D(waveSampler, float2(fRayCoordsX.w, fRayCoordsY.w) - fPlanes.w * fRayCoordDelta).xzyw;
|
|
|
|
// Decode Normal
|
|
float3 vRayNormal = (fRay1.xyz + fRay2.xyz + fRay3.xyz + fRay4.xyz) / 4.0f;
|
|
vRayNormal.xz = vRayNormal.xz * 2.0f - 1.0f;
|
|
vRayNormal = normalize(vRayNormal);
|
|
|
|
float4 fLight;
|
|
|
|
// Light
|
|
fLight.x = fRay1.w;
|
|
fLight.y = fRay2.w;
|
|
fLight.z = fRay3.w;
|
|
fLight.w = fRay4.w;
|
|
|
|
// fLight *= fLight * fLight;
|
|
|
|
float fLightSubmerged = 0.05f * max( fPlaneIntersect * dot(vSubmerged, lightDir), 0.0f);
|
|
|
|
// Fade rays
|
|
fLight *= fPlanesLightInt * fPlaneWeight * saturate(fSubmerged) / (1.0f + fLightSubmerged * fLightSubmerged);
|
|
fLight *= saturate(g_fWaterLevel - viewPos.y + 1.0f);
|
|
|
|
float fRayAngle = saturate( 1.0f - dot(vRayNormal, -lightDir) );
|
|
float fRayColor = 0.1f * saturate( dot(EyeDir, vRayNormal - lightDir) );
|
|
fRayAngle = frac( fRayAngle );
|
|
|
|
float3 fLightColor = 1.0f;
|
|
fLightColor.r += saturate( 1.0f - pow(3.0f * fRayAngle - 3.0f * (fRayAngle > 1.0f / 3.0f), 2) ) * fRayColor;
|
|
fLightColor.g += saturate( 1.0f - pow(3.0f * fRayAngle - 1.0f, 2) ) * fRayColor;
|
|
fLightColor.b += saturate( 1.0f - pow(3.0f * fRayAngle - 2.0f, 2) ) * fRayColor;
|
|
|
|
// God rays
|
|
fFog.xyz += dot(fLight, 0.04f) * fLightColor;
|
|
|
|
float3 vSurfacePoint = vEyePoint - vSubmerged;
|
|
vSurfacePoint.y = 0.0f;
|
|
float fFadeOut = 1.0f - saturate( max(dot(vSurfacePoint, vSurfacePoint) - 2000000.0f, 0.0f) / 10000000.0f )
|
|
* saturate(fUnderWater);
|
|
|
|
return fFog * fFadeOut;
|
|
}
|