Open2

FPS型の3DワールドにRaycasterを使った簡易的な当たり判定を導入する

EriFuruyama@KEY4d LAB.EriFuruyama@KEY4d LAB.

■モチベーション
・3Dモデル(gltfモデル)を読み込んだシーンで簡易的な当たり判定を導入したい。
・モデルの複雑性から行って物理エンジンを使うほどでもないので、できるだけ楽にしたい。

■方向性
・THREE.jsのAPI raycasterを使うことにする。
https://threejs.org/docs/#api/en/core/Raycaster にある通り、Raycasterの起点は基本的にマウス。
しかし今回はFPSかつpointerlock controlsを使用しているためマウスではなくカメラを起点にする。

■やること
・カメラからraycasterをz方向(進行方向)に発射
・モデルに当たった場合、当たり判定をだし、進行をストップする

■手順コード(めちゃめちゃ省略)

let raycaster
//省略
//initファンクションの中に下記
 raycaster = new THREE.Raycaster(new THREE.Vector3(), new THREE.Vector3(0, 0, -1), 0, 10)
  //進行方向(z軸へ向けたray発射)、ジャンプなどしたい場合y方向に出す。

    raycaster.ray.origin.copy(controls.getObject().position)//これはカメラの位置。raycasterの位置設定はVec3

    // intersectionの設定
    const intersections = raycaster.intersectObjects(objects, true); //このobjectはシーン内のモデル全て
    const collisionRange = 20
    const delta = (time - prevTime) / 1000
    const tempVelocity = velocity.clone().multiplyScalar(delta) 
    const nextPosition = controls.getObject().position.clone().add(tempVelocity)
    const playerPosition = controls.getObject().position; //カメラの位置
    for (let i = 0; i < objects.length; i++) {
        let objectDirection = object.position.clone().sub(playerPosition).normalize()
        raycaster.set(nextPosition, objectDirection) //set the position and direction
        let directionIntersects = raycaster.intersectObject(objects[i])
        if (directionIntersects.length > 1.5 && directionIntersects[0].distance < collisionRange) {
            moveForward = false //当たったら前に進めないようにする
        }
    }

■所感
collisionRangeのくだりはなくても良かったかも。このあたりはモデルによる。
あと本当に正確な当たり判定を出したければやはり物理エンジン。
物理エンジンがOverkillってときにraycasterでいいかも。。
あとそもそもモデルのbounding boxを大きく設定しておかないと微妙に突っ込む部分も出てくる。
collidarを細かいメッシュで読み込むライブラリもあるようなので時間がある時はそっちも試す。