3. こんにちは物理世界

         

ODE

ゲーム開発やロボットの研究者にも使われているオープンソースの物理計算エンジンODE(Open Dynamics Engine、オープン ダイナミクスエンジン)を学ぶODE初級講座の3回目です。

今回はODEを使ったシミュレーションの流れを動力学計算を中心に基本的なAPIと関連付けて説明します.サンプルプログラムとしては,物理シミュレーションで最も簡単な物体の落下を取り上げます.プログラミングの教科書では初めの例題はHello Worldを表示する例が定番です。ここではHello Worldの物理シミュレーション版を紹介します.

ODEを使ったシミュレーションの流れを代表的なAPIと関連付けて列挙します。

  • シミュレーションの流れ
    • 描画用関数ドロースタッフの設定
      • カメラの設定 dsSetViewPoint()
    • ODEの初期化 dInitODE()
    • 動力学計算の世界worldの生成 dWorldCreate()
    • 重力加速度の設定 dWorldSetGravity()
    • 剛体の生成
      • 質量の設定 dBodySetMass()
      • 位置の設定 dBodySetPosition()
      • 姿勢の設定 dBodySetRotation()
    • シミュレーションループ(この部分は繰り返し実行される)
      • 動力学計算の実施 dWorldStep()
      • シミュレーションに必要な処理を書く
    • 動力学worldの破壊 dWorldDestroy()
    • ODEの終了 dCloseODE()



  • 動力学計算

    シミュレーションの流れでは色々なAPIを使っていますが、今回は物理エンジンの最も重要な動力学計算のAPIについて説明します。動力学計算をするAPIはdWorldStep()とdWorldQuickStep()です.違いはdWorldStep()の方が精度は高いですが速度は遅く,dWorldQuickStep()はその逆です.dWorldStep()とdWorldQuickStep()ではシミュレーションの結果が違うので,速度に問題なければ精度の高いdWorldStep()を使ってください.これらのAPIはシミュレーションで毎回呼び出さなければいけないのでサンプルプログラムのようにsimLoop関数の中で呼び出してください.

    • void dWorldStep(dWorldID, dReal stepsize);
    • シミュレーションを引数stepsieze[s]だけ1ステップ進めます。stepsizeは数値積分の時間刻み幅、単位は秒。大きいと精度が悪くなりますが、スピードは遅くなります。

    • void dWorldQuickStep(dWorldID, dReal stepsize);
    • シミュレーションを引数stepsize [s] だけ1ステップ進めます。上と機能は同じですが、dWorldStep()よりは高速ですが、精度は高くなります.

    • void dWorldSetQuickStepNumIteration(dWorldID, int num);
    • dWorldQuickStep()の繰り返し計算の回数を設定します.numの値を大きくすると精度は高くなりますが速度は遅くなります.このAPIを呼び出さない場合,つまりnumのデフォルト値は20です.一般的にはdsSimulationLoop()を呼び出す前に指定します.

  • ソースコード
    • 次に、詳しいコメントのついたソースコードを以下に示します。main関数から読んでください。なお,文字化けするために一部全角文字を使っています.カットアンドペーストではなく,ここからサンプルプログラム3をダウンロードしてお試しください.

  • // Hello World  by でむ
    #include <ode/ode.h>   // ODEのヘッダーファイル(動力学計算用)
    #include <drawstuff/drawtuff.h> // ドロースタッフヘッダーファイル(3Dグラフィクス用)
    
    #ifdef  dDOUBLE
    #define dsDrawSphere dsDrawSphereD   // 単精度と倍精度の描画関数に対応するおまじない
    #endif
    
    static dWorldID world;  // 動力学計算用ワールド
    dBodyID ball;        // 玉
    const dReal radius = 0.2, mass = 1.0; // 玉の半径(m)、玉の重さ(kg)
    
    // シミュレーションループ 毎回呼び出され実行されます。
    // 動力学計算はステップサイズをここで指定すれば自動的に計算される
    // ただし、描画はここで書かないと何も表示されません。
    static void simLoop (int pause)
    {
      const dReal *pos,*R; // 位置、回転行列
      dWorldStep(world,0.05);  // シミュレーションの1ステップ進める。その時間を0.05秒に設定。  
      dsSetColor(1.0,0.0,0.0);  // 色の設定。引数は光の3原色(赤、緑、青)。値は0から1.
      pos = dBodyGetPosition(ball);  // 玉の位置を取得
      R = dBodyGetRotation(ball);   // 玉の姿勢を取得
      dsDrawSphere(pos,R,radius);   //赤玉を描画
    }
    
    // ドロースタッフの前処理関数
    void start()
    {
      // カメラの設定
      static float xyz[3] = {0.0,-3.0,1.0}; // 視点の位置 (x, y, z [m])
      static float hpr[3] = {90.0,0.0,0.0}; // 視線の方向(ヘッド、ピッチ、ロール[°])
      dsSetViewpoint (xyz,hpr);        // 視点の設定
    }
    
    // メイン関数 ここから読んでください。
    int main (int argc, char **argv)
    {
      dReal x0 = 0.0, y0 = 0.0, z0 = 1.0; // ボールの初期位置[m]
      dMass m1; // 質量パラメータ構造体(質量、慣性モーメントなど)
    
      // 描画API(ドロースタッフ)のおまじない(設定)
      dsFunctions fn;     // ドロースタッフ構造体
      fn.version = DS_VERSION;   // ドロースタッフのバージョン
      fn.start = &start;  //  シミュレーションの前処理関数
      fn.step = &simLoop;  // シミュレーションの各ステップで呼ばれる関数
      fn.command = NULL; // 関数がないのでNULLポインタを指定
      fn.stop    = NULL;  // 関数がないのでNULLポインタを指定
      fn.path_to_textures = "../../drawstuff/textures"; // テクスチャへのパス
    
      // 動力学計算用世界の創造
      dInitODE();                  // ODEの初期化
      world = dWorldCreate();     // 動力学計算の対象となる剛体を入れるworldを作る。戻り値はそのID番号。
      dWorldSetGravity(world,0,0,-0.001); // 重力加速度(x, y, z)の設定  -0.001 m/s^2
    
      // 玉を作る
      ball = dBodyCreate(world);  // 剛体を作る。戻り値はそのID番号
      dMassSetZero(&m1);    // 質量パラメータm1の初期化
      dMassSetSphereTotal(&m1,mass,radius); // 質量パラメータm1に剛体の質量を設定
      dBodySetMass(ball,&m1);   // 剛体に質量パラメータm1を設定
      dBodySetPosition(ball, x0, y0, z0);  // 剛体ballの絶対座標での位置(x, y, z)を設定
    
      // シミュレーション本体
      // argc, argvはmain関数の引数、ウインドウサイズ352 x 288ピクセル, fnはドロースタッフ構造
      dsSimulationLoop (argc,argv,352,288,&fn);
    
      // 世界の破壊
      dWorldDestroy (world);  // 動力学計算の対象であるworldを破壊する  
      dCloseODE();            // ODEの終了
      return 0;
    } 

    これは赤玉の自由落下のプログラムです。ODEのシミュレーションの流れでは、まず、dInitODE()でODEを初期化します。次に、物理計算をするworld(ワールド)をdWorldCreate()で作ります。物理計算を受ける物体はその中に作らなければなりません。ODEでは物体のことをbody(ボディ)と呼んでいます。物体はdBodyCreate(world)で作ります。物体を作ったら、次にその質量パラメータと位置や姿勢を設定します。このプログラムでは球の質量パラメータと位置だけを設定しています。

    物体の生成と設定が終わったら、次はシミュレーションを進めます。これはdsSimulationLoop()で繰り替えしsimLoop関数が呼び出すことにより実行されています。simLoop関数のdWorldStep(world, 0.05)はシミュレーションを1ステップ進めています。進める時間は2番目の引数、この場合は0.05秒となります。dsDrawSphere()で落下する球を表示しています。

    シミュレーションが終わると,後片付けを行います。dWorldDestroy(world)でワールドを破壊し,dCloseODE()でODEの終了処理をします。

    なお、小文字のdで始まる関数はODEのAPI(application interface)で、dsで始まる関数はdrawstuff(ドロースタッフ)のAPIです。drawstuffはODE付属テストプログラム表示用のライブラリのことです。

    登場したAPIの詳細についての説明はここをクリックしてください.

    説明はこのぐらいにしてサンプルプログラム3をダウンロード、ビルドして実行してみましょう!Visual C++ 2008とCode::Blocks 8.02用のプロジェクトファイルが同封されています。

    ここでは重力加速度を赤玉がゆっくり落下していきますが、なんと地面を通り抜けて消えてしまいます。実は上のプログラムには衝突検出機能が組み込まれていなかったのです。

    次回はODE付属の3Dグラフィクスライブラリdrawstuffについて学びましょう。

7 Responses to “ 3. こんにちは物理世界 ”

  1. neko MonsterID Icon neko 2009-12-18

    でむさん

    お世話になりました.うまくhello.cbpが動きました.
    これからはでむさんページ+自力で勉強します.

    どうもありがとうございました.

  2. neko MonsterID Icon neko 2009-12-17

    とても分かりやすいサイトをありがとうございます.
    ODEを初めて使ってみようと勉強させていただいております.
    さて,サンプルプログラム(sample3.cbp)などを開こうとすると

    mingw32-g++.exe – ディスクがありません
    ドライブにディスクがありません.ディスクをドライブ D:に挿入してください.

    というエラーが出て,操作不能になるのですが,そのような事例ご存知でしょうか.
    アドバイスいただけたら幸いです.
    よろしくお願いいたします.

  3. demu MonsterID Icon demu 2009-12-17

    nekoさん,

    コメントありがとうございます.分かりやすいサイトといって頂けてとてもうれしいです.

    さて,以下のファイルはありますか?

    c:\Program Files\CodeBlocks\MinGW

    ない場合は,MinGW付きのCodeBlocksをダウンロードしてください.

    でむ

  4. neko MonsterID Icon neko 2009-12-18

    でむさん

    早速にありがとうございます.
    ご指摘のMinGWはあります.
    今日は,cdpファイルはダブルクリックしてもcodeblocksは起動されるものの,プログラムは何も表示されない状態です.
    cppファイルはプログラムが表示されますが,ビルドするとエラー多数で,ode/ode.hとdrawstuff/drawstuff.hがNo Such Fileになっています.
    でむさんもcodeblocksのverは8.02ですか.
    ビルドFeb 27 2008となっています.

    起動がうまくいけば,楽しく遊べそうなのですが,お手数をおかけしますが,どうぞよろしくお願いします.

  5. neko MonsterID Icon neko 2009-12-18

    うまくいきましたので,これは無しで大丈夫です.

  6. demu MonsterID Icon demu 2009-12-18

    後学のためにうまくいかなかった原因を教えて頂けますか?

    でむ

  7. demu MonsterID Icon demu 2009-12-19

    おめでとうございます.

    また,コメントくださいね.

    でむ

コメントどうぞ (Leave a Reply)

カウンタ (since 2008-3-15)