124 lines
3.4 KiB
C
124 lines
3.4 KiB
C
/**
|
|
* @ Version: SCREEN SPACE SHADERS - UPDATE 22
|
|
* @ Description: Water implementation
|
|
* @ Modified time: 2024-11-16 07:21
|
|
* @ Author: https://www.moddb.com/members/ascii1457
|
|
* @ Mod: https://www.moddb.com/mods/stalker-anomaly/addons/screen-space-shaders
|
|
*/
|
|
|
|
#include "screenspace_common.h"
|
|
#include "settings_screenspace_WATER.h"
|
|
|
|
uniform float3 eye_direction;
|
|
|
|
static const int2 q_steps[5] =
|
|
{
|
|
int2(8,3),
|
|
int2(16,2),
|
|
int2(24,2),
|
|
int2(32,2),
|
|
int2(64,1)
|
|
};
|
|
|
|
float3 SSFX_ssr_water_ray(float3 ray_start_vs, float3 ray_dir_vs, float noise, out float HitDepth, float2 tc, uint iSample : SV_SAMPLEINDEX)
|
|
{
|
|
// Some vars to use later...
|
|
float4 prev_step;
|
|
int prev_sign;
|
|
float3 behind_hit = 0;
|
|
|
|
HitDepth = 0;
|
|
|
|
float RayThick = clamp( 48.0f / q_steps[SSFX_WATER_QUALITY].x, 1.0f, 3.0f);
|
|
|
|
// Initialize Ray
|
|
RayTrace ssr_ray = SSFX_ray_init(ray_start_vs, ray_dir_vs, 150, q_steps[SSFX_WATER_QUALITY].x, noise);
|
|
|
|
// Horizontal stretch to avoid borders
|
|
float2 stretch_uv = 1.0f - smoothstep(0.9f, 1.0f, float2(tc.x, 1.0 - tc.x));
|
|
|
|
// Apply stretch
|
|
ssr_ray.r_step.x *= saturate(stretch_uv.x * stretch_uv.y + saturate(eye_direction.y * 3.0f));
|
|
|
|
// Adjust the starting Point
|
|
ssr_ray.r_pos = ssr_ray.r_start + ssr_ray.r_step * noise;
|
|
|
|
// Depth from the start of the ray
|
|
float ray_depthstart = SSFX_get_depth(ssr_ray.r_start, iSample);
|
|
|
|
// Ray-march
|
|
[unroll (q_steps[SSFX_WATER_QUALITY].x)]
|
|
for (int st = 1; st <= q_steps[SSFX_WATER_QUALITY].x; st++)
|
|
{
|
|
// Ray out of screen...
|
|
if (!SSFX_is_valid_uv(ssr_ray.r_pos.xy))
|
|
return 0;
|
|
|
|
// Ray intersect check ( x = difference | y = depth sample )
|
|
float3 ray_check = SSFX_ray_intersect(ssr_ray, iSample);
|
|
|
|
HitDepth = ray_check.y;
|
|
|
|
// Sampled depth is not weapon or sky ( SKY_EPS float(0.001) )
|
|
bool NoWpnSky = ray_check.y > 1.3f;
|
|
|
|
// Don't want interaction with weapons or sky
|
|
ray_check.x *= NoWpnSky;
|
|
|
|
// Depth difference positive...
|
|
if (ray_check.x > 0)
|
|
{
|
|
// Conditions to use as reflection...
|
|
if (ray_check.x <= RayThick || (ray_depthstart + 40.0f < ray_check.y))
|
|
return float3(ssr_ray.r_pos, ray_check.y);
|
|
|
|
// Current ray pos & step to use later...
|
|
prev_step.xy = ssr_ray.r_pos;
|
|
prev_step.zw = ssr_ray.r_step;
|
|
|
|
prev_sign = -1;
|
|
|
|
// Binary Search
|
|
for (int x = 0; x < q_steps[SSFX_WATER_QUALITY].y; x++)
|
|
{
|
|
// Half and flip depending on depth difference sign
|
|
if (sign(ray_check.x) != prev_sign)
|
|
{
|
|
ssr_ray.r_step *= -0.5f;
|
|
prev_sign = sign(ray_check.x);
|
|
}
|
|
|
|
// Step ray
|
|
ssr_ray.r_pos += ssr_ray.r_step;
|
|
|
|
// Ray intersect check
|
|
ray_check = SSFX_ray_intersect(ssr_ray, iSample);
|
|
|
|
// Depth test... Conditions to use as reflections...
|
|
if (abs(ray_check.x) <= RayThick)
|
|
return float3(ssr_ray.r_pos, ray_check.y);
|
|
}
|
|
|
|
// Restore previous ray position & step
|
|
ssr_ray.r_pos = prev_step.xy;
|
|
ssr_ray.r_step = prev_step.zw;
|
|
}
|
|
else
|
|
{
|
|
// Sample behind... Let's use this coor to fill...
|
|
behind_hit = float3(ssr_ray.r_pos, ray_check.y);
|
|
|
|
// Reset or keep depending on... ( > 1.3f = no interaction with weapons and sky )
|
|
behind_hit *= (ray_depthstart - 2.0f < ray_check.y) && NoWpnSky;
|
|
}
|
|
|
|
// Pass through condition
|
|
bool PTh = (!NoWpnSky && ray_check.y > 0.01f && st > q_steps[SSFX_WATER_QUALITY].x * 0.4f);
|
|
|
|
// Step ray... Try to pass through closer objects ( Like weapons and sights )
|
|
ssr_ray.r_pos += ssr_ray.r_step * (1.0f + 2.5f * PTh);
|
|
}
|
|
|
|
return behind_hit;
|
|
}
|