3

ボディがポイントAとポイントBの間をスライドできるようにするスライダーコンストレイントをインスタンス化します。コンストレイントをインスタンス化するために、2つのボディをコンストレイントに割り当てます。この場合、1つのダイナミックボディを静的な世界にコンストレイントします。スライディングドアを考えてください。 。3番目と4番目のパラメーターは、変換、参照フレームAおよび参照フレームBです。変換を作成および操作するために、ライブラリはクォータニオン、行列、オイラー角をサポートしています。

デフォルトのスライダー制約は、ボディをx軸に沿ってスライドさせます。私の質問は 、2つの変換を設定して、ボディBがそれ自体の原点と空間内の追加の点によって指定された軸に沿ってスライドするようにするにはどうすればよいですか?

素朴に私は試しました:

frameA.setOrigin(origin_of_point); //since the world itself has origin (0,0,0)
frameA.setRotation(Quaternion(directionToB, 0 rotation));

frameB.setOrigin(0,0,0); //axis goes through origin of object
frameB.setRotation(Quaternion(directionToPoint,0))

ただし、クォータニオンは期待どおりに機能していないようです。それらについての私の数学的知識はよくないので、誰かがこれがうまくいかない理由について私に記入してくれるなら、私は感謝するでしょう。何が起こるかというと、体はその方向に直交する軸に沿ってスライドします。Quaternionコンストラクターで回転部分を変更すると、ボディはそのスライド方向を中心に回転します。

編集: フレームワークは弾丸物理学です。2つの変換は、各ボディのローカル座標系に関して、スライダージョイントが各ボディにどのように取り付けられるかです。

Edit2 直交基底を介して変換の回転部分を設定することもできますが、その場合、単一のベクトルから直交基底を確実に構築する必要があります。クォータニオンがこれを防ぐことを望みました。

Edit3 私は次の手順でいくつかの限られた成功を収めています:

btTransform trafoA, trafoB;
trafoA.setIdentity();
trafoB.setIdentity();

vec3 bodyorigin(entA->getTrafo().col_t);
vec3 thisorigin(trafo.col_t);
vec3 dir=bodyorigin-thisorigin;
dir.Normalize();

mat4x4 dg=dgGrammSchmidt(dir);
mat4x4 dg2=dgGrammSchmidt(-dir);

btMatrix3x3 m(
    dg.col_x.x, dg.col_y.x, dg.col_z.x,
    dg.col_x.y, dg.col_y.y, dg.col_z.y,
    dg.col_x.z, dg.col_y.z, dg.col_z.z);
btMatrix3x3 m2(
    dg2.col_x.x, dg2.col_y.x, dg2.col_z.x,
    dg2.col_x.y, dg2.col_y.y, dg2.col_z.y,
    dg2.col_x.z, dg2.col_y.z, dg2.col_z.z);


trafoA.setBasis(m);
trafoB.setBasis(m2);

trafoA.setOrigin(btVector3(trafo.col_t.x,trafo.col_t.y,trafo.col_t.z));
btSliderConstraint* sc=new btSliderConstraint(*game.worldBody, *entA->getBody(), trafoA, trafoB, true);

ただし、GramSchmidtは常にtrafoBマトリックスの一部の軸を反転し、ドアは上下逆または右から左に表示されます。私はこれを解決するためのよりエレガントな方法を望んでいました。 Edit4 解決策を見つけましたが、上部のベクトルがスライド方向と一致している場合、これによって制約ソルバーに特異点が生じるかどうかはわかりません。

btTransform rbat = rba->getCenterOfMassTransform();
btVector3 up(rbat.getBasis()[0][0], rbat.getBasis()[1][0], rbat.getBasis()[2][0]);
btVector3 direction = (rbb->getWorldTransform().getOrigin() - btVector3(trafo.col_t.x, trafo.col_t.y, trafo.col_t.z)).normalize();

btScalar angle = acos(up.dot(direction));
btVector3 axis = up.cross(direction);
trafoA.setRotation(btQuaternion(axis, angle));
trafoB.setRotation(btQuaternion(axis, angle));
trafoA.setOrigin(btVector3(trafo.col_t.x,trafo.col_t.y,trafo.col_t.z));
4

3 に答える 3

1

この方法を複雑にしすぎている可能性はありますか?単純なパラメトリック変換 ( x = p*A+(1-p)*B) のように思えます。引き戸の類推が正確であれば、回転/向き全体はニシンです。

一方、2 つの方向の間の補間に制限しようとしている場合は、追加の制限を設定する必要があります。これは、一般的なケースでは一意の解決策がないためです。

-- マーカスQ

于 2009-03-03T20:12:06.010 に答える
0

使用しているフレームワークまたは API を言うか、呼び出している関数のドキュメントをコピーして貼り付けていただけると助かります。そのような詳細がなければ、私は推測することしかできません:

背景: クォータニオンは、スケールと組み合わせた 3 次元の回転を表します。(通常、スケールの管理に伴う複雑さは望ましくないため、回転のみを表す単位クォータニオンを使用します。) 行列とオイラー角は、回転を表す 2 つの代替方法です。

参照フレームは、位置に回転を加えたものです。空間のある位置に置かれたオブジェクトを回転させて、特定の方向を向くようにすることを考えてみてください。

したがって、フレーム A はおそらくオブジェクトの初期位置と回転 (スライダーが一方の端にある場合) であり、フレーム B はオブジェクトの最終位置と回転 (スライダーがもう一方の端にある場合) である必要があります。特に、オブジェクトをしっかりとスライドさせたいので、2 つの回転はおそらく同じである必要があります。

しかし、私が言うように、これは単なる推測です。

更新: これはBullet Physicsですか? ドキュメンテーションの方法はあまりないようですよね?

于 2009-02-21T21:56:38.510 に答える
0

おそらくあなたはslerpを探していますか?

Slerp は、3D 回転をアニメートする目的で四元数補間のコンテキストで Ken Shoemake によって導入された、球面線形補間の省略形です。これは、端点と 0 から 1 の間の補間パラメータが与えられると、単位半径の大円弧に沿った一定速度の動きを表します。

結局のところ、物事を回転させるには従来の回転行列が必要です。

編集:だから、私はまだ推測していますが、フレームワークがslerpingを処理し、開始状態と終了状態を記述する2つの変換が必要だと思いますか?

アフィン変換を他のものの上に積み重ねることができます。あなたが後ろ向きに考えなければならないことを除いて。たとえば、引き戸が開始状態で東向き (1, 1, 1) に配置されていて、北に向かって (0, 1, 0) だけスライドさせたいとします。ドアは (1, 1, 1) + (0, 1, 0) になります。

開始状態では、ドアを東に回転させます。その上で、別の平行移動行列を適用して、ドアを (1, 1, 1) に移動します。終了状態の場合も、ドアを東に回転させてから、平行移動行列を再度適用してドアを (1, 1, 1) に移動します。次に、平行移動行列 (0, 1, 0) を適用します。

于 2009-02-21T21:57:26.403 に答える