乗算済みアルファとは? その1:補間アルファの問題点
これまでXNA Game Studio 4.0の機能のひとつとして乗算済みアルファを紹介してきましたが、今回からは数回に渡って乗算済みアルファ自体について紹介していきます。
乗算済みアルファの歴史
乗算済みアルファ、英語でPremultiplied Alphaという言葉は意外に古くからあります。例えば1984年のSIGGRAPHで発表された「Compositing Digital Images」という論文のなかでPremultiplied Alphaという言葉がでてきます。この論文の中ではアルファチャンネルを持った映像を合成する時には乗算済みアルファを使った方が高速化と正しい結果になると言及しています。
余談ですが、1984年のSIGGRAPHといえば「トイ・ストーリー」や「カーズ」の監督で有名なジョン・ラセターが後にピクサーとして独立するILMのCG部門で、3Dアニメーション短編である「アンドレとウォーリーB.の冒険」を発表した年でもあります。
この論文ではデジタル画像の合成を目的としていたので、その後の動画編集ソフトでは乗算済みアルファが採用されるようになりました。例えばAfter Effectsの場合、チュートリアル(英語)にあるようにPremultiplied AlphaとStraight Alphaというように区別されています。日本語では合成、ストレートと呼ばれているようです。
ゲームの世界で乗算済みアルファという言葉が使われたのは、私が知る限りでは1998年のDirect X 6.0でサポートされたDXT圧縮が最初だと思われます。DXT2とDXT4が乗算済みアルファ形式になっていますが、当時、乗算済みアルファは半透明計算の高速化の手法のひとつとして紹介されたので、後のGPU高速化によって意義がなくなり、DX10ではDXT2、DXT4形式はサポートされなくなってしまいました。
こういった経緯があるので、ゲーム製作の中で乗算済みアルファという言葉を聞くことは少なくなりました。
しかし、GPU性能の発達によって、同じシーンを何度もレンダリングして合成するというのが当たり前になってきた今、ゲームでも乗算アルファが必要なシーンが増えてきたのではないでしょうか?
補間アルファの問題
通常のアルファブレンディング(以降、補間アルファ(Interpolated Alpha)と呼びます)以下の二つの問題があります。
- 計算自体が間違っていて、これが色のにじみ問題の元となっている
- 半透明を使ったシーンの合成、つまりコンポジションができない
今回は、1の計算が間違っているという問題を見ていきます。
アルファ値は透明度
アルファブレンディング、つまり半透明というのは現実の世界でガラス板(擦りガラス等)などを通してどれだけ背景が透けて見えるか、逆に言えばガラス板がどれだけ背景の光を通すのかという現象を表現することです。
補間アルファの場合、以下の式を使って計算します。
レンダーターゲット.rgb = テクスチャ.rgb * テクスチャ.a + レンダーターゲット.rgb * ( 1 – テクスチャ.a )
この式だと、どれだけ背景の光を通すのかという現象を表現するのと同時に元の色の明るさをもアルファ値ひとつで設定することになってしまいます。例えば発光体を表現するためにテクスチャに明るい色があったとしてもアルファ値を小さくしてしまうと発光体の色自体が暗くなってしまいます。
対して乗算済みアルファは以下の式になります。
レンダーターゲット.rgb = テクスチャ.rgb + レンダーターゲット.rgb * ( 1 – テクスチャ.a )
これは単純に補間アルファの式からテクスチャ.rgbにアルファ値を掛けるのをやめただけの式になります。この式にすることで、アルファ値はどれだけ背景の光を通すのか、つまり透明度のみをコントロールすることになり、より現実に近い計算結果になります。
バイリニアフィルタリングをすると明るさが変わってしまう
補間アルファでのアルファ値が透明度と元の色の明るさの二つを操作してしまう、という問題は多くの場合、気にならずに問題になったとしても素材の方を修正して終わりということが殆どです。
ですが、補間アルファはバイリニアフィルタリングと併用することで色のにじみ問題として避けては通れない問題に発展してしまいます。
バイリニアフィルタリングはサブピクセルレベルで色の補間をするのですが、この処理はピクセルシェーダー内でテクスチャをフェッチしたときに行われます。そして、その後にアルファブレンディング処理をします。ここで問題なのはテクスチャをフェッチしたときにアルファ値も一緒に補間されてしまうことです。補間アルファの場合、この補間されたRGB値とアルファ値を使ってアルファブレンディング処理を施すので、計算結果が線形ではなくなってしまいます。
例えば、2x1ピクセルのテクスチャがあったとして、左側が不透明の赤(255, 0, 0, 255)で右側が透明な黒(0, 0, 0, 0)になっているとします。そして、レンダーターゲットを白(255, 255, 255, 255)でクリアしたとします。ここで注意するのは赤も白もHSV色空間に変換した場合、どちらも明度が100% となるということです。
この時に二つのピクセルの中央でフェッチした場合、バイリニアフィルタ後の値は(128, 0, 0, 128)となり、半分の透明度で半分の明るさの赤となります。
乗算済みアルファの場合はアルファブレンド後の色は(255,128, 128, 128)となり、HSVにした場合の明度は100% のままになります。
対照的に補間アルファの場合は(192, 128, 128, 128)となり、HSVにした場合の明度は75% と暗くなってしまいます。
と、数字をならべても判りづらいので、乗算済みアルファブレンディングと補間アルファブレンディングの違いを図にしてみました。
クリックで拡大します
一番上は2x1ピクセルのアルファブレンディングの結果を拡大したものです。続いてアルファブレンディングの計算経過をグラフにしたものを並べています。それぞれの図の緑色の線は色の明度を表しています。
乗算済みアルファの方はテクスチャとレンダーターゲットの色が線形に変化し、結果が綺麗に赤から白へ変化しており、明度が変わっていないことが判ります。
対して補間アルファの方はレンダーターゲットの色は線形に変化していますが、テクスチャの色がアルファ値と乗算することによって曲線になってしまっています。そして結果を見ると、補間中の明度が75%まで下がっているのと、赤と白の間に黒いにじみがでているのが判ります。
このように、一般的に半透明処理に使われている補間アルファの計算式は、半透明の計算式としては正しくないということが判りました。
次回は半透明があるシーンのコンポジションをする場合の乗算済みアルファと補間アルファの違いを紹介します。