crowさんどうも、DXライブラリの管理人です。
描画対象にすることが出来るαチャンネル付き画像を作成する機能と、
αチャンネル付き画像に描画するに当たって少し必要になる機能を
追加しました。
ただ、ちょっと曲者です。
http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe //VC用
http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe //BCC用
(中身を既存のライブラリのファイルに上書きして、BCCをお使いの
場合は『再構築』、VCをお使いの場合は『リビルド』をして下さい)
このバージョンで追加した関数は以下の通りです。
// 描画可能なαチャンネル付き画像を作成するかどうかのフラグをセットする
// SetDrawValidGraphCreateFlag 関数で描画可能画像を作成するように
// 設定されていないと効果がない( TRUE:αチャンネル付き FALSE:αチャンネルなし )
int SetDrawValidAlphaChannelGraphCreateFlag( int Flag );
// SetDrawBlendMode 関数の第一引数に DX_BLENDMODE_NOBLEND を代入した際に
// デフォルトでは第二引数は内部で255を指定したことになるが
// その自動255化をしないかどうかを設定する
// TRUE:しない(第二引数の値が使用される)
// FALSE:する(第二引数の値は無視されて 255 が常に使用される)(デフォルト) )
// αチャンネル付き画像に対して描画を行う場合のみ意味がある関数
int SetUseNoBlendModeParam( int Flag );
まず、普通に SetDrawValidGraphCreateFlag( TRUE ); をした状態で MakeGraph 関数で
画像を作成すると、αチャンネルの無い画像となってしまいますので、
SetDrawValidGraphCreateFlag( TRUE ); をして、且つ
SetDrawValidAlphaChannelGraphCreateFlag( TRUE ); もした上で MakeGraph 関数で
画像を作成すると、αチャンネル付きの描画対象に出来る画像が作成されます。
作成した描画対象に出来るαチャンネル付き画像を描画対象にして ClearDrawScreen
を実行すると、RGBA の値全てが0に初期化されます。
で、書き込まれるアルファ値についてですが、
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 255 );
SetDrawBright( 255,255,255 );
の状態で画像を描画すると元の画像そのままのものが描画されますが、αチャンネル
にも見た目そのままの値が書き込まれます。(つまり透明情報がそのまま描画されます)
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 128 );
の状態で画像を描画すると書き込まれるRGB値と同じ様に書き込まれるα値も、
画像のα値の半分の値が書き込まれます。
(DX_BLENDMODE_ALPHA,128 で描画すると丁度50%不透明の描画なので)
で、この半透明描画、理屈は合っていますが、直感的ではない結果になります。
例えばαチャンネル付き画像に
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 128 );
DrawBox( 0,0,100,100,GetColor(255,255,255), TRUE );
とした上で、このボックスを描画したαチャンネル付き画像を
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 255 );
DrawGraph( 0, 0, 描画対象に出来るαチャンネル付き画像, TRUE );
とした場合は、一見透明度50%の白い四角が描画されそうですが、
実際は灰色の透明度25%の四角が描画されます。
これは、αチャンネル付き画像に描画する際に以下の様な演算が行われて
いるからです。
αチャンネル付き画像に書き込まれるR = (書き込み先のR×(255−書き込み元のA) + 書き込み元のR×書き込み元のA)÷255
αチャンネル付き画像に書き込まれるG = (書き込み先のG×(255−書き込み元のA) + 書き込み元のG×書き込み元のA)÷255
αチャンネル付き画像に書き込まれるB = (書き込み先のB×(255−書き込み元のA) + 書き込み元のB×書き込み元のA)÷255
αチャンネル付き画像に書き込まれるA = (書き込み先のA×(255−書き込み元のA) + 書き込み元のA×書き込み元のA)÷255
この演算を上記の例に当てはめると結果は以下の様になります。
(書き込み先は真っ黒(RGBA=0000)と仮定します)
αチャンネル付き画像に書き込まれるR 128 = ( 0 x (255 - 128 ) + 255 x 128 ) / 255
αチャンネル付き画像に書き込まれるG 128 = ( 0 x (255 - 128 ) + 255 x 128 ) / 255
αチャンネル付き画像に書き込まれるB 128 = ( 0 x (255 - 128 ) + 255 x 128 ) / 255
αチャンネル付き画像に書き込まれるA 64 = ( 0 x (255 - 128 ) + 128 x 128 ) / 255
つまり、αチャンネル付き画像には灰色(R:128 G:128 B:128)の、透明度25%(64)の
ピクセルが書き込まれてしまうわけです。
なので、透明度50%の白の四角をαチャンネル付き画像に書き込みたい場合は
以下の様にする必要があります。
SetUseNoBlendModeParam( TRUE );
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 128 );
DrawBox( 0,0,100,100, GetColor(255,255,255), TRUE );
ブレンドモードを DX_BLENDMODE_NOBLEND にすると、書き込み時に使用される
α値が必ず 255 になってしまうので、SetUseNoBlendModeParam( TRUE );
を実行して DX_BLENDMODE_NOBLEND 時の第二引数を書き込み時のα値に
なるようにしています。
というわけで、ブレンドなしの場合は指定したα値がなんの演算もされずに
そのままαチャンネル付き画像に R=255 G=255 B=255 A=128 の値が書き込まれる
ので、その画像を後に
DrawGraph( 0, 0, 描画対象に出来るαチャンネル付き画像, TRUE );
としても、予想通り透明度50%の四角が画面に描画されるわけです。
というわけで、描画可能なαチャンネル付き画像に対するブレンド描画は全然直感的ではありません。
別の例として、αチャンネル付き画像に
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 128 );
DrawBox( 0,0,100,100, GetColor(255,255,255), TRUE );
DrawBox( 0,0,100,100, GetColor(255,255,255), TRUE );
と、透明度50%の四角を2回描画したら、直感的には
透明度25%の真っ白(明度100%)の四角が残りそうですが、実際は
透明度62.5%の灰色の四角(明度75%)が残るだけとなります。
何故ならこの2回の描画を上記の式に当てはめると
1回目の DrawBox
R: 128 = ( 0 x ( 255 - 128 ) + 255 x 128 ) 255
G: 128 = ( 0 x ( 255 - 128 ) + 255 x 128 ) 255
B: 128 = ( 0 x ( 255 - 128 ) + 255 x 128 ) 255
A: 64 = ( 0 x ( 255 - 128 ) + 128 x 128 ) 255
2回目の DrawBox
R: 192 = ( 128 x ( 255 - 128 ) + 255 x 128 ) / 255
G: 192 = ( 128 x ( 255 - 128 ) + 255 x 128 ) / 255
B: 192 = ( 128 x ( 255 - 128 ) + 255 x 128 ) / 255
A: 96 = ( 64 x ( 255 - 128 ) + 128 x 128 ) / 255
となるからです。
そして、実際は直感的な描画結果を得るには以下の様な演算をする必要があります。
書き込まれるA = 書き込み先A+(255−書き込み先A)×書き込むA÷255
書き込まれるR = (書き込み先R×(書き込まれるA−書き込むA)+書き込むR×書き込むA)÷書き込まれるA
書き込まれるG = (書き込み先G×(書き込まれるA−書き込むA)+書き込むG×書き込むA)÷書き込まれるA
書き込まれるB = (書き込み先B×(書き込まれるA−書き込むA)+書き込むB×書き込むA)÷書き込まれるA
ただ、このような演算は簡単には出来ず、ちょっと考えただけでもかなりの
グラフィックチップ性能が必要になりそうです。
というわけで、現時点では直感的ではない描画しか出来ません。
特殊な映像効果としては面白いことが出来るかもしれませんが、リアルな(理屈に合った)
映像表現をしようと思った場合はかなり扱い辛いかもしれません。
そんな感じですが、宜しければお使いになってみて下さい。m(_ _)m