はりうすブログ (のすけのメモ)

湘南にある小さな会社 代表 ”のすけ”のブログです

babylon.js ステップ12 レイキャスト(Raycasts)

babylon.jsのチュートリアルシリーズ 12回目

今回はレイキャストをやっていきます

いきましょう!

レイキャストとは光線による衝突判定

前回の11回ではマウスの位置と、壁の衝突判定を行いましたが。

レイキャストは、光線(レーザー・)による衝突または、交差チェックを行う機能です。

FPSゲームの弾丸の軌道なんかはレイキャストで行います。


マウスクリックで、選択されたメッシュ情報を取得する方法(scene.pick)を使用しました。

一方レイキャストでは似たようなメソッド、 scene.pickWithRay() を使っていきます

光線と最初に接したメッシュの取得

光線と最初に接したメッシュの取得をやっていきます。

f:id:hollywis:20200708020632j:plain


真ん中に、光線を出力する赤い箱があります(箱はマウスで動かせる)

そして、その光線と接する可能性のある、青い箱が2つと緑の箱があります。


なお、奥の青い箱は、光線が届きません。

光線が当てられた箱は上に伸びていきます。


デモはこちら

https://www.babylonjs-playground.com/#KNE0O#84


まず、最初に光線の出力もとである赤い箱には、衝突検出をoffにする設定を入れます。赤い箱自体が衝突判定されてしまっては困りますので。

box.isPickable = false; 

次に、箱から出る光線のベクトルを定義します。その際,箱の位置()を差し引いて箱の原点origin(光線が始まる場所)からの方向を取得します。

// 赤い箱との方向ベクトル
var forward = new BABYLON.Vector3(0,0,1);        
forward = vecToLocal(forward, box);

// 箱の方向
var direction = forward.subtract(origin);
direction = BABYLON.Vector3.Normalize(direction);

vecToLocalは箱からの方向を取得する関数です。Normalizeは正規化(長さを1に)する作業です。

そして、取得した単位ベクトルから任意の長さの光線を作成します。

var ray = new BABYLON.Ray(origin, direction, length);

最後に、接触した箱(mesh)の接触点を取得します

var hit = scene.pickWithRay(ray);

あとは、衝突したメッシュのyを増やしてあげれば良いです

if (hit.pickedMesh) {
   hit.pickedMesh.scaling.y  += 0.01;
}

Predicate関数を使用したレイキャスト

予め、衝突判定するメッシュを定義するための関数を作ることができます。

// boxとbox2は衝突判定をしない,それ以外はする
function predicate(mesh){
  if (mesh == box2 || mesh == box){
    return false;
  }
  return true;
}

そして、pickWithRayの時に、Predicateを渡してあげます。こうすることで、個別にxxx.isPickable = false; のおような設定を省略できます。

scene.pickWithRay(ray, predicate);

例はこちら。手前の青い箱のPickableをfalseにしているので、後ろの箱に衝突判定があります

https://www.babylonjs-playground.com/#KNE0O#18


マルチピック

scene.multiPickWithRay光線を最初の障害物で停止させたくない場合は、次のように使用できます。

https://www.babylonjs-playground.com/#KNE0O#19


f:id:hollywis:20200708024443j:plain

 var hits = scene.multiPickWithRay(ray);

hit算出をmultiPickWithRayに変えることで、貫通する衝突判定が可能です。

multiPickWithRayの戻り値は配列になっていることに注意してください.


そのほかRayクラスを直接利用することで、ここのメッシュの交差判定をしたり

Ray.intersectsMesh(mesh, fastCheck) → PickingInfo

ローカルスペースへ変更したりできます

Ray.Transform(ray, matrix) → Ray

Picking Ray

カメラから無限遠に向かって、衝突判定(照準)することができます。

そのためにはcreatePickingRay関数を使います。

前の11ステップでは壁との衝突判定を行いましたが、任意のメッシュの場合にはこちらの方が便利そうです。

例はこちら

https://playground.babylonjs.com/#AC8XPN

デバッグ用のRayHelper

デバッグ用に光線に色をつけることができます。

BABYLON.RayHelper.CreateAndShow(ray, scene, new BABYLON.Color3(1, 1, 0.1));

例はこちら

https://www.babylonjs-playground.com/#ZHDBJ#48

まとめ

pickWithRay() を使って光線的な衝突を検出し、そこから衝突したメッシュを取得することができました。

また、multiPickWithRay()を使えば貫通する光線を用いて一度に複数の衝突も取得できました。


また、カメラからの照準(選択)する方法としてcreatePickingRay()を用いる方法を学びました。

以上です!

長かったですが、これで衝突判定系は終わりです。

次回は2D表現のスプライトいっみます