📖

Three.js Cannon.es 調査資料 - Constraint確認/DistanceConstraint

2024/10/29に公開

この記事のスナップショット

DistanceConstraintの挙動

ソース

https://github.com/fnamuoo/webgl/blob/main/015

動かし方

  • ソース一式を WEB サーバ上に配置してください
  • マウス操作 .. カメラ位置の変更

概要

  • DistanceConstraintの挙動を確認します。

CANNON の制約(constraint)

物理エンジン Cannon.es において古典力学のふるまい、とりわけ2つの物体の動きを制限するものとして下記があります。

クラス名 説明・例
Spring バネ
DistanceConstraint 中心同士を一定の長さで固定。
PointToPointConstraint 点結合。振り子。
LockConstraint 固定。
HingeConstraint 軸結合。扉のちょうつがい。回転モーター。
ConeTwistConstraint 軸結合+ひねり。ragdoll の関節。

残念ながら平行移動(slider)はサポートされてないようです。

今回は DistanceConstraint について取り上げます。

やったこと(1)

まず3つの状態を用意しました。

  • 振り子を模して球を結合した場合 .. 左に配置
  • 振り子を模して立方体を結合した場合 .. 中央に配置
  • 振り子を模して立方体を結合して力を加えた場合 .. 右に配置

DistanceConstraint の使い方は、繋ぎたい 2つのオブジェクトと距離を指定し、world に追加するだけです。

下記では1番目(球の振り子)の例を示します。

  const radius = 1;
  const moObj1AShape = new CANNON.Sphere(radius);
  const moObj1ABody = new CANNON.Body({mass: 0, shape: moObj1AShape, position: new CANNON.Vec3(-10, 5, 0)});
  world.addBody(moObj1ABody)
  const viObj1AGeo = new THREE.SphereGeometry(radius, 6, 6);
  const viObj1AMtr = new THREE.MeshNormalMaterial({wireframe: true});
  const viObj1AMesh = new THREE.Mesh(viObj1AGeo, viObj1AMtr);
  viObj1AMesh.position.copy(moObj1ABody.position);
  viObj1AMesh.quaternion.copy(moObj1ABody.quaternion);
  scene.add(viObj1AMesh);
  //
  const moObj1BShape = new CANNON.Sphere(radius);
  const moObj1BBody = new CANNON.Body({mass: 1, shape: moObj1BShape, position: new CANNON.Vec3(-10, 5, 3)});
  world.addBody(moObj1BBody)
  const viObj1BGeo = new THREE.SphereGeometry(radius, 6, 6);
  const viObj1BMtr = new THREE.MeshNormalMaterial({wireframe: true});
  const viObj1BMesh = new THREE.Mesh(viObj1BGeo, viObj1BMtr);
  viObj1BMesh.position.copy(moObj1BBody.position);
  viObj1BMesh.quaternion.copy(moObj1BBody.quaternion);
  scene.add(viObj1BMesh);
  // 一定距離(=4)でつなぐ
  const moObj1Const = new CANNON.DistanceConstraint(moObj1ABody, moObj1BBody, 4);
  world.addConstraint(moObj1Const);
  // DistanceConstraintの可視化 二つのオブジェクトの中心をつないで線を引く
  const viObj1Mtr = new THREE.LineBasicMaterial( { color: 0x0000ff } );
  const viObj1Points = [];
  viObj1Points.push( moObj1ABody.position );
  viObj1Points.push( moObj1BBody.position );
  const viObj1Geo = new THREE.BufferGeometry().setFromPoints(viObj1Points);
  const viObj1Line = new THREE.Line(viObj1Geo, viObj1Mtr);
  scene.add(viObj1Line);

DistanceConstraint は物体の中心を端点にしてつなぎます。その動きを注視して見ると少々違和感を感じます。矩形の振り子がわかりやすいですが、姿勢(向きを)変えずに振り子の動きをしています。
ちなみに真ん中の振り子が床をこすっているのはご愛敬。

やったこと(2)

振り子の動きが気になってしまい、なんとか解消できないものかと考えた結果、振り子の球とアンカー(もう 1つの固定された球)を PointToPointConstraint でつなげば良さげです。

DistanceConstraint は距離だけでつなぐので、繋がれたオブジェクトの姿勢を制限しません。一方、PointToPointConstraint ではオブジェクトからの任意の位置で繋ぐので、繋がれた方向に向いて姿勢が固定されます。

球の場合と立方体の場合を追加、左奥と中央奥に配置しました。
振り子っぽくなってますね。すっきりしました。

すっきりした振り子

次は PointToPointConstraint を扱います。

Discussion