Temporal AA sharpening

Very nice! I really hope you are able to convince them that its good enough for a general case at some point. I am using your dynamic sharpen in my VR game and I never noticed any introduced jittering, but it surely can’t hurt to have it fixed.

Tell me when you updated the repo with the things you fixed based on the feedback you got on your PR :slight_smile:

Progress on flickering caused by the depth jittering. (look at the right tunnel)

First seconds are default TAA, then sharpen 0.5 for 10 sec, and then with 0.5 with fix applied.
The video is recorded at 640x360 and scaled to show the pixels. (There is some jitter left that is from TAA and not the sharpen.)

Ah, its definitely very visible there and it seems you perfectly fixed it :slight_smile:

You need to zoom 300% to see it clearly. I didn’t notice it before I knew what to look for. :stuck_out_tongue:
But I think I found a good fix. I can’t reproduce any flicker that isn’t already there with default TAA.

Still need some real world translucency examples. Since they don’t show up in the depth pass.

Updated the initial post with the latest changes. Rewrote pretty much everything. :slight_smile:

Very nice. I see you updated the 4.17 branch, but the 4.15 branch is still the “old” version without the jitter fixed, right?

hi, here’s a small contribution from me:

one of hallatore’s contributions was about modifying the CurrentFrameWeight based on the camera movement. this one was the most effective method to reduce ghosting in my use case (or rather, a controllable aliasing vs ghosting tradeoff). however it had 3 downsides:

  • per-frame logspam
  • having to pass stuff from the CPU (via blueprint) to the renderer every frame
  • taking over and invalidating anything you put into both r.TemporalAACurrentFrameWeight and r.Tonemapper.Sharpen

sadly it didn’t make it past that initial blueprint proof of concept, so I’ve just taken the concept and implemented it directly into the engine. however I took just the part about the CurrentFrameWeight and ignored the tonemapper sharpen entirely (so I expect this could work great side-by-side with the latest TemporalAASharpen from this thread

unfortunately I don’t know my way about git and having an own repo/fork etc, so I’ll just post the code here in hopes that someone picks it up
I’ve added a few lines that go before the new code so it’s easier to find in case the line numbers have changed (I’m using 4.17). everything goes in PostProcessTemporalAA.cpp


// existing code, line 41
static TAutoConsoleVariable<float> CVarTemporalAACurrentFrameWeight(
 TEXT("r.TemporalAACurrentFrameWeight"),
 .04f,
 TEXT("Weight of current frame's contribution to the history.  Low values cause blurriness and ghosting, high values fail to hide jittering."),
 ECVF_Scalability | ECVF_RenderThreadSafe);

// add new code
static TAutoConsoleVariable<float> CVarTemporalAACurrentFrameWeightMax (
 TEXT("r.TemporalAACurrentFrameWeightMax"),
 .5f,
 TEXT("Max Weight of current frame's contribution to the history."),
 ECVF_Scalability | ECVF_RenderThreadSafe);

static TAutoConsoleVariable<float> CVarTemporalAAFrameWeightThreshold(
 TEXT("r.TemporalAAFrameWeightThreshold"),
 250.0f,
 TEXT("Threshold to blend between TemporalAACurrentFrameWeight and TemporalAACurrentFrameWeightMax."),
 ECVF_Scalability | ECVF_RenderThreadSafe);


// existing code, line 73
/** Default constructor. */
 FPostProcessTemporalAAPS() {}

// add new code
FVector PrevFrameCameraLoc;


// existing code, line 192
const bool bIgnoreVelocity = (ViewState && ViewState->bSequencerIsPaused);
  SetShaderValue(Context.RHICmdList, ShaderRHI, VelocityScaling, bIgnoreVelocity ? 0.0f : 1.0f);

// remove this code
SetShaderValue(Context.RHICmdList, ShaderRHI, CurrentFrameWeight, CVarTemporalAACurrentFrameWeight.GetValueOnRenderThread());

// add new code
 const float frameBlend = FMath::Min(FVector(Context.View.ViewLocation - PrevFrameCameraLoc).SizeSquared(), CVarTemporalAAFrameWeightThreshold.GetValueOnRenderThread()) / CVarTemporalAAFrameWeightThreshold.GetValueOnRenderThread();
  const float newFrameWeight = FMath::Lerp(CVarTemporalAACurrentFrameWeight.GetValueOnRenderThread(), CVarTemporalAACurrentFrameWeightMax.GetValueOnRenderThread(), frameBlend);
  SetShaderValue(Context.RHICmdList, ShaderRHI, CurrentFrameWeight, newFrameWeight);
  PrevFrameCameraLoc = Context.View.ViewLocation;

an option to make it more friendly to Epic’s policy (and more likely to be accepted as a pull request), would be to only make the blend (vs falling back to the old code) if TemporalAACurrentFrameWeightMax is above 0.0f - and the default value could be set to 0.0f instead, thus disabling the code out of the box

They are both updated. I squashed the commits so you only need to look at one commit. https://github.com/hallatore/UnrealEngine/commit/260ea0123a53166072998feda932d22ee62fb9c6

Ah, thanks! Didn’t notice that. I’m wondering though, what about the movement blur reduction?

Edit: I was just wondering why the BlendFinal isn’t modified, but now I think that your movement blur reduction actually worked differently, right?

I removed that code to focus solely on the sharpening aspect of it. You can still combine it with the code from the forum thread Konflict had.

But your blur reduction worked differently than his I think?

gonna try the latest one now. however I had to add this to PostProcessTemporalAASharpen.cpp for it to compile:


#include "PipelineStateCache.h"

this is on 4.17

I’ve updated the depth difference to use scene depth. This makes objects get the same sharpens regardless of distance.

Change **half MaxDepthDifference = CenterDepth / 150; **at line 81 in PostProcessTemporalAASharpen.usf.
https://github.com/hallatore/UnrealEngine/blob/TAA_Sharpen_4.17/Engine/Shaders/Private/PostProcessTemporalAASharpen.usf#L81

nice, I’ll try that when I get some time (when I get back from vacation)

what about the code I posted related to the CurrentFrameWeight ?

When you lower the currentFrameWeight you get a slightly sharper result. This can cause a un-blurred halo around the character, so it’s not a perfect solution. But it works good enough in many scenarios. In the latest commits epic also did something like this with the TemporalAA shader. It blends based on camera pixel velocity.

I was playing around with keeping a HistorySceneDepth and compare that with the current scene depth. I then had a basic blur of the neighboring pixels and blend between that and the TAA result based on how much they depth match. This seems to cause less artifacts than just ramping up currentFrameWeight. But that was just a proof of concept, so it’s probably not perfect.

With the changes and the different CVar (r.TemporalAASharpen now), are the values referenced earlier in this thread still in the appropriate range?

One more issue: when you squash your commits, it completely erases the history of any changes made in prior iterations (unless you stored them in another branch). Which means that, at least for folks like me that manage a fairly heavily-customized fork of UE, figuring out what changes to undo is kind of a pain, as it requires searching my own repo’s history to see the series of related commits. In this case, there was only the issue of a CVar being not taken care of, but: in general, squashing commits is not super helpful.

It’s around the same as before, just a slight change.

Not going to squash any more commits. It was mostly for the initial version. :slight_smile:

Any chance of a pull request ? This looks like completely gold.