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;
}