three.js で衝突判定


demo

画像をクリックでデモページが開きます。
市街地の3Dモデルは http://tf3dm.com のものを使用させていただいています。

three.js のカメラとオブジェクトの衝突判定を行う必要があったため、色々調べて実装してみたのでメモ。

three.js で衝突判定を行うためには Raycaster という二次元平面上の一点から光線を引いてその線上のオブジェクト(Mash)との衝突を判定するクラスで行うそうです。

で、この Raycaster を使用した衝突判定の実装方法ですが、まず衝突の判定先となるメッシュ(上記サンプルでは建物や地面のメッシュ)を配列に格納します。

var meshs = [];
for( var i = 0; i > object.children.length; i++ )
{
  // 読み込んだ obj モデルから Object3D を取り出す
  var obj3d = object.children[ i ];
  for( var j = 0; j > obj3d.children.length; j++ )
  {
    // Object3D から Mesh を取得し配列に入れる
    meshs.push( obj3d.children[ j ] );
  }
}

次に、Raycaster オブジェクトを作成して衝突判定を行いたい Vector3 オブジェクト(今回はカメラのポジション)と、衝突判定を行う(Raycaster を向ける)方向(Vector3)を設定します。
最後に Raycaster.intersectObjects に先ほど作成した衝突判定対象となるメッシュのリストを渡して完了です。

// camera に Raycaster を作成して下方向に ray を向ける
var ray = new THREE.Raycaster(camera.position, new THREE.Vector3(0, -1, 0));
// intersectObjects に衝突判定対象のメッシュのリストを渡す
var objs = ray.intersectObjects( meshs );

この Raycaster.intersectObjects を毎フレーム監視すると衝突がある場合はこのオブジェクトの要素数が 1 以上になり、この配列の中のオブジェクトのキー distance で衝突判定対象までの距離が取得できます。

あとは、この距離を利用して移動を止めたりイベントを発生させたりとやりたいことをやれば完了です。

if( objs.length > 0 )
{
	var dist = objs[0].distance;
	console.log( dist ); // 衝突判定対象までの距離

	// 例)衝突対象オブジェクトとの距離が 0 になった場合
	if( dist <= 0 )
	{
	  // やりたい処理を行う
	}
}

基本的にはこのような流れで実装できます。

今回のサンプルは Raycaster を使用して、下方向の判定で段差をを越えるときカメラの高さが上がるようにしているのと、前後左右方向の判定で建物をカメラがすり抜けないように衝突判定を行っています。

■ 今回参考にさせていただいたページ
http://threejs.org/docs/#Reference/Core/Raycaster
http://threejs.org/examples/#webgl_geometry_terrain_raycast
http://qiita.com/edo_m18/items/5aff5c5e4f421ddd97dc
http://naoyashiga.hatenablog.com/entry/2013/10/14/235134