ODE講座6補講:衝突検出


ODE講座6のソースコードでは地面と球との接触を判定する変数をグローバル変数としていました。授業ではグローバル変数の使用を避けるように説明しているので、ソースコードをローカル変数に改めましょう。今年度からプログラミングの講義にODEを使い、学生のモチベーションとプログラミングスキルを高めるという試みをしているので、今回の補講はその一環です。

ポイントはdSpaceCollide(dSpaceID space, void *data, dNearCallback *callback);がcallback関数に引数dataを渡すことができるので、そのdataとして衝突判定の変数を渡すことです。なお、dataはvoidへのポインタになっています。void *汎用ポインタと呼ばれるもので、関数の引数として色々な型を取ることができる万能選手です。

注意する点としては、次のソースコード4行目のように使いたい型にキャストすることです。


[code]
//  衝突検出のコールバック関数
static void nearCallback(void *data, dGeomID o1, dGeomID o2)
{
int *flag = (int *) data; // 汎用ポインタは使いたい型にキャストが必要
static const int N = 4;    // 接触点数の上限は4個 staticを忘れずにつけてください.

dContact contact[N];

int isGround = ((ground == o1) || (ground == o2)); // 衝突する2つのうちどちらかが地面ならisGroundのフラグを立てる
int n = dCollide(o1,o2,N,&contact[0].geom,sizeof(dContact)); // nは衝突点数

if (isGround) { // 衝突する可能性のあるジオメトリのどちらかが地面なら
if (n >= 1) *flag = 1; // 変更した部分
else *flag = 0; // 変更した部分
for (int i = 0; i < n; i++) {
contact[i].surface.mode = dContactBounce; // 地面の反発係数を設定
contact[i].surface.bounce = 0.0; // (0.0~1.0) 反発係数は0から1まで
contact[i].surface.bounce_vel = 0.0; // (0.0以上) 反発に必要な最低速度

// コンタクトジョイント生成
dJointID c = dJointCreateContact(world,contactgroup,&contact[i]);
// 接触している2つのgeometryをコンタクトジョイントで拘束
dJointAttach (c,dGeomGetBody(contact[i].geom.g1),
dGeomGetBody(contact[i].geom.g2));
}
}
}

static void simLoop (int pause)
{
const dReal *pos,*R;
int flag = 0; // 地面との衝突flagを0にセット

// 衝突判定、flagのアドレスがnearCallback関数に引数として渡される。
// この例では地面と衝突するとflagに1、衝突しない場合は0が入る。
dSpaceCollide(space, &flag,&nearCallback);

dWorldStep(world,0.01);      // シミュレーションを1ステップ進める
dJointGroupEmpty(contactgroup); // ジョイントグループを空にする

if (flag == 0) dsSetColor(1.0, 0.0, 0.0);  // 赤色の設定
else dsSetColor(0.0, 0.0, 1.0); // 青色の設定
pos = dBodyGetPosition(ball.body);  // 位置
R = dBodyGetRotation(ball.body);  // 回転行列
dsDrawSphere(pos,R,radius);    // 球の描画
}
[/code]

今回はこの辺で…

コメントを残す

メールアドレスが公開されることはありません。