ODE講座23:関節中心点の取得とスケルトン表示


Open Dynamics Engine

上の図はジョイント(関節)の中心に球を描画し、各ボディの重心と各関節中心を直線で結び、それが外部から見えるようにボディを半透明にしスケルトン表示しています。

ODE (Open Dynamics Engine) 講座の23回目です。 11月に入り、カニ漁が解禁になりました。雄のズワイガニはとても有名ですが、その雌は香箱ガニと呼ばれ体は小さいのですが、卵が美味で珍味として重宝されています。今年は豊漁のようで、金沢では近所のスーパーで3杯1000円程度で購入できます。金沢では美味しい食べ物とお酒と温泉がこれからの楽しみとなります。

さて、チップさんから、関節中心点の取得法について質問があり、ODE本を読んでもよくわからないとのことだったのでここで補足します。

この例では、関節の中心を球で表示し、重心と関節中心を線で表示しています。さらに、線が見えるようにボディを半透明にしています。 半透明で描画するAPIはdsSetColorAlphaです。

1.  関節中心点の取得

ここでは関節としてヒンジジョイントを例に取ります。ヒンジジョイントの関節中心点を取得するAPIは次の2つあります。

  • dJointGetHingeAnchor(  dJointID  joint, dVector3 result)
  • dJointGetHingeAnchor2(dJointID joint,  dVector3 result)

ヒンジジョイントjointの関節中心を絶対座標系で取得し、その値をresultに代入します。dVector3はdReal型の要素数3個の配列です。正確には要素数4個の配列ですが、これは計算を高速にするためのテクニックで、実際には最初の3個の要素しか使われません。

1番目と2番目のAPIの違いは前者はボディ1に対応するヒンジの中心点で、後者のdJointGetHingeAnchor2はボディ2に対応するヒンジの中心点です。ヒンジを生成したときは両者の中心点は一致していますが、シミュレーションを重ねる度にずれが生じます。それぞれを直すのがEFPパラメータです。

2. スケルトン表示(半透明色の設定)

シミュレーションによっては内部の構造を見せるためにスケルトン表示したい場合があります。描画ライブラリであるdrawstuffを使い半透明の物体を描画するには次のAPIを使います。

  • dsSetColorAlpha(float r, float g, float b, float alpha);

ここで、最初の引数 r, g, bは赤、緑、青の三原色、alphaは透明度を表し、0から1までの範囲を取り、透明度で0は透明、1は不透明です。

なお、スケルトン表示する場合は描画の順番が大切です。この例の場合は、まず不透明の骨に相当する直線を描画し、その後に半透明の関節やボディを描画します。この順番を間違えると表示されません。

関係部分のソースコードを以下に示します。全ソースコードはここから取得可能です。
サンプルプログラムではbキーを押すとボディ描画の表示を切り替えます。


[code]
static void simLoop (int pause)
{

const dReal *pos[BODY_NUM],*R[BODY_NUM];
dMatrix3 R1;
dVector3 ap[BODY_NUM-1]; // 関節中心点 anchor point
float ar = 0.06; // 関節表示用球の半径 anchor radius

if (!pause) {
if (steps++ < 10) dBodyAddForce (leg[0].body, 0, 1.0, 0);
for (int i = 0; i < BODY_NUM-1; i++)  control(i, joint[i]);
dSpaceCollide(space,0,&nearCallback);
dWorldStep(world,0.01);
dJointGroupEmpty(contactgroup);
}

// 重心位置と回転行列の取得 calculate positions and orientaitons
for (int i = 0; i < BODY_NUM; i++) {
pos[i] = dBodyGetPosition(leg[i].body);
R[i] = dBodyGetRotation(leg[i].body);
}

// 関節中心の取得  calculate anchor points
dRSetIdentity(R1);
for (int i = 0; i < BODY_NUM-1; i++) {
dJointGetHingeAnchor(joint[i], ap[i]);
}

// 関節中心から重心まで直線で描画 draw lines
for (int i = 0; i < BODY_NUM-1; i++) {
dsSetColorAlpha(1.3, 1.3, 1.3, 1.0);
dsDrawLine(pos[i], ap[i]);
dsSetColorAlpha(0.0, 0.0, 0.0, 1.0);
dsDrawLine(ap[i], pos[i+1]);
}

dsSetColorAlpha(1.3, 0.0, 0.0, 0.5);
// 関節中心を中心とした球の描画 draw anchors
for (int i = 0; i < BODY_NUM-1; i++) {
dJointGetHingeAnchor(joint[i], ap[i]); // 関節中心点の取得
dsDrawSphere(ap[i], R1, ar);
}

// ボディの描画 draw legs
dsSetColorAlpha(0.0, 0.0, 1.3, 0.5); // 透明色の設定
for (int i = 0; i < BODY_NUM; i++) {
if (drawBody) dsDrawCapsule(pos[i],R[i],leg[i].length,leg[i].radius);
}
}

[/code]


続く…

コメントを残す

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