318 lines
8.4 KiB
C
318 lines
8.4 KiB
C
/**
|
|
* @ Version: SCREEN SPACE SHADERS - UPDATE 14
|
|
* @ Description: Main file
|
|
* @ Modified time: 2023-01-18 21:11
|
|
* @ Author: https://www.moddb.com/members/ascii1457
|
|
* @ Mod: https://www.moddb.com/mods/stalker-anomaly/addons/screen-space-shaders
|
|
*/
|
|
|
|
#define SSFX_READY
|
|
|
|
#include "common.h"
|
|
#include "lmodel.h"
|
|
#include "hmodel.h"
|
|
|
|
#include "screenspace_common_noise.h"
|
|
#include "screenspace_common_ripples.h"
|
|
|
|
#include "check_screenspace.h"
|
|
|
|
static const float3 ssfx_hemisphere[32] =
|
|
{
|
|
float3(-0.134, 0.044, -0.825), float3(0.045, -0.431, -0.529), float3(-0.537, 0.195, -0.371),
|
|
float3(0.525, -0.397, 0.713), float3(0.895, 0.302, 0.139), float3(-0.613, -0.408, -0.141),
|
|
float3(0.307, 0.822, 0.169), float3(-0.819, 0.037, -0.388), float3(0.376, 0.009, 0.193),
|
|
float3(-0.006, -0.103, -0.035), float3(0.098, 0.393, 0.019), float3(0.542, -0.218, -0.593),
|
|
float3(0.526, -0.183, 0.424), float3(-0.529, -0.178, 0.684), float3(0.066, -0.657, -0.570),
|
|
float3(-0.214, 0.288, 0.188), float3(-0.689, -0.222, -0.192), float3(-0.008, -0.212, -0.721),
|
|
float3(0.053, -0.863, 0.054), float3(0.639, -0.558, 0.289), float3(-0.255, 0.958, 0.099),
|
|
float3(-0.488, 0.473, -0.381), float3(-0.592, -0.332, 0.137), float3(0.080, 0.756, -0.494),
|
|
float3(-0.638, 0.319, 0.686), float3(-0.663, 0.230, -0.634), float3(0.235, -0.547, 0.664),
|
|
float3(0.164, -0.710, 0.086), float3(-0.009, 0.493, -0.038), float3(-0.322, 0.147, -0.105),
|
|
float3(-0.554, -0.725, 0.289), float3(0.534, 0.157, -0.250),
|
|
};
|
|
|
|
#ifdef USE_MSAA
|
|
Texture2DMS<float4,MSAA_SAMPLES> s_rimage;
|
|
#else
|
|
Texture2D s_rimage;
|
|
#endif
|
|
|
|
uniform float4 sky_color;
|
|
|
|
TextureCube sky_s0;
|
|
TextureCube sky_s1;
|
|
|
|
static const float2 ssfx_pixel_size = 1.0f / screen_res.xy;
|
|
static const float ssfx_PI = 3.14159265f;
|
|
|
|
struct RayTrace
|
|
{
|
|
float2 r_pos;
|
|
float2 r_step;
|
|
float2 r_start;
|
|
float r_length;
|
|
float z_start;
|
|
float z_end;
|
|
};
|
|
|
|
bool SSFX_is_saturated(float2 value) { return (value.x == saturate(value.x) && value.y == saturate(value.y)); }
|
|
|
|
bool SSFX_is_valid_uv(float2 value) { return (value.x >= 0.0f && value.x <= 1.0f) && (value.y >= 0.0f && value.y <= 1.0f); }
|
|
|
|
float2 SSFX_view_to_uv(float3 Pos)
|
|
{
|
|
float4 tc = mul(m_P, float4(Pos, 1));
|
|
return (tc.xy / tc.w) * float2(0.5f, -0.5f) + 0.5f;
|
|
}
|
|
|
|
float SSFX_calc_SSR_fade(float2 tc, float start, float end)
|
|
{
|
|
// Vectical fade
|
|
float ray_fade = saturate(tc.y * 5.0f);
|
|
|
|
// Horizontal fade
|
|
float2 calc_edges = smoothstep(start, end, float2(tc.x, 1.0f - tc.x));
|
|
ray_fade *= calc_edges.x * calc_edges.y;
|
|
|
|
return ray_fade;
|
|
}
|
|
|
|
float3 SSFX_yaw_vector(float3 Vec, float Rot)
|
|
{
|
|
float s, c;
|
|
sincos(Rot, s, c);
|
|
|
|
// y-axis rotation matrix
|
|
float3x3 rot_mat =
|
|
{
|
|
c, 0, s,
|
|
0, 1, 0,
|
|
-s, 0, c
|
|
};
|
|
return mul(rot_mat, Vec);
|
|
}
|
|
|
|
float SSFX_get_depth(float2 tc, uint iSample : SV_SAMPLEINDEX)
|
|
{
|
|
#ifndef USE_MSAA
|
|
return s_position.Sample(smp_nofilter, tc).z;
|
|
#else
|
|
return s_position.Load(int3(tc * screen_res.xy, 0), iSample).z;
|
|
#endif
|
|
}
|
|
|
|
float4 SSFX_get_position(float2 tc, uint iSample : SV_SAMPLEINDEX)
|
|
{
|
|
#ifndef USE_MSAA
|
|
return s_position.Sample(smp_nofilter, tc);
|
|
#else
|
|
return s_position.Load(int3(tc * screen_res.xy, 0), iSample);
|
|
#endif
|
|
}
|
|
|
|
float3 SSFX_get_image(float2 tc, uint iSample : SV_SAMPLEINDEX)
|
|
{
|
|
#ifndef USE_MSAA
|
|
return s_rimage.Sample(smp_nofilter, tc).rgb;
|
|
#else
|
|
return s_rimage.Load(int3(tc * screen_res.xy, 0), 0).rgb;
|
|
#endif
|
|
}
|
|
|
|
RayTrace SSFX_ray_init(float3 ray_start_vs, float3 ray_dir_vs, float ray_max_dist, int ray_steps, float noise)
|
|
{
|
|
RayTrace rt;
|
|
|
|
float3 ray_end_vs = ray_start_vs + ray_dir_vs * ray_max_dist;
|
|
|
|
// Ray depth ( from start and end point )
|
|
rt.z_start = ray_start_vs.z;
|
|
rt.z_end = ray_end_vs.z;
|
|
|
|
// Compute ray start and end (in UV space)
|
|
rt.r_start = SSFX_view_to_uv(ray_start_vs);
|
|
float2 ray_end = SSFX_view_to_uv(ray_end_vs);
|
|
|
|
// Compute ray step
|
|
float2 ray_diff = ray_end - rt.r_start;
|
|
rt.r_step = ray_diff / (float)ray_steps;
|
|
rt.r_length = length(ray_diff);
|
|
|
|
rt.r_pos = rt.r_start + rt.r_step * noise;
|
|
|
|
return rt;
|
|
}
|
|
|
|
float3 SSFX_ray_intersect(RayTrace Ray, uint iSample)
|
|
{
|
|
float len = length(Ray.r_pos - Ray.r_start);
|
|
float alpha = len / Ray.r_length;
|
|
float depth_ray = (Ray.z_start * Ray.z_end) / lerp(Ray.z_end, Ray.z_start, alpha);
|
|
float depth_scene = SSFX_get_depth(Ray.r_pos, iSample);
|
|
|
|
return float3(depth_ray.x - depth_scene, depth_scene, len);
|
|
}
|
|
|
|
// Half-way scene lighting
|
|
float4 SSFX_get_fast_scenelighting(float2 tc, uint iSample : SV_SAMPLEINDEX)
|
|
{
|
|
#ifndef USE_MSAA
|
|
float4 rL = s_accumulator.Sample(smp_nofilter, tc);
|
|
float4 C = s_diffuse.Sample( smp_nofilter, tc );
|
|
#else
|
|
float4 rL = s_accumulator.Load(int3(tc * screen_res.xy, 0), iSample);
|
|
float4 C = s_diffuse.Load(int3( tc * screen_res.xy, 0 ), iSample);
|
|
#endif
|
|
|
|
#ifdef SSFX_ENHANCED_SHADERS // We have Enhanced Shaders installed
|
|
|
|
/*float3 hdiffuse = C.rgb + L_ambient.rgb;
|
|
|
|
rL.rgb += rL.a * SRGBToLinear(C.rgb);
|
|
|
|
return float4(LinearTosRGB((rL.rgb + hdiffuse) * saturate(rL.rrr * 100)), C.w);*/
|
|
|
|
float3 result = rL.rgb + rL.a * C.rgb;
|
|
result *= env_color.rgb;
|
|
|
|
return float4(result, C.w);
|
|
|
|
#else
|
|
|
|
float3 hdiffuse = C.rgb + L_ambient.rgb;
|
|
|
|
return float4((rL.rgb + hdiffuse) * saturate(rL.rrr * 100), C.w);
|
|
|
|
#endif
|
|
}
|
|
|
|
// Full scene lighting
|
|
float3 SSFX_get_scene(float2 tc, uint iSample : SV_SAMPLEINDEX)
|
|
{
|
|
#ifndef USE_MSAA
|
|
float4 rP = s_position.Sample( smp_nofilter, tc );
|
|
#else
|
|
float4 rP = s_position.Load(int3(tc * screen_res.xy, 0), iSample);
|
|
#endif
|
|
|
|
if (rP.z <= 0.05f)
|
|
return 0;
|
|
|
|
#ifndef USE_MSAA
|
|
float4 rD = s_diffuse.Sample( smp_nofilter, tc );
|
|
float4 rL = s_accumulator.Sample(smp_nofilter, tc);
|
|
#else
|
|
float4 rD = s_diffuse.Load(int3(tc * screen_res.xy, 0), iSample);
|
|
float4 rL = s_accumulator.Load(int3(tc * screen_res.xy, 0), iSample);
|
|
#endif
|
|
|
|
// Remove emissive materials for now...
|
|
if (length(rL) > 10.0f)
|
|
rL = 0;
|
|
|
|
float3 rN = gbuf_unpack_normal( rP.xy );
|
|
float rMtl = gbuf_unpack_mtl( rP.w );
|
|
float rHemi = gbuf_unpack_hemi( rP.w );
|
|
|
|
float3 nw = mul( m_inv_V, rN );
|
|
|
|
#ifdef SSFX_ENHANCED_SHADERS
|
|
|
|
rL.rgb += rL.a * SRGBToLinear(rD.rgb);
|
|
|
|
// hemisphere
|
|
float3 hdiffuse, hspecular;
|
|
hmodel(hdiffuse, hspecular, rMtl, rHemi, rD, rP, rN);
|
|
|
|
// Final color
|
|
float3 rcolor = rL.rgb + hdiffuse.rgb;
|
|
return LinearTosRGB(rcolor);
|
|
|
|
#else
|
|
|
|
// hemisphere
|
|
float3 hdiffuse, hspecular;
|
|
hmodel(hdiffuse, hspecular, rMtl, rHemi, rD.w, rP, rN);
|
|
|
|
// Final color
|
|
float4 light = float4(rL.rgb + hdiffuse, rL.w);
|
|
float4 C = rD * light;
|
|
float3 spec = C.www * rL.rgb;
|
|
|
|
return C.rgb + spec;
|
|
|
|
#endif
|
|
}
|
|
|
|
float3 SSFX_calc_sky(float3 dir)
|
|
{
|
|
dir = SSFX_yaw_vector(dir, -sky_color.w); // Sky rotation
|
|
|
|
dir.y = (dir.y - max(cos(dir.x) * 0.65f, cos(dir.z) * 0.65f)) * 2.1f; // Fix perspective
|
|
dir.y -= -0.35; // Altitude
|
|
|
|
float3 sky0 = sky_s0.SampleLevel(smp_base, dir, 0).xyz;
|
|
float3 sky1 = sky_s1.SampleLevel(smp_base, dir, 0).xyz;
|
|
|
|
// Use hemi color or real sky color if the modded executable is installed.
|
|
#ifndef SSFX_MODEXE
|
|
return saturate(L_hemi_color.rgb * 3.0f) * lerp(sky0, sky1, L_ambient.w);
|
|
#else
|
|
return saturate(sky_color.bgr * 3.0f) * lerp(sky0, sky1, L_ambient.w);
|
|
#endif
|
|
}
|
|
|
|
float3 SSFX_calc_env(float3 dir)
|
|
{
|
|
float3 env0 = env_s0.SampleLevel(smp_base, dir, 0).xyz;
|
|
float3 env1 = env_s1.SampleLevel(smp_base, dir, 0).xyz;
|
|
|
|
return env_color.xyz * lerp( env0, env1, env_color.w );
|
|
}
|
|
|
|
// https://www.scratchapixel.com/lessons/3d-basic-rendering/introduction-to-shading/reflection-refraction-fresnel
|
|
// 1.3f water ~ 1.5f glass ~ 1.8f diamond
|
|
float SSFX_calc_fresnel(float3 V, float3 N, float ior)
|
|
{
|
|
float cosi = clamp(-1, 1, dot(V, N));
|
|
float etai = 1, etat = ior;
|
|
if (cosi > 0)
|
|
{
|
|
etai = ior;
|
|
etat = 1;
|
|
}
|
|
// Compute sini using Snell's law
|
|
float sint = etai / etat * sqrt(max(0.f, 1 - cosi * cosi));
|
|
// Total internal reflection
|
|
if (sint >= 1)
|
|
return 1.0f;
|
|
|
|
float cost = sqrt(max(0.f, 1 - sint * sint));
|
|
cosi = abs(cosi);
|
|
float Rs = ((etat * cosi) - (etai * cost)) / ((etat * cosi) + (etai * cost));
|
|
float Rp = ((etai * cosi) - (etat * cost)) / ((etai * cosi) + (etat * cost));
|
|
|
|
return (Rs * Rs + Rp * Rp) / 2;
|
|
}
|
|
|
|
static const float2x2 pp_rotation_matrix = { -0.666276f, 0.745705f, -0.745705f, -0.666276f };
|
|
|
|
float4 SSFX_Blur(float2 uv, float radius)
|
|
{
|
|
float3 blur = 0;
|
|
radius *= SSFX_gradient_noise_IGN(uv / 2.0 * screen_res.xy) * 6.28f;
|
|
|
|
float2 offset = float2(radius, radius);
|
|
float r = 0.9f;
|
|
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
r += 1.0f / r;
|
|
offset = mul(offset, pp_rotation_matrix);
|
|
blur += s_image.SampleLevel(smp_rtlinear, uv + (offset * (r - 1.0f) * ssfx_pixel_size), 0).rgb;
|
|
}
|
|
float3 image = blur / 16;
|
|
|
|
return float4(image, 1.0f);
|
|
} |