スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

DXライブラリでDLAA

こんにちは、ぺっちりぺちぺちペチコです

言葉の意味はわからないけど語呂はいいネ


アンチエイリアス第三弾
今回はDirectionally Localized Anti-Aliasing (DLAA)
EdgeAAなどと同じく、エッジにブラーを掛ける技法ですが、長いエッジにも対応した比較的新しいものです
スターウォーズのゲームに搭載されて話題になったそうです

AAなし4x
AAなし
4x

DLAAEdgeAA2
DLAA
EdgeAA
毎度のことで、クリックで拡大してタブ切り替えで比較しないと違いはわかりません

拡大比較
拡大比較
ブラーベースなのでどうしてもボケたカンジになります
各々のシェーダは得意分野が違うので、単純に比較はできないのですが、参考程度に

4x vs DLAA
船首のこの部分なんかはDLAAの方が滑らかに見えるような気がします
ただDLAAは暗い部分(この画像だと右側の重なり部分)に弱いのでアンチエイリアスが掛かっていません
こういう所に強いのはFXAAですが、FXAAはそれ故画像全体がボケボケになります
一長一短ですね

実装ですが、使うスクリーンは通常用とプリパス用(エッジ検出)の2つです
深度も法線もいりません

ただしアルファ値を計算に使うので
プリパス用スクリーンをint ScreenHandle2 = MakeScreen( 1024, 768 ,TRUE ); こんなカンジでアルファTRUE
プリパス→DLAA描画前にSetDrawAlphaTest( DX_CMP_ALWAYS, 0 );で常に描画にしておきます

アルファテストはDXライブラリの他の部分でも使っているそうなので、描画が終わったら念のため
SetDrawAlphaTest( -1 ,0);
でデフォルトに戻しておいた方がいいでしょう

後はいつものように、2D描画用頂点を用意しておいて、DrawPolygon2DToShaderやDrawPrimitive2DToShaderで通常描画の結果をシェーダで描画するだけです(プリパスとDLAA描画の2Passです)

HLSLはすがすがしいまでの丸パクリなので説明等はありません!
コピーライトが付いてたのでパス毎に付記しました

まずプリパス。エッジの検出を行ってます
DLAA_1PS.pso
//
// Directionally Localized Anti-Aliasing (DLAA)
// by Dmitry Andreev
// Copyright (C) LucasArts 2010-2011
//

// ディフューズマップテクスチャ
sampler DiffuseMapTexture : register( s0 ) ;

//スクリーン比用。ここでは決め打ち(通常はスクリーンサイズをレジスタで渡します)
const static float2 rcpres = float2(1.0f/1024.0f,1.0f/768.0f);

#define LD(o, dx, dy) o = tex2D(DiffuseMapTexture, Tex + float2(dx, dy) * rcpres);

float GetIntensity( const float3 rgb )
{
return dot( rgb, float3( 0.333f, 0.334f, 0.333f ) );
//return dot( rgb, float3( 0.299f, 0.587f, 0.114f ) );
}

float4 main(float2 Tex : TEXCOORD0) : COLOR0
{
float4 center, left, right, top, bottom;

LD( center, 0, 0 )
LD( left, -1, 0 )
LD( right, 1, 0 )
LD( top, 0, -1 )
LD( bottom, 0, 1 )

float4 edges = 4.0f * abs( ( left + right + top + bottom ) - 4.0f * center );
float edges_lum = GetIntensity( edges.xyz );

return float4( center.xyz, edges_lum );
}

通常描画画面をこのシェーダで描画します
//ディフューズマップテクスチャにレジスタs0で通常描画画面を渡しておいてください

↑で描画した画面を裏画面に次のシェーダで描画します
DLAA_2PS.pso
//
// Directionally Localized Anti-Aliasing (DLAA)
// by Dmitry Andreev
// Copyright (C) LucasArts 2010-2011
//

// ディフューズマップテクスチャ
sampler DiffuseMapTexture : register( s0 ) ;

//スクリーン比用。ここでは決め打ち(通常はスクリーンサイズをレジスタで渡します)
const static float2 rcpres = float2(1.0f/1024.0f,1.0f/768.0f);

#define LD(o, dx, dy) o = tex2D(DiffuseMapTexture, Tex + float2(dx, dy) * rcpres);


float GetIntensity( const float3 rgb )
{
// return dot( rgb, float3( 0.333f, 0.334f, 0.333f ) );
return dot( rgb, float3( 0.299f, 0.587f, 0.114f ) );
}

float4 main(float2 Tex : TEXCOORD0) : COLOR0
{
const float lambda = 3.0f;
const float epsilon = 0.1f;

//
// Short Edges
//

float4 center, left_01, right_01, top_01, bottom_01;

// sample 5x5 cross
LD( center, 0, 0 )
LD( left_01, -1.5, 0 )
LD( right_01, 1.5, 0 )
LD( top_01, 0,-1.5 )
LD( bottom_01, 0, 1.5 )

float4 w_h = 2.0f * ( left_01 + right_01 );
float4 w_v = 2.0f * ( top_01 + bottom_01 );

// Sharper (3-pixel wide high-pass)
float4 left, right, top, bottom;

LD( left, -1, 0 )
LD( right, 1, 0 )
LD( top, 0, -1 )
LD( bottom, 0, 1 )

float4 edge_h = abs( left + right - 2.0f * center ) / 2.0f;
float4 edge_v = abs( top + bottom - 2.0f * center ) / 2.0f;


float4 blurred_h = ( w_h + 2.0f * center ) / 6.0f;
float4 blurred_v = ( w_v + 2.0f * center ) / 6.0f;

float edge_h_lum = GetIntensity( edge_h.xyz );
float edge_v_lum = GetIntensity( edge_v.xyz );
float blurred_h_lum = GetIntensity( blurred_h.xyz );
float blurred_v_lum = GetIntensity( blurred_v.xyz );

float edge_mask_h = saturate( ( lambda * edge_h_lum - epsilon ) / blurred_v_lum );
float edge_mask_v = saturate( ( lambda * edge_v_lum - epsilon ) / blurred_h_lum );

float4 clr = center;
clr = lerp( clr, blurred_h, edge_mask_v );
clr = lerp( clr, blurred_v, edge_mask_h * 0.5f ); // TFU2 uses 1.0f instead of 0.5f

//
// Long Edges
//

float4 h0, h1, h2, h3, h4, h5, h6, h7;
float4 v0, v1, v2, v3, v4, v5, v6, v7;

// sample 16x16 cross (sparse-sample on X360, incremental kernel update on SPUs)
LD( h0, 1.5, 0 ) LD( h1, 3.5, 0 ) LD( h2, 5.5, 0 ) LD( h3, 7.5, 0 ) LD( h4, -1.5,0 ) LD( h5, -3.5,0 ) LD( h6, -5.5,0 ) LD( h7, -7.5,0 )
LD( v0, 0, 1.5 ) LD( v1, 0, 3.5 ) LD( v2, 0, 5.5 ) LD( v3, 0, 7.5 ) LD( v4, 0,-1.5 ) LD( v5, 0,-3.5 ) LD( v6, 0,-5.5 ) LD( v7, 0,-7.5 )

float long_edge_mask_h = ( h0.a + h1.a + h2.a + h3.a + h4.a + h5.a + h6.a + h7.a ) / 8.0f;
float long_edge_mask_v = ( v0.a + v1.a + v2.a + v3.a + v4.a + v5.a + v6.a + v7.a ) / 8.0f;

long_edge_mask_h = saturate( long_edge_mask_h * 2.0f - 1.0f );
long_edge_mask_v = saturate( long_edge_mask_v * 2.0f - 1.0f );

// if ( long_edge_mask_h > 0 || long_edge_mask_v > 0 ) // faster but less resistant to noise (TFU2 X360)
if ( abs( long_edge_mask_h - long_edge_mask_v ) > 0.2f ) // resistant to noise (TFU2 SPUs)
{
float4 left, right, top, bottom;

LD( left, -1, 0 )
LD( right, 1, 0 )
LD( top, 0, -1 )
LD( bottom, 0, 1 )

float4 long_blurred_h = ( h0 + h1 + h2 + h3 + h4 + h5 + h6 + h7 ) / 8.0f;
float4 long_blurred_v = ( v0 + v1 + v2 + v3 + v4 + v5 + v6 + v7 ) / 8.0f;

float lb_h_lum = GetIntensity( long_blurred_h.xyz );
float lb_v_lum = GetIntensity( long_blurred_v.xyz );

float center_lum = GetIntensity( center.xyz );
float left_lum = GetIntensity( left.xyz );
float right_lum = GetIntensity( right.xyz );
float top_lum = GetIntensity( top.xyz );
float bottom_lum = GetIntensity( bottom.xyz );

float4 clr_v = center;
float4 clr_h = center;

// naive search
float hx = saturate( ( lb_h_lum - top_lum ) / ( center_lum - top_lum ) );
float hy = saturate( ( lb_h_lum - center_lum ) / ( bottom_lum - center_lum ) );
float vx = saturate( ( lb_v_lum - left_lum ) / ( center_lum - left_lum ) );
float vy = saturate( ( lb_v_lum - center_lum ) / ( right_lum - center_lum ) );

if ( hx == 0 ) hx = 1;
if ( vx == 0 ) vx = 1;

clr_v = lerp( left, clr_v, vx );
if ( vy < 1 ) clr_v = lerp( clr_v, right, vy );

clr_h = lerp( top, clr_h, hx );
if ( hy < 1 ) clr_h = lerp( clr_h, bottom, hy );


clr = lerp( clr, clr_v, long_edge_mask_v );
clr = lerp( clr, clr_h, long_edge_mask_h );
}

//
// Preserve high frequencies
//

float4 r0, r1;
float4 r2, r3;

LD( r0, -1.5, -1.5 )
LD( r1, 1.5, -1.5 )
LD( r2, -1.5, 1.5 )
LD( r3, 1.5, 1.5 )

// faster version
//r0 = top_01;
//r1 = bottom_01;
//r2 = left_01;
//r3 = right_01;

float4 r = ( 4.0f * ( r0 + r1 + r2 + r3 ) + center + top_01 + bottom_01 + left_01 + right_01 ) / 25.0f;
clr = lerp( clr, center, saturate( r.a * 3.0f - 1.5f ) );

return clr;
}

長いです
ところどころfaster versionがコメントアウトになっていますが、速いのかしら?(ためしてない)


パフォーマンスはFXAAの時の400隻の大船団で測ってみました

DLAAパフォーマンス
※計測は前と同じシーンで行っています

AAなし1300-1600FXAA1400-18004x1600-200016x2000-16000DLAA2000-14000


ううむ、揺れ幅が大きくてよくわかりませんでした
きっとシェーダ以外のペチコード(ペチコのコード。うまいこと言ったつもり)に問題がある気がします
一般的にFXAAと同等、4xより軽い位と言われています
DXライブラリではtechniqueが使えず、パス処理毎にGPUからCPUを経緯するのでその辺も関係してるのかも
※あくまで推測です

何はともあれ、アンチエイリアス一つとっても、他にもまだまだ技法があって、色々遊べる所がシェーダの面白いところだと思います

パクりしかやってませんけど


コメントの投稿

非公開コメント

プロフィール

ペチコートさん

Author:ペチコートさん
大航海時代オンライン
Zephyros、Eurosサーバーに潜伏中

偽ペチコ1号・2号
ペチコの手下達
Zephyrosサーバーに潜伏中

最新記事
月別アーカイブ
カテゴリ
リンク
最新コメント
検索フォーム
QRコード
QR
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。