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