意外と知られていない?MSAAの副産物「AlphaToCoverage」について

タイトル装飾

意外と知られていない?MSAAの副産物「AlphaToCoverage」について

 
意外と知られていない?MSAAの副産物「AlphaToCoverage」について

皆さんはAlphaToCoverageという機能についてご存じでしょうか?

この記事のターゲット

・ゲーム内で草を描画したいけど、透明部分と不透明部分の間のエッジが気になる方

・MSAAは知ってるけどDeferredRenderingで使えないから使っていない方

目次

・概要

・仕組み

 →MSAAの仕組み

  メリットデメリット

 →A2Cの仕組み

・各APIやエンジンでの有効化の手順

・注意点

概要

AlphaToCoverage(A2C)とはGPUに搭載されているMSAA(Multi Sample Anti-Ailiasing)の機能を

利用したテクスチャサンプル時のエッジ表現を改善するための機能です。

仕組み

→MSAAの仕組み

 ポリゴンのラスタライズ時にピクセルの中の特定のポイントがどの程度覆われているか

(カバレッジ)をチェックして、その情報を見て最終的な画像に出力する(Resolveと呼ばれる)

機能です

 ピクセル内のチェックするポイントの数はクオリティの設定によって変わってきます

(2x、4x、8x等)

→メリット

 ポリゴンのエッジ部分が滑らかになる

→デメリット

 データ量がサンプル数分増える

 DeferredRenderingに不向き(ほぼ使えない)

→AlphaToCoverageの仕組み

 AlphaToCoverageでは、ピクセルシェーダーから出力されたアルファ値に応じてカバレッジ数を変えて描画します。

実際に適用した画像を見てみましょう

ほとんど変わりませんね…

ではメリットは何でしょうか?

以下のGIFでメリットは分かります。

なんとアルファブレンドの場合とAlphaToCoverageの場合でこのような違いが現れました。

これがメリットです。

なぜこのようなことが起こるのでしょうか?

答えはAlphaToCoverageは不透明で描画できるため、描画順の影響を受けないからです。

少し不親切でしょうか

もう少し詳しく考えてみましょう

アルファブレンドの場合、深度値を書き込むと見た目が透明でも深度値でクリップされてしまい、空白の領域ができます。

ではアルファブレンドを使わずに透明な部分を破棄してみるとどうでしょう?

結果はこのように境界部分が際立ってしまいます。

改めてAlphaToCoverageを使った描画を見てみましょう

深度値を書き込めるので、ポリゴンの前後関係を気にすることなくかつ、きれいに草のようなエッジのある者の描画ができました

とてもきれいですね!

ただ、ちょっとぼやけてる気がしますね。。。

ここでこちらのサイトで紹介されているアプローチを見てみましょうhttps://bgolus.medium.com/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f

col.a = (col.a – _Cutoff) / max(fwidth(col.a), 0.0001) + 0.5;

fwidthの定義は以下になります。

abs(ddx(value)) + abs(ddy(value))

結果を見てみましょう。

左がAlphaToCoverageそのままの結果、右が上記の補正をかけた結果です。

いかがでしょうか?

とてもきれいでぼやけなくなったと思いませんか?

各APIやエンジンでの有効化の手順

VulkanやDirectXではパイプライン設定での初期化になります。

Vulkanでは

VkPipelineMultisampleStateCreateInfoという構造体で設定できるようです。

DirectX12では

D3D12_BLEND_DESCという構造体で設定できるようです。

Unityの場合は簡単で、シェーダーに

AlphaToMask On

の記述を入れるだけです。

Unrealではフォワードシェーディングがモバイル向けなのかマテリアルのモバイル向けの設定項目にあります。

注意点

MSAAがディファードシェーディングにそのままでは対応できない都合上、AlphaToCoverageはフォワードシェーディング向けになります。

AlphaToCoverageを有効にしたい場合、透過パスで描画することになるでしょう

作者
  Y.M
  プログラマ

目次

目次を生成中...