252 lines
7.4 KiB
C
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);
|
||
|
}
|