メインコンテンツまでスキップ

ジョイント

アルファ版

Jointコンポーネントはアルファ版のため、その挙動やAPIは変わる可能性があります。すべての環境でコードから利用でき、Web Componentsではタグとしても利用できますが、エディターにはまだ専用のインスペクターがなく、PlayCanvas Reactには対応するコンポーネントがありません。

ジョイントは2つのRigidBodyの相対的な動きを拘束します。ヒンジで回るドア、レールの上を滑る引き出し、リンクの連なった鎖、スプリングで上下に揺れる木箱、あるいは何かが強くぶつかって溶接が壊れるまで一体になっているブロックの塔などです。

Joints

ジョイントの仕組み

ジョイントは、独自のエンティティに付いたJointComponentです。そのエンティティ自身は拘束されません。そのワールドトランスフォームがジョイントフレームを定義します。位置は拘束が作用するアンカーポイントで、ローカルX軸が主軸です。ヒンジはXを中心に回転し、スライダーはXに沿って移動し、ボールジョイントはXを中心にひねります。ジョイントの向きを決めるには、ジョイントのエンティティを回転させます。

拘束する2つのボディはentityAentityBで設定し、どちらにもrigidbodyコンポーネントが必要です。entityBを空にすると、entityAはワールド空間の固定点に拘束されます。これが何もないところに物を吊り下げる方法です。よくある構成は、ジョイントのエンティティをピボット位置でentityAの子にすることで、ピボットが属する部品と一緒に動くようになります。

つまずきやすい点が2つあります。

  • フレームは一度だけ取得されます。 取得は拘束が作成されるときで、通常はコンポーネントが有効になり、両方のボディがシミュレーションに存在した時点です。その後にジョイントのエンティティを動かしても、コンポーネントのrefreshFrames()を呼び出して現在のトランスフォームからフレームを再取得するまで何も変わりません。エンティティのスケールはRigidBodyと同様、全体を通して無視されます。
  • リミットは開始時の姿勢を基準に測られます。 ジョイントのエンティティが基準ではありません。拘束が作成された瞬間に2つのジョイントフレームは一致するため、すべての自由度はそこで0になります。ヒンジのリミット0から110度は「ボディの開始位置からさらに110度まで」という意味であり、絶対的な角度ではありません。

ジョイントのタイプ

typeプロパティで拘束の種類を選び、それによって他のどのプロパティが意味を持つかが決まります。

タイプ定数拘束する内容使用するプロパティ
fixedJOINTTYPE_FIXEDボディ同士を剛体的に固定するなし
ballJOINTTYPE_BALLボールソケット:アンカーを中心に自由に回転し、オプションでスイングとツイストのリミットを持つswingLimitYswingLimitZtwistLimit
hingeJOINTTYPE_HINGEフレームのX軸を中心とした回転。オプションでリミットとモーターを持つlimitsmotorSpeedmaxMotorForce
sliderJOINTTYPE_SLIDERフレームのX軸に沿った移動。オプションでリミットとモーターを持つlimitsmotorSpeedmaxMotorForce
6dofJOINTTYPE_6DOF各直線軸と回転軸を個別にロック、制限、自由に設定し、オプションでスプリングを持つlinearMotionX/Y/ZangularMotionX/Y/ZlinearLimitsX/Y/ZangularLimitsX/Y/ZlinearStiffnessangularStiffnesslinearDampingangularDampinglinearEquilibriumangularEquilibrium

すべてのタイプは、2つのボディが互いに衝突し続けるかどうかを決めるenableCollision(デフォルトはオフ)と、breakImpulseも受け付けます。

6dofジョイントでは各軸がMOTION_LOCKEDから始まるため、他に何も設定しなければfixedジョイントと同じように振る舞います。動かしたい軸をMOTION_FREEまたはMOTION_LIMITEDで開放し、制限した軸には対応するリミットを設定します。ある軸に0より大きい剛性を設定すると、その軸は平衡値に向かって引き戻すスプリングになります。

ジョイントの追加

このドアヒンジは、Dynamicなドアを Staticなドア枠に拘束します。ジョイントのエンティティはヒンジの線上に置き、ローカルX軸が上を向くように回転させ、0から110度のリミットでドアが一方向にだけ開くようにします。

const hinge = new pc.Entity('hinge');
hinge.setPosition(1, 1, 0);
hinge.setEulerAngles(0, 0, 90); // ローカルX軸が上を向く
hinge.addComponent('joint', {
type: pc.JOINTTYPE_HINGE,
entityA: door,
entityB: doorFrame,
enableLimits: true,
limits: new pc.Vec2(0, 110)
});
app.root.addChild(hinge);

pc.ApplicationはJointコンポーネントシステムを登録します。pc.AppBaseから構築する場合は、CollisionとRigidBodyのシステムと共にpc.JointComponentSystemAppOptions.componentSystemsに追加してください。

モーター、リミット、破断

リミットは二重にオプトインです。enableLimitsを設定し、かつリミット値を指定する必要があります。limitsを設定してもenableLimitsがfalseのままのヒンジは自由に回ります。

ヒンジとスライダーにはモーターがあります。モーターはmaxMotorForceが0より大きい間だけ作動し、motorSpeedの速さでジョイントを駆動します。単位はヒンジでは度/秒、スライダーではユニット/秒です。リミットが有効なモーターはストッパーで止まります。

// 風車:ヒンジ軸を中心にローターを毎秒90度で回す
hinge.joint.motorSpeed = 90;
hinge.joint.maxMotorForce = 100;

どのジョイントも壊れることがあります。breakImpulseに拘束が壊れるインパルスのしきい値を設定します。デフォルトはInfinityで、決して壊れません。壊れるとコンポーネントはbreakイベントを発火し、isBrokenがtrueになり、ボディは独立して動くようになります。refreshFrames()を呼び出すと、ボディの現在のトランスフォームからジョイントが再接続されます。

const weld = jointEntity.joint;
weld.breakImpulse = 60;
weld.on('break', () => {
console.log('The weld snapped');
});
注記

拘束の状態を公開していないammo.jsのビルドでは、6dofジョイントの破断を検出できないため、これらのジョイントではbreakイベントが発火しません。他のジョイントタイプには影響しません。

関連情報

  • JointComponent - すべてのジョイントプロパティのAPIリファレンス
  • <pc-joint> - Web Componentsでの同じジョイント。各タイプのライブ例付き
  • Ragdoll - ボールジョイントとヒンジジョイントでキャラクターを組み立てるエンジンの例
  • RigidBody - すべてのジョイントが拘束するボディ