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

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

Three.jsでオブジェクト同士の接触を判定する 📦

DEMO

https://kimizuka.org/mock/collision

f:id:kimizuka:20220112233951g:plain

画面をクリックすると、オブジェクトが近づいて行って接触すると「HIT!」と表示されます。

実装方針

色々方法はあると思うのですが、今回は Sphere.intersectsSphere を使って球体と交差している球体があるかを判定しようと思います。

threejs.org

なので、

❶ 衝突判定をしたいジオメトリのboundingSphereを取得する
❷ 取得したboundingSphereと同じ座標、同じ大きさのSphereを作成する
❸ 毎フレーム、Sphereの座標をジオメトリの座標に合わせる
❹ 毎フレーム、Sphere.intersectsSphereで交差するSphereの有無を調べる

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

JavaScript(抜粋)

const scene = new THREE.Scene();
const cubeA = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshNormalMaterial()
);
const cubeB = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshNormalMaterial()
);

cubeA.position.set(-1, 0, 0);
cubeB.position.set(1, 0, 0)

if (!cubeA.geometry.boundingSphere) {
  cubeA.geometry.computeBoundingSphere(); // ❶
  cubeA.hit = new THREE.Sphere( // ❷
    cubeA.position,
    cubeA.geometry.boundingSphere.radius
  );
}

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

scene.add(cubeA);
scene.add(cubeB);

renderer.setAnimationLoop(() => {
  cubeA.hit.center.set(cubeA.position.x, cubeA.position.y, cubeA.position.z); // ❸
  cubeB.hit.center.set(cubeB.position.x, cubeB.position.y, cubeB.position.z);

  if (cubeA.hit.intersectsSphere(cubeB.hit)) { // ❹
    console.log('HIT!');
  }

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

renderer.domElement.addEventListener('click', function () { // クリックされたら座標を更新
  cubeA.position.x += .1;
  cubeB.position.x -= .1;
});

という感じです。