From cf3145273faa74ba5d12e604d72623f06589a3dc Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Tue, 19 Mar 2024 16:02:50 +0100 Subject: [PATCH] Fix TAA jitter in post-resolve passes such as editor primitives and debug gizmos --- Source/Engine/Debug/DebugDraw.cpp | 3 +- Source/Engine/Graphics/RenderView.cpp | 37 +++++++++++++++++++++ Source/Engine/Graphics/RenderView.h | 24 ++++++++++++- Source/Engine/Renderer/AntiAliasing/TAA.cpp | 3 ++ Source/Engine/Renderer/RenderList.cpp | 1 + Source/Engine/Renderer/Renderer.cpp | 2 +- 6 files changed, 67 insertions(+), 3 deletions(-) diff --git a/Source/Engine/Debug/DebugDraw.cpp b/Source/Engine/Debug/DebugDraw.cpp index 46b15a6e2..b0164124c 100644 --- a/Source/Engine/Debug/DebugDraw.cpp +++ b/Source/Engine/Debug/DebugDraw.cpp @@ -739,6 +739,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe } Context->LastViewPos = view.Position; Context->LastViewProj = view.Projection; + TaaJitterRemoveContext taaJitterRemove(view); // Fallback to task buffers if (target == nullptr && renderContext.Task) @@ -766,7 +767,7 @@ void DebugDraw::Draw(RenderContext& renderContext, GPUTextureView* target, GPUTe const auto cb = DebugDrawShader->GetShader()->GetCB(0); Data data; Matrix vp; - Matrix::Multiply(view.View, view.NonJitteredProjection, vp); + Matrix::Multiply(view.View, view.Projection, vp); Matrix::Transpose(vp, data.ViewProjection); data.EnableDepthTest = enableDepthTest; context->UpdateCB(cb, &data); diff --git a/Source/Engine/Graphics/RenderView.cpp b/Source/Engine/Graphics/RenderView.cpp index d59a16463..f72c8f406 100644 --- a/Source/Engine/Graphics/RenderView.cpp +++ b/Source/Engine/Graphics/RenderView.cpp @@ -18,6 +18,7 @@ void RenderView::Prepare(RenderContext& renderContext) // Check if use TAA (need to modify the projection matrix) Float2 taaJitter; NonJitteredProjection = Projection; + IsTaaResolved = false; if (renderContext.List->Setup.UseTemporalAAJitter) { // Move to the next frame @@ -82,6 +83,18 @@ void RenderView::PrepareCache(const RenderContext& renderContext, float width, f MainScreenSize = mainView->ScreenSize; } +void RenderView::UpdateCachedData() +{ + Matrix::Invert(View, IV); + Matrix::Invert(Projection, IP); + Matrix viewProjection; + Matrix::Multiply(View, Projection, viewProjection); + Frustum.SetMatrix(viewProjection); + Matrix::Invert(viewProjection, IVP); + CullingFrustum = Frustum; + NonJitteredProjection = Projection; +} + void RenderView::SetUp(const Matrix& viewProjection) { // Copy data @@ -201,3 +214,27 @@ void RenderView::GetWorldMatrix(const Transform& transform, Matrix& world) const const Float3 translation = transform.Translation - Origin; Matrix::Transformation(transform.Scale, transform.Orientation, translation, world); } + +TaaJitterRemoveContext::TaaJitterRemoveContext(const RenderView& view) +{ + if (view.IsTaaResolved) + { + // Cancel-out sub-pixel jitter when drawing geometry after TAA has been resolved + _view = (RenderView*)&view; + _prevProjection = view.Projection; + _prevNonJitteredProjection = view.NonJitteredProjection; + _view->Projection = _prevNonJitteredProjection; + _view->UpdateCachedData(); + } +} + +TaaJitterRemoveContext::~TaaJitterRemoveContext() +{ + if (_view) + { + // Restore projection + _view->Projection = _prevProjection; + _view->UpdateCachedData(); + _view->NonJitteredProjection = _prevNonJitteredProjection; + } +} diff --git a/Source/Engine/Graphics/RenderView.h b/Source/Engine/Graphics/RenderView.h index d73b45c53..0b37e8b28 100644 --- a/Source/Engine/Graphics/RenderView.h +++ b/Source/Engine/Graphics/RenderView.h @@ -117,6 +117,11 @@ public: /// API_FIELD() bool IsCullingDisabled = false; + /// + /// True if TAA has been resolved when rendering view and frame doesn't contain jitter anymore. Rendering geometry after this point should not use jitter anymore (eg. editor gizmos or custom geometry as overlay). + /// + API_FIELD() bool IsTaaResolved = false; + /// /// The static flags mask used to hide objects that don't have a given static flags. Eg. use StaticFlags::Lightmap to render only objects that can use lightmap. /// @@ -160,7 +165,7 @@ public: API_FIELD() DEPRECATED float ShadowModelLODDistanceFactor = 1.0f; /// - /// The Temporal Anti-Aliasing jitter frame index. + /// Temporal Anti-Aliasing jitter frame index. /// API_FIELD() int32 TaaFrameIndex = 0; @@ -261,6 +266,11 @@ public: RenderView& operator=(const RenderView& other) = default; PRAGMA_ENABLE_DEPRECATION_WARNINGS + /// + /// Updates the cached data for the view (inverse matrices, etc.). + /// + void UpdateCachedData(); + // Set up view with custom params // @param viewProjection View * Projection matrix void SetUp(const Matrix& viewProjection); @@ -344,3 +354,15 @@ public: world.M43 -= Origin.Z; } }; + +// Removes TAA jitter from the RenderView when drawing geometry after TAA has been resolved to prevent unwanted jittering. +struct TaaJitterRemoveContext +{ +private: + RenderView* _view = nullptr; + Matrix _prevProjection, _prevNonJitteredProjection; + +public: + TaaJitterRemoveContext(const RenderView& view); + ~TaaJitterRemoveContext(); +}; diff --git a/Source/Engine/Renderer/AntiAliasing/TAA.cpp b/Source/Engine/Renderer/AntiAliasing/TAA.cpp index f48e0955a..22ed7a806 100644 --- a/Source/Engine/Renderer/AntiAliasing/TAA.cpp +++ b/Source/Engine/Renderer/AntiAliasing/TAA.cpp @@ -146,4 +146,7 @@ void TAA::Render(const RenderContext& renderContext, GPUTexture* input, GPUTextu context->Draw(output); renderContext.Buffers->TemporalAA = outputHistory; } + + // Mark TAA jitter as resolved for future drawing + (bool&)renderContext.View.IsTaaResolved = true; } diff --git a/Source/Engine/Renderer/RenderList.cpp b/Source/Engine/Renderer/RenderList.cpp index af2495b67..01da9e2ea 100644 --- a/Source/Engine/Renderer/RenderList.cpp +++ b/Source/Engine/Renderer/RenderList.cpp @@ -652,6 +652,7 @@ void RenderList::ExecuteDrawCalls(const RenderContext& renderContext, DrawCallsL const auto* batchesData = list.Batches.Get(); const auto context = GPUDevice::Instance->GetMainContext(); bool useInstancing = list.CanUseInstancing && CanUseInstancing(renderContext.View.Pass) && GPUDevice::Instance->Limits.HasInstancing; + TaaJitterRemoveContext taaJitterRemove(renderContext.View); // Clear SR slots to prevent any resources binding issues (leftovers from the previous passes) context->ResetSR(); diff --git a/Source/Engine/Renderer/Renderer.cpp b/Source/Engine/Renderer/Renderer.cpp index 3246b6d85..f3c4ac6d2 100644 --- a/Source/Engine/Renderer/Renderer.cpp +++ b/Source/Engine/Renderer/Renderer.cpp @@ -612,7 +612,7 @@ void RenderInner(SceneRenderTask* task, RenderContext& renderContext, RenderCont // Color Grading LUT generation auto colorGradingLUT = ColorGradingPass::Instance()->RenderLUT(renderContext); - // Post processing + // Post-processing EyeAdaptationPass::Instance()->Render(renderContext, frameBuffer); PostProcessingPass::Instance()->Render(renderContext, frameBuffer, tempBuffer, colorGradingLUT); RenderTargetPool::Release(colorGradingLUT);