トップページ > 記事閲覧
DrawMaskの拡大・回転版
名前:platypus 日時: 2016/03/15 16:10

始めまして、いつもDxLibを使わせて頂いております、platypusと申します。 任意の半径・角度のリングの一部のような形(丸括弧のような形)のマスクを描画したいのですが、 SetDataToMaskを用いて実装しようとしたところ、一ピクセルずつ0か255かの判定を行うため、 マスクのサイズが大きい場合、処理が60fpsに間に合いませんでした。 (特にDebugビルドの場合巨大なマスクにおいては2〜3fpsまで落ちてしまい、処理落ちがひどいです…) そのため、円の画像を用意してマスクデータに変換し、 それの拡大・回転描画を行うことによって時間短縮を図りたいのですが、 マスク画像を描画する関数はDrawMaskしかなかったため、 DrawExtendGraphやDrawRotaGraphのように、画像の拡大や回転をする関数を マスクデータにおいても実装してもらえないでしょうか? 自分の見落としで既にそのような関数が実装されている、 またはすでにある関数の組み合わせで実装できる場合は、 教えて頂けると幸いです。 宜しくお願いします。
メンテ

Page: 1 |

Re: DrawMaskの拡大・回転版 ( No.1 )
名前:管理人 日時:2016/03/21 15:25

ご返信が遅くなり申し訳ありません 現在のマスク機能の内部構造の関係で拡大や回転の機能を実装しようとすると かなりの作業時間が必要になってしまうので、ちょっと関数を追加するのは難しいです ただ、マスクよりは扱いが面倒ですが SetBlendGraphParam という関数を使えば マスクのような処理が実装できますので、よろしければ使用してみてください // 描画処理時に描画する画像とブレンドする画像のブレンド設定を行う // BlendGraph を -1 にすれば設定を解除、その場合 BlendType とその後ろのパラメータは無視される int SetBlendGraphParam( int BlendGraph, int BlendType, ... ) ; 引数の BlendType には現在のところ3つ種類があります int SetBlendGraphParam( int BlendGraph, DX_BLENDGRAPHTYPE_NORMAL, int Ratio = ( 0( ブレンド率0% )〜255( ブレンド率100% ) ) ) ; int SetBlendGraphParam( int BlendGraph, DX_BLENDGRAPHTYPE_WIPE, int BorderParam = 境界位置(0〜255), int BorderRange = 境界幅(指定できる値は1、64、128、255の4つ) ) ; int SetBlendGraphParam( int BlendGraph, DX_BLENDGRAPHTYPE_ALPHA ) ; が、今回は DX_BLENDGRAPHTYPE_ALPHA を使用します、こちらはシンプルに引数 BlendGraph で指定した グラフィックハンドルのアルファ値と、DrawGraph などで描画する画像のアルファ値を合成する、というものです これを利用して仮の画面に描画したものと、マスク用の画面に描画したものを合成して裏画面に 描画すれば、マスク処理のような効果が得られるというわけです 試しに仮画面全体に描画した画像の一部をこの機能を使って裏画面に描画するというサンプルを 組んでみましたので、よろしければご覧になってみてください m(_ _)m #include "DxLib.h" #include <math.h> int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int Handle ; int MaskScreen ; int TempScreen ; float Angle ; int i ; // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // 画像を読み込む Handle = LoadGraph( "Test1.bmp" ) ; // マスクと合成するための仮画面を作成 TempScreen = MakeScreen( 640, 480, TRUE ) ; // マスク用の画面を作成 MaskScreen = MakeScreen( 640, 480, TRUE ) ; // 結果がわかりやすいように背景色をグレーに設定 SetBackgroundColor( 128,128,128 ) ; // 円の回転角度を初期化 Angle = 0.0f ; // メインループ while( ProcessMessage() == 0 ) { // 円の回転角度を変更 Angle += 0.05f ; // 仮画面全体に画像を描画 SetDrawScreen( TempScreen ) ; ClearDrawScreen() ; for( i = 0 ; i < 6 ; i ++ ) { DrawGraph( i * 119, 0, Handle, TRUE ) ; } // マスク用の画面に回転する円を描画 SetDrawScreen( MaskScreen ) ; ClearDrawScreen() ; DrawCircle( ( int )( cos( Angle ) * 160.0f ) + 320, ( int )( sin( Angle ) * 120.0f ) + 240, 128, GetColor( 255,255,255 ), TRUE ) ; // 描画先を裏画面に変更 SetDrawScreen( DX_SCREEN_BACK ) ; ClearDrawScreen() ; // 描画時の合成画像にマスク画面を設定 // ( マスク画面のアルファ値と仮画面のアルファ値を合成する ) SetBlendGraphParam( MaskScreen, DX_BLENDGRAPHTYPE_ALPHA ) ; // 仮画面を裏画面に描画( マスク画面のアルファ値も使用しつつ ) DrawGraph( 0, 0, TempScreen, TRUE ) ; // 合成設定を解除 SetBlendGraphParam( -1, DX_BLENDGRAPHTYPE_NORMAL ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリの後始末 DxLib_End() ; return 0 ; }
メンテ
Re: DrawMaskの拡大・回転版 ( No.2 )
名前:platypus 日時:2016/03/24 18:03

管理人様、 SetBlendGraphParamの紹介をありがとうございます! しかし、リングのような形が描画されているマスクスクリーンを再現するために、 DrawCircleの直下に DrawCircle( ( int )( cos( Angle ) * 160.0f ) + 320, ( int )( sin( Angle ) * 120.0f ) + 240, 64, GetColor( 0,0,0 ), TRUE ) ; のように半径の小さい黒色の円を上から描画しても、 管理人様の提示して下さったソースの画面と変わらず、 「一つの回っている円の穴から奥の画像が見えている」ような状態でありました。 調べてみたところ、どうやら「黒色=100%透過」ではなく、 アルファ値に関係が有るとのことが分かったのですが、 理解力が足りず手こずっています… (お恥ずかしながら、SetBlendGraphParamの仕組み自体100%理解できているか、 と聞かれてもそうと断言が出来ない状態です…) そこで、 MaskScreenに描画されたピクセルは、DrawMaskToDirectDataの配列のように、 黒=透過しない 白=透過する という認識であっているでしょうか? またそうでない場合、DrawCircleの組み合わせで どのようにリングのような形を再現できるのでしょうか?
メンテ
Re: DrawMaskの拡大・回転版 ( No.3 )
名前:管理人 日時:2016/03/27 22:08

> MaskScreenに描画されたピクセルは、DrawMaskToDirectDataの配列のように、 > 黒=透過しない 白=透過する という認識であっているでしょうか? いえ、マスクスクリーンとは異なり色( RGB )ではなくスクリーンに書かれたアルファ値( A )が 透過するかどうかに影響します ご希望の処理を実現するには描画ブレンドモード DX_BLENDMODE_SRCCOLOR を使用します こちらは「描画色( RGBA )を何の細工もせずにそのまま描画先に書き込む」というモードで、 例えば、普通のアルファブレンドを行う DX_BLENDMODE_ALPHA を使用して SetDrawBlendMode( DX_BLENDMODE_ALPHA, 0 ) ; とした場合はアルファ値が0、つまり 完全透明の状態になって描画先には何も描画されませんが、SetDrawBlendMode( DX_BLENDMODE_SRCCOLOR, 0 ) ; とした場合はアルファ値0の値が描画先に描画されます、これを利用してアルファ値が0ではない通常の円を 描画した後、その円より小さいアルファ値0の円を描画すればご希望の処理を実現できます #include "DxLib.h" #include <math.h> int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int Handle ; int MaskScreen ; int TempScreen ; float Angle ; int i ; // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // 画像を読み込む Handle = LoadGraph( "Test1.bmp" ) ; // マスクと合成するための仮画面を作成 TempScreen = MakeScreen( 640, 480, TRUE ) ; // マスク用の画面を作成 MaskScreen = MakeScreen( 640, 480, TRUE ) ; // 結果がわかりやすいように背景色をグレーに設定 SetBackgroundColor( 128,128,128 ) ; // 円の回転角度を初期化 Angle = 0.0f ; // メインループ while( ProcessMessage() == 0 ) { // 円の回転角度を変更 Angle += 0.05f ; // 仮画面全体に画像を描画 SetDrawScreen( TempScreen ) ; ClearDrawScreen() ; for( i = 0 ; i < 6 ; i ++ ) { DrawGraph( i * 119, 0, Handle, TRUE ) ; } // マスク用の画面に回転する円を描画 SetDrawScreen( MaskScreen ) ; ClearDrawScreen() ; // 通常の円を描画 DrawCircle( ( int )( cos( Angle ) * 160.0f ) + 320, ( int )( sin( Angle ) * 120.0f ) + 240, 128, GetColor( 255,255,255 ), TRUE ) ; // 内部を DX_BLENDMODE_SRCCOLOR でくり貫く SetDrawBlendMode( DX_BLENDMODE_SRCCOLOR, 0 ) ; DrawCircle( ( int )( cos( Angle ) * 160.0f ) + 320, ( int )( sin( Angle ) * 120.0f ) + 240, 64, GetColor( 255,255,255 ), TRUE ) ; SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 255 ) ; // 描画先を裏画面に変更 SetDrawScreen( DX_SCREEN_BACK ) ; ClearDrawScreen() ; // 描画時の合成画像にマスク画面を設定 // ( マスク画面のアルファ値と仮画面のアルファ値を合成する ) SetBlendGraphParam( MaskScreen, DX_BLENDGRAPHTYPE_ALPHA ) ; // 仮画面を裏画面に描画( マスク画面のアルファ値も使用しつつ ) DrawGraph( 0, 0, TempScreen, TRUE ) ; // 合成設定を解除 SetBlendGraphParam( -1, DX_BLENDGRAPHTYPE_NORMAL ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリの後始末 DxLib_End() ; return 0 ; }
メンテ
Re: DrawMaskの拡大・回転版 ( No.4 )
名前:platypus(解決) 日時:2016/03/28 19:38

管理人様、 ありがとうございます! これでやりたかった動作を再現できました。 まだまだ修行途中のプログラマーですので、また質問したときはよろしくお願いします! 解決です。
メンテ
Re: DrawMaskの拡大・回転版 ( No.5 )
名前:platypus 日時:2016/03/31 21:16

すみません、解決としていましたがもう一つ問題が発生したので質問します。 仮画面を裏画面に描画する場所 DrawGraph( 0, 0, TempScreen, TRUE ) ; の代わりに、 DrawBox(0, 0, 640, 480, GetColor(0, 0, 255), TRUE); と、画面いっぱいに青い四角形を描画したところ、 本来ブレンドによって描画されないべき場所までもが描画されていました。 リファレンスのSetDrawBlendModeの説明にはDrawBoxを使用しても 正しくブレンドされると表記されているのですが、 SetBlendGraphParamを使用するときは違うのでしょうか。 また、可能ならばDrawBoxを使っての描画時もSetBlendGraphParamを使ったブレンドに 対応してもらいたいと思っています。
メンテ
Re: DrawMaskの拡大・回転版 ( No.6 )
名前:管理人 日時:2016/04/03 12:48

> 仮画面を裏画面に描画する場所 > DrawGraph( 0, 0, TempScreen, TRUE ) ; > の代わりに、 > DrawBox(0, 0, 640, 480, GetColor(0, 0, 255), TRUE); > と、画面いっぱいに青い四角形を描画したところ、 > 本来ブレンドによって描画されないべき場所までもが描画されていました。 もしマスク効果の効いた画面いっぱいの青い四角形を描画されようとしたのでしたら 多少面倒で申し訳ありませんが、仮画面全体に青い四角形を描画したあと、 SetBlendGraphParam でマスク画面と合成する設定にしたうえで 仮画面を裏画面に DrawGraph で描画するようにしてください m(_ _)m > リファレンスのSetDrawBlendModeの説明にはDrawBoxを使用しても > 正しくブレンドされると表記されているのですが、 > SetBlendGraphParamを使用するときは違うのでしょうか。 はい、SetDrawBlendMode と SetBlendGraphParam は名前は似ていますが全く別の機能です SetBlendGraphParam はあくまで画像を描画する際に影響を与える機能となっています > また、可能ならばDrawBoxを使っての描画時もSetBlendGraphParamを使ったブレンドに > 対応してもらいたいと思っています。 DrawBox や DrawLine や DrawCircle などの図形描画関数は画像を使用しないので、 各描画ピクセルを『ブレンドする画像』のどこの座標のピクセルに対応させるのかを 決定することができません なので申し訳ありませんが対応することはできません m(_ _;m
メンテ
Re: DrawMaskの拡大・回転版 ( No.7 )
名前:platypus(解決) 日時:2016/04/04 08:42

なるほど、そういう事情があったのですね! DrawBoxは直に使わない方針で行こうと思います。 解決です。
メンテ

Page: 1 |

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

   クッキー保存