もっと深く! Direct3D

アバター
あーる@Reputeless
記事: 84
登録日時: 15年前
住所: 千葉

もっと深く! Direct3D

投稿記事 by あーる@Reputeless » 15年前

-
Direct3D の技術メモを月1ぐらいのペースで書いてみます。
説明は詳しく、コードはシンプルに、が目標です。

まだ DirectX に触れたことがない方には、こんなことができるんだなーと知ってもらえれば、
普段から DirectX に親しんでる方には、あたらしい利用法を発見するきっかけにしていただければ... いいな。

-------------------------
-Alpha to Coverage-
-------------------------


Direct3D 9.0 の時代は長く続いたので、GPUベンダーは 9.0 +α の機能を独自に開発してきました。
それは従来のシェーダでは対処できなかった課題を解決するもので、Direct3D 10 の機能を先取りしているものもあります。

今回紹介する「Alpha to Coverage」は Direct3D 9.0 で「アルファテストに対するAA(アンチエイリアシング)」を可能にする技術です。
(NVIDIA はこれを "Transparency AA" と呼んでいますが、ここでは両方を含んで Alpha to~ と言うことにします)
後述しますが、Direct3D 10 でこの機能は正式に採用されました。

Direct3D 9.0 の マルチサンプリングAA(MSAA) はプリミティブの境界にしか適用されないので、ポリゴン内部に生じた描画されない(=アルファテストで破棄された)ピクセルの境界に対しては効果を発揮しません。
そのため、金網や植物など、アルファテストで切り抜いて描画するものにジャギーが生じるのが悩みのタネでした。

この問題に対する従来の解決法は、原始的なスーパーサンプリング(高解像度のレンダーターゲットに描画後、縮小してフィルタリング)しかありませんでしたが、Alpha to Coverage 技術によってアルファテストに対するマルチサンプリングが可能になり、パフォーマンスを改善できるようになりました。
この機能、GeForce は 7シリーズ以上、Radeon は X1000 以上が対応していますが、両者はそれぞれ異なる実装をしています。

GeForce で Alpha to Coverage を有効にする方法

GPUベンダー独自規格である Alpha to Coverage のための D3DRENDERSTATETYPE は Direct3D 9.0 には存在しないので、
普段使われることのない D3DRS_ADAPTIVETESS_Y をオーバーロードすることになっています。
(ちなみに、本来 D3DRS_ADAPTIVETESS_Y は テセレーション関連のステートですが、GeForce 7 はテセレーションに対応していないので問題ありません)

まず Alpha to Coverage が利用可能かを調べ、SetRenderState で有効にします。
もちろん、アルファテストも有効にしていなければいけません。
こうすることで、アルファテストに対するマルチサンプリング、Alpha to Coverage が適用された描画ができます。

CODE:

if(pd3d->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,0,D3DRTYPE_SURFACE,
(D3DFORMAT)MAKEFOURCC('A','T','O','C')) == S_OK)
{
	pd3dDevice->SetRenderState(D3DRS_ADAPTIVETESS_Y,(D3DFORMAT)MAKEFOURCC('A','T','O','C'));
}
無効にするときはこうします。

CODE:

pd3dDevice->SetRenderState(D3DRS_ADAPTIVETESS_Y, D3DFMT_UNKNOWN);
マルチサンプリングによる Alpha to Coverage とは別に、スーパーサンプリングによる Alpha to Coverage もサポートしていますが、品質とパフォーマンスは劣ります。

CODE:

pd3dDevice->SetRenderState(D3DRS_ADAPTIVETESS_Y,(D3DFORMAT)MAKEFOURCC('S','S','A','A'));
 
上の画像は[NV08]のスクリーンショットで3パターンを比較したものです

Radeon の場合はD3DRS_POINTSIZE をオーバーロードします。

有効にする。

CODE:

pd3dDevice->SetRenderState(D3DRS_POINTSIZE,(D3DFORMAT)MAKEFOURCC('A','2','M','1'));
 
無効にする。

CODE:

pd3dDevice->SetRenderState(D3DRS_POINTSIZE,(D3DFORMAT)MAKEFOURCC('A','2','M','0'));
Radeon の実装では、この機能が利用可能かをチェックする方法がありませんが、[AMD09]には "All ATI cards supporting the DirectX9 feature set expose alpha to coverage." と書かれているので、pd3d->GetAdapterIdentifier で Radeon を識別できたら使用することにしましょう。

Diretct3D 10 ではAlphaToCoverageEnable というステートが新しく作られ、どのGPUでもこの機能を利用することができるようになりました。

参考
-
[NV08] GeForce の実装での Alpha to Coverage(ムービー、サンプルデモ、ホワイトペーパー)
http://www.nvidia.co.jp/object/transparency_aa.html

*Radeon の実装での Alpha to Coverage(サンプルデモ、ホワイトペーパー)
http://developer.amd.com/gpu/radeon/pag ... ments.aspx

*Direct3D 10 での Alpha to Coverage(下のほうに解説、サンプルは DirectX SDK内)
http://msdn.microsoft.com/en-us/library ... 85%29.aspx

[AMD09] (PDF)
http://developer.amd.com/gpu_assets/Adv ... 0Cards.pdf

-
添付ファイル
img3.png
img3.png (171.68 KiB) 閲覧数: 230 回
img2.png
img2.png (179.32 KiB) 閲覧数: 210 回
img.png
img.png (192.08 KiB) 閲覧数: 222 回
最後に編集したユーザー あーる@Reputeless on 2010年11月29日(月) 18:26 [ 編集 3 回目 ]

アバター
Ciel
記事: 252
登録日時: 15年前

Re: もっと深く! Direct3D

投稿記事 by Ciel » 15年前

おおお・・!
これは正に私がアルファテストを行った後に抱えていた悩みそのものの解決策じゃないですか!

もうしゃーないなーと思って放置していたんですが、解決策あったんですね。すばらしい。

まだ知識不足であまり理解できませんが、参考にさせていただきます!

ありがとうございます!

アバター
あーる@Reputeless
記事: 84
登録日時: 15年前
住所: 千葉

Re: もっと深く! Direct3D

投稿記事 by あーる@Reputeless » 15年前

>Ciel さん
お役にたててよかったです(´ω`*
わかりやすい技術メモにするために、次回から内容&書き方を工夫したいです。