α合成と加算合成

・まず。

 α合成というのはアルファブレンディング(alpha blending)で、加算合成というのは加算ブレンディング(add blending?)のことを指します。響きはアルファブレンディングの方が好きなんですけど、そうすると加算合成をアッドブレンディングと表記しないとなんか釣り合いが取れないような気がして。いや、α合成と加算合成も釣り合い取れてないかもしれないですけど。
ブレンディングを合成と書くのは、タイプするのが面倒なだけです。文字数少なくて済むし。

 SrcDestという言葉を使いますが、これは描画する画像と元々画面にある画像を区別するために使います。これから描画しようとする方がSrc、元々画面に書いてあった方がDestです。Direct3Dと同じです。

例) 予め書いてある背景の上に、砲台の絵を描画する


Dest

 
Src
 
描画結果

 

・加算合成

 加算合成色の足し算です。DestとSrcの色をそのまま足します。

 
 
 
3つを加算合成 
ありがちな、
光の3原色の例

 例えば、この絵では(rgb( 1.0, 0.0, 0.0 ))と(rgb( 0.0, 1.0, 0.0 ))が加算合成された部分の色は、rgb( 1.0+0.0, 0.0+1.0, 0.0+0.0 )(rgb( 1.0, 1.0, 0.0 ))になっています。
加算合成は色の足し算、というよりは色をそのまま足す事を加算合成と呼んでいる、の方が適当かもしれません。

 

 加算合成の得意分野は、やっぱり光の表現ですね。


これに
           

このテクスチャを
3つ加算合成

まぁきれい

 単純に加算合成使うだけで、これだけ見栄えのするものができます。

 Direct3Dでは、DirectX5のHELのRampEmulationスペキュラーハイライト(鏡面反射の光)α合成を使った半透明を使ってますが、RGBEmulation加算合成を使っています。実際の見た目と同じ表現を目指すなら加算合成が正しく、見た目もきれいです。ポリゴンに色が着いている時に大きく違いが出ます。
そういえばWindowsについてるOpenGLのスクリーンセーバーを見ると、スペキュラーハイライトがα合成の半透明ですね。色付きポリゴンのスペキュラーハイライトが風船のスペキュラーみたいに見える。アクセラレータなしの話ですけど、アクセラレータあっても同じなんでしょうか?

 加算合成はどんな順番で描画しても結果は変わりません。足し算をどのような順番でやっても結果は同じになるのと一緒ですな。プレステなんかはハードがZバッファをサポートしてないので都合がいいですねぇ。

 ちなみに、加算合成や半透明など、α合成を使う時はZバッファへの書き込みを止める場合が多いと思います。Zテスト(Zバッファの参照・比較)はしますよ。

 

 次に欠点。色を単純に加算するので、書きたい色が書けない時があります。

  
背景は青
  
赤い丸を加算合成
  
紫の丸に
なってしまった
      
背景は赤
  
緑の丸を加算合成
  
黄色の丸

 この絵の例は極端ですが、実際問題としては青空に爆発を加算合成したら紫色っぽくなってしまったりします。

 

 そして、加算合成最大の敵は明度1.0の限界にあります。

 例えば、rgb( 0.0, 0.75, 1.0 )とrgb( 1.0, 1.0, 0.0 )を加算合成すると、rgb( 1.0, 1.75, 1.0 )になります。ちょっとまぶしいくらいのライトグリーンですかね。しかし、色の明度が1.0を超えても、表示される色は1.0になります。つまり、先ほどの例では表示される色はrgb( 1.0, 1.0, 1.0 )になってしまいます。

  
rgb( 0.0, 0.75, 1.0)
 
rgb( 1.0, 1.0, 0.0)
 
緑じゃなくて白

  
 背景は黄色 

  
赤い丸を加算合成

  
 み、見えない…… 

 

この1.0の限界が原因となる別のケース。まず、以下のようなテクスチャがあったとしましょう。

青いレーザーみたいなー

 これに同じテクスチャを加算合成してみると……。

色の境目くっきり

 グラデーションじゃなくなってしまいました。これにまた同じテクスチャを加算合成すればするほど色の境目がはっきりしてきます。

 図で解説すると……。


パソコンに付いてきたExcel5.0(古い)で作成
  
同じものを加算合成後(薄い線は合成前)

 1.0の飽和処理(クリッピング)の餌食になってますね。最初の状態では、明るくなっていってもどれかの色は明度が上昇してますが、加算処理後はどの色の明度も変化していない部分があります。それで色の境目が目立つようになります。
これは爆発などを重ねる時に問題になる場合があります。

 他にも、例えば明るさ0.1程度の色の絵でも、どんどん加算合成していったら真っ白になってしまって元の色や形がわからなくなった、という事も起こります。

 

 加算処理は、どの色・明度でどんな形で、どのくらい重なるかなどをよく考えて使いましょう。じゃないとあっと言う間に真っ白です。

 

 

・α合成による半透明

 今まで説明してきた加算合成は、Direct3Dではα合成(アルファブレンディング)を使って行います。α合成はSrcとDestに、同じもしくはそれぞれ別のα値を掛けて、その結果を足すという方法で加算合成半透明などを使う事ができます。加算合成はSrcもDestもα値は1.0、つまりそのまま足すのと同じです。

 α合成を使うと、半透明も表現できます。α合成でも二大使用頻度を誇ると思われる加算合成と半透明ですが、加算合成の次は半透明について説明しましょう。

 

 半透明にはDest * ( 1.0 - Srcα ) + Src * Srcα という式を使います(SrcαはSrcのα値で、この式では不透明度を表す)。不透明度が75%なら、α値は0.75で Dest * 0.25 + Src * 0.75 という式になります。
証明。

Srcの色 : rgba( 0.0, 0.5, 1.0, 0.5←これがSrcα )  Destの色 : rgb( 1.0, 1.0, 0.0 )

Dest * ( 1.0 - Srcα ) + Src * Srcαという式に当てはめると……
rgb( 0.0, 0.5, 1.0 ) * ( 1.0 - 0.5 ) + rgb( 1.0, 1.0, 0.0 ) * 0.5
= rgb( 0.0, 0.5, 1.0 ) * 0.5 + rgb( 1.0, 1.0, 0.0 ) * 0.5
= rgb( 0.0, 0.25, 0.5 ) + rgb( 0.5, 0.5, 0.0 )
= rgb( 0.5, 0.75, 0.5 )


Dest

 
Src(不透明度が
100%の場合の色)
 
描画結果。真ん中が
rgb( 0.5, 0.75, 0.5 )

 

 加算合成は光に使えますが、じゃあ半透明は主に何に使うかと言うと……半透明の物体や半透明に見える現象・表現に使います。そのまんまですけど、結構使えますよ、半透明。他にもウィンドウの表示とかフェードイン・アウトでは半透明はなかなか便利です。

 半透明に見える現象としては、モーションブラーがありますが、これは別の機会に。

 半透明の物と言えば……半透明ごみ袋ですかね。これは半透明を使えば表現できます(当然)。
それよりも、を表現するのに活躍します。要は透けて向こう側が見える物ならほとんどが半透明を使って表現できます。実際には見えないですがなんかにも使えます。


Dest
やっぱりグラデー
ションは良いなぁ
 
SrcのRGBのビット
真っ白みたいだけど
実はちょっと灰色
 
Srcのαビット
適当に書いた雲
 
描画結果
 
2つ重ねても
自然な仕上がり

 半透明の真の威力を発揮するのが、↑のようにαビットを使った時です。これはビット毎に不透明度の情報を持つ事で、雲の薄い所とか濃い所とかも表現できます。これが使えないと、半透明も単純な表現しか使えません。


αビット使わずカラーキーで。
なんだこりゃ

 しかし、Direct3Dでαビットを使うためには望み通りのテクスチャのピクセルフォーマット(Rに何ビット、Gに何ビット使えるかとか。565ならRに5ビットGに6ビットBに5ビットを意味)を選ぶようにしないといけないし、αビットの書き込みはBitBltが対応してないのでLockを使って直書きする必要があったりでなかなか面倒です。
ダウンロードのページに、このページの絵を作成するのに使ったD3DTextrのαビット対応版を置いておくので、使ってみてください。

 簡単なグラデーションなら、αビットを使わなくてもαグローシェーディング(α値の補間)を使うという手もありますが、これは対応してない3Dカードも多いので(何よりVoodoo1が対応してないらしい)、使わない方が無難です。


先程の絵にαグローを使用

 黒の半透明を使えば、明るさを暗くしたりするのにも使えます。半透明で使われる手法の中ではこれが一番使われるんじゃないでしょうかね。陰影に使えばリアルさも増します。


浮かぶ球
  

半透明による薄い影

 半透明による影の例。αビットを使って影がぼやけた感じにしています(半影ですね)。陰影は、マルチテクスチャ(テクスチャの重ね合わせ)を使えばより効果的に表現できるでしょう。

 半透明は、書く順番によって結果が変わります。例えば真っ暗な画面に、水色と黄色それぞれをα値を0.8にして描画するという計算をしてみましょう。

Destが真っ黒で、その後
Srcが黄色で描画、Srcが水色で描画、の場合 
Destが真っ黒で、その後
Srcが水色で描画、Srcが黄色で描画、の場合
まず黄色
rgb( 1.0, 1.0, 0.0 ) * 0.8
= rgb( 0.8, 0.8, 0.0 )
次に水色
= rgb( 0.8, 0.8, 0.0 ) * 0.2 + rgb( 0.0, 0.5, 1.0 ) * 0.8 
= rgb( 0.16, 0.16, 0.0 ) + rgb( 0.0, 0.4, 0.8 )
= rgb( 0.16, 0.56, 0.80 )
まず水色
rgb( 0.0, 0.5, 1.0 ) * 0.8
= rgb( 0.0, 0.4, 0.8 )
次に黄色
= rgb( 0.0, 0.4, 0.8 ) * 0.2 + rgb( 1.0, 1.0, 0.0 ) * 0.8
= rgb( 0.0, 0.08, 0.16 ) + rgb( 0.8, 0.8, 0.0 )
= rgb( 0.80, 0.88, 0.16 )

 見てのとおり、色が違います。先に書いた方は二度α値の掛け算をしているために、後に書いた色の方が強く出ていますね。
これが問題になる場合もあります。手前と奥にそれぞれ半透明の物体があったとして、もし手前の方を先に書いたら、結果は正確な色ではなくなります。まぁ両方の色が近ければそれほど目立ちませんが。
これを解消するには、書く順番を工夫する事になります。Zソートをして、奥から手前に順番に描画されるようにすると正しく描画できます。

 

 半透明は加算合成でも何とか表現できますが、見た目がおかしい場合があります(灰色の煙に加算合成使ったら真っ白な煙になった、とか)。でもわざわざα値やαビットを使わなくても明るさ落とせば同じ効果が得られるので、加算合成だと楽ができます。だから「加算合成で済ませちゃえ〜」という事がよくあるでしょうね(^^; αビット付きテクスチャに対応させるのも面倒だし。
日本のインターネットで見られるDirect3Dのデモ・ゲームの現状は、「α合成ならなんでもかんでも加算合成」というのをよく見ますが、αビット付きテクスチャの作成ももっと浸透してほしいですねぇ。今や、α合成対応でαビット付きテクスチャにも対応した3Dカードがほとんどで(HELでさえ対応してる)、α値を使っても大丈夫なくらいテクスチャメモリがあるので、ハードの面で問題があるわけではないですし。

 

 以上、加算合成と、α合成の半透明について説明してきました。まだ説明だけで、向き不向きについてはそれほどつっこんだことはまだ書いてませんが、今回は紙面の都合で(紙面?)ここまで、ということにしておきます。げっ、もう27KBにもなってるよ……。
今後書く予定の「加算合成vs半透明」「ブレンドファクター121」でもα合成について書くつもりですんで、興味のある方は付き合ってみてください。
半透明は光の表現にも使えますが、それについても「加算合成vs半透明」で。

 

written by Y.Ohde  e-mail : oode@alles.or.jp

back