diff --git a/Content/Shaders/TAA.flax b/Content/Shaders/TAA.flax index c8e96e9ed..e719850ac 100644 --- a/Content/Shaders/TAA.flax +++ b/Content/Shaders/TAA.flax @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:707c2630916ad6f0d2b604e6cda290fdc24e027a1ee6e435f62e6efb393e8ada -size 3265 +oid sha256:97f24b13b752313dae0eda0540748554fa98ffbb6c05e0fca95ee5f4b37f3a03 +size 4285 diff --git a/Source/Engine/Graphics/PostProcessSettings.h b/Source/Engine/Graphics/PostProcessSettings.h index 17bcdb3a9..ad28f1dce 100644 --- a/Source/Engine/Graphics/PostProcessSettings.h +++ b/Source/Engine/Graphics/PostProcessSettings.h @@ -1889,13 +1889,13 @@ API_STRUCT() struct FLAXENGINE_API AntiAliasingSettings : ISerializable /// The diameter (in texels) inside which jitter samples are spread. Smaller values result in crisper but more aliased output, while larger values result in more stable but blurrier output. /// API_FIELD(Attributes="Limit(0.1f, 1f, 0.001f), EditorOrder(1), PostProcessSetting((int)AntiAliasingSettingsOverride.TAA_JitterSpread), EditorDisplay(null, \"TAA Jitter Spread\")") - float TAA_JitterSpread = 0.75f; + float TAA_JitterSpread = 1.0f; /// /// Controls the amount of sharpening applied to the color buffer. TAA can induce a slight loss of details in high frequency regions. Sharpening alleviates this issue. High values may introduce dark-border artifacts. /// API_FIELD(Attributes="Limit(0, 3f, 0.001f), EditorOrder(2), PostProcessSetting((int)AntiAliasingSettingsOverride.TAA_Sharpness), EditorDisplay(null, \"TAA Sharpness\")") - float TAA_Sharpness = 0.0f; + float TAA_Sharpness = 0.1f; /// /// The blend coefficient for stationary fragments. Controls the percentage of history samples blended into the final color for fragments with minimal active motion. @@ -1907,7 +1907,7 @@ API_STRUCT() struct FLAXENGINE_API AntiAliasingSettings : ISerializable /// The blending coefficient for moving fragments. Controls the percentage of history samples blended into the final color for fragments with significant active motion. /// API_FIELD(Attributes="Limit(0, 0.99f, 0.001f), EditorOrder(4), PostProcessSetting((int)AntiAliasingSettingsOverride.TAA_MotionBlending), EditorDisplay(null, \"TAA Motion Blending\")") - float TAA_MotionBlending = 0.7f; + float TAA_MotionBlending = 0.85f; public: /// diff --git a/Source/Engine/Graphics/RenderView.cpp b/Source/Engine/Graphics/RenderView.cpp index d59a16463..95a09f6c4 100644 --- a/Source/Engine/Graphics/RenderView.cpp +++ b/Source/Engine/Graphics/RenderView.cpp @@ -26,7 +26,7 @@ void RenderView::Prepare(RenderContext& renderContext) TaaFrameIndex = 0; // Calculate jitter - const float jitterSpread = renderContext.List->Settings.AntiAliasing.TAA_JitterSpread / 0.75f; + const float jitterSpread = renderContext.List->Settings.AntiAliasing.TAA_JitterSpread; const float jitterX = (RendererUtils::TemporalHalton(TaaFrameIndex + 1, 2) - 0.5f) * jitterSpread; const float jitterY = (RendererUtils::TemporalHalton(TaaFrameIndex + 1, 3) - 0.5f) * jitterSpread; taaJitter = Float2(jitterX * 2.0f / width, jitterY * 2.0f / height); diff --git a/Source/Engine/Renderer/AntiAliasing/TAA.cpp b/Source/Engine/Renderer/AntiAliasing/TAA.cpp index f48e0955a..e83870d9d 100644 --- a/Source/Engine/Renderer/AntiAliasing/TAA.cpp +++ b/Source/Engine/Renderer/AntiAliasing/TAA.cpp @@ -8,6 +8,7 @@ #include "Engine/Graphics/RenderBuffers.h" #include "Engine/Graphics/RenderTask.h" #include "Engine/Renderer/RenderList.h" +#include "Engine/Renderer/GBufferPass.h" #include "Engine/Engine/Engine.h" PACK_STRUCT(struct Data @@ -18,6 +19,7 @@ PACK_STRUCT(struct Data float StationaryBlending; float MotionBlending; float Dummy0; + GBufferData GBuffer; }); bool TAA::Init() @@ -125,6 +127,7 @@ void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTextu data.Sharpness = settings.TAA_Sharpness; data.StationaryBlending = settings.TAA_StationaryBlending * blendStrength; data.MotionBlending = settings.TAA_MotionBlending * blendStrength; + GBufferPass::SetInputs(renderContext.View, data.GBuffer); const auto cb = _shader->GetShader()->GetCB(0); context->UpdateCB(cb, &data); context->BindCB(0, cb); diff --git a/Source/Shaders/TAA.shader b/Source/Shaders/TAA.shader index 04a5006e2..5ae3444b7 100644 --- a/Source/Shaders/TAA.shader +++ b/Source/Shaders/TAA.shader @@ -1,6 +1,10 @@ // Copyright (c) 2012-2024 Wojciech Figat. All rights reserved. +#define DEBUG_HISTORY_REJECTION 0 +#define NO_GBUFFER_SAMPLING + #include "./Flax/Common.hlsl" +#include "./Flax/GBuffer.hlsl" META_CB_BEGIN(0, Data) float2 ScreenSizeInv; @@ -9,6 +13,7 @@ float Sharpness; float StationaryBlending; float MotionBlending; float Dummy0; +GBufferData GBuffer; META_CB_END Texture2D Input : register(t0); @@ -31,37 +36,42 @@ float4 ClipToAABB(float4 color, float4 minimum, float4 maximum) META_PS(true, FEATURE_LEVEL_ES2) float4 PS(Quad_VS2PS input) : SV_Target0 { + float2 tanHalfFOV = float2(GBuffer.InvProjectionMatrix[0][0], GBuffer.InvProjectionMatrix[1][1]); + + // Calculate previous frame UVs based on per-pixel velocity + float2 velocity = SAMPLE_RT_LINEAR(MotionVectors, input.TexCoord).xy; + float velocityLength = length(velocity); + float2 prevUV = input.TexCoord - velocity; + float prevDepth = LinearizeZ(GBuffer, SAMPLE_RT(Depth, prevUV).r); + // Find the closest pixel in 3x3 neighborhood - float bestDepth = 1; - float2 bestUV = float2(0, 0); + float currentDepth = 1; float4 neighborhoodMin = 100000; float4 neighborhoodMax = -10000; float4 current; float4 neighborhoodSum = 0; + float minDepthDiff = 100000; for (int x = -1; x <= 1; ++x) { for (int y = -1; y <= 1; ++y) { float2 sampleUV = input.TexCoord + float2(x, y) * ScreenSizeInv; - float4 neighbor = SAMPLE_RT_LINEAR(Input, sampleUV); + float4 neighbor = SAMPLE_RT(Input, sampleUV); neighborhoodMin = min(neighborhoodMin, neighbor); neighborhoodMax = max(neighborhoodMax, neighbor); - if (x == 0 && y == 0) - current = neighbor; neighborhoodSum += neighbor; - float depth = SAMPLE_RT(Depth, sampleUV).r; - if (depth < bestDepth) + float neighborDepth = LinearizeZ(GBuffer, SAMPLE_RT(Depth, sampleUV).r); + float depthDiff = abs(max(neighborDepth - prevDepth, 0)); + minDepthDiff = min(minDepthDiff, depthDiff); + if (x == 0 && y == 0) { - bestDepth = depth; - bestUV = sampleUV; + current = neighbor; + currentDepth = neighborDepth; } } } - float2 velocity = SAMPLE_RT_LINEAR(MotionVectors, bestUV).xy; - float velocityLength = length(velocity); - float2 prevUV = input.TexCoord - velocity; // Apply sharpening float4 neighborhoodAvg = neighborhoodSum / 9.0; @@ -76,11 +86,23 @@ float4 PS(Quad_VS2PS input) : SV_Target0 // Calculate history blending factor float motion = saturate(velocityLength * 1000.0f); - float blendfactor = any(abs(prevUV * 2 - 1) >= 1.0f) ? 0.0f : lerp(StationaryBlending, MotionBlending, motion); + float blendfactor = lerp(StationaryBlending, MotionBlending, motion); // Perform linear accumulation of the previous samples with a current one float4 color = lerp(current, history, blendfactor); - color = clamp(color, 0, HDR_CLAMP_MAX); + // Reduce history blend in favor of neighborhood blend when sample has no valid prevous frame data + float miss = any(abs(prevUV * 2 - 1) >= 1.0f) ? 1 : 0; + float currentDepthWorld = currentDepth * GBuffer.ViewFar; + float minDepthDiffWorld = minDepthDiff * GBuffer.ViewFar; + float depthError = tanHalfFOV.x * ScreenSizeInv.x * 200.0f * (currentDepthWorld + 10.0f); + miss += minDepthDiffWorld > depthError ? 1 : 0; + float4 neighborhoodSharp = lerp(neighborhoodAvg, current, 0.5f); +#if DEBUG_HISTORY_REJECTION + neighborhoodSharp = float4(1, 0, 0, 1); +#endif + color = lerp(color, neighborhoodSharp, saturate(miss)); + + color = clamp(color, 0, HDR_CLAMP_MAX); return color; }