Alpha Blending の2種類の算出方法と使い分け

アルファブレンドのイメージ。

透明な色の重なりを考慮して最終的な色を決定する処理を、アルファブレンディングと呼びます。 このアルファブレンディングですが、ペイントソフト(DTP)と CG やゲームでは算出方法が異なることがあります。 環境によって計算方法は異なるので必ず異なるわけではありませんが、アーティストはよく注意して使う必要があります。

計算方法の解説とその算出に当たって

計算とその表記にあたって次のことを定義しておきます。 また値に関して、ゲームや CG プログラミングなどでは RGBA 値が 0 ~ 1 で扱われることがありますが、ここでは分かりやすさのために 0 ~ 255 とします。

C
R,G,B 色成分をまとめて表す。
Color の略称。
A
透過値を表す。
Alpha の略称。
係数d
重ねられる色のパラメータであることを表す。
Destination の略称。
係数s
重ねる色のパラメータであることを表す。
Source の略称。
係数r
合成結果のパラメータであることを表す。
Result の略称。

例えば Cr は合成して得られた結果の (R, G, B) 色成分を表します。Cd * 1 は (Rd, Gd, Bd) * 1 となり (Rd * 1, Gd * 1, Bd * 1) に等しいです。

透過度 A の値に関しては計算の過程で 0 ~ 1 の値へ戻ります。 A の値が 0 ~ 255 で与えられるとき、A の値は A / 255 で求めることができます。 A = 0 のとき、完全に透過して、A = 1 のときに不透明です。

(1) ゲームなどで用いられる手法

最も簡単なアルファブレンドのサンプル。

ゲームなどで用いられるアルファブレンディングの計算式は一般には次の様になっています。

ゲームで用いられるアルファブレンディングの計算式
Cr = Cd * (1 - As) + Cs * As

図の様な場合の計算をして見ます。赤い画像 (Rd, Gd, Bd, Ad) = (255, 0, 0, 255) に、青い画像 (Rs, Gs, Bs, As) = (0, 0, 255, 128) をアルファブレンディングします。

Ad = 255/255 = 1
As = 128/255 ≒ 0.5

Cr = Cd(255, 0, 0) * (1 - As) + Cs(0, 0, 255) * As
   = (255, 0, 0) * 0.5 + (0, 0, 255) * 0.5
   = (127, 0, 0) + (0, 0, 127)
   = (127, 0, 127, 255)

※小数点の切り捨て、切り上げなどの違いで若干数値が異なる可能性があります。

Ad の値が一切使われていない点に注意してください。ゲームなどの CG で用いられるアルファブレンディングは、描画元の透過度 Ad を考慮しません。 また、合成した結果得られる色の透過度 Ar は必ず 255( = 1) になったり、単純に Ad + As (Ad <= 1) となる場合があります。

例えば PowetPoint や Photoshop などのペイントソフト等では、算出方法が異なり描画元の色成分 Cd に含まれる透過度 Ad を考慮します。これに関しては次の項目で解説します。

マシンスペックの向上と、表現技術の向上のために、比較的新しい世代のゲーム開発環境では透過度を考慮するようになっている場合もあるでしょう。 後述しますが BlendState などでコントロールできる場合もあると思います。

(2) ペイントツールなどで用いられる手法

透過度を考慮した複雑なアルファブレンド。

ペイントツールなどでアルファブレンディングが行われる場合は、先に紹介した算出方法と異なります。 2 つの透過値をもった色が与えられる場合に、先の方法とは異なる結果を示すことに注意してください。

ペイントツールなどで用いられるアルファブレンディングの計算式は一般的には次の様になっています。

ペイントツールなどで用いられるアルファブレンディングの計算式
Ar = As + (1 - As) * Ad
Cr = [(Cs * As) + (Cd * (1 - As) * Ad)] / Ar

上の図の左は "赤" の上に "青" が、図の右は "青" の上に "赤" が乗る形で合成されています。 "赤" は A = 77 (30% 透過)、"青" は A = 125 (50% 透過) と、異なる透明度 A を持っています。ここでは左の図のアルファブレンドの算出だけ例にとります。

Ad = 77 / 255 ≒ 0.3
As = 128 / 255 ≒ 0.5
Ar = 0.5 + (1 - 0.5) * 0.3 = 0.65

Cr = ((0, 0, 255) * 0.5 + (255, 0, 0) * 0.5 * 0.3) / 0.65
   = ((0, 0, 128) + (38, 0, 0)) / 0.65
   = (58, 0, 197, Ar)
   = (58, 0, 197, 0.65 * 255)
   = (58, 0, 197, 166)

※小数点の切り捨て、切り上げなどの違いで若干数値が異なる可能性があります。

この計算によって算出された結果を確認する際には注意が必要です。 例えば Photoshop のスポイトツールで色を確認するときは問題ありません。 一方で既定の背景色が設定されるような環境では、算出された色と、既定の背景色とのアルファブレンドを再度算出します。 良くあるのは白地 (255, 255, 255, 255) の背景です。

重ねられる色 Cd の透過度 Ad が考慮されないとき

(2) の算出方法ですが、(1) の算出方式の例のように、重ねられる色 Cd の透明度 Ad が、255 のときは、(1) の算出例と同じ結果が得られます。 つまり、重ねられる色 Cd の透過度 Ad を考慮しないシチュエーションでは、どちらの算出方法であっても結果が変わらないということです。

Ar = 0.5 + (1 - 0.5) * 1
Cr = ((0, 0, 255) * 0.5 + (255, 0, 0) * 0.5 * 1) / 1
   = (128, 0, 128, 255)
透過度を考慮しない方法で算出された透過度のあるアルファブレンドのサンプル。

また、(1) の算出方式に、(2) のような Ad, As がそれぞれ設定されるような例を適用したとします。 このとき、(1) の算出方式は、Ad を考慮しませんから、得られる結果は (1) の算出例と変わらないということになります。

考察

ゲームなどで用いられる手法の方が算出コストが低いです。 乗算除算の回数も異なりますし、最終的に出力される色の透過度 Ar は常に 1 になりますから、そもそも合成回数も異なります。 リアルタイムに計算しなければならない都合上、多少簡略化した方が都合が良いとのことでこのように算出されているのだと思います。

ゲームでは特にレンダリングする順序を考慮して実装するので、透過度 A を考慮しない合成はさして問題にならないハズです。 逆に言うと、こういう知識を持っていなければ「透過しているはずなのに透過していない」となってしまうわけですが、 今時の開発環境でそこまで考慮しなければいけないような状況は稀な気もします。

プログラミングして実装していく上では AlphaBlend の算出方法を決定する BlendState なるパラメータが多くの環境で導入されていますので、 ひょっとすると (1) (2) のような算出方法の切り替えが実装されている可能性もあります。

様々な合成方法

2枚の絵を重ねる方法は他にもいくつかあって、Photoshop などのペイントソフトではスクリーン合成やオーバーレイ合成として見られますね。 透過度 A を考慮したそれらの合成方法の算出などはここでは割愛します。長くなりますし、自分も個人のレベルでは中々記事にできません。

それらの算出方法自体は様々な場所で紹介されていますし、Adobe PDF のリファレンスなんかが参考になります。 (Adobe PDF Reference は Ar の算出方法がイマイチ良く分かりませんが)

参考