ODEで学ぶC言語のStep4です.今回は関数を練習しましょう.関数については既にわかっているものとし,ホームワークを通じて関数を使うとプログラムがとても簡単になることを実感してもらうことが狙いです.
今まで描画について学んできましたが,今回から動力学計算も学んでいきます.サンプルプログラムとしては,物理シミュレーションで最も簡単な物体の落下を取り上げます.プログラミングの教科書では初めの例題はHello Worldを表示する例が定番です。ここではHello Worldの物理シミュレーション版を紹介します.
ODEを使ったシミュレーションの流れを代表的なAPIと関連付けて列挙します。
- シミュレーションの流れ
- ODEの初期化 dInitODE()
- 動力学計算の世界worldの生成 dWorldCreate()
- 重力加速度の設定 dWorldSetGravity()
- 剛体の生成
- 質量の設定 dBodySetMass()
- 位置の設定 dBodySetPosition()
- 姿勢の設定 dBodySetRotation()
- シミュレーションループ(この部分は繰り返し実行される)
- 動力学計算の実施 dWorldStep()
- シミュレーションに必要な処理を書く
- 動力学worldの破壊 dWorldDestroy()
- ODEの終了 dCloseODE()
- 動力学計算
シミュレーションの流れでは色々なAPIを使っていますが、今回は物理エンジンの最も重要な動力学計算のAPIについて説明します。動力学計算をするAPIはdWorldStep()です.このAPIはシミュレーションで毎回呼び出さなければいけないのでサンプルプログラムのようにsimLoop関数の中で呼び出してください.
- void dWorldStep(dWorldID, dReal stepsize);
- void dWorldQuickStep(dWorldID, dReal stepsize);
シミュレーションを引数stepsieze[s]だけ1ステップ進めます。stepsizeは数値積分の時間刻み幅、単位は秒。大きいと精度が悪くなりますが、スピードは遅くなります。
- ソースコード
次に、詳しいコメントのついたソースコードを以下に示します。main関数から読んでください。
/* step4 リンゴ(林檎)の落下 */ #include "dm4.h" dWorldID world; // 動力学の世界 dBodyID apple; // リンゴ dReal r = 0.2, m = 1.0; // リンゴの半径,質量 void simLoop(int pause) /*** シミュレーションループ ***/ { dWorldStep(world,0.01); // シミュレーションを1ステップ進める dsSetColor(1.0,0.0,0.0); // 赤色の設定(r,g,b) const double *p = dBodyGetPosition(apple); // 位置を取得 const double *R = dBodyGetRotation(apple); // 姿勢を取得 dsDrawSphere(p,R,r); // リンゴの描画 } int main() /*** main関数 ***/ { dInitODE(); // ODEの初期化 world = dWorldCreate(); // 世界の創造 dWorldSetGravity(world,0,0,-0.2); // 重力設定 apple = dBodyCreate(world); // リンゴの生成 dMass mass; // 構造体massの宣言 dMassSetZero(&mass); // 構造体massの初期化 dMassSetSphereTotal(&mass,m,r); // 構造体massに質量を設定 dBodySetMass(apple,&mass); // リンゴにmassを設定 dBodySetPosition(apple, 0.0, 0.0, 2.0); // 位置設定(x,y,z) dmLoop(800, 600); // ウインドウの幅,高 dWorldDestroy(world); // 世界の破壊 dCloseODE(); // ODEの終了 return 0; }
- これは赤玉の自由落下のプログラムです。ODEのシミュレーションの流れでは、まず、dInitODE()でODEを初期化します。次に、物理計算をするworld(ワールド)をdWorldCreate()で作ります。物理計算を受ける物体はその中に作らなければなりません。ODEでは物体のことをbody(ボディ)と呼んでいます。物体はdBodyCreate(world)で作ります。物体を作ったら、次にその質量パラメータと位置や姿勢を設定します。このプログラムでは球の質量パラメータと位置だけを設定しています。
物体の生成と設定が終わったら、次はシミュレーションを進めます。これはdmLoop()で繰り替えし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付属テストプログラム表示用のライブラリのことです。最後に,dmで始まる関数は私の作成した関数です.
ここでは重力加速度を赤玉がゆっくり落下していきますが、なんと地面を通り抜けて消えてしまいます。実は上のプログラムには衝突検出機能が組み込まれていなかったのです。
- step4-090626.zipをダウンロードして実行しよう!
- ODE本を読んで,ボックス(直方体)を落下させよ!
- ODE本を読んで,円柱を落下させよ!
- ODE本を読んで,カプセルを落下させよ!
- 上で作成したプログラムの中で球を作るところを関数化しなさい.引数として位置,姿勢,物体生成に必要なパラメータを使うこと.
- dBodyID dmCreateSphere(double p[3], double R[12], double r , double m);
- 位置 p[3], 姿勢 R[12], 半径 r, 質量 m
- 同様にボックスの生成を関数化しなさい.
- dBodyID dmCreateBox(double p[3], double R[12], double sides[3], double m);
- 位置 p[3], 姿勢 R[12], サイズ sides[3], 半径 r, 質量 m
- 円柱の生成を関数化しなさい.
- dBodyID dmCreateCylinder(double p[3], double R[12], double l, double r, double m, int dir);
- 位置 p[3], 姿勢 R[12], 半径 r, 質量 m, 長軸の方向 dir
- カプセルの生成を関数化しなさい.
- dBodyID dmCreateCapsule(double p[3], double R[12], double l, double r);
- 位置 p[3], 姿勢 R[12], 半径 r, 質量 m, 長軸の方向 dir
コメント