みかづきブログ・カスタム

基本的にはちょちょいのほいです。

コントローラーでオブジェクトを掴むことができるWebVRをつくる ✊

f:id:kimizuka:20220304233207g:plain

まだ片手にしか対応できてませんが、コントローラーでオブジェクトを掴むことができるWebVRをつくりました。
cannon.jsで物理演算しているので、掴んだオブジェクトを放り投げることもできます。

実装方針

マウスで3Dオブジェクトを掴んで放り投げるモック をVR化しようと思ったのですが、どうにもうまくいかず、実装方針を大きく変更しました。

blog.kimizuka.org

❶ コントローラーとオブジェクトの当たり判定を取る

blog.kimizuka.org

❷ コントローラーとオブジェクトが接触している際、トリガーの入力を確認する

blog.kimizuka.org

❸ コントローラーとオブジェクトが接触していて、トリガーが引かれている際、コントローラーの位置に力を掛ける

blog.kimizuka.org

❹ トリガーを離した際、掛けていた力を解除する

という流れで実装しました。

❸のときに、pivotを考慮していないので、必ずコントローラーの座標にオブジェクトの中心がきます。
また、コントローラーを回転させてもオブジェクトは回転しないという問題もあります。この辺りは要改善です。

ソースコード(抜粋)

renderer.setAnimationLoop(() => {
  controllerRef.current[0].hit.center.set(
    controllerRef.current[0].position.x,
    controllerRef.current[0].position.y,
    controllerRef.current[0].position.z
  );
  cubeRef.current.hit.center.set(
    cubeRef.current.position.x,
    cubeRef.current.position.y,
    cubeRef.current.position.z
  );

  isHitRef.current = controllerRef.current[0].hit.intersectsSphere(cubeRef.current.hit); // 毎フレーム接触を判定

  handlePointerMove(); // コントローラー移動時のコールバックを呼び出す
  renderer.render(scene, camera);
});

function handlePointerDown() { // トリガーを引いた際のコールバック
  if (isHitRef.current) { // コントローラーとオブジェクトが接触している時
    targerCannonObjectRef.current = findCannonBodyFromId(cubeRef.current.uuid);
    targerCannonObjectRef.current.position.copy(controllerRef.current[0].position);
    targerCannonObjectRef.current.quaternion.copy(controllerRef.current[0].quaternion);
    addPointToPointConstraint( // コントローラーの位置に力を掛ける
      controllerRef.current[0].position.x,
      controllerRef.current[0].position.y,
      controllerRef.current[0].position.z,
      targerCannonObjectRef.current
    );
  }
}

function handlePointerMove() {
  if (
    targerCannonObjectRef.current &&
    pointToPointConstraintRef.current
  ) {
    if (isHitRef.current) {
      currsor.position.copy(controllerRef.current[0].position); // 力を掛ける位置を移動
    } else {
      handlePointerUp();
    }
  }
}

function handlePointerUp() {
  targerCannonObjectRef.current = null;
  world.removeConstraint(pointToPointConstraintRef.current); // 
  pointToPointConstraintRef.current = null;
}