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

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

Three.jsでVRコントローラーとオブジェクトとの接触を判定する 🕶

DEMO

f:id:kimizuka:20220114224930g:plain

Oculus Quest用 DEMO 👉 https://kimizuka.org/mock/r127/vr-collision
Oculus Rift用 DEMO 👉 https://kimizuka.org/mock/r111/vr-collision

※ r111はコントローラーの位置にCubeが表示されます

解説

こちらの記事で作ったコードを改造して、VRコントローラーの当たり判定を取りました。

blog.kimizuka.org

r111にはXRControllerModelFactory.jsが無いのでコントローラーの姿を再現することは諦め、コントローラーの位置にCubeを置いています。

f:id:kimizuka:20220114230720g:plain

blog.kimizuka.org

ソースコード抜粋

const controllerModelFactory = new XRControllerModelFactory();
const controller = renderer.vr.getController(0);
const controllerModel = controllerModelFactory.createControllerModel(controller);
const mesh = new THREE.Mesh(
  new THREE.SphereGeometry(.06, 8, 8), // ❶ BoxGeometryからSphereGeometryに変更
  new THREE.MeshNormalMaterial()
);
const cube = new THREE.Mesh(
  new THREE.BoxGeometry(.1, .1, .1),
  new THREE.MeshNormalMaterial()
);

mesh.material.transparent = true;
mesh.material.alphaToCoverage = true;
mesh.material.opacity = 0; // ❷ メッシュを透明にする

controller.add(controllerModel);
controller.add(mesh);

if (!mesh.geometry.boundingSphere) {
  mesh.geometry.computeBoundingSphere();
  controller.hit = new THREE.Sphere(
    controller.position,
    mesh.geometry.boundingSphere.radius
  );
}

if (!cube.geometry.boundingSphere) {
  cube.geometry.computeBoundingSphere();
  cube.hit = new THREE.Sphere(
    cube.position,
    cube.geometry.boundingSphere.radius
  );
}

renderer.setAnimationLoop(() => {
  orbitControls && orbitControls.update();

  controller.hit.center.set(controller.position.x, controller.position.y, controller.position.z);
  cube.hit.center.set(cube.position.x, cube.position.y, cube.position.z);

  if (controller.hit.intersectsSphere(cube.hit)) {
    debug.log('HIT!');
  } else {
    debug.log('');
  }

  renderer.render(scene, camera);
});

前回との変更点で言うと、

❶ BoxGeometryからSphereGeometryに変更 → 当たり判定用にコントローラぐらいのサイズの球を作りました
❷ 当たり判定用の球を透明にする → 当たり判定は肉眼で確認出来なくて良いので透明にしました

の2点で、boundingSphereを使わずに当たり判定用のメッシュを作る方針にしました。
これは、controllerModelからboundingSphereを作る方法がわからないがための苦肉の策だったのですが、よく考えると、透明化を解除すれば当たり判定が目視確認できるのはデバッグ時に役に立ちそうだと思い、今後はこちらの方法を採用しようと思いました。