diff --git a/Content/Shaders/SSR.flax b/Content/Shaders/SSR.flax index 116d1415b..7e249afb5 100644 --- a/Content/Shaders/SSR.flax +++ b/Content/Shaders/SSR.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8047ea5ef2604e1111db1c559def9a63700bbd88a0f6f32264f7490a14c8c86 -size 13442 +oid sha256:fd2d0c05638d8e4c6c307d70d57a29f2475c9c0d8dfb43f8b8ff09189e4a62bb +size 9341 diff --git a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp index 2b226af85..10b9636c8 100644 --- a/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp +++ b/Source/Engine/Renderer/ScreenSpaceReflectionsPass.cpp @@ -42,13 +42,10 @@ PACK_STRUCT(struct Data float TemporalScale; float RayTraceStep; - float NoTemporalEffect; + float TemporalEffect; float Intensity; float FadeOutDistance; - Vector3 Dummy0; - float InvFadeDistance; - Matrix ViewMatrix; Matrix ViewProjectionMatrix; }); @@ -248,11 +245,10 @@ void ScreenSpaceReflectionsPass::Render(RenderContext& renderContext, GPUTexture data.MaxColorMiplevel = settings.UseColorBufferMips ? (float)colorBufferMips - 2.0f : 0.0f; data.RayTraceStep = static_cast(settings.DepthResolution) / (float)width; data.Intensity = settings.Intensity; - data.FadeOutDistance = settings.FadeOutDistance; - data.InvFadeDistance = 1.0f / settings.FadeDistance; + data.FadeOutDistance = Math::Max(settings.FadeOutDistance, 100.0f); data.TemporalScale = settings.TemporalScale; data.TemporalResponse = settings.TemporalResponse; - data.NoTemporalEffect = useTemporal ? 0.0f : 1.0f; + data.TemporalEffect = useTemporal ? 1.0f : 0.0f; if (useTemporal) { const float time = Time::Draw.UnscaledTime.GetTotalSeconds(); diff --git a/Source/Shaders/SSR.hlsl b/Source/Shaders/SSR.hlsl index 838cf9482..86d8c5f6b 100644 --- a/Source/Shaders/SSR.hlsl +++ b/Source/Shaders/SSR.hlsl @@ -52,7 +52,7 @@ float RayAttenBorder(float2 pos, float value) // Screen Space Reflection ray tracing utility. // Returns: xy: hitUV, z: hitMask, where hitUV is the result UV of hit pixel, hitMask is the normalized sample weight (0 if no hit). -float3 TraceSceenSpaceReflection(float2 uv, GBufferSample gBuffer, Texture2D depthBuffer, float3 viewPos, float4x4 viewMatrix, float4x4 viewProjectionMatrix, float stepSize, float maxSamples = 20, bool temporal = true, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f) +float3 TraceSceenSpaceReflection(float2 uv, GBufferSample gBuffer, Texture2D depthBuffer, float3 viewPos, float4x4 viewMatrix, float4x4 viewProjectionMatrix, float stepSize, float maxSamples = 20, bool temporal = false, float temporalTime = 0.0f, float worldAntiSelfOcclusionBias = 0.1f, float brdfBias = 0.82f, float drawDistance = 5000.0f, float roughnessThreshold = 0.4f, float edgeFade = 0.1f) { // Reject invalid pixels if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > roughnessThreshold || gBuffer.ViewPos.z > drawDistance) diff --git a/Source/Shaders/SSR.shader b/Source/Shaders/SSR.shader index 659290afe..5893a6ad1 100644 --- a/Source/Shaders/SSR.shader +++ b/Source/Shaders/SSR.shader @@ -1,13 +1,10 @@ // Copyright (c) 2012-2022 Wojciech Figat. All rights reserved. #include "./Flax/Common.hlsl" -#include "./Flax/BRDF.hlsl" -#include "./Flax/Random.hlsl" -#include "./Flax/MonteCarlo.hlsl" #include "./Flax/LightingCommon.hlsl" -#include "./Flax/GBuffer.hlsl" #include "./Flax/ReflectionsCommon.hlsl" -#include "./Flax/BRDF.hlsl" +#include "./Flax/SSR.hlsl" +#include "./Flax/GBuffer.hlsl" // Enable/disable luminance filter to reduce reflections highlights #define SSR_REDUCE_HIGHLIGHTS 1 @@ -34,13 +31,10 @@ float TemporalResponse; float TemporalScale; float RayTraceStep; -float NoTemporalEffect; +float TemporalEffect; float Intensity; float FadeOutDistance; -float3 Dummy0; -float InvFadeDistance; - float4x4 ViewMatrix; float4x4 ViewProjectionMatrix; @@ -52,50 +46,6 @@ Texture2D Texture0 : register(t4); Texture2D Texture1 : register(t5); Texture2D Texture2 : register(t6); -float max2(float2 v) -{ - return max(v.x, v.y); -} - -float2 RandN2(float2 pos, float2 random) -{ - return frac(sin(dot(pos.xy + random, float2(12.9898, 78.233))) * float2(43758.5453, 28001.8384)); -} - -// 1:-1 to 0:1 -float2 ClipToUv(float2 clipPos) -{ - return clipPos * float2(0.5, -0.5) + float2(0.5, 0.5); -} - -// go into clip space (-1:1 from bottom/left to up/right) -float3 ProjectWorldToClip(float3 wsPos) -{ - float4 clipPos = mul(float4(wsPos, 1), ViewProjectionMatrix); - return clipPos.xyz / clipPos.w; -} - -// go into UV space. (0:1 from top/left to bottom/right) -float3 ProjectWorldToUv(float3 wsPos) -{ - float3 clipPos = ProjectWorldToClip(wsPos); - return float3(ClipToUv(clipPos.xy), clipPos.z); -} - -float4 TangentToWorld(float3 N, float4 H) -{ - float3 upVector = abs(N.z) < 0.999 ? float3(0.0, 0.0, 1.0) : float3(1.0, 0.0, 0.0); - float3 T = normalize(cross(upVector, N)); - float3 B = cross(N, T); - return float4((T * H.x) + (B * H.y) + (N * H.z), H.w); -} - -float RayAttenBorder(float2 pos, float value) -{ - float borderDist = min(1.0 - max(pos.x, pos.y), min(pos.x, pos.y)); - return saturate(borderDist > value ? 1.0 : borderDist / value); -} - // Pixel Shader for screen space reflections rendering - combine pass META_PS(true, FEATURE_LEVEL_ES2) float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0 @@ -135,112 +85,15 @@ float4 PS_CombinePass(Quad_VS2PS input) : SV_Target0 META_PS(true, FEATURE_LEVEL_ES2) float4 PS_RayTracePass(Quad_VS2PS input) : SV_Target0 { - float2 uv = input.TexCoord; - // Sample GBuffer GBufferData gBufferData = GetGBufferData(); - GBufferSample gBuffer = SampleGBuffer(gBufferData, uv); + GBufferSample gBuffer = SampleGBuffer(gBufferData, input.TexCoord); - // Reject invalid pixels - if (gBuffer.ShadingModel == SHADING_MODEL_UNLIT || gBuffer.Roughness > RoughnessFade || gBuffer.ViewPos.z > FadeOutDistance) - return 0; - - // Calculate view space normal vector - float3 normalVS = mul(gBuffer.Normal, (float3x3)ViewMatrix); - - // Randomize it a little - float2 jitter = RandN2(uv, TemporalTime); - float2 Xi = jitter; - Xi.y = lerp(Xi.y, 0.0, BRDFBias); - - float4 H = TangentToWorld(gBuffer.Normal, ImportanceSampleGGX(Xi, gBuffer.Roughness)); - if (NoTemporalEffect) - H.xyz = gBuffer.Normal; - - // Calculate normalized view space reflection vector - float3 reflectVS = normalize(reflect(gBuffer.ViewPos, normalVS)); - if (gBuffer.ViewPos.z < 1.0 && reflectVS.z < 0.4) - return 0; - - float3 viewWS = normalize(gBuffer.WorldPos - GBuffer.ViewPos); - float3 reflectWS = reflect(viewWS, H.xyz); - - float3 startWS = gBuffer.WorldPos + gBuffer.Normal * WorldAntiSelfOcclusionBias; - float3 startUV = ProjectWorldToUv(startWS); - float3 endUV = ProjectWorldToUv(startWS + reflectWS); - - float3 rayUV = endUV - startUV; - rayUV *= RayTraceStep / max2(abs(rayUV.xy)); - float3 startUv = startUV + rayUV * 2; - - float3 currOffset = startUv; - float3 rayStep = rayUV * 2; - - // Calculate number of samples - float3 samplesToEdge = ((sign(rayStep.xyz) * 0.5 + 0.5) - currOffset.xyz) / rayStep.xyz; - samplesToEdge.x = min(samplesToEdge.x, min(samplesToEdge.y, samplesToEdge.z)) * 1.05f; - float numSamples = min(MaxTraceSamples, samplesToEdge.x); - rayStep *= samplesToEdge.x / numSamples; - - // Calculate depth difference error - float depthDiffError = 1.3f * abs(rayStep.z); - - // Ray trace - float currSampleIndex = 0; - float currSample, depthDiff; - LOOP - while (currSampleIndex < numSamples) - { - // Sample depth buffer and calculate depth difference - currSample = SampleZ(currOffset.xy); - depthDiff = currOffset.z - currSample; - - // Check intersection - if (depthDiff >= 0) - { - if (depthDiff < depthDiffError) - { - break; - } - else - { - currOffset -= rayStep; - rayStep *= 0.5; - } - } - - // Move forward - currOffset += rayStep; - currSampleIndex++; - } - - // Check if has valid result after ray tracing - if (currSampleIndex >= numSamples) - { - // All samples done but no result - return 0; - } - - float2 hitUV = currOffset.xy; - - // Fade rays close to screen edge - const float fadeStart = 0.9f; - const float fadeEnd = 1.0f; - const float fadeDiffRcp = 1.0f / (fadeEnd - fadeStart); - float2 boundary = abs(hitUV - float2(0.5f, 0.5f)) * 2.0f; - float fadeOnBorder = 1.0f - saturate((boundary.x - fadeStart) * fadeDiffRcp); - fadeOnBorder *= 1.0f - saturate((boundary.y - fadeStart) * fadeDiffRcp); - fadeOnBorder = smoothstep(0.0f, 1.0f, fadeOnBorder); - fadeOnBorder *= RayAttenBorder(hitUV, EdgeFadeFactor); - - // Fade rays on high roughness - float roughnessFade = saturate((RoughnessFade - gBuffer.Roughness) * 20); - - // Fade on distance - float distanceFade = saturate((FadeOutDistance - gBuffer.ViewPos.z) * InvFadeDistance); + // Trace depth buffer to find intersection + float3 hit = TraceSceenSpaceReflection(input.TexCoord, gBuffer, Depth, gBufferData.ViewPos, ViewMatrix, ViewProjectionMatrix, RayTraceStep, MaxTraceSamples, TemporalEffect, TemporalTime, WorldAntiSelfOcclusionBias, BRDFBias, FadeOutDistance, RoughnessFade, EdgeFadeFactor); // Output: xy: hitUV, z: hitMask, w: unused - return float4(hitUV, fadeOnBorder * roughnessFade * distanceFade * Intensity, 0); + return float4(hit.xy, hit.z * Intensity, 0); } #ifndef RESOLVE_SAMPLES