レイキャスターを利用した移動1
3Dオブジェクトの移動、回転、拡縮の操作を行えるようになりました。しかし、3D空間内のオブジェクトを選択したり、その選択したオブジェクトをドラッグしたりはできていません。そういったことができれば、ゲームやツールが非常に作りやすくなります。
「three.js」では、こういった処理を比較的簡単に行うための機能が用意されています。それが「Raycaster」です。レイキャスターという名前のとおり、ある点から光を照射して、その光線がオブジェクトに交差するか否かを判定させることができます。
この「Raycaster」を使い、カメラの位置から、マウスをクリックした場所に光線を放ち、3Dオブジェクトに光が当たるかどうかを判定します。そして、見事当たれば、その3Dオブジェクトをマウスで選択していると判断して、ドラッグ操作を行う処理ができます。
この判定結果は「Raycaster」の「intersectObject」関数で取得できます。この関数の第1引数は、判定を行う3dオブジェクトです。第2引数は、再帰処理を行うか否かです。この第2引数の使い方は、次の「レイキャスターを利用した移動2」で紹介していきます。
「intersectObject」は、結果を配列で戻します。配列が1以上であれば、光線が交差したオブジェクトが存在します。ここではオブジェクトを1つだけ指定するので、配列の数は0か1になります。
以下、レイキャスターを利用して、3Dオブジェクトを移動する「crocro.bc.useRaycaster1.js」を掲載します。
//= サンプル:レイキャスターを利用した移動1
//== レイキャスターを利用した移動1
crocro.bc.useRaycaster1 = function() {
// 変数の初期化
var d3 = crocro.bc.d3; // 3D格納用
// 要素の作成と格納
plt = crocro.bc.mkColPlate(0xff0000);
plt.scale.x = 2;
plt.scale.y = 2;
plt.scale.z = 2;
d3.scene.add(plt);
crocro.bc.render();
// マウス操作の作成
d3.tgt = plt;
crocro.bc.useRaycaster1_setMouse();
// 終了処理
crocro.bc.setFinalize(function() {
var d3 = crocro.bc.d3; // 3D格納用
d3.tgt = null;
d3.prjctr = null;
})
};
//== マウス操作の作成
crocro.bc.useRaycaster1_setMouse = function() {
// 変数の初期化
var d3 = crocro.bc.d3; // 3D格納用
var cntnr = crocro.bc.cntnr; // コンテナー
var isAct = false;
var posX, posY;
var prjctr = new THREE.Projector(); // プロジェクター
var offset = new THREE.Vector3();
//=== イベントを元に光線の交差判定
var chckIntrsct = function(event) {
// 中心からの位置の取得
posX = event.pageX - cntnr.offset().left;
posY = event.pageY - cntnr.offset().top;
// 描画範囲の比率に変換
posX = (posX / d3.w) * 2 - 1;
posY = -(posY / d3.h) * 2 + 1;
// マウス座標の作成
var vector = new THREE.Vector3(posX, posY, 1);
// スクリーン座標系をオブジェクトの座標系に変換
prjctr.unprojectVector(vector, d3.camera);
// レイキャスターを作成
var ray = new THREE.Raycaster(
d3.camera.position, // 始点
vector.sub(d3.camera.position).normalize() // 向きベクトル
);
// 交差判定
var intersects = ray.intersectObject(d3.tgt, false);
// 結果を戻す
return intersects;
};
//=== マウス操作 開始
var msStrt = function(event) {
isAct = true; // 動作状態に移行
// イベントを元に光線の交差判定
var intersects = chckIntrsct(event);
// 有効か確認
if (intersects.length > 0) {
// 交差したのでオフセットを記録
offset.copy(intersects[0].point).sub(d3.tgt.position);
} else {
isAct = false; // 動作状態を解除
}
};
//=== マウス操作 移動
var msMv = function(event) {
// 動作状態でなければ終了
if (! isAct) {return;}
// イベントを元に光線の交差判定
var intersects = chckIntrsct(event);
// 有効か確認
if (intersects.length > 0) {
// 交差しているので移動
var pos = intersects[0].point.sub(offset);
d3.tgt.position = pos;
}
// レンダリング
crocro.bc.render();
};
//=== マウス操作 終了
var msEnd = function() {
isAct = false; // 動作状態を解除
};
//=== マウス操作の登録
cntnr.mousedown(msStrt);
cntnr.mousemove(msMv);
cntnr.mouseup(msEnd);
$(window).blur(msEnd);
}
