Divergent/mods/Screen Space Shaders/gamedata/shaders/r3/ssfx_il.ps

183 lines
4.8 KiB
PostScript
Raw Normal View History

/**
* @ Version: SCREEN SPACE SHADERS - UPDATE 21
* @ Description: IL implementation
* @ Modified time: 2024-08-10 04:51
* @ Author: https://www.moddb.com/members/ascii1457
* @ Mod: https://www.moddb.com/mods/stalker-anomaly/addons/screen-space-shaders
*/
#ifndef SSFX_READY
#include "screenspace_common.h"
#endif
#include "settings_screenspace_IL.h"
// Internal values
uniform float4 ao_setup; // Res, Global Int, Vibrance, Blur
uniform float4 ssfx_il_setup2; // Distance, HUD, Flora, -
float4x4 m_current; // Current projection matrix
float4x4 m_previous; // Previous projection matrix
// Textures
Texture2D ssfx_ao;
Texture2D s_hud_mask;
Texture2D s_prev_pos;
Texture2D jitter0;
sampler smp_jitter;
float4 main(p_screen I) : SV_Target
{
// Scale TexCoor
float2 tc = I.tc0.xy * ao_setup.x;
float2 Pos2D = I.hpos.xy * ao_setup.x;
// Sample buffers
#ifndef USE_MSAA
float4 Pos = s_position.Sample( smp_nofilter, tc );
#else
float4 Pos = s_position.Load( int3( Pos2D, 0 ), 0 );
#endif
// Reconstruct Position, Normal and Material
float3 P = float3( Pos.z * ( Pos2D * pos_decompression_params.zw - pos_decompression_params.xy ), Pos.z );
float3 N = gbuf_unpack_normal( Pos.xy );
float mtl = gbuf_unpack_mtl( Pos.w );
// Rendering AO till G_SSDO_RENDER_DIST
if (P.z >= ssfx_il_setup2.x || P.z <= SKY_EPS)
return float4(0,0,0,1);
// Ao Noise
float3 ao_noise = jitter0.Sample(smp_jitter, (tc + timers.xx) * 100).xyz;
// MAT_FLORA from current pixel?
bool mat_flora = abs(mtl - MAT_FLORA) <= 0.04f;
// If MAT_FLORA we use a fake normal to align the hemisphere
N.xyz = mat_flora ? mul(m_V, float3(0.0f, 0.25f, 0.0f)) : N.xyz;
// A factor to adjust some values to only affect weapons ( closer objects )
float3 HudMask = s_hud_mask.Sample(smp_nofilter, tc).rgb;
// Var to accumulate the IL
float3 il = 0;
float4 gain = 1.0f;
float Seed = 0.04f;
// Sample radius
float radius = 3.0f;
[unroll (SSFX_IL_QUALITY)]
for (int i = 0; i < SSFX_IL_QUALITY; i++)
{
ao_noise.xyz = hash33(float3(tc.x + Seed, ao_noise.x + Seed, ao_noise.z - Seed));
ao_noise.xyz = ao_noise.xyz * 2 - 1;
Seed += 0.1031f;
// Use surface normal and add the hemisphere distribution
float3 sample_rays = reflect(ssfx_hemisphere[i], ao_noise * 1.5f) + N.xyz;
// Sample position
float3 occ_pos = P.xyz + sample_rays * radius;
// Sample position to UV
float2 occ_pos_uv = SSFX_view_to_uv(occ_pos);
// Process valid UV coor
if (SSFX_is_valid_uv(occ_pos_uv))
{
// Sample depth buffer
float4 sample_pos = SSFX_get_position(occ_pos_uv, 0);
// Difference
float3 diff = float3( sample_pos.z * ( Pos2D * pos_decompression_params.zw - pos_decompression_params.xy ), sample_pos.z ) - occ_pos;
// Distance
float Dist = length(diff);
// Intensity. Distance Falloff
float il_intensity = 1.0f - saturate(Dist * 0.066f);
// Use normal to adjust Intensity.
il_intensity *= max(0.0, dot(gbuf_unpack_normal( sample_pos.xy ), normalize(diff)) + 0.25f);
// Adjust intensity of Flora
bool IsFlora = (abs(sample_pos.w - MAT_FLORA) <= 0.04f) || mat_flora;
il_intensity *= 1.0f - saturate(IsFlora - ssfx_il_setup2.z);
// Sample light accumulator
#ifndef USE_MSAA
float3 L = saturate(s_accumulator.Sample( smp_nofilter, occ_pos_uv ) * 10);
#else
float3 L = saturate(s_accumulator.Load( int3( occ_pos_uv * screen_res.xy, 0 ), 0 ) * 10);
#endif
// Accumulate IL
il += L.rgb * gain.rgb * il_intensity * 300;
gain.rgb *= 1.0f / (1.0 + il.rgb);
}
}
// Normalize IL
il /= SSFX_IL_QUALITY;
// Fadeout using ssfx_il_setup2.x
float Fadeoff = smoothstep(ssfx_il_setup2.x * 0.7f, ssfx_il_setup2.x, P.z);
il *= 1.0f - Fadeoff;
// -------------
// Position
float4 P4 = float4(P.xyz, 1.0);
// Get current
float4 p_current = mul(m_current, P4);
float2 current = p_current.xy / p_current.w;
// Get previous
float4 p_previous = mul(m_previous, P4);
float2 previous = p_previous.xy / p_previous.w;
// Reprojection UV
float2 uv_rp = current.xy - previous.xy;
uv_rp = float2(uv_rp.x, -uv_rp.y) * 0.5f;
// Velocity
float vel = distance(current.xy, previous.xy);
// HUD Mask
if (HudMask.r <= 0)
{
// Use HUD motion vectors for reprojection
uv_rp = float2(HudMask.y, -HudMask.z) * 0.5f;
vel = 0;
}
// Sample previous frame + Reprojection UV
float4 prev = ssfx_ao.Sample(smp_linear, (tc - uv_rp) / ao_setup.x);
// Prev Position + Reprojection UV
float4 prev_P = s_prev_pos.Sample( smp_nofilter, (tc - uv_rp) );
// Offscreen?
int outoffsrc = any((tc - uv_rp) < 0) + any((tc - uv_rp) > 1);
// Disocclusion
float docc = abs(1.0f - P.z / prev_P.z);
// 0 Current frame ~ 1 Prev frame
float weight = saturate( 0.97f - vel - outoffsrc );
// Small IL decay
il = saturate(il - 0.01f);
// Mix previous frames
il = lerp(il, prev.rgb, saturate(weight - docc * 0.5f));
// -------------
return saturate(float4( il.rgb, 1.0f ));
}