Various Changes; Updated and Added Mods

This commit is contained in:
2024-03-27 00:55:00 -04:00
parent 8abddf23c7
commit 46265b6fcc
2193 changed files with 23397 additions and 56583 deletions
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="windows-1251"?>
<string_table>
<string id="ui_mcm_menu_fps_based_mblur">
<text>FPS Based MBlur</text>
</string>
<string id="ui_mcm_fps_based_mblur_title">
<text>FPS Based Motion Blur</text>
</string>
<string id="ui_mcm_fps_based_mblur_ENABLED">
<text>Enabled</text>
</string>
<string id="ui_mcm_fps_based_mblur_BASE_MBLUR">
<text>Motion Blur Amount</text>
</string>
<string id="ui_mcm_fps_based_mblur_BASE_MBLUR_desc">
<text>
The Motion Blur in the Settings are useless, so edit Motion Blur amount here.\nWarning! r2_mblur is multiplicated by 10 in the shader, so still edit Motion Blur amount here even if you disabled mod by option.
</text>
</string>
<string id="ui_mcm_fps_based_mblur_DEBUG">
<text>Debug</text>
</string>
<string id="ui_mcm_fps_based_mblur_DEBUG_desc">
<text>Enable some debug info that makes logs very big, so don't touch it unless you have to.</text>
</string>
</string_table>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="windows-1251"?>
<string_table>
<string id="ui_mcm_menu_fps_based_mblur">
<text>FPS Based MBlur</text>
</string>
<string id="ui_mcm_fps_based_mblur_title">
<text>FPS Based Motion Blur</text>
</string>
<string id="ui_mcm_fps_based_mblur_ENABLED">
<text>Âêëþ÷¸í</text>
</string>
<string id="ui_mcm_fps_based_mblur_BASE_MBLUR">
<text>Êîëè÷åñòâî ðàçìûòèÿ â äâèæåíèè</text>
</string>
<string id="ui_mcm_fps_based_mblur_BASE_MBLUR_desc">
<text>
Íàñòðàèâàòü ðàçìûòèå â äâèæåíèè â íàñòðîéêàõ íå èìååò ñìûëñëà, òàê êàê ìîä äèíàìè÷åñêè èçìåíÿåò r2_mblur, òàê ÷òî ðåãóëèðóé åãî çäåñü.\nÂíèìàíèå! Äàæå åñëè ìîä âûêëþ÷åí îïöèåé, ñòîèò ïðîäîëæàòü íàñòðàèâàòü çäåñü, ïîòîìó ÷òî r2_mblur óìíîæàåòñÿ íà 10 â ùåéäåðå (0.1 -> 1).
</text>
</string>
<string id="ui_mcm_fps_based_mblur_DEBUG">
<text>Ðåæèì îòëàäêè</text>
</string>
<string id="ui_mcm_fps_based_mblur_DEBUG_desc">
<text>Âêëþ÷àåò âûâîä èíôîðìàöèè äëÿ îòëàäêè â ëîãè, èç-çà ÷åãî îíè ñòàíîâÿòñÿ î÷åíü áîëüøèìè, à òàêæå ìîæåò ïîíèçèòñÿ ïðîèçâîäèòåëüíîñòü.  îáùåì íå òðîãàé ýòó îïöèþ åñëè íå íàäî.</text>
</string>
</string_table>
@@ -0,0 +1,40 @@
local BASE_MBLUR_MAX = 10
local CALLBACK_REGISTERED = true
local ENABLED
local BASE_MBLUR
local CACHE
local print_dbg = fps_based_mblur_mcm.print_dbg
local get_config = fps_based_mblur_mcm.get_config
function load_settings()
ENABLED = get_config("ENABLED")
BASE_MBLUR = get_config("BASE_MBLUR")
CACHE = 1 / 50 * BASE_MBLUR / BASE_MBLUR_MAX
if ENABLED and not CALLBACK_REGISTERED then
RegisterScriptCallback("actor_on_update", actor_on_update)
CALLBACK_REGISTERED = true
elseif not ENABLED and CALLBACK_REGISTERED then
UnregisterScriptCallback("actor_on_update", actor_on_update)
CALLBACK_REGISTERED = false
get_console():execute("r2_mblur " .. BASE_MBLUR / BASE_MBLUR_MAX)
end
end
function actor_on_update()
local delta = device().f_time_delta
print_dbg("delta: %s", delta)
print_dbg("not clamped amount: %s", CACHE / delta)
get_console():execute("r2_mblur " .. clamp(CACHE / delta, 0, 1))
end
function on_game_start()
RegisterScriptCallback("on_option_change", load_settings)
RegisterScriptCallback("actor_on_first_update", load_settings)
RegisterScriptCallback("actor_on_update", actor_on_update)
end
@@ -0,0 +1,49 @@
-- If you don't use MCM, change your defaults from here.
local defaults = {
["ENABLED"] = true,
["BASE_MBLUR"] = 1.0,
["DEBUG"] = false,
}
function get_config(key)
if ui_mcm then
return ui_mcm.get("fps_based_mblur/" .. key)
else
return defaults[key]
end
end
local dbg_log
function print_dbg(text, ...)
if get_config("DEBUG") or false then
dbg_log = dbg_log or mcm_log and mcm_log.new("DBG")
if dbg_log then
dbg_log.enabled = true
dbg_log:log(text, ...)
else
printf("fps based mblur: | %s | " .. text, time_global(), ...)
end
end
return nil
end
function on_mcm_load()
op = {
id = "fps_based_mblur",
sh = true,
gr = {
{
id = "title",
type = "slide",
link = "ui_options_slider_player",
text = "ui_mcm_fps_based_mblur_title",
size = { 512, 50 },
spacing = 20,
},
{ id = "ENABLED", type = "check", val = 1, def = true },
{ id = "BASE_MBLUR", type = "track", val = 2, def = 1.0, min = 0.0, max = 10.0, step = 0.025 },
{ id = "DEBUG", type = "check", val = 1, def = false },
},
}
return op
end
@@ -0,0 +1,86 @@
#include "common.h"
#include "lmodel.h"
#include "shadow.h"
// Check Screen Space Shaders modules & addons
#include "check_screenspace.h"
//////////////////////////////////////////////////////////////////////////////////////////
// This is the basic primitive used by convex, volumetric lights
// for example spot-lights, one face of the omni lights, etc.
//////////////////////////////////////////////////////////////////////////////////////////
// following options are available to configure compilation:
// USE_LMAP
// USE_LMAPXFORM
// USE_SHADOW
//////////////////////////////////////////////////////////////////////////////////////////
float4 m_lmap[2];
#ifdef MSAA_OPTIMIZATION
float4 main(p_volume I, float4 pos2d : SV_Position, uint iSample : SV_SAMPLEINDEX ) : SV_Target
#else
float4 main(p_volume I, float4 pos2d : SV_Position ) : SV_Target
#endif
{
float2 tcProj = I.tc.xy / I.tc.w;
gbuffer_data gbd = gbuffer_load_data(GLD_P(tcProj, pos2d, ISAMPLE) );
float4 _P = float4(gbd.P, gbd.mtl );
float4 _N = float4(gbd.N, gbd.hemi );
float4 _C = float4(gbd.C, gbd.gloss );
float m = xmaterial ;
#ifndef USE_R2_STATIC_SUN
m = _P.w;
#endif
// FLORA FIXES & IMPROVEMENTS - SSS Update 14.2
// Fix Flora ilumination ( Align normal to light )
#ifdef SSFX_FLORAFIX
if(abs(m - MAT_FLORA) <= 0.05)
{
_N.rgb = -normalize(_P - Ldynamic_pos.xyz);
_C.w *= 0.3f;
}
#endif
// ----- light-model
float rsqr;
float4 light = plight_local(m, _P, _N, _C, Ldynamic_pos, Ldynamic_pos.w, rsqr );
// ----- shadow
float3 Offset = 0;
#ifdef SSFX_SHADOWS
// Biasing ( Use the nDotL from plight_local... )
float bias_int = (1.0 - saturate(dot(_N, -normalize(_P - Ldynamic_pos.xyz)))) * rsqr * Ldynamic_pos.w;
Offset = _N * (0.025f + bias_int * ssfx_shadow_bias.x) * (1536.0/float(SMAP_size));
#endif
float4 P4 = float4(_P.xyz + Offset, 1);
float4 PS = mul(m_shadow, P4 );
float s = 1.h;
#ifdef USE_SHADOW
s = shadow( PS, pos2d.xy );
#endif
// ----- lightmap
float4 lightmap= 1.h;
#ifdef USE_LMAP
#ifdef USE_LMAPXFORM
PS.x = dot(P4, m_lmap[0] );
PS.y = dot(P4, m_lmap[1] );
#endif
// Can use linear with mip point
lightmap = s_lmap.SampleLevel(smp_rtlinear, PS.xy / PS.w, 0 );
#endif
#ifdef SSFX_ENHANCED_SHADERS
return float4(SRGBToLinear(Ldynamic_color.rgb * lightmap.rgb * s.xxx),1) * light;
#else
return float4( Ldynamic_color * light * s * lightmap);
#endif
}
@@ -0,0 +1,4 @@
#define USE_SHADOW
#define SLB_SHADOW_OMNI
#include "accum_base.ps"
@@ -0,0 +1,5 @@
#define USE_SHADOW
#define USE_LMAP
#define SLB_SHADOW_OMNI
#include "accum_base.ps"
@@ -0,0 +1,5 @@
#define USE_SHADOW
#define USE_LMAP
#define SLB_SHADOW_SPOT
#include "accum_base.ps"
@@ -0,0 +1,6 @@
#define USE_LMAP
#define USE_LMAPXFORM
#define USE_SHADOW
#define SLB_SHADOW_SPOT
#include "accum_base.ps"
@@ -0,0 +1,103 @@
#include "common.h"
#include "lmodel.h"
// Check Screen Space Shaders modules & addons
#include "check_screenspace.h"
#ifdef SSFX_SSS
#include "screenspace_shadows.h"
#endif
#ifdef USE_MINMAX_SM
#define SM_MINMAX
#endif
#if SUN_QUALITY>2
#define ULTRA_SHADOWS_ON
#endif // SUN_QUALITY>2
#ifdef ULTRA_SHADOWS_ON
#define USE_ULTRA_SHADOWS
#endif
#define SLB_SHADOW_SUN_FAR
#include "shadow.h"
uniform float3 view_shadow_proj; // Unused
#ifdef USE_SUNFILTER
#ifdef MSAA_OPTIMIZATION
float4 main ( v2p_volume I, uint iSample : SV_SAMPLEINDEX ) : SV_Target
#else
float4 main ( v2p_volume I ) : SV_Target
#endif
{
gbuffer_data gbd = gbuffer_load_data( GLD_P(I.tc, I.hpos, ISAMPLE) );
float4 _P = float4( gbd.P, 1.0);
float4 PS = mul( m_shadow, _P );
float s = shadowtest_sun( PS, I.tcJ ) * sunmask( _P );
return s;
}
#else
#ifdef MSAA_OPTIMIZATION
float4 main ( v2p_volume I, uint iSample : SV_SAMPLEINDEX ) : SV_Target
#else
float4 main ( v2p_volume I ) : SV_Target
#endif
{
gbuffer_data gbd = gbuffer_load_data( GLD_P(I.tc.xy/I.tc.w, I.hpos, ISAMPLE) );
float4 _P = float4( gbd.P, gbd.mtl );
float4 _N = float4( gbd.N, gbd.hemi );
float4 _C = float4( gbd.C, gbd.gloss );
// ----- light-model
float m = xmaterial;
#ifndef USE_R2_STATIC_SUN
m = _P.w;
#endif
float4 light = plight_infinity ( m, _P, _N, _C, Ldynamic_dir );
// ----- shadow
// SHADOWS FIXES - SSS Update 19
// Normal Offset for biasing
float3 NormalOffset = 0;
#ifdef SSFX_SHADOWS
// NormalOffset = _N * ssfx_shadow_bias.y;
#endif
float4 P4 = float4( _P.xyz + NormalOffset, 1.0);
float4 PS = mul( m_shadow, P4 );
// SHADOWS FIXES - SSS Update 14.7
// New far edge fading code
float s = shadow( PS, I.hpos.xy ); // Far Shadows
float shadows = sunmask( P4 ); // Clouds. Don't fade clouds.
// Fade UV
float2 FadeUV = PS.xy / PS.w;
// Fade calc
float4 fade = smoothstep(0.0f, 0.1f, float4(FadeUV.x, 1.0f - FadeUV.x, FadeUV.y, 1.0f - FadeUV.y));
float f = fade.x * fade.y * fade.z * fade.w;
s += ( 1.0f - s ) * ( 1.0f - f );
#ifdef SSFX_SSS
s *= SSFX_ScreenSpaceShadows_Far(_P, I.hpos, ISAMPLE);
#endif
// Add Shadows
shadows *= s;
#ifdef SSFX_ENHANCED_SHADERS
return blend( float4( SRGBToLinear( Ldynamic_color.rgb * shadows.xxx ), 1.0f ) * light, I.tc );
#else
return blend( Ldynamic_color * light * shadows, I.tc );
#endif
}
#endif
@@ -0,0 +1,88 @@
#include "common.h"
#include "lmodel.h"
#ifdef USE_MINMAX_SM
#define SM_MINMAX
#endif
#if SUN_QUALITY>2
#define ULTRA_SHADOWS_ON
#endif // SUN_QUALITY>2
#ifdef ULTRA_SHADOWS_ON
#define USE_ULTRA_SHADOWS
#endif
#define SLB_SHADOW_SUN_NEAR
#include "shadow.h"
// Check Screen Space Shaders modules & addons
#include "check_screenspace.h"
#ifdef SSFX_SSS
#include "screenspace_shadows.h"
#endif
#ifdef USE_SUNFILTER
#ifdef MSAA_OPTIMIZATION
float4 main ( v2p_volume I, uint iSample : SV_SAMPLEINDEX ) : SV_Target
#else
float4 main ( v2p_volume I ) : SV_Target
#endif
{
gbuffer_data gbd = gbuffer_load_data( GLD_P(I.tc, I.hpos, ISAMPLE) );
float4 _P = float4( gbd.P, 1.0);
float4 PS = mul( m_shadow, _P );
float s = shadowtest_sun( PS, I.tcJ ) * sunmask( _P );
return s;
}
#else
#ifdef MSAA_OPTIMIZATION
float4 main ( v2p_volume I, uint iSample : SV_SAMPLEINDEX ) : SV_Target
#else
float4 main ( v2p_volume I ) : SV_Target
#endif
{
gbuffer_data gbd = gbuffer_load_data( GLD_P(I.tc.xy/I.tc.w, I.hpos, ISAMPLE) );
float4 _P = float4( gbd.P, gbd.mtl );
float4 _N = float4( gbd.N, gbd.hemi );
float4 _C = float4( gbd.C, gbd.gloss );
// ----- light-model
float m = xmaterial;
#ifndef USE_R2_STATIC_SUN
m = _P.w;
#endif
float4 light = plight_infinity ( m, _P, _N, _C, Ldynamic_dir );
// ----- shadow
// SHADOWS FIXES - SSS Update 19
// Normal Offset for biasing
float3 NormalOffset = 0;
#ifdef SSFX_SHADOWS
// NormalOffset = _N * ssfx_shadow_bias.y;
#endif
float4 P4 = float4( _P.xyz + NormalOffset, 1.0);
float4 PS = mul( m_shadow, P4 );
float s = sunmask( P4 );
s *= shadow( PS, I.hpos.xy );
#ifdef SSFX_SSS
s *= SSFX_ScreenSpaceShadows(_P, I.hpos, ISAMPLE);
#endif
#ifdef SSFX_ENHANCED_SHADERS // We have Enhanced Shaders installed
return float4( SRGBToLinear(Ldynamic_color.rgb * s.xxx),1) * light;
#else
return float4( Ldynamic_color * light * s);
#endif
}
#endif
@@ -0,0 +1,39 @@
#ifndef MBLUR_H
#define MBLUR_H
#ifndef USE_MBLUR
float3 mblur (float2 UV, float3 pos, float3 c_original) { return c_original; }
#else
#include "common.h"
#include "slb_motion_blur.h"
////////////////////////////////////////
float4x4 m_current; //Current projection matrix
float4x4 m_previous; //Previous projection matrix
float2 m_blur;
////////////////////////////////////////
float3 mblur(float2 UV, float3 pos, float3 img)
{
//Fix sky ghosting caused by infinite depth value (KD)
pos.z = is_sky(pos.z) > 0.5 ? 10000.0 : pos.z;
//Sample position buffer
float4 pos4 = float4(pos, 1.0);
//Get current texture coordinates
float4 p_current = mul(m_current, pos4);
float2 current_tc = p_current.xy /= p_current.w;
//Get previous texture coordinates
float4 p_previous = mul(m_previous, pos4);
float2 previous_tc = p_previous.xy / p_previous.w;
//Get velocity (multiplied with motion blur intensity)
float2 p_velocity = (current_tc - previous_tc) * m_blur;
return SLB_MBlur(UV, pos, img, p_velocity, 0);
}
#endif
#endif
@@ -0,0 +1,30 @@
#include "common.h"
#include "lmodel.h"
#include "shadow.h"
Texture2D s_water;
float4 main ( float2 tc : TEXCOORD0, float2 tcJ : TEXCOORD1, float4 pos2d : SV_Position ) : SV_Target
{
gbuffer_data gbd = gbuffer_load_data( tc, pos2d );
float4 _P = float4( gbd.P, 1.0 );
float4 PS = mul( m_shadow, _P );
float s = shadow(PS, pos2d.xy);
float2 tc1 = mul( m_sunmask, _P ); //
tc1 /= 2;
tc1 = frac(tc1);
float4 water = s_water.SampleLevel( smp_linear, tc1, 0 );
water.xyz = (water.xzy-0.5)*2;
water.xyz = mul( m_V, water.xyz );
water *= s;
return float4(water.xyz,s);
}
@@ -0,0 +1,335 @@
#ifndef SHADOW_H
#define SHADOW_H
#include "common.h"
//uniform sampler s_smap : register(ps,s0); // 2D/cube shadowmap
//Texture2D<float> s_smap; // 2D/cube shadowmap
// Used for RGBA texture too ?!
Texture2D s_smap : register(ps,t0); // 2D/cube shadowmap
Texture2D<float> s_smap_minmax; // 2D/cube shadowmap
#include "gather.ps"
SamplerComparisonState smp_smap; // Special comare sampler
sampler smp_jitter;
uniform float4 ssfx_shadow_bias;
Texture2D jitter0;
Texture2D jitter1;
Texture2D jitterMipped;
#ifndef USE_ULTRA_SHADOWS
#define KERNEL 0.6f
#else
#define KERNEL 1.0f
#endif
#define PCSS_PIXEL int(4)
#define PCSS_STEP int(2)
#define PCSS_PIXEL_MIN float(1.0)
#define PCSS_SUN_WIDTH float(150.0)
float modify_light( float light )
{
return ( light > 0.7 ? 1.0 : lerp( 0.0, 1.0, saturate( light / 0.7 ) ) );
}
//////////////////////////////////////////////////////////////////////////////////////////
// hardware + PCF
//////////////////////////////////////////////////////////////////////////////////////////
float sample_hw_pcf (float4 tc,float4 shift)
{
static const float ts = KERNEL / float(SMAP_size);
tc.xyz /= tc.w;
tc.xy += shift.xy * ts;
return s_smap.SampleCmpLevelZero( smp_smap, tc.xy, tc.z).x;
}
float shadow_hw( float4 tc )
{
float s0 = sample_hw_pcf( tc, float4( -1, -1, 0, 0) );
float s1 = sample_hw_pcf( tc, float4( +1, -1, 0, 0) );
float s2 = sample_hw_pcf( tc, float4( -1, +1, 0, 0) );
float s3 = sample_hw_pcf( tc, float4( +1, +1, 0, 0) );
return (s0+s1+s2+s3)/4.h;
}
#ifdef SM_MINMAX
bool cheap_reject( float3 tc, inout bool full_light )
{
float4 plane0 = sm_minmax_gather( tc.xy, int2( -1,-1 ) );
float4 plane1 = sm_minmax_gather( tc.xy, int2( 1,-1 ) );
float4 plane2 = sm_minmax_gather( tc.xy, int2( -1, 1 ) );
float4 plane3 = sm_minmax_gather( tc.xy, int2( 1, 1 ) );
bool plane = all( ( plane0 >= (0).xxxx ) * ( plane1 >= (0).xxxx ) * ( plane2 >= (0).xxxx ) * ( plane3 >= (0).xxxx ) );
[flatten] if( !plane ) // if there are no proper plane equations in the support region
{
bool no_plane = all( ( plane0 < (0).xxxx ) * ( plane1 < (0).xxxx ) * ( plane2 < (0).xxxx ) * ( plane3 < (0).xxxx ) );
float4 z = ( tc.z - 0.0005 ).xxxx;
bool reject = all( ( z > -plane0 ) * ( z > -plane1 ) * ( z > -plane2 ) * ( z > -plane3 ) );
[flatten] if( no_plane && reject )
{
full_light = false;
return true;
}
else
{
return false;
}
}
else // plane equation detected
{
// compute corrected z for texel pos
static const float scale = float( SMAP_size / 4 );
float2 fc = frac( tc.xy * scale );
float z = lerp( lerp( plane0.y, plane1.x, fc.x ), lerp( plane2.z, plane3.w, fc.x ), fc.y );
// do minmax test with new z
full_light = ( ( tc.z - 0.0001 ) <= z );
return true;
}
}
//Sunshafts
float shadow_dx10_1_sunshafts( float4 tc, float2 pos2d )
{
float3 t = tc.xyz / tc.w;
float minmax = s_smap_minmax.SampleLevel( smp_nofilter, t, 0 ).x;
bool umbra = ( ( minmax.x < 0 ) && ( t.z > -minmax.x ) );
[branch] if( umbra )
{
return 0.0;
}
else
{
return shadow_hw( tc );
}
}
#endif // SM_MINMAX
//PCSS shadows
static const float2 poissonDisk[32] = {
float2(0.0617981, 0.07294159),
float2(0.6470215, 0.7474022),
float2(-0.5987766, -0.7512833),
float2(-0.693034, 0.6913887),
float2(0.6987045, -0.6843052),
float2(-0.9402866, 0.04474335),
float2(0.8934509, 0.07369385),
float2(0.1592735, -0.9686295),
float2(-0.05664673, 0.995282),
float2(-0.1203411, -0.1301079),
float2(0.1741608, -0.1682285),
float2(-0.09369049, 0.3196758),
float2(0.185363, 0.3213367),
float2(-0.1493771, -0.3147511),
float2(0.4452095, 0.2580113),
float2(-0.1080467, -0.5329178),
float2(0.1604507, 0.5460774),
float2(-0.4037193, -0.2611179),
float2(0.5947998, -0.2146744),
float2(0.3276062, 0.9244621),
float2(-0.6518704, -0.2503952),
float2(-0.3580975, 0.2806469),
float2(0.8587891, 0.4838005),
float2(-0.1596546, -0.8791054),
float2(-0.3096867, 0.5588146),
float2(-0.5128918, 0.1448544),
float2(0.8581337, -0.424046),
float2(0.1562584, -0.5610626),
float2(-0.7647934, 0.2709858),
float2(-0.3090832, 0.9020988),
float2(0.3935608, 0.4609676),
float2(0.3929337, -0.5010948),
};
//Quality tokens --Fine
#if !defined(SUN_QUALITY)
#define PCSS_NUM_SAMPLES int(1)
#elif SUN_QUALITY==1
#define PCSS_NUM_SAMPLES int(8)
#elif SUN_QUALITY==2
#define PCSS_NUM_SAMPLES int(12)
#elif SUN_QUALITY==3
#define PCSS_NUM_SAMPLES int(20)
#elif (SUN_QUALITY==4 || SUN_QUALITY==5)
#define PCSS_NUM_SAMPLES int(32)
#endif
float shadow_pcss( float4 tc )
{
// - Small modification to fix flickering and black squares.
// - Added a extra performance option with lower SUN_QUALITY settings.
// - Extended the blocker search from 3x3 to 4x4 for better results.
// https://www.moddb.com/mods/stalker-anomaly/addons/screen-space-shaders/
tc.xyz /= tc.w;
#if SUN_QUALITY > 3 // Blocker search ( Penumbra ) and filter
int3 uv = int3(tc.xy * float(SMAP_size), 0);
float zBlock = tc.z - 0.0001;
float avgBlockerDepth = 0.0;
float blockerCount = 0.0;
[unroll]
for( int row = -PCSS_PIXEL; row <= PCSS_PIXEL; row += PCSS_STEP )
{
[unroll]
for( int col = -PCSS_PIXEL; col <= PCSS_PIXEL; col += PCSS_STEP )
{
float shadowMapDepth = s_smap.Load( uv, int2( col, row ) ).x;
float b1 = ( shadowMapDepth < zBlock ) ? 1.0 : 0.0;
blockerCount += b1;
avgBlockerDepth += shadowMapDepth * b1;
}
}
if(blockerCount < 1)
return 1.0;
avgBlockerDepth /= blockerCount;
float fRatio = saturate( ( ( tc.z - avgBlockerDepth ) * PCSS_SUN_WIDTH ) / avgBlockerDepth );
fRatio *= fRatio;
fRatio = max(PCSS_PIXEL_MIN, fRatio * float(PCSS_PIXEL)) / float(SMAP_size);
float s = 0.0;
[unroll]
for( uint i = 0; i < PCSS_NUM_SAMPLES; ++i )
{
float2 offset = poissonDisk[i] * fRatio;
s += s_smap.SampleCmpLevelZero( smp_smap, tc.xy + offset, tc.z ).x;
}
return s / PCSS_NUM_SAMPLES;
#else // No blocker search ( Penumbra ), just filter
float fRatio = 4.0f / float(SMAP_size);
float s = 0.0;
[unroll]
for( uint i = 0; i < PCSS_NUM_SAMPLES; ++i )
{
float2 offset = poissonDisk[i] * fRatio;
float test = s_smap.SampleCmpLevelZero( smp_smap, tc.xy + offset, tc.z ).x;
s += test;
}
return s / PCSS_NUM_SAMPLES;
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////
// D24X8+PCF
//////////////////////////////////////////////////////////////////////////////////////////
float4 test (float4 tc, float2 offset)
{
tc.xyz /= tc.w;
tc.xy += offset;
return s_smap.SampleCmpLevelZero( smp_smap, tc.xy, tc.z).x;
}
half shadowtest_sun (float4 tc, float4 tcJ) // jittered sampling
{
half4 r;
const float scale = (0.7/float(SMAP_size));
float2 tc_J = frac(tc.xy/tc.w*SMAP_size/4.0 )*0.5;
float4 J0 = jitter0.Sample(smp_jitter,tc_J)*scale;
const float k = 0.5/float(SMAP_size);
r.x = test (tc, J0.xy+half2(-k,-k)).x;
r.y = test (tc, J0.wz+half2( k,-k)).y;
r.z = test (tc,-J0.xy+half2(-k, k)).z;
r.w = test (tc,-J0.wz+half2( k, k)).x;
return dot(r,1.0/4.0);
}
float shadow_hw_hq( float4 tc )
{
#ifdef SM_MINMAX
bool full_light = false;
bool cheap_path = cheap_reject( tc.xyz / tc.w, full_light );
[branch] if( cheap_path )
{
[branch] if( full_light == true )
return 1.0;
else
return sample_hw_pcf( tc, (0).xxxx );
}
else
{
return shadow_pcss(tc);
}
#else // SM_MINMAX
return shadow_pcss(tc);
#endif // SM_MINMAX
}
uniform float4x4 m_shadow;
#include "slb_shadow.h"
float shadow( float4 tc, float2 pos2d )
{
return SLB_Shadow(tc, pos2d);
#ifdef USE_ULTRA_SHADOWS
#ifdef SM_MINMAX
return modify_light( shadow_hw_hq( tc ) );
#else
return shadow_hw_hq( tc );
#endif
#else
return shadow_pcss(tc);
#endif
}
//////////////////////////////////////////////////////////////////////////////////////////
// testbed
float shadow_rain(float4 tc, float2 tcJ) // jittered sampling
{
float4 r;
const float scale = (4.0/float(SMAP_size));
float4 J0 = jitter0.Sample( smp_linear, tcJ )*scale;
float4 J1 = jitter1.Sample( smp_linear, tcJ )*scale;
r.x = test (tc,J0.xy).x;
r.y = test (tc,J0.wz).y;
r.z = test (tc,J1.xy).z;
r.w = test (tc,J1.wz).x;
return dot(r,1.0/4.0);
}
//////////////////////////////////////////////////////////////////////////////////////////
#ifdef USE_SUNMASK
float3x4 m_sunmask; // ortho-projection
float sunmask( float4 P )
{
float2 tc = mul( m_sunmask, P ); //
return s_lmap.SampleLevel( smp_linear, tc, 0 ).w; //Hemi map - ambient occlusion
}
#else
float sunmask( float4 P ) { return 1.0; } //
#endif
//////////////////////////////////////////////////////////////////////////////////////////
#endif
@@ -0,0 +1,49 @@
#ifndef SLB_ALIASES_H
#define SLB_ALIASES_H
#ifdef SLB_GLSL /// We are in glslViewer
#define SLB_SAMPLER_LOAD(sampler_name, texture_coord) texelFetch(sampler_name, texture_coord.xy, texture_coord.z)
#define SLB_BRANCH
#define SLB_UNROLL(x)
#define SLB_STATIC_CONST const
/// HLSL shit
#define frac(x) fract(x)
#define saturate(x) clamp(x, 0.0, 1.0)
#define mul(a, b) (a * b)
#define reversebits(x) bitfieldReverse(x)
#define asuint(x) floatBitsToUint(x)
#define lerp(a, b, x) mix(a, b, x)
#define ddx(x) dFdx(x)
#define ddy(x) dFdy(x)
#define float2 vec2
#define float3 vec3
#define float4 vec4
#define float2x2 mat2
#define float3x3 mat3
#define float4x4 mat4
#define int2 ivec2
#define int3 ivec3
#define int4 ivec4
#define uint2 uvec2
#define uint3 uvec3
#define uint4 uvec4
#else /// We are in stalker
#define SLB_SAMPLER_LOAD(sampler_name, texture_coord) sampler_name.Load(texture_coord)
#define SLB_SAMPLER_LOAD_MSAA(sampler_name, texture_coord, iSample) sampler_name.Load(texture_coord, iSample)
#define SLB_BRANCH [branch]
#define SLB_UNROLL(x) [unroll(x)]
#define SLB_STATIC_CONST static const
#endif
#endif /// SLB_ALIASES_H
@@ -0,0 +1,248 @@
#ifndef SLB_COMMON_H
#define SLB_COMMON_H
#include "slb_aliases.h"
#define SLB_PI 3.14159265358979323846
#define SLB_TAU 6.28318530717958647693
#define SLB_GoldenAngle 2.39996322972865332223
#define SLB_GoldenRatio 0.61803398874989484820
/// Taken from https://gist.github.com/yiwenl/3f804e80d0930e34a0b33359259b556c
float2x2 SLB_Rotate2Matrix(float a) {
float s = sin(a);
float c = cos(a);
return float2x2(float2(c, s), float2(-s, c));
}
float2 SLB_Rotate2(float2 v, float a) {
float2x2 m = SLB_Rotate2Matrix(a);
return mul(v, m);
}
float SLB_ToFloat1(uint v) {
return float(v) * (1.0/float(0xffffffffu));
}
float2 SLB_ToFloat2(uint2 v) {
return float2(v) * (1.0/float(0xffffffffu));
}
float3 SLB_ToFloat3(uint3 v) {
return float3(v) * (1.0/float(0xffffffffu));
}
float4 SLB_ToFloat4(uint4 v) {
return float4(v) * (1.0/float(0xffffffffu));
}
float SLB_Min3(float3 v) {
return min(v.x, min(v.y, v.z));
}
float SLB_Max3(float3 v) {
return max(v.x, max(v.y, v.z));
}
/// Taken from https://web.archive.org/web/20200306054846/http://lolengine.net:80/blog/2013/07/27/rgb-to-hsv-in-glsl
float3 SLB_RGB_To_HSV(float3 c) {
float4 K = float4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
float4 p = c.g < c.b ? float4(c.bg, K.wz) : float4(c.gb, K.xy);
float4 q = c.r < p.x ? float4(p.xyw, c.r) : float4(c.r, p.yzx);
float d = q.x - min(q.w, q.y);
const float e = 1.0e-10;
return float3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}
/// It took me long time to found this somewhere in vanilla shaders codebase;
float2 SLB_Pos2DToCoord(float2 pos2d) {
// return float2((pos2d.x * screen_res.z * 2.0 - 1.0), (pos2d.y * screen_res.w * 2.0 - 1.0))/2.0 * screen_res.xy;
return (pos2d.xy * screen_res.zw - 0.5) * screen_res.xy;
}
/// Taken from https://iquilezles.org/articles/smoothsteps
float SLB_Cubic1D(float x) {
return x*x*(3.0 - 2.0*x);
}
/// Taken from https://iquilezles.org/articles/smoothsteps
float SLB_Quartic1D(float x) {
return x*x*(2.0 - x*x);
}
/// Taken from https://iquilezles.org/articles/smoothsteps
float SLB_Quintic1D(float x) {
return x*x*x*(x*(6.0*x - 15.0) + 10.0);
}
/// Taken from https://iquilezles.org/articles/smoothsteps
float SLB_CubicRational1D(float x) {
return x*x*x/(3.0*x*x - 3.0*x + 1.0);
}
/// Taken from https://iquilezles.org/articles/smoothsteps
float SLB_QuarticRational1D(float x) {
return x*x*x*x/(2.0*x*x*x*x - 4.0*x*x*x + 6.0*x*x - 4.0*x + 1.0);
}
/// Taken from somewhere
float SLB_Gaussian1D(float x, float sigma) {
return exp(-(x * x) / (2.0 * sigma * sigma));
}
/// Taken from http://www.java-gaming.org/index.php?topic=35123.0
/// Idk how to name it
float4 SLB_Cubic_For_Bicubic(float v) {
float4 n = float4(1.0, 2.0, 3.0, 4.0) - v;
float4 s = n * n * n;
float x = s.x;
float y = s.y - 4.0 * s.x;
float z = s.z - 4.0 * s.y + 6.0 * s.x;
float w = 6.0 - x - y - z;
return float4(x, y, z, w) * (1.0/6.0);
}
float2 SLB_VogelDisk_Sample(const int sample_index, const int samples_count) {
const float r = sqrt(float(sample_index) + 0.5) / sqrt(float(samples_count));
const float theta = float(sample_index) * SLB_GoldenAngle;
const float sine = sin(theta), cosine = cos(theta);
return float2(r * cosine, r * sine);
}
/// Taken from https://extremelearning.com.au/unreasonable-effectiveness-of-quasirandom-sequences
float SLB_R1(float n) {
const float g = 1.6180339887498948482;
const float a1 = 1.0 - 1.0/g;
float _n = floor(n);
return frac(0.5 + a1*_n);
}
/// Taken from https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes
uint SLB_Part1By1(uint x) {
x &= 0x0000ffffu;
x = (x ^ (x << 8u)) & 0x00ff00ffu;
x = (x ^ (x << 4u)) & 0x0f0f0f0fu;
x = (x ^ (x << 2u)) & 0x33333333u;
x = (x ^ (x << 1u)) & 0x55555555u;
return x;
}
/// Taken from https://fgiesen.wordpress.com/2009/12/13/decoding-morton-codes
uint SLB_EncodeMorton2(uint x, uint y) {
return (SLB_Part1By1(y) << 1u) + SLB_Part1By1(x);
}
/// From https://psychopath.io post
uint SLB_OwenHash4(uint n, uint seed) {
n ^= n * 0x3d20adeau;
n ^= (n >> 1u) & (n << 1u) & 0x55555555u;
n += seed;
n *= (seed >> 16u) | 1u;
n ^= (n >> 1u) & (n << 1u) & 0x55555555u;
n ^= n * 0x05526c56u;
n ^= n * 0x53a22864u;
return n;
}
/// Inspired by https://www.shadertoy.com/view/ssBBW1 shader and https://psychopath.io posts
uint SLB_Morton_OwenHash4_Bluenoise(uint2 coord) {
uint m;
m = SLB_EncodeMorton2(coord.x, coord.y);
m = SLB_OwenHash4(reversebits(m), 0xe7843fbfu); // owen-scramble morton index
m = SLB_OwenHash4(reversebits(m), 0x8d8fb1e0u); // map morton index to sobol sequence and owen-scramble
return reversebits(m); // convert to float
}
float SLB_Morton_OwenHash4_Bluenoise_float(uint2 coord) {
return SLB_ToFloat1(SLB_Morton_OwenHash4_Bluenoise(coord));
}
/// Taken from https://www.shadertoy.com/view/wltSDn
uint SLB_PhiNoise(uint2 uv) {
// flip every other tile to reduce anisotropy
if(((uv.x ^ uv.y) & 4u) == 0u) uv = uv.yx;
// constants of 2d Roberts sequence rounded to nearest primes
const uint r0 = 3242174893u;// prime[(2^32-1) / phi_2 ]
const uint r1 = 2447445397u;// prime[(2^32-1) / phi_2^2]
// h = high-freq dither noise
uint h = (uv.x * r0) + (uv.y * r1);
// l = low-freq white noise
uv = uv >> 2u;// 3u works equally well (I think)
uint l = ((uv.x * r0) ^ (uv.y * r1)) * r1;
// combine low and high
return l + h;
}
float SLB_PhiNoise_float(uint2 uv) {
return SLB_ToFloat1(SLB_PhiNoise(uv));
}
/// Taken from https://www.shadertoy.com/view/wltSDn
uint SLB_PhiNoise2(uint2 uv) {
uint2 uv0 = uv;
// flip every other tile to reduce anisotropy
if(((uv.x ^ uv.y) & 4u) == 0u) uv = uv.yx;
if(((uv.x ) & 4u) == 0u) uv.x = -uv.x;// more iso but also more low-freq content
// constants of 2d Roberts sequence rounded to nearest primes
const uint r0 = 3242174893u;// prime[(2^32-1) / phi_2 ]
const uint r1 = 2447445397u;// prime[(2^32-1) / phi_2^2]
// h = high-freq dither noise
uint h = (uv.x * r0) + (uv.y * r1);
uint l;
{
uv = uv0 >> 2u;
if(((uv.x ^ uv.y) & 4u) == 0u) uv = uv.yx;
if(((uv.x ) & 4u) == 0u) uv.x = -uv.x;
uint h = (uv.x * r0) + (uv.y * r1);
h = h ^ 0xE2E17FDCu;
l = h;
{
uv = uv0 >> 4u;
if(((uv.x ^ uv.y) & 4u) == 0u) uv = uv.yx;
if(((uv.x ) & 4u) == 0u) uv.x = -uv.x;
uint h = (uv.x * r0) + (uv.y * r1);
h = h ^ 0x1B98264Du;
l += h;
}
}
// combine low and high
return l + h;
}
float SLB_PhiNoise2_float(uint2 uv) {
return SLB_ToFloat1(SLB_PhiNoise2(uv));
}
/// Taken from paper named "Hash Functions for GPU Rendering"
uint4 SLB_PCG4D(uint4 v) {
v = v * 1664525u + 1013904223u;
v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;
v ^= v >> 16u;
v.x += v.y*v.w; v.y += v.z*v.x; v.z += v.x*v.y; v.w += v.y*v.z;
return v;
}
/// Taken from https://www.pcg-random.org
uint SLB_PCG(uint v) {
uint state = v * 747796405u + 2891336453u;
uint word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
}
#endif // SLB_COMMON_H
@@ -0,0 +1,173 @@
#ifndef SLB_MOTION_BLUR_H
#define SLB_MOTION_BLUR_H
#include "slb_common.h"
#include "slb_motion_blur_settings.h"
float3 SLB_Screen_GetImage(float2 tc, uint iSample) {
return SLB_SAMPLER_LOAD(s_image, int3(tc * screen_res.xy - 0.25, 0)).rgb;
}
float4 SLB_Screen_GetPosition(float2 tc, uint iSample) {
#ifdef SLB_GLSL /// return dummy
return float4(0.5, 0.5, float(abs(tc.x - 0.5) < 0.25)*10.0+0.01, 0.0);
#else
#ifdef USE_MSAA
return SLB_SAMPLER_LOAD_MSAA(s_position, int3(tc * screen_res.xy - 0.25, 0), iSample);
#else
return SLB_SAMPLER_LOAD(s_position, int3(tc * screen_res.xy - 0.25, 0));
#endif
#endif
}
// uniform float4 shader_param_6 = float4(0.9,0,9,0);
float SLB_MBlur_SightMask(float2 tc, float3 img, float2 aspect, uint iSample) {
float len = saturate(SLB_MBLUR_SIGHT_MASK_SIZE - length((tc - 0.5)*aspect)*75.);
#ifdef SLB_MBLUR_SIGHT_MASK_COLOR
#ifdef SLB_MBLUR_SIGHT_MASK_COLOR_SLOWER
float threshold = SLB_MBLUR_SIGHT_MASK_COLOR_SLOWER_THRESHOLD;
float mask = 0.0;
float2 dirs[9] = {
float2( 0, 0),
float2( 1, 0),
float2( 0, 1),
float2(-1, 0),
float2( 0, -1),
float2( 0.7071, 0.7071),
float2( 0.7071, -0.7071),
float2(-0.7071, -0.7071),
float2(-0.7071, 0.7071)
};
SLB_UNROLL(9)
for(int i = 0; i < 9; i++) {
float3 s;
if(i == 0) {
s = img;
} else {
float2 offset = dirs[i]*1.5/1000.0/aspect;
s = SLB_Screen_GetImage(tc + offset, iSample);
}
float3 hsv = SLB_RGB_To_HSV(s);
mask += float(hsv.y > threshold && hsv.z > threshold);
mask += float(abs(hsv.x - 0.406) < 0.01 && hsv.y > 0.5 && hsv.z > 0.5);
// mask += float(abs(hsv.x - 0.986) < 0.005 && hsv.y > 0.5 && hsv.z > 0.5);
}
return 1.0 - len * saturate(mask);
#else
float threshold = SLB_MBLUR_SIGHT_MASK_COLOR_THRESHOLD;
float mask = 0.0;
mask += step(threshold, img.r - (img.g + img.b));
mask += step(threshold, img.g - (img.r + img.b));
return 1.0 - len * saturate(mask);
#endif
#else
return 1.0 - len;
#endif
}
float SLB_MBlur_WeaponMask(float3 pos) {
return saturate((length(pos) - SLB_MBLUR_WPN_RADIUS) / SLB_MBLUR_WPN_RADIUS_SMOOTHING);
}
float3 SLB_MBlur(float2 uv, float3 pos, float3 img, float2 pixel_velocity, uint iSample) {
float2 aspect = screen_res.x > screen_res.y ? float2(screen_res.x/screen_res.y, 1.) : float2(1., screen_res.y/screen_res.x);
#ifdef SLB_MBLUR_REVERSED
pixel_velocity = -pixel_velocity;
#endif
pixel_velocity *= SLB_MBLUR_LENGTH;
float2 pixel_velocity_clamp = abs(normalize(pixel_velocity)) * SLB_MBLUR_CLAMP / aspect;
pixel_velocity = clamp(pixel_velocity, -pixel_velocity_clamp, +pixel_velocity_clamp);
#ifdef SLB_MBLUR_WPN
pixel_velocity *= SLB_MBlur_WeaponMask(pos);
#endif
#ifdef SLB_MBLUR_SIGHT_MASK
pixel_velocity *= SLB_MBlur_SightMask(uv, img, aspect, iSample);
#endif
/// Accumulate motion blur samples
float3 accum = img * 1e-2;
float occ = 1e-2;
uint noise_offset = 0;
#ifdef SLB_MBLUR_ANIMATED_DITHER
noise_offset = SLB_PCG(asuint(timers.y));
#endif
float noise = SLB_PhiNoise2_float(uint2(uv*screen_res.xy) + uint2(noise_offset, noise_offset));
#ifdef SLB_MBLUR_DUAL
float dither = noise - 0.5;
#else
float dither = noise;
#endif
float2 p_velocity_orig = pixel_velocity;
//gimme ze blur
SLB_UNROLL(SLB_MBLUR_SAMPLES*2+1)
#ifdef SLB_MBLUR_DUAL
for (int i = -SLB_MBLUR_SAMPLES; i <= SLB_MBLUR_SAMPLES; i++) {
#else
for (int i = 0; i <= SLB_MBLUR_SAMPLES*2; i++) {
#endif
if(abs(SLB_MBLUR_CONE_DITHER) > 0.001) {
float dither_cone = SLB_R1(noise*1024.0 + float(i)) - 0.5;
pixel_velocity = SLB_Rotate2(p_velocity_orig, dither_cone * SLB_MBLUR_CONE_DITHER * SLB_PI);
}
float2 offset;
offset = pixel_velocity * float(i);
offset /= float(SLB_MBLUR_SAMPLES*2+1);
offset += pixel_velocity/float(SLB_MBLUR_SAMPLES*2+1) * dither;
float2 tc = uv + offset;
float amount = float((0.0 < tc.x && tc.x < 1.0) && (0.0 < tc.y && tc.y < 1.0)); /// Fix black borders
if(SLB_MBLUR_SAMPLES == 0) {
tc = clamp(tc, 0.0, 0.999);
amount = 1.0;
}
float3 simg = SLB_Screen_GetImage(tc, iSample).rgb;
if(i != 0) {
#ifdef SLB_MBLUR_WPN
float3 spos = SLB_Screen_GetPosition(tc, iSample).xyz;
/// Fix sky ghosting caused by infinite depth value (KD)
spos.z = is_sky(spos.z) > 0.5 ? 10000.0 : spos.z;
amount *= SLB_MBlur_WeaponMask(spos);
#endif
#ifdef SLB_MBLUR_SIGHT_MASK
amount *= SLB_MBlur_SightMask(tc, simg, aspect, iSample);
#endif
}
accum += simg * amount;
occ += amount;
}
accum /= occ + 1e-6; /// fix Nans
return accum;
}
#endif // SLB_MOTION_BLUR_H
@@ -0,0 +1,27 @@
#ifndef SLB_MOTION_BLUR_SETTINGS_H
#define SLB_MOTION_BLUR_SETTINGS_H
#define SLB_MBLUR_SAMPLES int(4) /// Blur samples /// default int(4) /// vanilla int(6)
#define SLB_MBLUR_CLAMP float(0.1) /// Max blur length /// default float(0.1) /// vanilla float(0.012)
#define SLB_MBLUR_LENGTH float(120) /// Blur length /// default float(120) /// vanilla float(12)
#define SLB_MBLUR_ANIMATED_DITHER /// Comment to disable
#define SLB_MBLUR_CONE_DITHER float(0.0) /// Cone like dithering aka blurriness // default float(0.0)
#define SLB_MBLUR_DUAL /// Blur in both directions. Comment to disable
#define SLB_MBLUR_REVERSED /// Reverse blur direction. Comment to disable
#define SLB_MBLUR_WPN /// Disabled motion blur for weapon and hud. Comment to disable
#define SLB_MBLUR_WPN_RADIUS float(1.3) /// default float(1.3)
#define SLB_MBLUR_WPN_RADIUS_SMOOTHING float(1.0) /// default float(1.0)
#define SLB_MBLUR_SIGHT_MASK /// Try its best to detect reticle but too many false positives
#define SLB_MBLUR_SIGHT_MASK_SIZE float(5.0) /// Radius for searching /// default float(5.0)
#define SLB_MBLUR_SIGHT_MASK_COLOR /// Color based sight detection
#define SLB_MBLUR_SIGHT_MASK_COLOR_THRESHOLD float(0.5) /// Threshold for masking /// default float(0.5)
// #define SLB_MBLUR_SIGHT_MASK_COLOR_SLOWER /// Slower and maybe better
#define SLB_MBLUR_SIGHT_MASK_COLOR_SLOWER_THRESHOLD float(0.8) /// Threshold for masking /// default float(0.8)
#endif /// SLB_MOTION_BLUR_SETTINGS_H
@@ -0,0 +1,487 @@
#ifndef SLB_SHADOW_H
#define SLB_SHADOW_H
#include "slb_common.h"
#include "slb_shadow_settings.h"
#ifdef SLB_GLSL /// As always dummy
float SLB_Shadow_Load(float2 uv) {
return texelFetch(s_smap, int2(frac(uv)*float(SMAP_size)), 0).x;
}
float SLB_Shadow_LoadOffset(float2 uv, int2 offset) {
return texelFetch(s_smap, int2(frac(uv)*float(SMAP_size)) + offset, 0).x;
}
float SLB_Shadow_SampleCmp(float2 uv, float z) {
return textureLod(s_smap, uv, 0.0).x;
}
float4 SLB_Shadow_Gather(float2 uv) {
return textureGather(s_smap, uv);
}
float4 SLB_Shadow_GatherOffset(float2 uv, int2 offset) {
return textureGatherOffset(s_smap, uv, offset);
}
float4 SLB_Shadow_GatherCmp(float2 uv, float z) {
return textureGather(s_smap, uv);
}
#else
float SLB_Shadow_Load(float2 uv) {
return s_smap.Load(int3(uv*float(SMAP_size) - 0.25, 0));
}
float SLB_Shadow_LoadOffset(float2 uv, int2 offset) {
return s_smap.Load(int3(uv*float(SMAP_size) - 0.25, 0), offset);
}
float SLB_Shadow_SampleCmp(float2 uv, float z) {
return s_smap.SampleCmpLevelZero(smp_smap, uv, z).x;
}
float4 SLB_Shadow_Gather(float2 uv) {
return s_smap.Gather(smp_nofilter, uv);
}
float4 SLB_Shadow_GatherOffset(float2 uv, int2 offset) {
return s_smap.Gather(smp_nofilter, uv, offset);
}
float4 SLB_Shadow_GatherCmp(float2 uv, float z) {
return s_smap.GatherCmp(smp_smap, uv, z);
}
#endif
float SLB_Shadow_Linear(float4 tc) {
return SLB_Shadow_SampleCmp(tc.xy, tc.z);
}
/// Taken from https://www.shadertoy.com/view/XsfGDn
float SLB_Shadow_Nice(float4 tc) {
float2 uv = tc.xy;
float2 textureResolution = float2(float(SMAP_size), float(SMAP_size));
uv = uv*textureResolution + 0.5;
float2 iuv = floor(uv);
float2 fuv = frac(uv);
uv = iuv + fuv*fuv*(3.0-2.0*fuv);
uv = (uv - 0.5)/textureResolution;
return SLB_Shadow_SampleCmp(uv, tc.z);
}
/// Taken from http://www.java-gaming.org/index.php?topic=35123.0
float SLB_Shadow_Bicubic(float4 tc) {
float2 texCoords = tc.xy;
float2 texSize = float2(float(SMAP_size), float(SMAP_size));
float2 invTexSize = 1.0 / texSize;
texCoords = texCoords * texSize - 0.5;
float2 fxy = frac(texCoords);
texCoords -= fxy;
float4 xcubic = SLB_Cubic_For_Bicubic(fxy.x);
float4 ycubic = SLB_Cubic_For_Bicubic(fxy.y);
float4 c = texCoords.xxyy + float2(-0.5, +1.5).xyxy;
float4 s = float4(xcubic.xz + xcubic.yw, ycubic.xz + ycubic.yw);
float4 offset = c + float4(xcubic.yw, ycubic.yw) / s;
offset *= invTexSize.xxyy;
float sample0 = SLB_Shadow_SampleCmp(offset.xz, tc.z);
float sample1 = SLB_Shadow_SampleCmp(offset.yz, tc.z);
float sample2 = SLB_Shadow_SampleCmp(offset.xw, tc.z);
float sample3 = SLB_Shadow_SampleCmp(offset.yw, tc.z);
float sx = s.x / (s.x + s.y);
float sy = s.z / (s.z + s.w);
return lerp(lerp(sample3, sample2, sx), lerp(sample1, sample0, sx), sy);
}
#if 0
#include "slb_shadow_normal.h"
#endif
#include "slb_shadow_optimized_pcf.h"
float SLB_Shadow_CHS(float4 tc, float noise) {
float light_width = slb_shadow_settings_pcss_light_width;
float average_blocker_depth = 0.0;
{
float average_blocker_div = 1e-6;
float blocker_count = 0.0;
int blocker_count_max = 0;
for(int i = -3; i <= 3; i += 2) {
for(int j = -3; j <= 3; j += 2) {
float4 gather = SLB_Shadow_GatherOffset(tc.xy, int2(i, j));
float4 weight = max(float4(0.0,0.0,0.0,0.0), tc.z - gather);
weight /= weight + 0.025;
#ifdef SLB_GLSL
weight = 1.0 - gather;
#endif
average_blocker_depth += dot(gather, weight);
average_blocker_div += dot(weight, float4(1.0, 1.0, 1.0, 1.0));
blocker_count += float(weight.x > 1e-6) + float(weight.y > 1e-6)
+ float(weight.z > 1e-6) + float(weight.w > 1e-6);
blocker_count_max += 4;
}
}
SLB_BRANCH
if(blocker_count < 0.5 || blocker_count > float(blocker_count_max) - 0.5) {
#if 1 /// Toggles debug
return 1.0 - blocker_count/float(blocker_count_max);
#else
return 0.0; } else { return 100.0;
#endif
}
average_blocker_depth /= average_blocker_div;
}
float penumbra_size = light_width * (tc.z - average_blocker_depth)/average_blocker_depth;
float lightness = SLB_Shadow_OptimizedPCF(tc);
float scurve = clamp(3.0/float(SMAP_size)/penumbra_size, 1.0, 100.0);
lightness = saturate((lightness*scurve + 0.5) - 0.5*scurve);
return lightness;
}
float SLB_Shadow_VogelFilter(float4 tc, float noise, float filter_size, float filter_size_real, const int filter_samples, bool linear_sample, float radial_bias) {
const float compare_window = 0.0001;
float lightness = 0.0;
float div = 1e-6; /// Migitate division by zero
if(linear_sample) {
float2x2 rot_mat = SLB_Rotate2Matrix(noise*SLB_TAU);
SLB_UNROLL(filter_samples)
for(int i = 0; i < filter_samples; i++) {
float2 offset = SLB_VogelDisk_Sample(i, filter_samples);
float offset_length = length(offset);
offset = mul(offset, rot_mat);
offset *= filter_size;
float biased_z = tc.z - radial_bias*offset_length*filter_size_real;
float2 uv = tc.xy + offset;
float notblocker;
{
float4 depths = SLB_Shadow_Gather(uv);
float4 notblockers = saturate((depths - biased_z + compare_window)/compare_window);
#ifdef SLB_GLSL
notblockers = depths;
#endif
float s1 = notblockers.x;
float s2 = notblockers.y;
float s3 = notblockers.z;
float s4 = notblockers.w;
float2 fract = frac(uv*float(SMAP_size)+0.5);
notblocker = lerp(lerp(s4, s3, fract.x), lerp(s1, s2, fract.x), fract.y);
lightness += notblocker;
div += 1.0;
}
}
} else {
float2x2 rot_mat = SLB_Rotate2Matrix(noise*SLB_TAU);
SLB_UNROLL(filter_samples)
for(int i = 0; i < filter_samples; i++) {
float2 offset = SLB_VogelDisk_Sample(i, filter_samples);
float offset_length = length(offset);
offset = mul(offset, rot_mat);
offset *= filter_size;
float biased_z = tc.z - radial_bias*offset_length*filter_size_real;
float2 uv = tc.xy + offset;
float depth = SLB_Shadow_Load(uv);
float notblocker = saturate((depth - biased_z)/compare_window);
float weight = float(depth > 1e-6);
#ifdef SLB_GLSL
notblocker = depth;
weight = 1.0;
#endif
lightness += notblocker * weight;
div += weight;
}
}
lightness /= div;
return lightness;
}
float SLB_Shadow_PCF(float4 tc, float noise) {
SLB_STATIC_CONST int filter_samples = max(1, int(slb_shadow_settings_pcss_filter_samples*slb_shadow_pcss_filter_samples_multiplier));
float pcss_size_min = slb_shadow_settings_pcss_size_min / float(SMAP_size) * slb_shadow_pcss_size_min_multiplier;
float filter_size = pcss_size_min;
#if defined(SLB_SHADOW_SPOT)
SLB_STATIC_CONST float radial_bias = 2.0;
#elif defined(SLB_SHADOW_OMNI)
SLB_STATIC_CONST float radial_bias = 1.0;
#else
SLB_STATIC_CONST float radial_bias = 0.3;
#endif
float lightness = SLB_Shadow_VogelFilter(tc, noise, filter_size, filter_size/2.0, filter_samples, true, radial_bias);
lightness = SLB_QuarticRational1D(lightness);
return lightness;
}
float SLB_Shadow_VogelCHS(float4 tc, float noise) {
SLB_STATIC_CONST int filter_samples = max(1, int(slb_shadow_settings_pcss_filter_samples*slb_shadow_pcss_filter_samples_multiplier));
SLB_STATIC_CONST float light_width = slb_shadow_settings_pcss_light_width;
float pcss_size_min = slb_shadow_settings_pcss_size_min / float(SMAP_size) * slb_shadow_pcss_size_min_multiplier;
float filter_size = pcss_size_min;
SLB_STATIC_CONST int biases = 4;
const float compare_window = 0.0001;
const float filter_bias[biases] = {0.0, 0.1, 0.2, 0.3};
float average_blocker_depth = 0.0;
float average_blocker_div = 1e-6; /// Migitate division by zero
float lightnesses[biases] = {0.0, 0.0, 0.0, 0.0};
float lightnesses_div[biases] = {1e-6, 1e-6, 1e-6, 1e-6}; /// Migitate division by zero
float2x2 rot_mat = SLB_Rotate2Matrix(noise*SLB_TAU);
SLB_UNROLL(filter_samples)
for(int i = 0; i < filter_samples; i++) {
float2 offset = SLB_VogelDisk_Sample(i, filter_samples);
float offset_length = length(offset);
offset = mul(offset, rot_mat);
offset *= filter_size;
float2 uv = tc.xy + offset;
float4 depths = SLB_Shadow_Gather(uv);
SLB_UNROLL(biases)
for(int j = 0; j < biases; j++) {
float biased_z = tc.z - filter_bias[j]*offset_length*filter_size;
{
float4 notblockers = saturate((depths - biased_z + compare_window)/compare_window);
#ifdef SLB_GLSL
notblockers = depths;
#endif
float s1 = notblockers.x;
float s2 = notblockers.y;
float s3 = notblockers.z;
float s4 = notblockers.w;
float2 fract = frac(uv*float(SMAP_size)+0.5);
float notblocker = lerp(lerp(s4, s3, fract.x), lerp(s1, s2, fract.x), fract.y);
lightnesses[j] += notblocker;
lightnesses_div[j] += 1.0;
}
{
float4 blockers = float4(float(biased_z - 0.0001*float(j-1) > depths.x),
float(biased_z - 0.0001*float(j-1) > depths.y),
float(biased_z - 0.0001*float(j-1) > depths.z),
float(biased_z - 0.0001*float(j-1) > depths.w));
average_blocker_depth += dot(depths, blockers);
average_blocker_div += dot(float4(1.0,1.0,1.0,1.0), blockers);
}
}
}
SLB_UNROLL(biases)
for(int i = 0; i < biases; i++) {
lightnesses[i] /= lightnesses_div[i];
}
average_blocker_depth /= average_blocker_div;
float penumbra_size = light_width * (tc.z - average_blocker_depth)/average_blocker_depth;
/// Choose bias
float lightness = lightnesses[0];
SLB_UNROLL(biases-1)
for(int i = 1; i < biases; i++) {
if(penumbra_size > float(i)/float(biases-1)*filter_size) {
lightness = lightnesses[i];
}
}
float scurve = clamp(filter_size/penumbra_size, 1.0, 2.0*float(filter_samples)/(filter_size*float(SMAP_size)));
lightness = saturate((lightness*scurve + 0.5) - 0.5*scurve);
return lightness;
}
float SLB_Shadow_PCSS(float4 tc, float noise) {
/// Settings
SLB_STATIC_CONST int blocker_samples = max(1, int(slb_shadow_settings_pcss_blocker_samples * slb_shadow_pcss_blocker_samples_multiplier));
SLB_STATIC_CONST int filter_samples = max(1, int(slb_shadow_settings_pcss_filter_samples * slb_shadow_pcss_filter_samples_multiplier));
SLB_STATIC_CONST int filter_small_samples = max(1, int(slb_shadow_settings_pcss_filter_small_samples * slb_shadow_pcss_filter_small_samples_multiplier));
float pcss_size = slb_shadow_settings_pcss_size / float(2048) * slb_shadow_pcss_size_multiplier;
float pcss_size_min = slb_shadow_settings_pcss_size_min / float(SMAP_size) * slb_shadow_pcss_size_min_multiplier;
float light_width = slb_shadow_settings_pcss_light_width;
float filter_size_real;
float filter_size;
#if defined(SLB_SHADOW_SPOT)
SLB_STATIC_CONST float radial_bias = 2.0;
#elif defined(SLB_SHADOW_OMNI)
SLB_STATIC_CONST float radial_bias = 1.0;
#else
SLB_STATIC_CONST float radial_bias = 0.3;
#endif
{
/// Blocker search
float blocker_size = pcss_size;
float average_blocker_depth = tc.z * 1e-6;
float average_blocker_div = 1e-6; /// Migitate division by zero
float2x2 rot_mat = SLB_Rotate2Matrix(noise*SLB_TAU);
SLB_UNROLL(blocker_samples)
for(int i = 0; i < blocker_samples; i++) {
float2 offset = SLB_VogelDisk_Sample(i, blocker_samples);
offset *= sqrt(length(offset));
float offset_length = length(offset);
offset = mul(offset, rot_mat);
offset *= blocker_size;
float depth = SLB_Shadow_Load(tc.xy + offset);
float biased_z = tc.z - radial_bias*offset_length*blocker_size;
float blocker = float(biased_z > depth && depth > 1e-6);
blocker *= 1.0/(offset_length + 1e-9);
average_blocker_depth += depth * blocker;
average_blocker_div += blocker;
}
average_blocker_depth /= average_blocker_div;
/// Calculate penumbra size
filter_size = light_width * (tc.z - average_blocker_depth)/average_blocker_depth;
#if defined(SLB_SHADOW_SPOT) || defined(SLB_SHADOW_OMNI)
filter_size *= 2 - average_blocker_depth;
#endif
#ifdef SLB_GLSL
filter_size += 1;
#endif
filter_size = min(pcss_size, filter_size);
#ifdef SLB_GLSL
// filter_size *= frac(timers.y/10.0);
// filter_size *= cos(timers.y/5.0)*0.5 + 0.5;
// filter_size *= abs(frac(timers.y/2.0/8.0)*2.0 - 1.0)*1.0 + 0.0;
// filter_size *= noise;
// filter_size *= 0.0;
// if(sin(tc.x*100.0) > 0.5) {
// filter_size = 2.9/float(SMAP_size);
// } else {
// filter_size = 3.000/float(SMAP_size);
// }
#endif
filter_size_real = max(pcss_size_min/1000.0, filter_size);
filter_size = max(pcss_size_min, filter_size);
}
float lightness;
SLB_BRANCH
if(filter_size_real < pcss_size_min) {
if (slb_shadow_pcss_early_quit) {
float lightness = SLB_Shadow_VogelFilter(tc, noise, filter_size*1.25, filter_size_real*1.25, 8, false, radial_bias);
float scurve = clamp(filter_size/filter_size_real, 1.0, 2/(pcss_size_min*float(SMAP_size)));
lightness = saturate((lightness*scurve + 0.5) - 0.5*scurve);
SLB_BRANCH
if(abs(lightness - 0.5) > 0.45)
#if 1
{ return lightness; }
#else
{ return 0.0; } else { return 10.0; }
#endif
}
lightness = SLB_Shadow_VogelFilter(tc, noise, filter_size, filter_size_real, filter_small_samples, true, radial_bias);
} else {
lightness = SLB_Shadow_VogelFilter(tc, noise, filter_size, filter_size_real, filter_samples, false, radial_bias);
}
float scurve = clamp(filter_size/filter_size_real, 1.0, 2.0*float(filter_small_samples)/(pcss_size_min*float(SMAP_size)));
lightness = saturate((lightness*scurve + 0.5) - 0.5*scurve);
return lightness;
}
float SLB_Shadow(float4 tc, float2 pos2d) {
float noise;
if(slb_shadow_animated_noise) {
uint noise_offset = SLB_PCG(asuint(timers.y));
uint2 noise_uv = uint2(pos2d+0.5) + uint2(noise_offset, noise_offset);
noise = SLB_PhiNoise2_float(noise_uv);
} else {
noise = SLB_Morton_OwenHash4_Bluenoise_float(uint2(pos2d+0.5));
}
tc.xyz /= tc.w;
float lightness = 1.0;
if(slb_shadow_settings_method == slb_shadow_method_linear) {
lightness = SLB_Shadow_Linear(tc);
} else if (slb_shadow_settings_method == slb_shadow_method_nice) {
lightness = SLB_Shadow_Nice(tc);
} else if (slb_shadow_settings_method == slb_shadow_method_bicubic) {
lightness = SLB_Shadow_Bicubic(tc);
} else if (slb_shadow_settings_method == slb_shadow_method_optimized_pcf) {
lightness = SLB_CubicRational1D(SLB_Shadow_OptimizedPCF(tc));
} else if (slb_shadow_settings_method == slb_shadow_method_chs) {
lightness = SLB_Shadow_CHS(tc, noise);
} else if (slb_shadow_settings_method == slb_shadow_method_pcf) {
lightness = SLB_Shadow_PCF(tc, noise);
} else if (slb_shadow_settings_method == slb_shadow_method_vogel_chs) {
lightness = SLB_Shadow_VogelCHS(tc, noise);
} else if (slb_shadow_settings_method == slb_shadow_method_pcss) {
lightness = SLB_Shadow_PCSS(tc, noise);
}
return lightness;
}
#endif /// SLB_SHADOW_H
@@ -0,0 +1,63 @@
#ifndef SLB_SHADOW_NORMAL_H
#define SLB_SHADOW_NORMAL_H
float3 SLB_Shadow_ViewSpacePosAtScreenUV(float2 pos) {
return float3(pos.x, pos.y, SLB_Shadow_Sample(pos)); // * float2(float(SMAP_size), 1.0).xxy;
}
float3 SLB_Shadow_Normal(float2 vpos) {
float2 texelSize = float2(1.0, 1.0)/float2(float(SMAP_size), float(SMAP_size));
// screen uv from vpos
float2 uv = floor(vpos/texelSize)*texelSize;
// current pixel's depth
float c = SLB_Shadow_Sample(uv);
// get current pixel's view space position
float3 viewSpacePos_c = SLB_Shadow_ViewSpacePosAtScreenUV(uv);
// get view space position at 1 pixel offsets in each major direction
float3 viewSpacePos_l = SLB_Shadow_ViewSpacePosAtScreenUV(uv + float2(-1.0, 0.0) * texelSize);
float3 viewSpacePos_r = SLB_Shadow_ViewSpacePosAtScreenUV(uv + float2( 1.0, 0.0) * texelSize);
float3 viewSpacePos_d = SLB_Shadow_ViewSpacePosAtScreenUV(uv + float2( 0.0,-1.0) * texelSize);
float3 viewSpacePos_u = SLB_Shadow_ViewSpacePosAtScreenUV(uv + float2( 0.0, 1.0) * texelSize);
// get the difference between the current and each offset position
float3 l = viewSpacePos_c - viewSpacePos_l;
float3 r = viewSpacePos_r - viewSpacePos_c;
float3 d = viewSpacePos_c - viewSpacePos_d;
float3 u = viewSpacePos_u - viewSpacePos_c;
// get depth values at 1 & 2 pixels offsets from current along the horizontal axis
float4 H = float4(
SLB_Shadow_Sample(uv + float2(-1.0, 0.0) * texelSize),
SLB_Shadow_Sample(uv + float2( 1.0, 0.0) * texelSize),
SLB_Shadow_Sample(uv + float2(-2.0, 0.0) * texelSize),
SLB_Shadow_Sample(uv + float2( 2.0, 0.0) * texelSize)
);
// get depth values at 1 & 2 pixels offsets from current along the vertical axis
float4 V = float4(
SLB_Shadow_Sample(uv + float2(0.0,-1.0) * texelSize),
SLB_Shadow_Sample(uv + float2(0.0, 1.0) * texelSize),
SLB_Shadow_Sample(uv + float2(0.0,-2.0) * texelSize),
SLB_Shadow_Sample(uv + float2(0.0, 2.0) * texelSize)
);
// current pixel's depth difference from slope of offset depth samples
// differs from original article because we're using non-linear depth values
// see article's comments
float2 he = abs((2 * H.xy - H.zw) - c);
float2 ve = abs((2 * V.xy - V.zw) - c);
// pick horizontal and vertical diff with the smallest depth difference from slopes
float3 hDeriv = he.x < he.y ? l : r;
float3 vDeriv = ve.x < ve.y ? d : u;
// get view space normal from the cross product of the best derivatives
float3 viewNormal = normalize(cross(hDeriv, vDeriv));
return viewNormal;
}
#endif /// SLB_SHADOW_NORMAL_H
@@ -0,0 +1,152 @@
#ifndef SLB_SHADOW_OPTIMIZED_PCF_H
#define SLB_SHADOW_OPTIMIZED_PCF_H
/// Source https://github.com/TheRealMJP/Shadows/blob/master/Shadows/Mesh.hlsl
float SLB_Shadow_OptimizedPCF_Sample(in float2 base_uv, in float u, in float v, in float depth) {
float2 shadowMapSize = float2(int2(SMAP_size, SMAP_size));
float2 shadowMapSizeInv = 1.0 / shadowMapSize;
float2 uv = base_uv + float2(u, v) * shadowMapSizeInv;
const float compare_window = 0.0001;
{
float4 depths = SLB_Shadow_Gather(uv);
float4 notblockers = saturate((depths - depth + compare_window)/compare_window);
#ifdef SLB_GLSL
notblockers = depths;
#endif
float s1 = notblockers.x;
float s2 = notblockers.y;
float s3 = notblockers.z;
float s4 = notblockers.w;
float2 fract = frac(uv*float(SMAP_size)+0.5);
float notblocker = lerp(lerp(s4, s3, fract.x), lerp(s1, s2, fract.x), fract.y);
return notblocker;
}
}
float SLB_Shadow_OptimizedPCF(float4 tc) {
const int filter_size = 7;
float2 shadowMapSize = float2(int2(SMAP_size, SMAP_size));
float2 shadowMapSizeInv = 1.0 / shadowMapSize;
float2 shadowPos = tc.xy;
float lightDepth = tc.z;
float2 uv = shadowPos.xy * shadowMapSize; // 1 unit - 1 texel
float2 base_uv;
base_uv.x = floor(uv.x + 0.5);
base_uv.y = floor(uv.y + 0.5);
float s = (uv.x + 0.5 - base_uv.x);
float t = (uv.y + 0.5 - base_uv.y);
base_uv -= float2(0.5, 0.5);
base_uv *= shadowMapSizeInv;
float sum = 0;
if(filter_size == 2) {
return SLB_Shadow_SampleCmp(shadowPos.xy, lightDepth);
} else if(filter_size == 3) {
float uw0 = (3 - 2 * s);
float uw1 = (1 + 2 * s);
float u0 = (2 - s) / uw0 - 1;
float u1 = s / uw1 + 1;
float vw0 = (3 - 2 * t);
float vw1 = (1 + 2 * t);
float v0 = (2 - t) / vw0 - 1;
float v1 = t / vw1 + 1;
sum += uw0 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v0, lightDepth);
sum += uw1 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v0, lightDepth);
sum += uw0 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v1, lightDepth);
sum += uw1 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v1, lightDepth);
return sum * 1.0f / 16;
} else if(filter_size == 5) {
float uw0 = (4 - 3 * s);
float uw1 = 7;
float uw2 = (1 + 3 * s);
float u0 = (3 - 2 * s) / uw0 - 2;
float u1 = (3 + s) / uw1;
float u2 = s / uw2 + 2;
float vw0 = (4 - 3 * t);
float vw1 = 7;
float vw2 = (1 + 3 * t);
float v0 = (3 - 2 * t) / vw0 - 2;
float v1 = (3 + t) / vw1;
float v2 = t / vw2 + 2;
sum += uw0 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v0, lightDepth);
sum += uw1 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v0, lightDepth);
sum += uw2 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u2, v0, lightDepth);
sum += uw0 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v1, lightDepth);
sum += uw1 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v1, lightDepth);
sum += uw2 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u2, v1, lightDepth);
sum += uw0 * vw2 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v2, lightDepth);
sum += uw1 * vw2 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v2, lightDepth);
sum += uw2 * vw2 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u2, v2, lightDepth);
return sum * 1.0f / 144;
} else if(filter_size == 7) {
float uw0 = (5 * s - 6);
float uw1 = (11 * s - 28);
float uw2 = -(11 * s + 17);
float uw3 = -(5 * s + 1);
float u0 = (4 * s - 5) / uw0 - 3;
float u1 = (4 * s - 16) / uw1 - 1;
float u2 = -(7 * s + 5) / uw2 + 1;
float u3 = -s / uw3 + 3;
float vw0 = (5 * t - 6);
float vw1 = (11 * t - 28);
float vw2 = -(11 * t + 17);
float vw3 = -(5 * t + 1);
float v0 = (4 * t - 5) / vw0 - 3;
float v1 = (4 * t - 16) / vw1 - 1;
float v2 = -(7 * t + 5) / vw2 + 1;
float v3 = -t / vw3 + 3;
sum += uw0 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v0, lightDepth);
sum += uw1 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v0, lightDepth);
sum += uw2 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u2, v0, lightDepth);
sum += uw3 * vw0 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u3, v0, lightDepth);
sum += uw0 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v1, lightDepth);
sum += uw1 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v1, lightDepth);
sum += uw2 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u2, v1, lightDepth);
sum += uw3 * vw1 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u3, v1, lightDepth);
sum += uw0 * vw2 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v2, lightDepth);
sum += uw1 * vw2 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v2, lightDepth);
sum += uw2 * vw2 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u2, v2, lightDepth);
sum += uw3 * vw2 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u3, v2, lightDepth);
sum += uw0 * vw3 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u0, v3, lightDepth);
sum += uw1 * vw3 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u1, v3, lightDepth);
sum += uw2 * vw3 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u2, v3, lightDepth);
sum += uw3 * vw3 * SLB_Shadow_OptimizedPCF_Sample(base_uv, u3, v3, lightDepth);
return sum * 1.0f / 2704;
} else {
return 1.0;
}
}
#endif /// SLB_SHADOW_OPTIMIZED_PCF_H
@@ -0,0 +1,109 @@
#ifndef SLB_SHADOW_SETTINGS_H
#define SLB_SHADOW_SETTINGS_H
/// Macro mess
#define SLB_SHADOW_SETTINGS_ADD_PRESET(preset, method, pcss_filter_samples, pcss_filter_small_samples, pcss_blocker_samples, pcss_size, pcss_size_min, pcss_light_width) \
SLB_STATIC_CONST int slb_shadow_settings_ ## preset ## _method = method; \
SLB_STATIC_CONST int slb_shadow_settings_ ## preset ## _pcss_filter_samples = pcss_filter_samples; \
SLB_STATIC_CONST int slb_shadow_settings_ ## preset ## _pcss_filter_small_samples = pcss_filter_small_samples; \
SLB_STATIC_CONST int slb_shadow_settings_ ## preset ## _pcss_blocker_samples = pcss_blocker_samples; \
SLB_STATIC_CONST float slb_shadow_settings_ ## preset ## _pcss_size = pcss_size; \
SLB_STATIC_CONST float slb_shadow_settings_ ## preset ## _pcss_size_min = pcss_size_min; \
SLB_STATIC_CONST float slb_shadow_settings_ ## preset ## _pcss_light_width = pcss_light_width;
#define SLB_SHADOW_SETTINGS_APPLY_PRESET(preset) \
SLB_STATIC_CONST int slb_shadow_settings_method = slb_shadow_settings_ ## preset ## _method; \
SLB_STATIC_CONST int slb_shadow_settings_pcss_filter_samples = slb_shadow_settings_ ## preset ## _pcss_filter_samples; \
SLB_STATIC_CONST int slb_shadow_settings_pcss_filter_small_samples = slb_shadow_settings_ ## preset ## _pcss_filter_small_samples; \
SLB_STATIC_CONST int slb_shadow_settings_pcss_blocker_samples = slb_shadow_settings_ ## preset ## _pcss_blocker_samples; \
SLB_STATIC_CONST float slb_shadow_settings_pcss_size = slb_shadow_settings_ ## preset ## _pcss_size; \
SLB_STATIC_CONST float slb_shadow_settings_pcss_size_min = slb_shadow_settings_ ## preset ## _pcss_size_min; \
SLB_STATIC_CONST float slb_shadow_settings_pcss_light_width = slb_shadow_settings_ ## preset ## _pcss_light_width;
/// Enums
SLB_STATIC_CONST int slb_shadow_method_linear = 0x252827bd;
SLB_STATIC_CONST int slb_shadow_method_nice = 0xeaa1fbca;
SLB_STATIC_CONST int slb_shadow_method_bicubic = 0xcb35b7d8;
SLB_STATIC_CONST int slb_shadow_method_optimized_pcf = 0xcf7d64d5;
SLB_STATIC_CONST int slb_shadow_method_chs = 0x15e654ad;
SLB_STATIC_CONST int slb_shadow_method_pcf = 0x92726cc9;
SLB_STATIC_CONST int slb_shadow_method_vogel_chs = 0x6f241210;
SLB_STATIC_CONST int slb_shadow_method_pcss = 0xa9fa8994;
SLB_STATIC_CONST float slb_shadow_pcss_filter_gaussian_sigma = 0.5;
/// Real settings starts here
/// slb_shadow_animated_noise: change noise every frame
/// slb_shadow_pcss_early_quit: improves performance a bit in synthetic test but idk.
SLB_STATIC_CONST bool slb_shadow_animated_noise = false; /// default false
SLB_STATIC_CONST bool slb_shadow_pcss_early_quit = false; /// default false
SLB_STATIC_CONST float slb_shadow_pcss_filter_samples_multiplier = 1.0; /// default 1.0
SLB_STATIC_CONST float slb_shadow_pcss_filter_small_samples_multiplier = 1.0; /// default 1.0
SLB_STATIC_CONST float slb_shadow_pcss_blocker_samples_multiplier = 1.0; /// default 1.0
SLB_STATIC_CONST float slb_shadow_pcss_size_multiplier = 1.0; /// default 1.0
SLB_STATIC_CONST float slb_shadow_pcss_size_min_multiplier = 1.0; /// default 1.0
/// Explanation:
/// sun_near - preset for sun near you
/// sun_near - preset for sun far from you
/// spot - preset for spot lights e.g. flashlights
/// omni - preset for omni lights e.g. some lamps
/// fallback - preset for ... rainlayer.ps IDK what it does
#ifndef SUN_QUALITY /// Low quality
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_near, slb_shadow_method_bicubic, 16, 16, 16, 8.0, 2.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_far, slb_shadow_method_bicubic, 16, 16, 16, 8.0, 2.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(spot, slb_shadow_method_bicubic, 16, 16, 16, 8.0, 2.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(omni, slb_shadow_method_bicubic, 16, 16, 16, 8.0, 2.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(fallback, slb_shadow_method_bicubic, 16, 16, 16, 8.0, 2.0, 0.1)
#elif SUN_QUALITY==1 /// medium quality
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_near, slb_shadow_method_optimized_pcf, 16, 16, 16, 8.0, 2.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_far, slb_shadow_method_optimized_pcf, 16, 16, 16, 8.0, 2.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(spot, slb_shadow_method_optimized_pcf, 16, 16, 16, 8.0, 2.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(omni, slb_shadow_method_optimized_pcf, 16, 16, 16, 8.0, 2.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(fallback, slb_shadow_method_bicubic, 16, 16, 16, 8.0, 2.0, 0.1)
#elif SUN_QUALITY==2 /// high quality
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_near, slb_shadow_method_vogel_chs, 16, 16, 16, 8.0, 3.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_far, slb_shadow_method_vogel_chs, 16, 16, 16, 8.0, 3.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(spot, slb_shadow_method_vogel_chs, 16, 16, 16, 8.0, 3.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(omni, slb_shadow_method_vogel_chs, 16, 16, 16, 8.0, 3.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(fallback, slb_shadow_method_bicubic, 16, 16, 16, 8.0, 3.0, 0.1)
#elif SUN_QUALITY==3 /// ultra quality
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_near, slb_shadow_method_pcss, 16, 16, 16, 8.0, 2.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_far, slb_shadow_method_pcss, 16, 16, 16, 2.0, 2.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(spot, slb_shadow_method_pcss, 16, 16, 16, 8.0, 2.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(omni, slb_shadow_method_pcss, 16, 16, 16, 8.0, 2.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(fallback, slb_shadow_method_bicubic, 16, 16, 16, 8.0, 2.0, 0.1)
#elif SUN_QUALITY>=4 /// extreme quality
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_near, slb_shadow_method_pcss, 32, 32, 32, 16.0, 2.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(sun_far, slb_shadow_method_pcss, 32, 32, 32, 4.0, 2.0, 0.1)
SLB_SHADOW_SETTINGS_ADD_PRESET(spot, slb_shadow_method_pcss, 32, 32, 32, 16.0, 2.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(omni, slb_shadow_method_pcss, 32, 32, 32, 16.0, 2.0, 0.02)
SLB_SHADOW_SETTINGS_ADD_PRESET(fallback, slb_shadow_method_bicubic, 32, 32, 32, 16.0, 2.0, 0.1)
#endif
/// Real settings ends here
#if defined(SLB_SHADOW_SUN_NEAR)
SLB_SHADOW_SETTINGS_APPLY_PRESET(sun_near)
#elif defined(SLB_SHADOW_SUN_FAR)
SLB_SHADOW_SETTINGS_APPLY_PRESET(sun_far)
#elif defined(SLB_SHADOW_SPOT)
SLB_SHADOW_SETTINGS_APPLY_PRESET(spot)
#elif defined(SLB_SHADOW_OMNI)
SLB_SHADOW_SETTINGS_APPLY_PRESET(omni)
#else
SLB_SHADOW_SETTINGS_APPLY_PRESET(fallback)
#endif
#endif /// SLB_SHADOW_SETTINGS_H
+34
View File
@@ -0,0 +1,34 @@
[General]
gameName=stalkeranomaly
modid=0
version=d2024.3.26.0
newestVersion=
category="-1,"
nexusFileStatus=1
installationFile=Shaders_Look_Better_v1.1.0.7z
repository=Nexus
ignoredVersion=
comments=
notes=
nexusDescription=
url=
hasCustomURL=true
lastNexusQuery=
lastNexusUpdate=
nexusLastModified=2024-03-26T07:24:23Z
nexusCategory=0
converted=false
validated=false
color=@Variant(\0\0\0\x43\0\xff\xff\0\0\0\0\0\0\0\0)
tracked=0
[installedFiles]
1\modid=0
size=1
1\fileid=0
[Plugins]
BAIN%20Installer\option0=00 Main
BAIN%20Installer\option1=05 Motion Blur
BAIN%20Installer\option2=10 Shadows
BAIN%20Installer\option3=11 Shadows SSS