/** * @ 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 )); }