トップページ > 過去ログ > 記事閲覧
爆発エフェクト
名前:埴輪 日時: 2011/06/28 15:46

いつもDXライブラリを使わせていただいております。 いま作成中のゲームで、爆発するモーションを必要としています。どのような爆発かは↓をご覧ください。 http://ll.la/63+c 画像を描いて上から、ブレンドすればいいかと思いきや、 質感といいますか、周りにマッチするものが描けず、なるべく処理で実装したいと思っています。 どうすればいいと思いますか? よろしくお願いします。

Page: 1 |

Re: 爆発エフェクト ( No.1 )
名前:いっち 日時:2011/06/28 19:54

> どうすればいいと思いますか? 画像を拝見しましたが、この画像がお求めになっているエフェクトの描画イメージなのか、 イメージ通りになっていない失敗例なのか、また、どのようにうまくいっていないのかがわかりませんでした。 もう少し詳細な説明を頂けますか?
Re: 爆発エフェクト ( No.2 )
名前:埴輪 日時:2011/06/28 20:20

すみません。 その画像のようにしたいです。 3D機能を使っているのですが、球が広がるだけとかではクオリティーに欠けるものがありますので・・・。
Re: 爆発エフェクト ( No.3 )
名前:いっち 日時:2011/06/28 21:16

着弾点(?)を中心に背景画像がゆがんでいるような効果が使用されていますが、これはコストがそれなりに高そうです。 背景画像固定であればソフトイメージでも何とかなるかもしれませんが、そうでなければシェーダーを使わないと無理っぽい(FPS次第ですが)です。 それ以外はブレンド方法を工夫すればパラパラ漫画的な手法でも出来そうです。
Re: 爆発エフェクト ( No.4 )
名前:埴輪 日時:2011/06/28 21:26

最初の、歪んでいくあいだは、他は止まっているようにするつもりなので、 爆発開始の瞬間のスクリーンから画像を作成し、その画像を加工していく、 としたいとおもいます。 >パラパラ漫画的な手法で やはり爆風画像は必要ですよね・・・。
Re: 爆発エフェクト ( No.5 )
名前:いっち 日時:2011/06/28 22:04

> やはり爆風画像は必要ですよね・・・。 計算だけで見栄えのする爆発のエフェクトを作るのは相当しんどいのではないかと思います。 画像を使わない理由があるのでしょうか?
Re: 爆発エフェクト ( No.6 )
名前:sy(サイ) 日時:2011/06/28 23:40

ht tp:// indianwills.com/2009/12/particlin.html こんなのを使うのが一番早いですよ。 そして、お話にある歪みのエフェクトもセットにするのが良いと思います。
Re: 爆発エフェクト ( No.7 )
名前:埴輪 日時:2011/06/29 00:15

周りは全て計算で描画しているものなので、計算で描画したら、 マッチする(浮かない)のになるのではないかと・・・ 合う画像が書けないから、というのが理由ですが、 パーティクリン、試してみます。 ソフトイメージがなんなのかはよくわかっていないのですが、歪むほうで使えそうということで、 もう少し調べてみます。 ありがとうございました。
Re: 爆発エフェクト ( No.8 )
名前:管理人 日時:2011/07/04 01:04

画面を歪ませる処理は描画可能画像と非公開関数の2Dポリゴンを描画する関数の DrawPrimitiveIndexed2D を使用すればシェーダーが無くても実現できます サンプルを組んでみましたので、よろしければご覧ください #include "DxLib.h" #include <math.h> #define CIRCLE_ANGLE_VERTEX_NUM 16 // 円周の頂点数 #define CIRCLE_RADIUS_VERTEX_NUM 8 // 半径の頂点数 #define SCREEN_W 640 // 画面の幅 #define SCREEN_H 480 // 画面の高さ // 画面を歪ませながら描画する関数 void DrawCircleScreen( int CenterX, // 円の中心座標X int CenterY, // 円の中心座標Y float InRadius, // 内側の円のサイズ float OutRadius, // 外側の円のサイズ float Absorption, // 内側の円に引き込まれるドット数 int ScreenHandle // 画面グラフィックハンドル ) { float CenterDistance ; float GraphCenterDistance ; float AbsorptionDistance ; float AbsorptionMoveX, AbsorptionMoveY ; float Angle ; int TextureW, TextureH ; float Sin, Cos ; COLOR_U8 DiffuseColor ; int i, j ; VERTEX2D *Vert ; WORD *Ind ; float AngleCosTable[ CIRCLE_ANGLE_VERTEX_NUM ] ; float AngleSinTable[ CIRCLE_ANGLE_VERTEX_NUM ] ; float InCircleCosTable[ CIRCLE_RADIUS_VERTEX_NUM ] ; // スタックに積むには大きいので static 配列にしました static VERTEX2D Vertex[ CIRCLE_RADIUS_VERTEX_NUM * CIRCLE_ANGLE_VERTEX_NUM ] ; static WORD Index[ ( CIRCLE_ANGLE_VERTEX_NUM + 1 ) * 6 * ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ] ; // 描画可能画像が使用しているテクスチャのサイズを取得しておく GetGraphTextureSize( ScreenHandle, &TextureW, &TextureH ) ; // 最初に普通に描画 DrawGraph( 0, 0, ScreenHandle, FALSE ) ; // 描画カラーを作成しておく DiffuseColor = GetColorU8( 255, 255, 255, 255 ) ; // 外周部分用の Sin, Cos テーブルを作成する Angle = 0.0f ; for( i = 0 ; i < CIRCLE_ANGLE_VERTEX_NUM ; i ++, Angle += PHI_F * 2.0f / CIRCLE_ANGLE_VERTEX_NUM ) { AngleSinTable[ i ] = ( float )sin( ( double )Angle ) ; AngleCosTable[ i ] = ( float )cos( ( double )Angle ) ; } // 内側の盛り上がっているように見せる箇所で使用する Cos テーブルを作成する Angle = 0.0f ; for( i = 0 ; i < CIRCLE_RADIUS_VERTEX_NUM ; i ++, Angle += ( PHI_F / 2.0f ) / ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ) { InCircleCosTable[ i ] = ( float )cos( ( double )Angle ) ; } // ポリゴン頂点インデックスの準備 Ind = Index ; for( i = 0 ; i < CIRCLE_ANGLE_VERTEX_NUM ; i ++ ) { for( j = 0 ; j < CIRCLE_RADIUS_VERTEX_NUM - 1 ; j ++, Ind += 6 ) { Ind[ 0 ] = i * CIRCLE_RADIUS_VERTEX_NUM + j ; Ind[ 1 ] = Ind[ 0 ] + 1 ; if( i == CIRCLE_ANGLE_VERTEX_NUM - 1 ) { Ind[ 2 ] = j ; Ind[ 3 ] = j + 1 ; } else { Ind[ 2 ] = Ind[ 0 ] + CIRCLE_RADIUS_VERTEX_NUM ; Ind[ 3 ] = Ind[ 0 ] + 1 + CIRCLE_RADIUS_VERTEX_NUM ; } Ind[ 4 ] = Ind[ 2 ] ; Ind[ 5 ] = Ind[ 1 ] ; } } // バイリニア補間描画にする SetDrawMode( DX_DRAWMODE_BILINEAR ) ; // 外側のドーナツ部分を描画 // 中心に向かうにしたがって中心方向にテクスチャ座標をずらす Vert = Vertex ; for( i = 0 ; i < CIRCLE_ANGLE_VERTEX_NUM ; i ++ ) { // 使用する Sin, Cos の値をセット Sin = AngleSinTable[ i ] ; Cos = AngleCosTable[ i ] ; for( j = 0 ; j < CIRCLE_RADIUS_VERTEX_NUM ; j ++, Vert ++ ) { // 円の中心までの距離を算出 CenterDistance = OutRadius - ( OutRadius - InRadius ) * j / ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ; // 中心に引き込まれる距離を算出 AbsorptionDistance = Absorption * j / ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ; // 中心に向かって移動する距離を算出 AbsorptionMoveX = Cos * AbsorptionDistance ; AbsorptionMoveY = Sin * AbsorptionDistance ; // スクリーン座標の決定 Vert->pos.x = Cos * CenterDistance + CenterX ; Vert->pos.y = Sin * CenterDistance + CenterY ; Vert->pos.z = 0.0f ; // テクスチャ座標のセット Vert->u = ( Vert->pos.x + AbsorptionMoveX ) / TextureW ; Vert->v = ( Vert->pos.y + AbsorptionMoveY ) / TextureH ; // その他のパラメータをセット Vert->rhw = 1.0f ; Vert->dif = DiffuseColor ; } } // 歪んだドーナツの描画 DrawPrimitiveIndexed2D( Vertex, sizeof( Vertex ) / sizeof( VERTEX2D ), Index, sizeof( Index ) / sizeof( WORD ), DX_PRIMTYPE_TRIANGLELIST, ScreenHandle, FALSE ) ; // 内側の盛り上がっているように見える部分を描画 // Cosテーブルにしたがってテクスチャ座標をずらす Vert = Vertex ; for( i = 0 ; i < CIRCLE_ANGLE_VERTEX_NUM ; i ++ ) { // 使用する Sin, Cos の値をセット Sin = AngleSinTable[ i ] ; Cos = AngleCosTable[ i ] ; for( j = 0 ; j < CIRCLE_RADIUS_VERTEX_NUM ; j ++, Vert ++ ) { // 円の中心までの距離を算出 CenterDistance = InCircleCosTable[ j ] * InRadius ; // 画像座標視点での円の中心までの距離を算出 GraphCenterDistance = ( ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) - j ) * ( Absorption + InRadius ) / ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ; // スクリーン座標の決定 Vert->pos.x = Cos * CenterDistance + CenterX ; Vert->pos.y = Sin * CenterDistance + CenterY ; Vert->pos.z = 0.0f ; // テクスチャ座標のセット Vert->u = ( Cos * GraphCenterDistance + CenterX ) / TextureW ; Vert->v = ( Sin * GraphCenterDistance + CenterY ) / TextureH ; // その他のパラメータをセット Vert->rhw = 1.0f ; Vert->dif = DiffuseColor ; } } // 中心の盛り上がって見える部分を描画 DrawPrimitiveIndexed2D( Vertex, sizeof( Vertex ) / sizeof( VERTEX2D ), Index, sizeof( Index ) / sizeof( WORD ), DX_PRIMTYPE_TRIANGLELIST, ScreenHandle, FALSE ) ; } // WinMain 関数 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int ScreenHandle ; int GrHandle ; int GraphX, GraphAddX ; int CircleX, CircleAddX ; int CircleAngle ; int i ; // ウインドウモードで起動 ChangeWindowMode( TRUE ); // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1; // 描画可能画像の作成 ScreenHandle = MakeScreen( SCREEN_W, SCREEN_H ) ; // 画像の読み込み GrHandle = LoadGraph( "Test1.bmp" ); // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ); // 画像と円の推移用パラメータを初期化 GraphX = 0 ; GraphAddX = 2 ; CircleX = 320 ; CircleAddX = -1 ; CircleAngle = 0 ; // メインループ(何かキーが押されたらループを抜ける) while( ProcessMessage() == 0 ) { // 画像を移動 GraphX += GraphAddX ; if( GraphX < 0 || GraphX > 640 - 119 ) GraphAddX = -GraphAddX ; // 歪み円を移動 CircleX += CircleAddX ; if( CircleX < 0 || CircleX > 640 ) CircleAddX = -CircleAddX ; // 歪み円の円周の値を揺らがせる処理 CircleAngle += 1 ; if( CircleAngle >= 360 ) CircleAngle = 0 ; // 描画先を描画可能画像にする SetDrawScreen( ScreenHandle ) ; // 画面のクリア ClearDrawScreen(); // 画面に格子を描画する for( i = 0 ; i < 640 / 16 ; i ++ ) DrawLine( i * 16 + 1, 0, i * 16 + 1, 480, GetColor( 128,128,128 ) ) ; for( i = 0 ; i < 480 / 16 ; i ++ ) DrawLine( 0, i * 16 + 1, 640, i * 16 + 1, GetColor( 128,128,128 ) ) ; // 画像の描画 DrawGraph( GraphX, 0, GrHandle, TRUE ); // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ) ; // 画面を歪ませて描画 DrawCircleScreen( CircleX, 240, // 中心座標 80.0f + sin( CircleAngle * PHI_F / 180.0f ) * 15.0f, // 内側の円のサイズ 200.0f + sin( CircleAngle * 2 * PHI_F / 180.0f ) * 50.0f, // 外側の円のサイズ 48.0f, // 内側に引き込まれるドット数 ScreenHandle ) ; // 裏画面の内容を表画面に反映 ScreenFlip(); } // DXライブラリの後始末 DxLib_End(); // ソフトの終了 return 0; } 手順としては、まず歪ませるものをすべて描画可能画像に描画した後、それを頂点座標と テクスチャー座標を歪んで見えるように操作した頂点データを用意して DrawPrimitiveIndexed2D で 円形内を敷き詰めるようにポリゴンを描画する、というものです ただ、こちらのサンプルで使用している関数 GetGraphTextureSize は今回追加したものですので、 コンパイルにはこちらの最新バージョンが必要です お手数ですが、よろしければダウンロードしてください m(_ _;m http://homepage2.nifty.com/natupaji/DxLib/DxLibVCTest.exe // VisualC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibBCCTest.exe // BorlandC++ 用 http://homepage2.nifty.com/natupaji/DxLib/DxLibGCCTest.exe // Gnu C++ 用 (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい) 爆発の炎と黒煙は、もやっとした白くて丸い煙の画像さえ用意できれば、 最初に SetDrawBlendMode( DX_BLENDMODE_ALPHA, 255 ) ; SetDrawBright( 0, 0, 0 ) ; の設定を行い真っ黒に描画されるようにした上で煙画像を何枚も描画して黒煙を表現した後、 SetDrawBlendMode( DX_BLENDMODE_ADD, 255 ) ; SetDrawBright( 255,180,64 ) ; の設定を行い赤っぽく、そして描画すればするほど輝度が加算されて明るくなるように上で 画像を何枚も描画して発光する炎を表現すればアップしていただいた爆発を表現できます 爆発が広がっていく様と、だんだん消える様を表現するには、それぞれ黒煙や炎を表現している画像一枚一枚を 徐々に爆心地から離れさせる処理と、一定時間経過したら SetDrawBlendMode の第二引数の値を徐々に下げて フェードアウトさせる処理が必要になります 爆発初期の閃光については、閃光の一枚絵を用意して単純に描画するのが一番簡単そうです ( その一枚絵を用意するのが大変そうですが・・・ )
Re: 爆発エフェクト ( No.9 )
名前:いっち 日時:2011/07/05 23:17

> 画面を歪ませる処理は描画可能画像と非公開関数の2Dポリゴンを描画する関数の > DrawPrimitiveIndexed2D を使用すればシェーダーが無くても実現できます 仰るとおりでした。ご指摘ありがとうございます。
Re: 爆発エフェクト ( No.10 )
名前:いっち 日時:2012/01/16 21:03

別件で話題に出ていたので気になったのですが、No.8 のコードで > static WORD Index[ ( CIRCLE_ANGLE_VERTEX_NUM + 1 ) * 6 * ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ] ; は誤りで > static WORD Index[ CIRCLE_ANGLE_VERTEX_NUM * 6 * ( CIRCLE_RADIUS_VERTEX_NUM - 1 ) ] ; が正しいと思います。 さらについでですが、理解の助けになるかもしれませんので書いておきます。 DrawPrimitiveIndexed2D が外周円と内周円の描画のために2箇所ありますが、その直後に > for ( i = 0; i < sizeof( Index ) / sizeof( WORD ); i+=3 ) { > DrawLine( Vertex[Index[i+0]].pos.x, Vertex[Index[i+0]].pos.y, Vertex[Index[i+1]].pos.x, Vertex[Index[i+1]].pos.y, GetColor( 255, 0, 0 ) ); > DrawLine( Vertex[Index[i+1]].pos.x, Vertex[Index[i+1]].pos.y, Vertex[Index[i+2]].pos.x, Vertex[Index[i+2]].pos.y, GetColor( 255, 0, 0 ) ); > DrawLine( Vertex[Index[i+2]].pos.x, Vertex[Index[i+2]].pos.y, Vertex[Index[i+0]].pos.x, Vertex[Index[i+0]].pos.y, GetColor( 255, 0, 0 ) ); > } といったコードを入れると描画しているポリゴンが見えるようになるので分かりやすくなると思います。 (外周円と内周円で色を分けるとさらに分かりやすいです)
Re: 爆発エフェクト ( No.11 )
名前:管理人 日時:2012/01/21 06:11

ご指摘ありがとうございます

Page: 1 |