トップページ > 記事閲覧
マルチスレッド:物理演算だけ別スレッドにしたい
名前:CYARACON 日時: 2015/05/14 06:16

いつも大変お世話になっております。 マルチスレッドの構成方法についてご相談させていただきます。 DXライブリーは、DXライブリーの処理さえ同じスレッドで実行すれば、プログラム自体はマルチスレッド対応可能と認識しております。 が、DXライブリーの処理を複数スレッドに分けることはできないでしょうか? 具体的には、「3D描画の処理」と「MMDモデルの物理演算の処理」を別スレッドにして、並行処理したいのです。 MMDモデルの数が増えてくると物理演算の処理が負担になるので、できればマルチコアCPUを活かせればと思っています。 もし可能でしたら、実現手段の概要を教えて下さい。
メンテ

Page: 1 |

Re: マルチスレッド:物理演算だけ別スレッドにしたい ( No.1 )
名前:管理人 日時:2015/05/16 22:30

> 具体的には、「3D描画の処理」と「MMDモデルの物理演算の処理」を別スレッドにして、並行処理したいのです。 残念ながらそれはできません というのも、「3D描画の処理」は「MMDモデルの物理演算の処理」の結果を踏まえて行うものだからです ただ、プログラムを見返してみたら「MMDモデルの物理演算の処理」( MV1PhysicsCalculation )は 「DXライブラリの関数を使用するスレッド」以外でも実行することが可能だったので、 SetUseASyncLoadFlag( TRUE ) ; が実行されて「非同期読み込み」に設定された状態で MV1PhysicsCalculation が呼ばれた場合は物理演算の処理を別スレッドで非同期に行うようにしてみました ( 『非同期』というだけで『読み込み』は関係ありませんが SetUseASyncLoadFlag を流用してしまいます・・・ ) ので、よろしければその変更を加えたこちらのバージョンをダウンロードしてください m(_ _)m https://dxlib.xsrv.jp/temp/DxLibVCTest.exe // VisualC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCCTest.exe // BorlandC++ 用 https://dxlib.xsrv.jp/temp/DxLibGCC_DevCppTest.exe // Dev-C++ 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.exe // MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // .NET用 https://dxlib.xsrv.jp/temp/DxLibMakeTest.exe // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい) 追加した非同期物理演算の仕組みを使用して10体の物理演算箇所付きMMDモデルをアニメーションさせて 描画するプログラムを組んでみましたので、よろしければご覧ください #include "DxLib.h" #define MODEL_NUM 10 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ) { int ModelHandle[ MODEL_NUM ] ; int AttachIndex[ MODEL_NUM ] ; int DrawFlag[ MODEL_NUM ] ; int DrawCount ; float TotalTime, PlayTime ; int i ; LONGLONG Time ; ChangeWindowMode( TRUE ) ; SetGraphMode( 1280, 720, 32 ) ; SetUseDirectInputFlag( FALSE ) ; // DXライブラリの初期化 if( DxLib_Init() < 0 ) { // エラーが発生したら直ちに終了 return -1 ; } // リアルタイム物理演算設定にする MV1SetLoadModelUsePhysicsMode( DX_LOADMODEL_PHYSICS_REALTIME ) ; // モデルの読み込み ModelHandle[ 0 ] = MV1LoadModel( "MMDモデル.pmx" ) ; // モデルの複製 for( i = 1 ; i < MODEL_NUM ; i ++ ) { ModelHandle[ i ] = MV1DuplicateModel( ModelHandle[ 0 ] ) ; } // モデルのアニメーションや位置の設定 for( i = 0 ; i < MODEL_NUM ; i ++ ) { // 3Dモデルの0番目のアニメーションをアタッチする AttachIndex[ i ] = MV1AttachAnim( ModelHandle[ i ], 0, -1, FALSE ) ; // 座標をセット MV1SetPosition( ModelHandle[ i ], VGet( ( i - ( float )( MODEL_NUM - 1 ) / 2 ) * 10.0f, 0.0f, 32.0f ) ) ; // 物理のリセット MV1PhysicsResetState( ModelHandle[ i ] ) ; } // 描画先を裏画面に変更 SetDrawScreen( DX_SCREEN_BACK ) ; // カメラの設定 SetCameraNearFar( 10.0f, 1000.0f ) ; SetCameraPositionAndTarget_UpVecY( VGet( 0.0f, 19.0f, -22.5f ), VGet( 0.0f, 10.0f, 32.0f ) ) ; // アタッチしたアニメーションの総再生時間を取得する TotalTime = MV1GetAttachAnimTotalTime( ModelHandle[ 0 ], AttachIndex[ 0 ] ) ; // 再生時間の初期化 PlayTime = 0.0f ; // メインループ while( ProcessMessage() == 0 ) { Time = GetNowHiPerformanceCount() ; // 画面をクリア ClearDrawScreen() ; // 再生時間を進める PlayTime += 0.5f ; // 再生時間がアニメーションの総再生時間に達したら再生時間を0に戻す if( PlayTime >= TotalTime ) { PlayTime = 0.0f ; } // 再生時間のセットと物理演算の実行 for( i = 0 ; i < MODEL_NUM ; i ++ ) { // 再生時間をセットする MV1SetAttachAnimTime( ModelHandle[ i ], AttachIndex[ i ], PlayTime ) ; // 物理演算 SetUseASyncLoadFlag( TRUE ) ; MV1PhysicsCalculation( ModelHandle[ i ], 1000.0f / 60.0f ) ; SetUseASyncLoadFlag( FALSE ) ; } // モデルを描画( 物理演算が終わった順に描画 ) memset( DrawFlag, 0, sizeof( DrawFlag ) ) ; DrawCount = 0 ; while( ProcessMessage() == 0 ) { // モデルの数だけ繰り返し for( i = 0 ; i < MODEL_NUM ; i ++ ) { // すでに描画が終わっていたら何もしない if( DrawFlag[ i ] ) { continue ; } // 物理演算が終わっていなかったら何もしない if( CheckHandleASyncLoad( ModelHandle[ i ] ) == TRUE ) { continue ; } // モデルを描画 MV1DrawModel( ModelHandle[ i ] ) ; // 描画したフラグを立てる DrawFlag[ i ] = TRUE ; // 描画した数を増やす DrawCount ++ ; } // すべてのモデルの描画が終わったらループを抜ける if( DrawCount == MODEL_NUM ) { break ; } // 他のスレッドに処理を回す Sleep( 0 ) ; } Time = GetNowHiPerformanceCount() - Time ; // 処理時間を描画 DrawFormatString( 0, 0, GetColor( 255,255,255 ), "Time:%d", ( int )Time ) ; // 裏画面の内容を表画面に反映 ScreenFlip() ; } // DXライブラリの後始末 DxLib_End() ; // ソフトの終了 return 0 ; } 要点は MV1PhysicsCalculation の前後にある SetUseASyncLoadFlag と、MV1DrawModel の前の CheckHandleASyncLoad で、 他スレッドに依頼した物理演算が完了するのを待ってから描画しています 画面の左上に処理に要した時間を描画していますが、MV1PhysicsCalculation の前後にある SetUseASyncLoadFlag を コメントアウトすると明らかに処理時間が増大するのがわかると思います( SetUseASyncLoadFlag( TRUE ) ; を コメントアウトした場合は非同期物理演算ではなくなるので ) あと、上記の例ではプログラムを簡素化するために一つのモデルを複製して同じアニメーションを再生していますが それぞれ異なるモデル、アニメーションでも問題なく非同期物理演算を行えます また、例では下記のように物理演算の非同期実行依頼を行った後すぐに物理演算をしているモデルの 物理演算終了待ち+描画処理を行っていますが、 非同期物理演算依頼  ↓ 非同期物理演算終了待ち+物理演算持ちのMMDモデル描画 実際はこちらのように非同期物理演算依頼を出したモデルとは関係の無いモデル( 地形モデル等 )の描画や、 物理演算や描画に関係の無い処理を非同期物理演算の終了待ちの間に実行すると、非同期物理演算終了待ちの時間を 有効利用できてより効果的です 非同期物理演算依頼  ↓ 物理演算の無いモデルの描画&その他描画以外の処理があればその処理を実行  ↓ 非同期物理演算終了待ち+物理演算持ちのMMDモデル描画 実際は半透明描画等の関係で例のような「物理演算が終了した順で描画」というわけには行かず、 いろいろ工夫する必要が出てくると思いますが、よろしければお試しください
メンテ
Re: マルチスレッド:物理演算だけ別スレッドにしたい ( No.2 )
名前:CYARACON(解決済) 日時:2015/05/17 00:21

管理人様。 サンプルまで作っていただき、恐縮です。 いつも具体的な回答をいただき、大変助かっております。なんとお礼を申し上げて良いのやら・・ さっそくいろいろ試させていただきます。 本当に、ありがとうございました。
メンテ
Re: マルチスレッド:物理演算だ ( No.3 )
名前:ヨッチー 日時:2018/04/04 09:21

マトリックス ライン載せられないでしょうか?
メンテ
Re: マルチスレッド:物理演算だけ別スレッドにしたい ( No.4 )
名前:管理人 日時:2018/04/05 01:04

すみません、マトリックス ライン とは何でしょうか? Google などで検索してみましたが、わかりませんでした・・・
メンテ

Page: 1 |

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

   クッキー保存