Open Dynamics Engine 入門
【1日目】球の描画と衝突判定
Open Dynamics Engine の利用方法
ODEのインストールから、コンパイル方法は、次のページに非常に詳しく紹介されていますので参照ください。
2. インストールと開発/demura.net: ロボットの開発と教育
球の描画と衝突判定
ボールを空から落下させるプログラムです。
プログラムソース
以下のプログラムソースは、demura.net: ロボットの開発と教育にて公開されているソースを利用させていただいております。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | #include <ode/ode.h> #include <drawstuff/drawstuff.h> #include <time.h> #ifdef dDOUBLE #define dsDrawSphere dsDrawSphereD #endif int WindowWidth = 352; //ウィンドウの幅 int WindowHeight = 288; //ウィンドウの高さ static dWorldID world; //ODE世界のID static dSpaceID space; //衝突空間のID(同じ衝突空間内のオブジェクトのみが衝突する) static dGeomID ground; //地面との衝突判定のID static dJointGroupID contactgroup; //ジョイントグループID dsFunctions fn; const int N = 200; //描画する球の数 const dReal radius = 0.2; //球の半径 const dReal mass = 1.0; //球の質量 typedef struct { //球の構造体 dBodyID body; //動力学計算用のボディ dGeomID geom; //衝突計算用のジオメトリ } MyObject; MyObject ball[N]; //球を描画するための配列 static void nearCallback( void *data, dGeomID o1, dGeomID o2) //2つのオブジェクトに衝突可能性がある場合に呼び出される { const int N = 10; dContact contact[N]; //地面との衝突であるかどうかの判定 int isGround = ((ground == o1) || (ground == o2)); //衝突の判定を実際に行う関数 3つ目の引数に衝突の情報を格納する int n = dCollide(o1,o2,N,&contact[0].geom, sizeof (dContact)); //if (isGround) {//もし地面との衝突だけを考える場合にはコメントアウトをはずす for ( int i = 0; i < n; i++) { contact[i].surface.mode = dContactBounce; //衝突モード contact[i].surface.mu = dInfinity; // 摩擦係数 contact[i].surface.bounce = 0.5; // 反発係数(0 ~ 1) contact[i].surface.bounce_vel = 0.0; // 最低反射速度 dJointID c = dJointCreateContact(world,contactgroup,&contact[i]); dJointAttach (c,dGeomGetBody(contact[i].geom.g1),dGeomGetBody(contact[i].geom.g2)); } //} } static void simLoop ( int pause) //無限ループ { const dReal *pos,*R; dSpaceCollide(space,0,&nearCallback); //衝突判定用の関数 dWorldStep(world, 0.01); //世界の時間を進める dJointGroupEmpty(contactgroup); //ジョイントグループを初期化 //球の描画を行う for ( int i=0;i<N;i++){ dsSetColor(1.0, 0.0, 0.0); //オブジェクトの色の設定 pos = dBodyGetPosition(ball[i].body); //オブジェクトの位置情報(posは配列) R = dBodyGetRotation(ball[i].body); //オブジェクトの回転情報(Rは配列) dsDrawSphere(pos,R,radius); //オブジェクトの描画 } } void start() //初期設定 { static float xyz[3] = {0.0,-3.0,1.0}; //カメラの位置 static float hpr[3] = {90.0,0.0,0.0}; //カメラの方向 //(z軸, y軸, x軸)における回転角度({0.0,0.0,0.0}でx軸方向を向いている) //上の場合は、y軸の方向を向いている dsSetViewpoint (xyz,hpr); //カメラの設定 } void prepDrawStuff() { //描画の初期化 fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = NULL; fn.stop = NULL; fn.path_to_textures = "C:/ode-0.11.1/drawstuff/textures" ; } //いよいよメイン関数 int main ( int argc, char *argv[]) { srand ( time (NULL)); //rand()の種 dReal x0 = 0.0, y0 = 0.0, z0 = 3.0; dMass m1; prepDrawStuff(); dInitODE(); world = dWorldCreate(); //世界の誕生(IDをworldに代入) space = dHashSpaceCreate(0); //衝突空間の生成(IDをspaceに代入) contactgroup = dJointGroupCreate(0); //ジョイント空間の生成(IDをcontactgroupに代入) dWorldSetGravity(world,0,0,-0.5); //世界の重力加速度を指定 //地面との衝突判定用ジオメトリの生成(描画なし) ground = dCreatePlane(space,0,0,1,0); //ボールの生成 for ( int i=0;i<N;i++){ ball[i].body = dBodyCreate(world); //動力学計算用ボディのIDを取得 dMassSetZero(&m1); //基本形状構造体の初期化 dMassSetSphereTotal(&m1, mass ,radius); //基本形状構造体に重心、慣性テンソルのパラメータをセットする(この場合は球) dBodySetMass(ball[i].body,&m1); //生成したオブジェクトと基本形状構造体とリンクさせる //生成したオブジェクトの初期位置を設定 dBodySetPosition(ball[i].body, x0+ double ( rand ()- rand ())/ double (RAND_MAX*10) , y0 + double ( rand ()- rand ())/ double (RAND_MAX*10) , z0 + double (i)/2.0); ball[i].geom = dCreateSphere(space,radius); //衝突計算用ジオメトリのIDを取得 dGeomSetBody(ball[i].geom,ball[i].body); //衝突計算用ジオメトリのIDと動力学計算用ボディのIDをリンク } dsSimulationLoop (argc,argv,WindowWidth, WindowHeight,&fn); //シミュレーション用の無限ループ dWorldDestroy (world); dCloseODE(); return 0; } |
参考ページ
■demura.net: ロボットの開発と教育(出村 公成 氏)
■ODE (Open Dynamics Engine) プログラミング解説(Crystal-Creation 氏)