Divergent/mods/Screen Space Shaders/gamedata/shaders/r3/screenspace_water.h

116 lines
3.2 KiB
C

/**
* @ Version: SCREEN SPACE SHADERS - UPDATE 12.6
* @ Description: Water implementation
* @ Modified time: 2022-11-26 02:05
* @ 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"
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, uint iSample : SV_SAMPLEINDEX)
{
// Some vars to use later...
float4 prev_step;
int prev_sign;
float3 behind_hit = 0;
float RayThick = clamp( 48.0f / q_steps[G_SSR_WATER_QUALITY].x, 1.0f, 3.0f);
// Initialize Ray
RayTrace ssr_ray = SSFX_ray_init(ray_start_vs, ray_dir_vs, 150, q_steps[G_SSR_WATER_QUALITY].x, noise);
// Save the original step.x
float ori_x = ssr_ray.r_step.x;
// Depth from the start of the ray
float ray_depthstart = SSFX_get_depth(ssr_ray.r_start, iSample);
// Ray-march
[unroll (q_steps[G_SSR_WATER_QUALITY].x)]
for (int st = 1; st <= q_steps[G_SSR_WATER_QUALITY].x; st++)
{
// Ray out of screen...
if (ssr_ray.r_pos.y < 0.0f || ssr_ray.r_pos.y > 1.0f)
return 0;
// Horizontal stretch to avoid borders
float2 hor = ssr_ray.r_pos.x > 0.5f ? float2(1.0f, -0.1) : float2(-0.1, 1.0f);
ssr_ray.r_step.x = ori_x * lerp(hor.x, hor.y, saturate(ssr_ray.r_pos.x * 2.0f));
// Ray intersect check ( x = difference | y = depth sample )
float2 ray_check = SSFX_ray_intersect(ssr_ray, iSample);
// 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[G_SSR_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[G_SSR_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;
}