はじめの一歩
ODEバージョンv0.11で確認。
コンパイル
メイク時にライブラリの指定する必要があるため、指定の場所に展開する必要があります。
$ cd ode-0.11 $ tar xvzf hajime_v02.tgz
$ make
特に、問題がなければこれでrun.xという実行ファイルが作成されるはず。
実行
作成された実行ファイルを実行してみて。
$ ./run.x

画面上でマウスを操作することで視点の切替えができます。
- 左ボタン ... 視点の方向変更
- 右ボタン ... xy方向の位置変更
- 中ボタン ... 高さ方向の位置変更
また、Ctrlキーを使っての操作も紹介しておきます。
- Ctrl-P : シミュレーションの一時停止(simLoopの引数pauseが変化する)
- Ctrl-O : 一時停止時に1ステップごとに進める
- Ctrl-T : テクスチャあり/なし(デフォルトではあり、なしにすると高速)
- Ctrl-S : 影あり/なし
- Ctrl-V : カメラ情報表示(x,y,z,h,p,r).
- Ctrl-W : ppmファイル取得(frame/frameNNN.ppm)、ただしあらかじめframeディレクトリを作成しておく
- Ctrl-X : 終了
説明
このプログラムは世界を作成して、ただ単に立方体を表示させるだけのプログラムになっています。
簡単にこのプログラムの流れを説明すると、
簡単にこのプログラムの流れを説明すると、
- ODE初期化処理
- 世界(world)を生成する
- 世界に剛体を生成する
- 剛体の設定(ここでは位置を決めている)
- シミュレーション実行(simLoop関数をループ)
ってかんじです。
ODEの初期化は、
dInitODE();
で行います。他にも、dInitODE2(0);とかあるようです。
世界の生成は,
world = dWorldCreate();
で行っています。生成した世界番号がworldに保持されます。
world変数は世界IDを保持する特別な変数で、
world変数は世界IDを保持する特別な変数で、
static dWorldID world;
で宣言を行っています。
生成した世界に剛体を作成するために次を行います。
box = dBodyCreate( world );
引数として世界IDであるworldを渡してあげてどの世界に生成するかを教える必要があります。
また、生成した剛体番号を保持するためにbox変数を次のように宣言しています。
また、生成した剛体番号を保持するためにbox変数を次のように宣言しています。
static dBodyID box;
剛体を生成した後、dBodySetPositionで位置を指定します。
dBodyCreateで剛体を生成する前に指定した場合は、エラーとなります。
dBodyCreateで剛体を生成する前に指定した場合は、エラーとなります。
そして、次でシミュレーションを実行します。(無限ループ)
dsSimulationLoop( argc, argv, 320, 240, &fn );
このとき、第1第2引数としてargc,argvを渡しています。
実行時に引数を使用することで、テクスチャや影をあらかじめ消した状態で実行が可能となります。
実行時に引数を使用することで、テクスチャや影をあらかじめ消した状態で実行が可能となります。
- テクスチャなし | -notex
- 影なし | -noshadow
また、第3第4引数でウィンドウのサイズ設定を行います。
第5引数はdsFunctions構造体のアドレスを渡します。
dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = 0; fn.stop = 0; fn.path_to_textures = "../drawstuff/textures";
dsFunctionsではイニシャライズ関数、シミュレーションループ関数やコマンドを受け付ける関数の指定を行います。
ここでは、シミュレーション開始時に実行する関数をstart()、シミュレーションループ関数としてsimLoop()を指定しています。
ここでは、シミュレーション開始時に実行する関数をstart()、シミュレーションループ関数としてsimLoop()を指定しています。
dsSimulationLoop実行後、始めにstart()関数を実行しています。
そのあと、simLoop()関数を実行(無限ループ)することになります。
start()関数内の22行目のdsSetViewpoint(xyz,hpr)ではグラフィック表示でのカメラ位置を指定しています。
第1引数でカメラ位置を設定し、第2引数でカメラの方向方位を設定します。
そのあと、simLoop()関数を実行(無限ループ)することになります。
start()関数内の22行目のdsSetViewpoint(xyz,hpr)ではグラフィック表示でのカメラ位置を指定しています。
第1引数でカメラ位置を設定し、第2引数でカメラの方向方位を設定します。
シミュレーションのメインループにあたるsimLoop()関数では、シミュレーションの進行と剛体の表示を行っています。
dWorldStep( world, 0.01 );
これはシミュレーションを進めます。
この関数が実行されるたびに第2引数で指定される数値だけシミュレーション時間が進行します。ここでは、1ステップで0.01進行します。単位は決まっていませんが、0.01秒と考えると良いでしょう。(おそらくSI単位系)
この関数が実行されるたびに第2引数で指定される数値だけシミュレーション時間が進行します。ここでは、1ステップで0.01進行します。単位は決まっていませんが、0.01秒と考えると良いでしょう。(おそらくSI単位系)
dsSetColor( 1, 1, 0 ); // RGB Color dsDrawBox( dBodyGetPosition( box ), dBodyGetRotation( box ), box_sizes );
ここで、剛体をグラフィック表示させています。
剛体の色をdsSetColorで指定し、その次に呼ばれるdraw関数に適用されます。
dsDrawBoxでは、指定された位置と方位で箱を表示させます。
剛体の位置はdBodyGetPosition()関数で取得して、
剛体の方位はdBodyGetRotation()関数で取得します。
剛体の色をdsSetColorで指定し、その次に呼ばれるdraw関数に適用されます。
dsDrawBoxでは、指定された位置と方位で箱を表示させます。
剛体の位置はdBodyGetPosition()関数で取得して、
剛体の方位はdBodyGetRotation()関数で取得します。
以上が簡単な流れになります。
プラス
//dWorldSetGravity( world, 0.0, 0.0, -9.8 );
↑
コメントアウトをはずして、再度コンパイルして実行してみて下さい。
すると、今度は剛体が落下していくのがわかると思います。
ここでは、世界に重力を設定しています。
コメントアウトをはずして、再度コンパイルして実行してみて下さい。
すると、今度は剛体が落下していくのがわかると思います。
ここでは、世界に重力を設定しています。
しかし、今度は剛体がどこまでも落下していくと思います。これは、まだ衝突に関するプログラムを記述していないためです。衝突に関する記述は少し複雑になりますが、決まった記述方法なので慣れればそんなに難しくないと思います。
まとめ
今回のプログラムは、物体を世界に生成するプログラムを紹介しました。
他のプログラムも基本的な構造はあまり変わらないのでこの構造や流れを掴んでおけば他のやつも理解しやすいと思います。
他のプログラムも基本的な構造はあまり変わらないのでこの構造や流れを掴んでおけば他のやつも理解しやすいと思います。
また、今回のプログラムでは、剛体に形を指定していません。
グラフィック表示では箱になっていますが、別にこれは球体(Sphere)を指定しても問題ありません。
世界では、位置や質量などについて表現できますが、形状や衝突に関することは表現できません。
物体同士を衝突させる場合には、力学的世界(geom)が必要になってきます。
グラフィック表示では箱になっていますが、別にこれは球体(Sphere)を指定しても問題ありません。
世界では、位置や質量などについて表現できますが、形状や衝突に関することは表現できません。
物体同士を衝突させる場合には、力学的世界(geom)が必要になってきます。
全ソースコード
/***********************************************************
* Hajime no Ippo --- file : hjime.cpp
***********************************************************/
#include <ode/ode.h>
#include <drawstuff/drawstuff.h>
static dWorldID world; // 世界ID
static dBodyID box; // 剛体ID
dReal box_sizes[3] = { 1.0, 1.0, 1.0 };
// 剛体のサイズ
#ifdef dDOUBLE
#define dsDrawBox dsDrawBoxD
#endif
// start simulation - set viewpoint
static void start()
{
static float xyz[3] = { 0.f, 5.f, 3.f };
static float hpr[3] = { -90.f, -15.f, 0.f };
dsSetViewpoint( xyz, hpr ); // カメラ位置と方向設定
}
// simulation loop
static void simLoop( int pause )
{
// Ctl+p が押されたらifに入らない
if (!pause)
{
dWorldStep( world, 0.01 ); // 世界を進める
}
// 剛体の表示
dsSetColor( 1.0f, 1.0f, 0.0f ); // RGB Color
dsDrawBox( dBodyGetPosition( box ),
dBodyGetRotation( box ),
box_sizes );
}
int main( int argc, char* argv[] )
{
dInitODE();
// setup pointers to drawstuff callback functions
dsFunctions fn;
fn.version = DS_VERSION;
fn.start = &start;
fn.step = &simLoop;
fn.command = 0;
fn.stop = 0;
fn.path_to_textures = "../drawstuff/textures";
world = dWorldCreate(); // 世界生成
//dWorldSetGravity( world, 0.0, 0.0, -9.8 );
// 世界に重力を生成(z方向に-9.8m/s/s)
box = dBodyCreate( world ); // 世界に剛体を作成
dReal pos[3] = { 0.0, 0.0, 3.0 };
dBodySetPosition( box, pos[0], pos[1], pos[2] );
// 剛体の位置を設定
dsSimulationLoop( argc, argv, 320, 240, &fn );
// シミュレーション開始(simLoopへ)
// + ウィンドウサイズ設定
dWorldDestroy( world ); // 世界の破壊
return 0;
}