153 lines
4.5 KiB
PostScript
153 lines
4.5 KiB
PostScript
|
/**
|
||
|
* @ Version: SCREEN SPACE SHADERS - UPDATE 14.6
|
||
|
* @ Description: SSDO implementation
|
||
|
* @ Modified time: 2023-02-07 00:11
|
||
|
* @ 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_AO.h"
|
||
|
|
||
|
#ifndef SSAO_QUALITY
|
||
|
float calc_ssdo (float3 P, float3 N, float2 tc, float4 pos2d, uint iSample)
|
||
|
{
|
||
|
return 1.0;
|
||
|
}
|
||
|
|
||
|
#else // SSAO_QUALITY
|
||
|
|
||
|
// Internal values
|
||
|
#if SSAO_QUALITY == 3
|
||
|
#define G_SSDO_SAMPLE 32
|
||
|
#elif SSAO_QUALITY == 2
|
||
|
#define G_SSDO_SAMPLE 16
|
||
|
#elif SSAO_QUALITY == 1
|
||
|
#define G_SSDO_SAMPLE 8
|
||
|
#endif
|
||
|
|
||
|
float calc_ssdo (float4 P, float3 N, float2 tc, float4 pos2d, uint iSample)
|
||
|
{
|
||
|
// Rendering AO till G_SSDO_RENDER_DIST
|
||
|
if (P.z >= G_SSDO_RENDER_DIST || P.z <= SKY_EPS)
|
||
|
return 1;
|
||
|
|
||
|
// Ao Noise
|
||
|
float ao_noise = frac(sin(dot(tc, float2(12.0, 78.0))) * 43758.0) * clamp(P.z * 0.05f, G_SSDO_NOISE_MIN, G_SSDO_NOISE_MAX);
|
||
|
|
||
|
// MAT_FLORA from current pixel?
|
||
|
bool mat_flora = abs(P.w - MAT_FLORA) <= 0.04f;
|
||
|
|
||
|
// If MAT_FLORA we use a fake normal to align the hemisphere ( We can't trust much about flora normal )
|
||
|
N.xyz = mat_flora ? float3(0.0f, 0.25f, 0.0f) : N.xyz;
|
||
|
|
||
|
// A factor to adjust some values to only affect weapons ( closer objects )
|
||
|
float WeaponFactor = 1.0f - smoothstep(G_SSDO_WEAPON_LENGTH * 0.5f, G_SSDO_WEAPON_LENGTH, length(P.xyz));
|
||
|
|
||
|
// Var to accumulate the AO
|
||
|
float occ = 0;
|
||
|
|
||
|
// AO Radius
|
||
|
float radius = G_SSDO_RADIUS;
|
||
|
|
||
|
// Radius weapon adjustements
|
||
|
radius *= lerp(1.0f, G_SSDO_WEAPON_RADIUS * clamp(P.z * 2.0f, 0.2f, 1.0f), WeaponFactor);
|
||
|
|
||
|
#ifdef G_SSDO_DETAILED_RADIUS
|
||
|
float detail_radius = radius * lerp(G_SSDO_DETAILED_RADIUS, G_SSDO_DETAILED_WEAPON_RADIUS, WeaponFactor);
|
||
|
#endif
|
||
|
|
||
|
[unroll (G_SSDO_SAMPLE)]
|
||
|
for (int i = 0; i < G_SSDO_SAMPLE; i++)
|
||
|
{
|
||
|
// Use surface normal and add the hemisphere distribution
|
||
|
float3 sample_rays = (ssfx_hemisphere[i] + N.xyz) * (1.0f + ao_noise);
|
||
|
|
||
|
// 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, iSample);
|
||
|
|
||
|
// AO Distance attenuation. To discard incorrect AO and add some attenuation through distance.
|
||
|
float atte = lerp( 0.1f, 4.0f, smoothstep(G_SSDO_WEAPON_LENGTH * 0.5f, G_SSDO_WEAPON_LENGTH, sample_pos.z));
|
||
|
|
||
|
// Pixel occluded?
|
||
|
float AO = step(sample_pos.z, occ_pos.z);
|
||
|
|
||
|
// Detailed Search if there's no AO
|
||
|
#ifdef G_SSDO_DETAILED_SEARCH
|
||
|
if (AO < 1)
|
||
|
{
|
||
|
// Same has before but with smaller radius
|
||
|
occ_pos = P.xyz + sample_rays * detail_radius;
|
||
|
occ_pos_uv = SSFX_view_to_uv(occ_pos); // We don't check for a valid UV coor, is already done and this sample radius is smaller ( in theory )
|
||
|
sample_pos = SSFX_get_position(occ_pos_uv, iSample); // Get Sample
|
||
|
AO = step(sample_pos.z, occ_pos.z); // Check occlusion
|
||
|
atte *= saturate(detail_radius + WeaponFactor); // Adjust attenuation for the scenary AO
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
// Distance between pixel and "occluder"
|
||
|
float3 Dist = distance(float3(occ_pos_uv.x, occ_pos_uv.y, sample_pos.z), float3(tc.x, tc.y, P.z));
|
||
|
|
||
|
// Difference attenuation
|
||
|
AO *= 1.0 - smoothstep(0.0f, atte, Dist );
|
||
|
|
||
|
// MAT_FLORA from sample?
|
||
|
bool sample_mat_flora = abs(gbuf_unpack_mtl(sample_pos.w) - MAT_FLORA) <= 0.04f || mat_flora;
|
||
|
|
||
|
// Value for dot product for full intensity ( Adjust value for WeaponFactor, we want a extremely sensitive AO for weapons )
|
||
|
float N_a = saturate( WeaponFactor ) * 0.8f;
|
||
|
|
||
|
// Dot product using current normal and sampled normal to adjust intensity ( Change mode if MAT_FLORA )
|
||
|
if (!sample_mat_flora)
|
||
|
AO *= smoothstep(1.0f, N_a, dot(gbuf_unpack_normal( sample_pos.xy ), N ));
|
||
|
else
|
||
|
AO *= G_SSDO_FLORA_INTENSITY;
|
||
|
|
||
|
// Discard incorrect occlusion from the sky.
|
||
|
AO *= !is_sky(sample_pos.z);
|
||
|
|
||
|
// Accumulate final AO
|
||
|
occ += AO;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Try next step with less radius
|
||
|
radius *= 0.75f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Normalize AO
|
||
|
occ /= G_SSDO_SAMPLE;
|
||
|
|
||
|
// Invert AO
|
||
|
occ = 1.0f - occ;
|
||
|
|
||
|
// AO intensity
|
||
|
occ = pow(occ, G_SSDO_INTENSITY * (1.0f - (1.0f - G_SSDO_WEAPON_INTENSITY) * WeaponFactor));
|
||
|
|
||
|
// AO softer
|
||
|
occ = lerp(occ, sqrt(occ), G_SSDO_SMOOTH);
|
||
|
|
||
|
// Limit AO maximum occlusion
|
||
|
occ = clamp(occ, G_SSDO_MAX_OCCLUSION, 1.0f);
|
||
|
|
||
|
// Fadeout using G_SSDO_RENDER_DIST
|
||
|
occ += smoothstep(G_SSDO_RENDER_DIST * 0.8f, G_SSDO_RENDER_DIST, P.z);
|
||
|
|
||
|
// Return AO
|
||
|
return saturate(occ);
|
||
|
}
|
||
|
|
||
|
#endif // SSAO_QUALITY
|