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

252 lines
7.4 KiB
C

/**
* @ Version: SCREEN SPACE SHADERS - UPDATE 18
* @ Description: SSR implementation
* @ Modified time: 2024-02-09 06:27
* @ Author: https://www.moddb.com/members/ascii1457
* @ Mod: https://www.moddb.com/mods/stalker-anomaly/addons/screen-space-shaders
*/
#ifndef SSFX_SSR_QUALITY
#define SSFX_SSR_QUALITY 0
#endif
#include "screenspace_common.h"
#include "settings_screenspace_SSR.h"
uniform float4 ssr_setup; // x: SSR Resolution | y: Blur Intensity | z: Temporal Intensity
uniform float4 ssfx_ssr_2; // x: Intensity | y: Sky Intensity | z: Weapon Intensity | w: Max Weapon Intensity
uniform float4 ssfx_is_underground;
Texture2D blue_noise;
static const int2 q_ssr_steps[6] =
{
int2(8,72),
int2(16,36),
int2(24,18),
int2(32,5),
int2(48,1),
int2(64,1),
};
/*static const float q_ssr_noise[6] =
{
float(0.04f),
float(0.04f),
float(0.04f),
float(0.06f),
float(0.08f),
float(0.08f),
};*/
float4 SSFX_ssr_fast_ray(float3 ray_start_vs, float3 ray_dir_vs, float2 tc, uint iSample : SV_SAMPLEINDEX)
{
float2 sky_tc = 0;
float2 behind_hit = 0;
// Noise to "improve" consistency between steps
float2 uv_noise = tc + timers.x * (ssr_setup.w > 0);
uv_noise.x *= screen_res.x / screen_res.y;
float noise = blue_noise.Sample(smp_linear, uv_noise).x * ssr_setup.w * 0.1f;
// Initialize Ray
RayTrace ssr_ray = SSFX_ray_init(ray_start_vs, ray_dir_vs, 150, q_ssr_steps[SSFX_SSR_QUALITY].x, 1.0f);
// 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);
float2 ray_check = 0;
// Ray-march
[unroll (q_ssr_steps[SSFX_SSR_QUALITY].x)]
for (int i = 0; i < q_ssr_steps[SSFX_SSR_QUALITY].x; i++)
{
// Ray out of screen...
if (ssr_ray.r_pos.y < 0.0f || ssr_ray.r_pos.y > 1.0f)
return 0;
// Trick for the horizontal out of bounds. Mirror border of the screen.
if (ssr_ray.r_pos.x < 0.0f || ssr_ray.r_pos.x > 1.0f)
{
ssr_ray.r_pos -= ssr_ray.r_step; // Step back
ssr_ray.r_step.x = -ssr_ray.r_step.x; // Invert Horizontal
ssr_ray.r_pos += ssr_ray.r_step; // Step
}
// Ray intersect check
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;
// Disable weapon and sky
ray_check.x *= NoWpnSky;
// Return if ray is not reflecting backward
if (ray_check.x > 0)
{
if (ray_check.x <= q_ssr_steps[SSFX_SSR_QUALITY].y)
return float4(ssr_ray.r_pos, ray_check.y, 0);
#if SSFX_SSR_QUALITY > 2 // 1 Binary Search step in higher quality settigns ( Quality 4 & 5 )
// Current ray pos & step to restore later...
float4 prev_step = 0;
prev_step.xy = ssr_ray.r_pos;
prev_step.zw = ssr_ray.r_step;
// Half and flip
ssr_ray.r_step *= -0.5f;
// 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) <= 1.25f)
return float4(ssr_ray.r_pos, ray_check.y, 0);
// Restore previous ray position & step
ssr_ray.r_pos = prev_step.xy;
ssr_ray.r_step = prev_step.zw;
#endif
}
else
{
// TexCoor for sky ( Used to fade "SSFX_calc_SSR_fade" )
if (ray_check.y <= SKY_EPS)
sky_tc = ssr_ray.r_pos;
behind_hit = ssr_ray.r_pos;
// Reset or keep depending on... ( > 1.3f = no interaction with weapons and sky )
behind_hit *= (ray_depthstart - 2.0f < ray_check.y) && NoWpnSky;
}
// Step the ray
ssr_ray.r_pos += ssr_ray.r_step * (1.0f + noise.x * (1.0f - smoothstep(0, q_ssr_steps[SSFX_SSR_QUALITY].x * 0.33f, i)));
//ssr_ray.r_pos += ssr_ray.r_step * (1.0f + (1.0f - smoothstep(0, q_ssr_steps[SSFX_SSR_QUALITY].x * 0.33f, i)));
}
return float4(behind_hit, ray_check.y, sky_tc.y);
}
void SSFX_ScreenSpaceReflections(float2 tc, float4 P, float3 N, float gloss, inout float4 color, uint iSample : SV_SAMPLEINDEX)
{
// Note: Distance falloff on "rain_patch_normal.ps"
// Material conditions ( MAT_FLORA and Terrain for now... )
bool m_terrain = abs(P.w - 0.95f) <= 0.02f;
bool m_flora = abs(P.w - MAT_FLORA) <= 0.04f;
// Let's start with pure gloss.
float refl_power = gloss;
// Calc reflection bounce
float3 inVec = normalize(P.xyz); // Incident
float3 reVec = reflect(inVec , N); // Reflected
// Transform space and calc reflection vector ( Skybox & Fresnel )
float3 nw = mul(m_inv_V, N);
float3 v2point = mul(m_inv_V, inVec);
float3 v2reflect = reflect(v2point, nw);
// Fresnel
float fresnel = saturate (dot(v2reflect, v2point));
float fresnel_amount = pow(fresnel, 3);
refl_power *= fresnel_amount;
float4 hit_uv = 0;
// Calc SSR ray. Discard low reflective pixels
if (refl_power > 0.02f)
hit_uv = SSFX_ssr_fast_ray(P.xyz, reVec, tc, iSample);
float3 refl_ray;
float3 reflection = 0;
float2 uvcoor = 0;
// Sky is the reflection base...
#ifdef G_SSR_CHEAP_SKYBOX
reflection = SSFX_calc_env(v2reflect) * ssfx_ssr_2.y * !ssfx_is_underground.x;
#else
reflection = SSFX_calc_sky(v2reflect) * ssfx_ssr_2.y * !ssfx_is_underground.x;
#endif
// Valid UV coor? SSFX_trace_ssr_ray return 0.0f if uv is out of bounds or sky.
if (all(hit_uv.xy))
{
// Get scene reflection
refl_ray = SSFX_get_image(hit_uv.xy, iSample);//SSFX_get_scene(hit_uv.xy, iSample);
// Set reflection UV
uvcoor = hit_uv.xy;
// Reflection fog fadeout
float refl_fog = 1.0 - saturate(( length(float3(inVec.x,inVec.y,hit_uv.z)) * fog_params.w + fog_params.x));
// Let's fade the reflection based on ray XY coor to avoid abrupt changes and glitches
float HitFade = saturate(hit_uv.y * refl_fog * refl_fog * G_SSR_VERTICAL_SCREENFADE);
// Mix base reflection ( skybox ) with ray reflection
reflection = lerp(reflection, refl_ray, HitFade);
}
else
{
// Reset gloss.
refl_power = gloss * fresnel_amount;
// Set reflection UV
uvcoor = float2(0, hit_uv.w);//hit_uv.zw;
}
// Fade sky if !m_terrain ( Terrain MAT )
float ray_fade = saturate(saturate(uvcoor.y * G_SSR_VERTICAL_SCREENFADE) + 1.0f * m_terrain);
// Adjust the intensity of MAT_FLORA
refl_power *= m_flora ? G_SSR_FLORA_INTENSITY : 1.0f;
// Weapon Attenuation factor.
float WeaponFactor = smoothstep(G_SSR_WEAPON_MAX_LENGTH - 0.2f, G_SSR_WEAPON_MAX_LENGTH, length(P.xyz));
// Terrain MAT overwrite WeaponFactor.
WeaponFactor = saturate(WeaponFactor + 1.0f * m_terrain);
// Global intensity and limit max value.
float main_clamp = clamp(refl_power * ssfx_ssr_2.x, 0, G_SSR_MAX_INTENSITY);
// Raise reflection intensity and max limit when raining. ( NOTE: Reverted to rain intensity, but improvements are on the way... )
float rain_extra = G_SSR_WEAPON_RAIN_FACTOR * rain_params.x;
// Weapon intensity and limit max value.
float wpn_clamp = clamp((refl_power + rain_extra) * ssfx_ssr_2.z, 0, ssfx_ssr_2.w + rain_extra);
#ifdef G_SSR_WEAPON_REFLECT_ONLY_WITH_RAIN
wpn_clamp *= rain_params.x;
#endif
// Lerp between general reflections and weapon reflections.
refl_power = lerp(wpn_clamp, main_clamp, WeaponFactor);
// Apply SSR fade to reflection.
refl_power *= ray_fade;
// 'Beefs Shader Based NVGs' optional intensity adjustment
#ifdef G_SSR_BEEFS_NVGs_ADJUSTMENT
refl_power *= saturate(1.0f - (1.0f - G_SSR_BEEFS_NVGs_ADJUSTMENT) * (shader_param_8.x > 0.0f));
#endif
// Fog Fix ( Render order problem... )
float fog = 1.0 - saturate(( length(P.xyz) * fog_params.w + fog_params.x));
// Add the reflection to the scene.
color = float4(reflection, refl_power * fog * fog);//lerp(color, reflection, refl_power);
}