#ifndef reflections_h_2134124_inc #define reflections_h_2134124_inc // Screen Space Sky Reflections off #define SKYBLED_FADE #define USE_BASE_HUD_REFLECTIONS #define USE_VASYAN_CUTOFF // #define VSLR_SLOW_BREAK // #define SSLR_SLOW_BREAK uniform float4 scaled_screen_res; float get_depth_fast(float2 tc) { float P = s_position.SampleLevel(smp_rtlinear, tc, 0).x; return depth_unpack.x * rcp(P - depth_unpack.y); } float3 gbuf_unpack_position(float2 uv) { float depth = get_depth_fast(uv); uv = uv * 2.0f - 1.0f; return float3(uv * pos_decompression_params.xy, 1.0f) * depth; } float3 gbuf_unpack_position(float2 uv, float depth) { uv = uv * 2.0f - 1.0f; return float3(uv * pos_decompression_params.xy, 1.0f) * depth; } float2 gbuf_unpack_uv(float3 position) { position.xy *= rcp(pos_decompression_params.xy * position.z); return saturate(position.xy * 0.5 + 0.5); } #define SSLR_STEPS 30 #define MAX_FIND_STEP 5 float BinaryRefinement(inout float3 EndProj, float3 Reflect) { float HitDepth = 0.0f; [unroll(MAX_FIND_STEP)] for(int i = 0; i < MAX_FIND_STEP; ++i) { HitDepth = s_env.SampleLevel(smp_nofilter, EndProj.xyz, 0).w; HitDepth *= HitDepth; Reflect *= 0.5f; EndProj += dot(EndProj, EndProj) > HitDepth ? -Reflect : Reflect; } HitDepth = s_env.SampleLevel(smp_nofilter, EndProj.xyz, 0).w; HitDepth *= HitDepth; return HitDepth; } float BinaryRefinementHUD(inout float3 EndProj, float3 Reflect) { float HitDepth = 0.0f; [unroll(MAX_FIND_STEP)] for(int i = 0; i < MAX_FIND_STEP; ++i) { HitDepth = s_position.SampleLevel(smp_nofilter, EndProj.xy, 0).x; Reflect *= 0.5f; EndProj += EndProj.z > HitDepth ? -Reflect : Reflect; } HitDepth = s_position.SampleLevel(smp_nofilter, EndProj.xy, 0).x; return HitDepth; } float4 FastViewReflections(float3 Point, float3 Reflect) { float3 SamplePoint = Reflect; float SampleHitPointLen = 0; float Step = rcp(SSLR_STEPS + 1) * 0.01f; float L = 0.011f; float RadiusS = fog_params.z * fog_params.z; float DistanceS = dot(Point, Point); float DirectionS = dot(Reflect, Reflect); if(DistanceS >= RadiusS) { return float4(SamplePoint, 0.0f); } Step *= fog_params.z - length(Point); //sqrt((RadiusS - DistanceS) * rcp(DirectionS)); float Fade = 0; float Delta = 0.0f; [loop] for(uint i = 0; i < SSLR_STEPS; ++i) { float JStep = Step * lerp(0.8f, 1.2f, Hash(dot(sin(SamplePoint.xyz * timers.x), float3(12.989, 42.364, 78.233)))); L += JStep; Step *= 1.25f; SamplePoint.xyz = Point.xyz + Reflect * L; SampleHitPointLen = s_env.SampleLevel(smp_nofilter, SamplePoint.xyz, 0).w; SampleHitPointLen *= SampleHitPointLen; Delta = dot(SamplePoint, SamplePoint) - SampleHitPointLen; if (Delta > 0 /*&& Delta <= JStep * 0.8f*/) { float3 JReflect = Reflect * JStep * 0.5f; SamplePoint.xyz -= JReflect; SampleHitPointLen = BinaryRefinement(SamplePoint.xyz, JReflect); Delta = dot(SamplePoint.xyz, SamplePoint.xyz) - SampleHitPointLen; Fade = abs(Delta) / max(dot(SamplePoint.xyz, SamplePoint.xyz), SampleHitPointLen) < 0.1f; #ifdef VSLR_SLOW_BREAK if(Fade) #endif break; } } SamplePoint = normalize(SamplePoint) * sqrt(SampleHitPointLen); return float4(SamplePoint, Fade); } float4 FastViewReflectionsSSR(float3 Point, float3 Reflect, bool is_hud) { float4 StartProj, EndProj; float3 ReflectBase = Reflect; float Step = rcp(SSLR_STEPS + 1); bool Fade = false; if(is_hud) { StartProj = mul(m_P_hud, float4(Point, 1.0f)); StartProj.xyz /= StartProj.w; EndProj = mul(m_P_hud, float4(Point + Reflect * Point.z, 1.0f)); EndProj.xyz /= EndProj.w; StartProj.z *= 0.02f; EndProj.z *= 0.02f; } else { StartProj = mul(m_P, float4(Point, 1.0f)); StartProj.xyz /= StartProj.w; EndProj = mul(m_P, float4(Point + Reflect * Point.z, 1.0f)); EndProj.xyz /= EndProj.w; } Reflect = EndProj.xyz - StartProj.xyz; StartProj.xy = StartProj.xy * float2(0.5f, -0.5f) + 0.5f; Reflect.xy = Reflect.xy * float2(0.5f, -0.5f); Reflect.xyz = normalize(Reflect.xyz); Step *= GetMaxDirLength(StartProj.xyz, rcp(Reflect)); float L = 0.001f; Step *= is_hud ? 0.2f : 1.0f; float StepScale = is_hud ? 1.095f : 1.0f; [loop] for(uint i = 0; i < SSLR_STEPS; ++i) { float JStep = Step * lerp(0.8f, 1.2f, Hash(dot(sin(EndProj.xyz * timers.x), float3(12.989, 42.364, 78.233)))); L += JStep; Step *= StepScale; EndProj.xyz = StartProj.xyz + Reflect * L; float HitDepth = s_position.SampleLevel(smp_nofilter, EndProj.xy, 0).x; float Delta = EndProj.z - HitDepth; if (Delta > 0 && (is_hud || HitDepth > 0.02f)) { float3 JReflect = Reflect * JStep * 0.5f; EndProj.xyz -= JReflect; HitDepth = BinaryRefinementHUD(EndProj.xyz, JReflect); float2 depthL = rcp(max(1.0f - HitDepth, 0.00001f)); float2 depthR = rcp(max(1.0f - EndProj.z, 0.00001f)); EndProj.z = HitDepth; Fade = is_hud || abs(depthL - depthR) * rcp(max(depthL, depthR)) < 0.01f; #ifdef SSLR_SLOW_BREAK if(Fade) #endif break; } } if(is_hud) { Fade = Fade && EndProj.z < 0.02f; #ifdef USE_BASE_HUD_REFLECTIONS if(!Fade && ReflectBase.z > 0.0f) { EndProj = mul(m_P, float4(ReflectBase, 1.0f)); EndProj.xyz /= EndProj.w; EndProj.xy = EndProj.xy * float2(0.5f, -0.5f) + 0.5f; EndProj.xy = saturate(EndProj.xy); EndProj.z = s_position.SampleLevel(smp_nofilter, EndProj.xy, 0).x; Fade = GetBorderAtten(EndProj.xy, 0.001f) > 0.0f; Fade = Fade && EndProj.z > 0.02f && EndProj.z < 1.0f; EndProj.z *= 0.0002f; } #endif } else { Fade = Fade && EndProj.z < 1.0f && EndProj.z > 0.02f; } float3 ReflPoint = GbufferGetPointRealUnjitter(EndProj.xy, EndProj.z); return float4(ReflPoint, Fade); } float4 ScreenSpaceLocalReflections(float3 Point, float3 Reflect) { float2 ReflUV = 0.0; float3 HitPos, TestPos; float L = 0.025f, DeltaL = 0.0f; float Fade = saturate(dot(Reflect, normalize(Point)) * 4.0f); if (Fade < 0.001f) { return 0.0f; } [unroll(15)] for (int i = 0; i < 15; i++) { TestPos = Point + Reflect * L; ReflUV = gbuf_unpack_uv(TestPos); HitPos = gbuf_unpack_position(ReflUV); if (all(min(min(1.f - ReflUV.x, ReflUV.x), min(1.f - ReflUV.y, ReflUV.y)))) { L = length(Point - HitPos); } else { return 0.0f; } } DeltaL = length(HitPos) - length(Point); Fade *= step(-0.4f, DeltaL); float Attention = GetBorderAtten(ReflUV, 0.125f); ReflUV -= s_velocity.SampleLevel(smp_rtlinear, ReflUV, 0).xy * float2(0.5f, -0.5f); Fade *= min(Attention, GetBorderAtten(ReflUV, 0.125f)); #ifdef SKYBLED_FADE float Fog = saturate(length(HitPos) * fog_params.w + fog_params.x); Fade *= 1.f - Fog * Fog; #endif float3 Color = s_image.SampleLevel(smp_rtlinear, ReflUV, 0).xyz; return float4(Color, Fade); } float4 calc_reflections(float2 pos2d, float zpos, float3 vreflect) { float3 Point = zpos * float3(pos2d * pos_decompression_params.zw - pos_decompression_params.xy, 1.0f); return ScreenSpaceLocalReflections(Point, mul((float3x3)m_V, vreflect)); } #endif