DLAA

Started by
7 comments, last by haxpor_ 12 years ago
Hi All,

I've been experimenting with full-screen AA techniques, and DLAA looked like a promising technique from what the developers said and the results in TFU2.
I had been looking for details on the this technique for a while but there isn't much out there, so I've set out to uncover the technique. Here are my results:

The technique is based on detecting short and long - vertical and horizontal edges.
1) The first pass does a simple color average space edge detection.
2) The second pass does localized edge detection and blurs directionally (vertically and horizontally).
Next it determines if the current edge is a long one, in which case it does a wider vertical and horizontal direction blur

that's about it.

The following pixel shader produces pretty much the same output as the 360 version of TFU2.
Performance is around ~3.2 ms in a X360 class GPU.


#define PIXEL_SIZE float2(1.0/1280, 1.0/720)

float4 sampleOffseted(const in sampler2D tex, const in float2 texCoord, const float2 pixelOffset )
{
return tex2D(tex, texCoord + pixelOffset * PIXEL_SIZE);
}

float3 avg(const in float3 value)
{
static const float oneThird = 1.0 / 3.0;
return dot(value.xyz, float3(oneThird, oneThird, oneThird) );
}

float4 firsPassEdgeDetect( float2 texCoord : TEXCOORD0 ) : COLOR
{
float4 sCenter = sampleOffseted(Texture0, texCoord, float2( 0.0, 0.0) );
float4 sUpLeft = sampleOffseted(Texture0, texCoord, float2(-0.5, -0.5) );
float4 sUpRight = sampleOffseted(Texture0, texCoord, float2( 0.5, -0.5) );
float4 sDownLeft = sampleOffseted(Texture0, texCoord, float2(-0.5, 0.5) );
float4 sDownRight = sampleOffseted(Texture0, texCoord, float2( 0.5, 0.5) );

float4 diff = abs( ((sUpLeft + sUpRight + sDownLeft + sDownRight) * 4.0) - (sCenter * 16.0) );
float edgeMask = avg(diff.xyz);

return float4(sCenter.rgb, edgeMask);
}


float4 secondPassEdgeDetectAndBlur( float2 texCoord : TEXCOORD0 ) : COLOR
{
// short edges
float4 sampleCenter = sampleOffseted(Texture0, texCoord.xy, float2( 0.0, 0.0) );
float4 sampleHorizNeg0 = sampleOffseted(Texture0, texCoord.xy, float2(-1.5, 0.0) );
float4 sampleHorizPos0 = sampleOffseted(Texture0, texCoord.xy, float2( 1.5, 0.0) );
float4 sampleVertNeg0 = sampleOffseted(Texture0, texCoord.xy, float2( 0.0, -1.5) );
float4 sampleVertPos0 = sampleOffseted(Texture0, texCoord.xy, float2( 0.0, 1.5) );

float4 sumHoriz = sampleHorizNeg0 + sampleHorizPos0;
float4 sumVert = sampleVertNeg0 + sampleVertPos0;

float4 diffToCenterHoriz = abs( sumHoriz - (2.0 * sampleCenter) ) / 2.0;
float4 diffToCenterVert = abs( sumHoriz - (2.0 * sampleCenter) ) / 2.0;

float valueEdgeHoriz = avg( diffToCenterHoriz.xyz );
float valueEdgeVert = avg( diffToCenterVert.xyz );

float edgeDetectHoriz = saturate( (3.0 * valueEdgeHoriz) - 0.1);
float edgeDetectVert = saturate( (3.0 * valueEdgeVert) - 0.1);

float4 avgHoriz = ( sumHoriz + sampleCenter) / 3.0;
float4 avgVert = ( sumVert + sampleCenter) / 3.0;

float valueHoriz = avg( avgHoriz.xyz );
float valueVert = avg( avgVert.xyz );

float blurAmountHoriz = saturate( edgeDetectHoriz / valueHoriz );
float blurAmountVert = saturate( edgeDetectVert / valueVert );

float4 aaResult = lerp( sampleCenter, avgHoriz, blurAmountHoriz );
aaResult = lerp( aaResult, avgVert, blurAmountVert );

// long edges
float4 sampleVertNeg1 = sampleOffseted(Texture0, texCoord.xy, float2(0.0, -3.5) );
float4 sampleVertNeg2 = sampleOffseted(Texture0, texCoord.xy, float2(0.0, -7.5) );
float4 sampleVertPos1 = sampleOffseted(Texture0, texCoord.xy, float2(0.0, 3.5) );
float4 sampleVertPos2 = sampleOffseted(Texture0, texCoord.xy, float2(0.0, 7.5) );

float4 sampleHorizNeg1 = sampleOffseted(Texture0, texCoord.xy, float2(-3.5, 0.0) );
float4 sampleHorizNeg2 = sampleOffseted(Texture0, texCoord.xy, float2(-7.5, 0.0) );
float4 sampleHorizPos1 = sampleOffseted(Texture0, texCoord.xy, float2( 3.5, 0.0) );
float4 sampleHorizPos2 = sampleOffseted(Texture0, texCoord.xy, float2( 7.5, 0.0) );

float pass1EdgeAvgHoriz = ( sampleHorizNeg2.a + sampleHorizNeg1.a + sampleCenter.a + sampleHorizPos1.a + sampleHorizPos2.a ) / 5.0;
float pass1EdgeAvgVert = ( sampleVertNeg2.a + sampleVertNeg1.a + sampleCenter.a + sampleVertPos1.a + sampleVertPos2.a ) / 5.0;
pass1EdgeAvgHoriz = saturate( pass1EdgeAvgHoriz * 2.0f - 1.0f );
pass1EdgeAvgVert = saturate( pass1EdgeAvgVert * 2.0f - 1.0f );
float longEdge = max( pass1EdgeAvgHoriz, pass1EdgeAvgVert);

if ( longEdge > 0 )
{
float4 avgHorizLong = ( sampleHorizNeg2 + sampleHorizNeg1 + sampleCenter + sampleHorizPos1 + sampleHorizPos2 ) / 5.0;
float4 avgVertLong = ( sampleVertNeg2 + sampleVertNeg1 + sampleCenter + sampleVertPos1 + sampleVertPos2 ) / 5.0;
float valueHorizLong = avg(avgHorizLong.xyz);
float valueVertLong = avg(avgVertLong.xyz);

float4 sampleLeft = sampleOffseted(Texture0, texCoord.xy, float2(-1.0, 0.0) );
float4 sampleRight = sampleOffseted(Texture0, texCoord.xy, float2( 1.0, 0.0) );
float4 sampleUp = sampleOffseted(Texture0, texCoord.xy, float2( 0.0, -1.0) );
float4 sampleDown = sampleOffseted(Texture0, texCoord.xy, float2( 0.0, 1.0) );

float valueCenter = avg(sampleCenter.xyz);
float valueLeft = avg(sampleLeft.xyz);
float valueRight = avg(sampleRight.xyz);
float valueTop = avg(sampleUp.xyz);
float valueBottom = avg(sampleDown.xyz);

float4 diffToCenter = valueCenter - float4(valueLeft, valueTop, valueRight, valueBottom);
float blurAmountLeft = saturate( 0.0 + ( valueVertLong - valueLeft ) / diffToCenter.x );
float blurAmountUp = saturate( 0.0 + ( valueHorizLong - valueTop ) / diffToCenter.y );
float blurAmountRight= saturate( 1.0 + ( valueVertLong - valueCenter ) / diffToCenter.z );
float blurAmountDown = saturate( 1.0 + ( valueHorizLong - valueCenter ) / diffToCenter.w );

float4 blurAmounts = float4( blurAmountLeft, blurAmountRight, blurAmountUp, blurAmountDown );
blurAmounts = (blurAmounts == float4(0.0, 0.0, 0.0, 0.0)) ? float4(1.0, 1.0, 1.0, 1.0) : blurAmounts;

float4 longBlurHoriz = lerp( sampleLeft, sampleCenter, blurAmounts.x );
longBlurHoriz = lerp( sampleRight, longBlurHoriz, blurAmounts.y );
float4 longBlurVert = lerp( sampleUp, sampleCenter, blurAmounts.z );
longBlurVert = lerp( sampleDown, longBlurVert, blurAmounts.w );

aaResult = lerp( aaResult, longBlurHoriz, pass1EdgeAvgVert);
aaResult = lerp( aaResult, longBlurVert, pass1EdgeAvgHoriz);
}

return float4(aaResult.rgb, 1.0f);
}



Hope it helps.
Advertisement
Example images would be most appreciated. ;)

[Hardware:] Falcon Northwest Tiki, Windows 7, Nvidia Geforce GTX 970

[Websites:] Development Blog | LinkedIn
[Unity3D :] Alloy Physical Shader Framework

Thank you for the code.

Could you speak a little more about this? I mean advantages and disadvantages over MLAA and so.


Thanks in advance.

Thank you for the code.

Could you speak a little more about this? I mean advantages and disadvantages over MLAA and so.


Thanks in advance.

Here's an article about DLAA inTFU2 including some images and a comparision to MLAA. Thought some comparision shots of the presented shader would be nice.
Thanks for the link, it looks great but a bit blurry (more than the MLAA techs)

Note: How "firsPassEdgeDetect" output is used on "secondPassEdgeDetectAndBlur"?

Thanks for the link, it looks great but a bit blurry (more than the MLAA techs)

Note: How "firsPassEdgeDetect" output is used on "secondPassEdgeDetectAndBlur"?


I've notice that Second uses First output as input
Thanks for the clarification and code snippets, appreciate it. It was really handy. :D
Is DLAA provided, or programmed into the computer system?
Thanks so much for DLAA code, and its explanation.
I have a look at http://www.gamedev.n...ls/page__st__20 before and applied to my engine, but no luck. It's still jaggy and bleeding.

I tried this DLAA, and the result is decent and I appreciate it.
I tested it with this set up: 1024 * 768, GTX 275

But just one point to mention, I wonder if there're some certain angles in which AA technique can't solve?
I have a long edge/line (runway) in far sight in which the camera is on not so tall tower. It's still jaggy.

TlBbN.jpg

6WSzI.jpg

Anyhow, another one.

YUYDs.jpg

2uuSC.jpg

My buffer is the same as resolution on to show which is 1024 * 768.
Any suggestions or how to solve the far sight jaggy?

This topic is closed to new replies.

Advertisement