トップページ > 記事閲覧
DX_BLENDMODE_INVDESブレンドモードについて
名前:へけぽん 日時: 2016/10/30 20:30

DX_BLENDMODE_INVDESTCOLORという 描画する画像の色をx,y,z  描画先にある色をr,g,bとすると ((255-r)*x,(255-g)*y,(255-b)*z)が結果として出てくる色になり SetIgnoreDrawGraphColorと組み合わせると面白い効果が得られそうなブレンドモードですが どうも透明な部分も同じように描画処理をしているようでちょっと狙った通りに上手くいきません SetIgnoreDrawGraphColorのフラグを立てないデフォルトの状態でも検証したり 二色の画像で片方が透過色というpngを用意して試してみてもやはり透過設定が無効のようです このブレンドモードでα値を考慮して描画する、つまり透明な部分は描画先に影響を与えないようにする方法は無いのでしょうか?
メンテ

Page: 1 |

Re: DX_BLENDMODE_INVDESブレンドモードについて ( No.1 )
名前:管理人 日時:2016/10/31 01:05

現時点ではアルファ値にも同じ演算をしてしまうブレンドモードしかないので、追加しようと思います 次の週末までは掛からないと思いますので、数日お待ちください m(_ _)m > このブレンドモードでα値を考慮して描画する、つまり透明な部分は描画先に影響を与えないようにする 描画先のα値がそのまま残り、描画元のα値は描画結果に全く影響を与えないということでしょうか?
メンテ
Re: DX_BLENDMODE_INVDESブレンドモードについて ( No.2 )
名前:へけぽん 日時:2016/10/31 07:33

>描画先のα値がそのまま残り、描画元のα値は描画結果に全く影響を与えないということでしょうか? えっとひょっとしたら私がちゃんと理解していないのかもしれないのですけれど 透過色が黒(0,0,0)の画像だったら、透過部分は((255-r)*0,(255-g)*0,(255-b)*0)になっていますし 透過色が青(0,0,255)だったら((255-r)*0,(255-g)*0,(255-b)*255)になっているように見えたので 描画元の画像の透過部分、つまりα値が0の部分も、そうではない部分と同じように計算されているのではないか? と思っているので先ほどの様な表現をしたのですが…… つまるところ望む効果としては描画した結果が 「描画元の画像の色が((255-r)*x,(255-g)*y,(255-b)*z)に変化し、α値はそのまま。という画像が、DX_BLENDMODE_ALPHAのブレンドモードで描画された」 と同じ結果になってくれれば満足なのですが
メンテ
Re: DX_BLENDMODE_INVDESブレンドモードについて ( No.3 )
名前:管理人 日時:2016/11/02 17:37

ご返答ありがとうございます、理解できました その上で、すみません、暫くブレンドモード関連に触れていなかったので 失念していたのですが、へけぽんさんがご所望のブレンドモードは 実装できないことがわかりました DXライブラリのブレンドモードは Direct3D が対応しているブレンド機能を ほぼそのまま使用しているのですが、Direct3D にも『描画先の色を反転したものと 描画元の色を乗算した上でアルファブレンドの処理も行う』ことができる機能は存在せず、 実現するにはシェーダーなどを使って幾つかの処理に分ける必要がありました DXライブラリの既存の機能でも『描画対象にできるグラフィックハンドル』と GraphBlendBlt を使用して実現することができましたので、よろしければ下記の サンプルプログラムをご覧ください m(_ _;m #include "DxLib.h" int TempScreen1 ; int TempScreen2 ; // アルファ値の透過処理付きのブレンドモード DX_BLENDMODE_INVDESTCOLOR 描画 int DrawInvDestColorBlendGraph( int x, int y, int GrHandle, int BlendParam ) { int TempScreenSizeX ; int TempScreenSizeY ; int Result ; int SizeX ; int SizeY ; int BackupBlendMode ; int BackupBlendParam ; int BackupDrawScreen ; // 現在のブレンドモードと描画先のグラフィックハンドルを取得 GetDrawBlendMode( &BackupBlendMode, &BackupBlendParam ) ; BackupDrawScreen = GetDrawScreen() ; // 描画先が裏画面や表画面の場合はエラー if( BackupDrawScreen == DX_SCREEN_BACK || BackupDrawScreen == DX_SCREEN_FRONT ) return -1 ; // 描画する画像のサイズを取得 if( GetGraphSize( GrHandle, &SizeX, &SizeY ) < 0 ) return -1 ; // 作業用グラフィックハンドルが無効の場合か、作業用グラフィックハンドルの // サイズが描画する画像のサイズより小さかったら作業用グラフィックハンドルを作成しなおす Result = GetGraphSize( TempScreen1, &TempScreenSizeX, &TempScreenSizeY ) ; if( Result < 0 || TempScreenSizeX < SizeX || TempScreenSizeY < SizeY ) { // 作業用グラフィックハンドルが有効だった場合は削除 if( Result >= 0 ) { DeleteGraph( TempScreen1 ) ; DeleteGraph( TempScreen2 ) ; } // 新しいサイズで作業用グラフィックハンドルを作成する TempScreen1 = MakeScreen( SizeX, SizeY, TRUE ) ; TempScreen2 = MakeScreen( SizeX, SizeY, TRUE ) ; if( TempScreen1 < 0 || TempScreen2 < 0 ) return -1 ; } // 作業用グラフィックハンドルに『GrHandle を描画する範囲』の『描画先の画像』をコピーする SetDrawScreen( TempScreen1 ) ; SetDrawBlendMode( DX_BLENDMODE_SRCCOLOR, 255 ) ; DrawGraph( -x, -y, BackupDrawScreen, TRUE ) ; // 作業用グラフィックハンドルに GrHandle をブレンドモード DX_BLENDMODE_INVDESTCOLOR で描画する SetDrawBlendMode( DX_BLENDMODE_INVDESTCOLOR, 255 ) ; DrawGraph( 0, 0, GrHandle, TRUE ) ; // 作業用グラフィックハンドルの RGB と、GrHandle の A を合成したものを // 作業用グラフィックハンドルその2に転送する GraphBlendBlt( GrHandle, TempScreen1, TempScreen2, 255, DX_GRAPH_BLEND_RGBA_SELECT_MIX, DX_RGBA_SELECT_BLEND_R, DX_RGBA_SELECT_BLEND_G, DX_RGBA_SELECT_BLEND_B, DX_RGBA_SELECT_SRC_A ) ; // 描画先を元に戻す SetDrawScreen( BackupDrawScreen ) ; // ブレンドモードを DX_BLENDMODE_ALPHA に変更する SetDrawBlendMode( DX_BLENDMODE_ALPHA, BlendParam ) ; // 指定の座標に作業用グラフィックハンドルその2を描画する DrawRectGraph( x, y, 0, 0, SizeX, SizeY, TempScreen2, TRUE, FALSE ) ; // ブレンドモードを元に戻す SetDrawBlendMode( BackupBlendMode, BackupBlendParam ) ; // 正常終了 return 0 ; } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int Screen ; int BackGrHandle ; int GrHandle ; // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // 仮の画面を作成 Screen = MakeScreen( 640, 480, FALSE ) ; // 背景画像を読み込み BackGrHandle = LoadGraph( "BackImage.bmp" ) ; // 描画画像を読み込み GrHandle = LoadGraph( "Test1.bmp" ) ; // メインループ while( ProcessMessage() == 0 ) { // 描画先を仮の画面に変更 SetDrawScreen( Screen ) ; // 描画先をクリア ClearDrawScreen() ; // 背景画像を描画 DrawGraph( 0, 0, BackGrHandle, FALSE ) ; // アルファ値の透過処理付きのブレンドモード DX_BLENDMODE_INVDESTCOLOR で画像を描画 DrawInvDestColorBlendGraph( 240, 0, GrHandle, 255 ) ; // 描画先を裏画面に変更 SetDrawScreen( DX_SCREEN_BACK ) ; // 裏画面に仮の画面を描画 DrawGraph( 0, 0, Screen, FALSE ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } DrawInvDestColorBlendGraph が「DX_BLENDMODE_ALPHA + DX_BLENDMODE_INVDESTCOLOR」を 行っている関数なのですが、仕組みとしては 1.描画先の画像を作業用画像1に転送 2.作業用画像1に引数で渡された画像を DX_BLENDMODE_INVDESTCOLOR で描画 3.RGB を作業用画像1、A を引数で渡された画像にしたものを作業用画像2に転送 4.描画先に作業用画像2を描画 というようなことを行っています WinMain で裏画面に直接描画せず、わざわざ MakeScreen で作成した『描画対象にできる画像』を 描画先にしているのは、上記の 1 を実行するためです( 裏画面の内容も GetDrawScreenGraph で 取得することができるのですが、『描画対象にできる画像』を DrawGraph で転送するほうが 圧倒的に高速なので ) 見ての通り沢山の処理を実行する必要があるので多用すると重いと思いますが、使い所を 考えて1フレームに数回実行するくらいでしたら問題ないと思います
メンテ
Re: DX_BLENDMODE_INVDESブレンドモードについて ( No.4 )
名前:へけぽん 日時:2016/11/02 19:48

返答ありがとうございます いただいたサンプルですが、現在作っている仕組みに導入するのは難しそうです ですが以前教えていただいた画像に穴をあけるやり方を使うことで一応自分の出したい結果にすることは出来るのでそれは大丈夫です ただそちらも複数の画面を頻繁に切り替えながら画像を作っていく事になるので重いことに変わりは無いんですが… あと最後に3つほど確認したいのですが、 1 描画元の色を乗算した上でアルファブレンドの処理も行うことが出来ない、ということなので 透過処理がされているpng画像をSetIgnoreDrawGraphColor(TRUE)としてDX_BLENDMODE_INVDESTCOLORで描画しても ただの真っ白な四角い画像をDX_BLENDMODE_INVDESTCOLORで描画したのと同じ結果になる 2 DrawOvalやDrawOval_Rect指定した円の範囲内だけ色を反転させることは可能だが それはそもそも円の範囲外については描画処理を行っていないから出来ることで 例えば円をDrawOval_Rectで作業用の画面に一度描いて、それを自作の関数で歪ませた画像をDerivationGraphなどで取り出して描画した場合は 取り出した画像の円の範囲外には「α値は0、RGBは透過色(デフォルトでは黒(0,0,0))」というピクセルのデータが追加されているため上手くいかない 3 上に書いた「描画元の画像の色が((255-r)*x,(255-g)*y,(255-b)*z)に変化し〜」は理想中の理想なので、実際のところ 「描画元の透明部分とそうでない部分を判別して、不透明な部分の描画先の色が反転する(つまり描画元の色(RGB)は関係ない)」 というだけでも十分過ぎるほど欲しい機能なのですが、それもやはりアルファブレンドが出来ないので不可能 こういう事でしょうか? 思いっきり具体的に書きますと、 マップ上に点在する毒の霧の表現に「霧に触れている部分だけが色が反転する」というのを使いたかったのですが 速度を考えると、DrawTriangleを組み合わせて座標を変化させることで表現するくらいが現実的でしょうか…
メンテ
Re: DX_BLENDMODE_INVDESブレンドモードについて ( No.5 )
名前:管理人 日時:2016/11/03 02:57

> 1 はい > 2 はい > 3 すみません、うっかりしていました、『透明部分とそうでない部分を判別して』という一文で ある機能を思い出しました 「アルファテスト」を使用すれば「描画元のアルファ値の値によって描画処理を行ったり 行わなかったりする」ことができるので、へけぽんさんのご所望の処理も実現できるかもしれません DXライブラリでアルファテストを設定するには SetDrawAlphaTest を使用します // 描画時のアルファテストの設定を行う // TestMode : 比較モード( DX_CMP_GREATER等 -1でデフォルト動作に戻す ) // TestParam : 描画アルファ値との比較に使用する値( 0〜255 ) int SetDrawAlphaTest( int TestMode, int TestParam ) ; // 比較モード #define DX_CMP_NEVER (1) // 必ず描画しない( 何のためにあるんだろう… ) #define DX_CMP_LESS (2) // 描画元アルファ < TestParam の場合に描画 #define DX_CMP_EQUAL (3) // 描画元アルファ == TestParam の場合に描画 #define DX_CMP_LESSEQUAL (4) // 描画元アルファ <= TestParam の場合に描画 #define DX_CMP_GREATER (5) // 描画元アルファ > TestParam の場合に描画 #define DX_CMP_NOTEQUAL (6) // 描画元アルファ != TestParam の場合に描画 #define DX_CMP_GREATEREQUAL (7) // 描画元アルファ >= TestParam の場合に描画 #define DX_CMP_ALWAYS (8) // 必ず描画する( 何のためにあるんだろう… ) 例えば SetDrawAlphaTest( DX_CMP_GREATER, 128 ) ; を実行した場合は、描画する画像の アルファ値が 128 より大きい箇所のみ描画され、128 以下の箇所は描画されなくなります なので、DX_BLENDMODE_INVDESTCOLOR を使った場合も以下のように SetDrawAlphaTest を 使用してアルファ値が 16 より大きい箇所のみ描画されるようにすれば、アルファ値が 0 の箇所や、16 以下の箇所は DX_BLENDMODE_INVDESTCOLOR の効果が反映されないように することができます // アルファ値が 16 より大きい箇所のみ描画するようにする SetDrawAlphaTest( DX_CMP_GREATER, 16 ) ; SetDrawBlendMode( DX_BLENDMODE_INVDESTCOLOR, 255 ) ; DrawGraph( 0, 0, GrHandle, TRUE ) ; SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ; // 設定を元にどす SetDrawAlphaTest( -1, 0 ) ; よろしければお試しください m(_ _;m
メンテ
Re: DX_BLENDMODE_INVDESブレンドモードについて ( No.6 )
名前:へけぽん(解決) 日時:2016/11/03 06:53

上手くいきました!! 単純に描画先の色を反転するだけでなく、ちゃんとその反転値に描画元の色を乗算した色にもなっています! ちなみにデフォルトの状態とはどういう状態なのでしょう? SetDrawAlphaTest(DX_CMP_NOTEQUAL,0)と設定しておけば 別にデフォルトに戻す必要はないのではないかとも思いましたが 「デフォルト設定ではそもそも比較自体を行わないので、  比較モードを設定している時よりも高速になる。  よって、通常はデフォルト設定の方が望ましい。」 という事でしょうか
メンテ
Re: DX_BLENDMODE_INVDESブレンドモードについて ( No.7 )
名前:管理人(解決) 日時:2016/11/04 22:00

> ちなみにデフォルトの状態とはどういう状態なのでしょう? デフォルトの状態ではブレンドモードによってアルファテストを ON にしたり OFF にしたりします 例えば DX_BLENDMODE_ALPHA や DX_BLENDMODE_ADD のような、アルファ値が0であればアルファテストをしても しなくてもブレンドの計算上何も描画されない( 描画先のピクセルの色が変化しない )場合は描画負荷軽減のために アルファテストを ON にします 逆に DX_BLENDMODE_MUL や DX_BLENDMODE_INVDESTCOLOR のような、アルファ値が0でも計算上は何か描画される ( 描画先のピクセルの色が変化する )場合はアルファテストを OFF にしています なので、ブレンド効果のマスキングのためにアルファテストを使用するのではなく、あくまで描画結果に影響を与えず 処理負荷軽減の為だけにアルファテストを使用するのがデフォルトの動作です > 「デフォルト設定ではそもそも比較自体を行わないので、 >  比較モードを設定している時よりも高速になる。 >  よって、通常はデフォルト設定の方が望ましい。」 デフォルト設定でもブレンドモードによってはアルファテストを行いますし、アルファテストで描画がキャンセルされる ピクセルが多いほうが高速なのでデフォルト設定が望ましいということはありません 「DX_BLENDMODE_MUL を指定して描画したら、計算上はアルファ値は関係ない筈なのに、何故かアルファ値が0の 部分が透過される」ということが無いような動作をするのがデフォルトの状態です
メンテ
Re: DX_BLENDMODE_INVDESブレンドモードについて ( No.8 )
名前:へけぽん(解決) 日時:2016/11/04 23:40

回答ありがとうございます よくわかりました
メンテ

Page: 1 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存