Temporal AA sharpening

Its more than 200 lines of changes, so a lot of stuff can have changed there between 4.15 and 4.18.

That’s true. But If it’s just a shader compiler error than it’s most likely easy to fix. Probably duplicate or unknown function declaration.
If the editor just crashes on the other hand… :stuck_out_tongue:

This looks very interesting! The bluriness of TXAA really ruins the feel of a scene. I hope this or a variation of it makes it into the engine.

I’ve squashed the commits so it’s easier to see what you need to copy etc.

I may have stumbled onto a bug after my integration, but I’m trying to figure out if it was just a really bizarre random thing that’s occurring or a legit bug (deleted my DDC, so waiting on that to be sure).

I have a fairly non-standard setup, but it looked like it was suddenly obscuring my sky entirely (trueSKY)? Anyway, I’m working on verifying.

I have a question! :cool:
Which one is default TAA and screen percentage set to 150, and which is Dynamic with only screen percentage 100. A or B?

Please send me some screenshots if you can.

This code should ignore the sky. Let me know if it helps, or if it was just a random thing.


void MainDynamicSharpenTemporalAAPS(
	in noperspective float2 UV: TEXCOORD0,
	float4 SvPosition : SV_POSITION,
	out float4 OutColor : SV_Target0 )
{
	float2 FullResUV = SvPosition.xy * PostprocessInput0Size.zw;
	float4 CenterColor = PostprocessInput0.SampleLevel( PostprocessInput0Sampler, UV, 0 );
	half CenterDepth = CalcSceneDepth(FullResUV);
	half DepthLimit = saturate(1 - CenterDepth / 1000000);

	float4 DepthQuad = GatherSceneDepth(UV, PostprocessInput1Size.zw);
	half D1 = abs(CenterDepth - DepthQuad.x);
	half D2 = abs(CenterDepth - DepthQuad.y);
	half D3 = abs(CenterDepth - DepthQuad.z);
	half D4 = abs(CenterDepth - DepthQuad.w);
	half NeighborDepth = max(max(D1, D2), max(D3, D4));

	half3 C1 = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0, int2(-1,  0)).rgb;
	half3 C2 = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0, int2( 1,  0)).rgb;
	half3 C3 = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0, int2(-1, -1)).rgb;
	half3 C4 = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0, int2(-1,  1)).rgb;

	half L1 = LuminanceDifference(C1.rgb, CenterColor.rgb);
	half L2 = LuminanceDifference(C2.rgb, CenterColor.rgb);
	half L3 = LuminanceDifference(C3.rgb, CenterColor.rgb);
	half L4 = LuminanceDifference(C4.rgb, CenterColor.rgb);
	half NeighborDifference = max(max(L1, L2), max(L3, L4));
	
	// Fade sharpen based on depth difference in world units. (0...5)
	half DepthFactor = saturate(1 - NeighborDepth / 5.0);

	// Fade sharpen based on luminance difference in percentage. (0...5)
	half LuminanceDifferenceFactor = saturate(1 - NeighborDifference * 20.0);

	half LerpFactor = -DynamicSharpen * DepthFactor * LuminanceDifferenceFactor;
	half3 DeltaColor = (C1 + C2 + C3 + C4) - CenterColor.rgb * 4;
	CenterColor.rgb += -DeltaColor * DynamicSharpen * DepthFactor * LuminanceDifferenceFactor * DepthLimit;
	OutColor = CenterColor;
}

Here is an image visualizing the dynamic sharpening strength. It goes from white (no sharpen) to red (max sharpen).
Comparison: Imgsli

36ba6d14ec3bd7ba4f9801d0cb0c32ef72f8e96e.jpeg

I’d say A is screen percentage set to 150 :wink:

On the left the grass looks better, but on the right the rock in the background looks better.

Boosh, here’s my scene with r.TemporalAADynamicSharpen set to 0.75. Tried to find a section with some more prominent lines (the grates on the gas tank); I dig it. It looks a fair bit better than my prior solution (some sharpening + a dedicated post pass pre-tonemapper that just sharpened based on luminosity), so yay.

Thanks for this. <3

f61c507fad7af75e16ac03cc4971c0db3954f106.jpeg

Glad you like it! :slight_smile:
PS: Can’t see any image though.

Here is the latest code btw. Just some minor tweaks.
Personally I found values between 0.2 and 0.4 to be closest to the reference. But it’s all about personal preference, and the code seems to scale pretty well to extreme values.


void MainDynamicSharpenTemporalAAPS(
	in noperspective float2 UV: TEXCOORD0,
	float4 SvPosition : SV_POSITION,
	out float4 OutColor : SV_Target0 )
{
	float4 CenterColor = PostprocessInput0.SampleLevel( PostprocessInput0Sampler, UV, 0 );

	if (DynamicSharpen <= 0)
	{
		OutColor = CenterColor;
		return;
	}

	float2 FullResUV = SvPosition.xy * PostprocessInput0Size.zw;
	half CenterDepth = CalcSceneDepth(FullResUV);

	float4 DepthQuad = GatherSceneDepth(UV, PostprocessInput1Size.zw);
	half D1 = abs(CenterDepth - DepthQuad.x);
	half D2 = abs(CenterDepth - DepthQuad.y);
	half D3 = abs(CenterDepth - DepthQuad.z);
	half D4 = abs(CenterDepth - DepthQuad.w);
	half NeighborDepth = max(max(D1, D2), max(D3, D4));

	half3 C1 = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0, int2(-1,  0)).rgb;
	half3 C2 = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0, int2( 1,  0)).rgb;
	half3 C3 = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0, int2(-1, -1)).rgb;
	half3 C4 = PostprocessInput0.SampleLevel(PostprocessInput0Sampler, UV, 0, int2(-1,  1)).rgb;

	half L1 = LuminanceDifference(C1.rgb, CenterColor.rgb);
	half L2 = LuminanceDifference(C2.rgb, CenterColor.rgb);
	half L3 = LuminanceDifference(C3.rgb, CenterColor.rgb);
	half L4 = LuminanceDifference(C4.rgb, CenterColor.rgb);
	half NeighborDifference = max(max(L1, L2), max(L3, L4));
	
	// Fade sharpen based on depth difference in world units. (0...15)
	half DepthFactor = saturate(1 - NeighborDepth / 15.0);

	// Fade sharpen based on luminance difference in percentage. (0...5)
	half LuminanceDifferenceFactor = saturate(1 - NeighborDifference * 20.0);

	// Ignore the sky since depth info will be wrong.
	half DepthLimit = saturate(1 - CenterDepth / 1000000);

	half LerpFactor = -DynamicSharpen * DepthFactor * LuminanceDifferenceFactor;
	half3 DeltaColor = (C1 + C2 + C3 + C4) - CenterColor.rgb * 4;	
	CenterColor.rgb += -DeltaColor * DynamicSharpen * DepthFactor * LuminanceDifferenceFactor * DepthLimit;
	OutColor = CenterColor;
}

Fixed the image. :slight_smile:

That image is extremely noisy, is that caused by this change or something else?

Nice! :slight_smile:
I see you like quite a bit of sharpen. I bet the tonemap.sharpen creates a few artifacts with the same strength.

0.75 is a huge value. I use 0.25 - 0.30 to get close to my reference image.
0.25 - 0.30 is just to combat the slight blur from TAA, not make it sharper than original. But I bet some feel it looks nice even higher.

Made a video visualizing the strength value from white to red. More red means sharper.

Noisy is largely due to the noise post settings. It’s still being tuned off and on.

And, yeah, just realized I have the tonemap sharpening still set as well (and my TAA samples were too high). Also just reduced the r.TemporalAADynamicSharpen to 0.3. Reduced the tonemap sharpening and the TAA sample count and this is that:

b69704f683fb490fe73012e2cf827ec4b1b0d894.jpeg

(I have a pretty intense post stack and custom changes/integrations, so getting the whole composition right takes… iteration)

Was still looking at it. Pushed it now. :slight_smile:

https://github.com/hallatore/UnrealEngine/tree/TAA_Sharpen