Sign in to follow this  

Recommended Posts

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.

[code]
#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);
}

[/code]

Hope it helps.

Share this post


Link to post
Share on other sites
Ashaman73    13715
[quote name='vilgeits' timestamp='1296555135' post='4767885']
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.
[/quote]
Here's an [url="http://www.eurogamer.net/articles/digitalfoundry-lucasarts-on-tfu2-tech-blog-entry"]article[/url] about DLAA inTFU2 including some images and a comparision to MLAA. Thought some comparision shots of the presented shader would be nice.

Share this post


Link to post
Share on other sites
vilgeits    100
Thanks for the link, it looks great but a bit blurry (more than the MLAA techs)

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

Share this post


Link to post
Share on other sites
vilgeits    100
[quote name='vilgeits' timestamp='1296559913' post='4767905']
Thanks for the link, it looks great but a bit blurry (more than the MLAA techs)

Note: How "firsPassEdgeDetect" output is used on "secondPassEdgeDetectAndBlur"?
[/quote]

I've notice that Second uses First output as input

Share this post


Link to post
Share on other sites
haxpor_2    124
Thanks so much for DLAA code, and its explanation.
I have a look at [url="http://www.gamedev.net/topic/580517-nfaa---a-post-process-anti-aliasing-filter-results-implementation-details/page__st__20"]http://www.gamedev.n...ls/page__st__20[/url] 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.

[img]http://i.imgur.com/TlBbN.jpg[/img]

[img]http://i.imgur.com/6WSzI.jpg[/img]

Anyhow, another one.

[img]http://i.imgur.com/YUYDs.jpg[/img]

[img]http://i.imgur.com/2uuSC.jpg[/img]

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this