トップページ > 記事閲覧
3Dモデルのフレームに対する当たり判定について
名前:nekoze 日時: 2018/08/18 20:06

いつもお世話になっております。 3Dモデル(pmx)を用いたアプリを制作しているのですが、当たり判定が上手く取得できないため、 ご助力お願いいたします。 やりたいこととしては、3Dモデルを読み込んだ後、対象フレームを指定したMV1SetupCollInfo関数でコリジョン情報を設定。 (ここで指定したフレームのFrameIndexを変数に保持) その後、マウスの左クリックが押された時に、マウスの座標を取得後、ワールドの座標に変換して MV1CollCheck_Line関数で当たり判定の取得をしようとしています。 ※MV1SetupCollInfo関数及びMV1CollCheck_Line関数のFrameIndexに-1を設定した場合では、 衝突情報は取得できています。 以下ソース(一部抜粋) ============================= // 当たり判定の準備 var frames = DX.MV1GetFrameNum(modelHandle); for (var i = 0; i < frames; i++) { var frameName = DX.MV1GetFrameName(modelHandle, i); if (frameName == "頭") { // 衝突判定の対象のフレームを設定 DX.MV1SetupCollInfo(modelHandle,i); frameIndex = i; } } 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜 // マウスのディスプレイ座標を取得 DX.GetMousePoint( out int mouseX, out int mouseY ); // マウスの左ボタンが押下されている場合 if ((DX.GetMouseInput() & DX.MOUSE_INPUT_LEFT) != 0) { DX.VECTOR dispPos; DX.VECTOR startPoint; DX.VECTOR endPoint; // 当たり判定用の線分を作成 dispPos.x = mouseX; dispPos.y = mouseY; dispPos.z = 0.0f; // 線分の始点 startPoint = DX.ConvScreenPosToWorldPos(dispPos); // 線分の終点 dispPos.z = 1.0f; endPoint = DX.ConvScreenPosToWorldPos(dispPos); // モデルと線分の当たり判定の評価実施 var Result = DX.MV1CollCheck_Line(modelHandle, frameIndex, startPoint, endPoint); // 当たった場合 if (Result.HitFlag == 1) { Console.WriteLine("衝突あり"); } }
メンテ

Page: 1 |

Re: 3Dモデルのフレームに対する当たり判定について ( No.1 )
名前:管理人 日時:2018/08/19 20:23

pmxファイルは基本的に人物モデルだと思いますが、人物モデルなどのスキニングメッシュモデルは 多くの場合メッシュ( ポリゴンの集合 )はフレーム番号0(フレーム名『Mesh』)にしかありませんので、 頭のフレームなどにはポリゴンが0個なので当たり判定を行うことはできません ( 『Mesh』以外の『センター』や『右ひじ』などのフレームは、『Mesh』フレームのポリゴンをどのように  変形させるかを決めるためのボーンとしての意味しかなく、『Mesh』以外のフレームにはポリゴンが  ひとつも無いのが一般的です ) よろしければDXライブラリのパッケージの中にある DxLibModelViewer.exe で pmxファイルを開いて、 フレームタブでフレームの一覧をご覧になってみてください フレーム名が黄色になっているのがポリゴンが存在するフレームで、白色のフレームはポリゴンが存在しないフレームです 恐らくフレーム番号0( Mesh )以外は全て文字の色が白いと思います
メンテ
Re: 3Dモデルのフレームに対する当たり判定について ( No.2 )
名前:nekoze 日時:2018/08/23 22:47

返信ありがとうございます。 DxLibModelViewer.exeで対象のpmxファイルを開いてフレーム番号0のMeshのみが黄色になっていることを確認できました。 今のモデルでは、MV1SetupCollInfo関数及びMV1CollCheck_Line関数のFrameIndexに-1を設定した場合のみ 衝突判定が取れるということですね。 衝突判定の代用方法として、メッシュの最大座標と最小座標から四角形の範囲を設定して、左クリック時の座標が前述の範囲内であるかを 検出しようとしましたが、この方法だとアニメーションを適用した場合でも対象範囲が移動(変動)しないため悩んでいます。 上記の方法の改善点ないし、別のベターな取得方法はあるのでしょうか?
メンテ
Re: 3Dモデルのフレームに対する当たり判定について ( No.3 )
名前:管理人 日時:2018/08/25 23:17

メッシュはフレーム番号0しか持っていませんが、そのメッシュの各頂点にはボーンの影響があるので、 MV1CollCheck_Line の戻り値で得られる MV1_COLL_RESULT_POLY 構造体のメンバー変数に以下のものを追加しました // 当たったポリゴンの座標がそれぞれ最も影響を受けているフレームの番号 int PosMaxWeightFrameIndex[ 3 ] ; ポリゴンが属しているフレームであるメンバー変数 FrameIndex は pmd や pmx の場合は基本的に 0 ですが、 上記の配列はポリゴンを形成している3頂点のそれぞれが一番影響を受けているボーンのフレーム番号が代入されます ( 『一番影響を受けているボーン』という言い方の通り、ひとつの頂点には複数のボーンの影響を受けるので  ( 例えばひざやひじの部分など、ボーンとボーンのつなぎ目の部分は二つ以上のボーンの影響を受けます )  その中でも一番影響を与えているボーンの番号が代入されています ) この変数を追加したバージョンをこちらにアップしましたので、よろしければダウンロードしてください m(_ _)m https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.2 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM.zip // Android版 ARM用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM64.zip // Android版 ARM64用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x86.zip // Android版 x86用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x64.zip // Android版 x64用 https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい) あと、こちらの変数を使用して『クリックされた箇所に一番影響を与えているフレーム名を表示する』プログラムを 組んでみましたので、よろしければご覧ください #include "DxLib.h" int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int ModelHandle ; int NowInput, EdgeInput, PrevInput ; int HitFrameIndex ; // ウインドウモードで起動 ChangeWindowMode( TRUE ) ; // 背景を灰色にする SetBackgroundColor( 128,128,128 ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) return -1 ; // モデルの読み込み ModelHandle = MV1LoadModel( "DxChara.x" ) ; // 描画先を裏画面にする SetDrawScreen( DX_SCREEN_BACK ) ; // カメラの設定 SetCameraPositionAndTarget_UpVecY( VGet( -400.0f, 700.0f, -760.0f ), VGet( 0.0f, 390.0f, 0.0f ) ); SetCameraNearFar( 15.0f, 3800.0f ); // 変数の初期化 NowInput = 0 ; EdgeInput = 0 ; PrevInput = 0 ; HitFrameIndex = -1 ; // メインループ(何かキーが押されたらループを抜ける) while( ProcessMessage() == 0 ) { int MouseX, MouseY ; // マウスカーソルの座標を取得 GetMousePoint( &MouseX, &MouseY ) ; // マウスボタンの入力状態を更新 PrevInput = NowInput ; NowInput = GetMouseInput() ; EdgeInput = NowInput & ~PrevInput ; // 左クリックされたらモデルをクリックしたかを調べる if( EdgeInput & MOUSE_INPUT_1 ) { VECTOR ScreenPos1 ; VECTOR ScreenPos2 ; VECTOR WorldPos1 ; VECTOR WorldPos2 ; // モデルとの当たり判定用の線分の2座標を作成 ScreenPos1.x = ( float )MouseX ; ScreenPos1.y = ( float )MouseY ; ScreenPos1.z = 0.0f ; ScreenPos2.x = ( float )MouseX ; ScreenPos2.y = ( float )MouseY ; ScreenPos2.z = 1.0f ; WorldPos1 = ConvScreenPosToWorldPos( ScreenPos1 ) ; WorldPos2 = ConvScreenPosToWorldPos( ScreenPos2 ) ; // モデルの当たり判定情報を更新 MV1RefreshCollInfo( ModelHandle, -1 ) ; // モデルと線分の当たり判定 MV1_COLL_RESULT_POLY Result = MV1CollCheck_Line( ModelHandle, -1, WorldPos1, WorldPos2 ) ; // 当たっていたらフレーム番号を保存する if( Result.HitFlag ) { // 一番影響している頂点に一番影響を与えているフレームの番号をセット if( Result.PositionWeight[ 0 ] > Result.PositionWeight[ 1 ] ) { HitFrameIndex = Result.PosMaxWeightFrameIndex[ Result.PositionWeight[ 0 ] > Result.PositionWeight[ 2 ] ? 0 : 2 ] ; } else { HitFrameIndex = Result.PosMaxWeightFrameIndex[ Result.PositionWeight[ 1 ] > Result.PositionWeight[ 2 ] ? 1 : 2 ] ; } } } // 画面のクリア ClearDrawScreen() ; // 3Dモデルの描画 MV1DrawModel( ModelHandle ) ; // クリックしたポリゴンに一番影響を与えているフレームの情報を表示 if( HitFrameIndex >= 0 ) { DrawFormatString( 0, 0, GetColor( 255,255,255 ), "FrameIndex:%d FrameName:%s", HitFrameIndex, MV1GetFrameName( ModelHandle, HitFrameIndex ) ) ; } // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; }
メンテ
Re: 3Dモデルのフレームに対する当たり判定について ( No.4 )
名前:nekoze(解決) 日時:2018/08/26 22:02

わざわざ変数の追加をしていただきありがとうございます。 求めていた実装も無事できました。 サンプルコードもいただき非常に分かりやすかったです。
メンテ

Page: 1 |

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

   クッキー保存