Fix Temporal Anti Aliasing ghosting and improve quality of blending
#1786
This commit is contained in:
BIN
Content/Shaders/TAA.flax
(Stored with Git LFS)
BIN
Content/Shaders/TAA.flax
(Stored with Git LFS)
Binary file not shown.
@@ -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.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
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:
|
||||
/// <summary>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user