飴屋

WebGL/インタラクション

能動的に動かす

3D表現がいろいろできるようになりましたが、立体物が動くだけならそういう動画を張り付けておけばそれで済むわけで、WebGLでその場でレンダリングする必要性がないわけです。やはりWebサイトを見てくれている人の動作(アクション)に反応して、立体物がリアクションを返してこそコンテンツの魅力が膨らむわけですね。命を吹き込む、的な?こういうアクションの応酬要素をみんな何て呼んでるのかわかりませんが、ここではインタラクションとでも呼んでおきます。UI屋さんとかインタラクションに命をかけていらっしゃいますよね。ゲームなんかはその最たるもので、「コントローラーのボタンを押したら、画面の中で何かが起こる」の連続が人をあれだけ画面に引き込むんだからすげーですね。

というわけで、いつか作った回転する箱をマウス操作で動かしてみようと思います。

let mouse = new THREE.Vector2;
window.addEventListener('mousemove', e => {
  mouse.x = e.clientX;
  mouse.y = e.clientY;
});

ウィンドウ上でマウスが動いたら、マウス座標を変数に捕獲します。ノリでthree.js謹製のベクトル型を使ってみましたが、今のところその必要はないです。

function draw() {
  box.rotation.y += 0.01;
  box.scale.x = box.scale.z = 1.0 - Math.abs(mouse.x-width*0.5)*2/width;
  box.scale.y = 1.0 - Math.abs(mouse.y-height*0.5)*2/height;
  renderer.render(scene, camera);
  requestAnimationFrame(draw);
}

アニメーションの一コマ分を描画する関数の中で、さっきのマウス座標を使って箱のサイズを変更するような処理を書いてみました。カンバスの中央で回っている箱からマウスが遠ざかるにつれてサイズが小さくなるような計算式になってます。マウスのX軸座標と箱のXZ座標スケールが、マウスのY軸座標と箱のY座標スケールがそれぞれ独立して連動しているので箱が立方体を保ってませんね。

うん、一応リアクションもあるのができたけど、three.jsならではのインタラクション用のギミックがもっと探せば備わってるんじゃない?って思いました。マウスやキーボード操作をうまく画面に反映させているだけでつまらない内容かもですね。

クリックした先にあるモノ

ゲームエンジンとかだとこういうとき物体検索する機能がありますよねってことでthree.jsのドキュメントに当たってみたら、やはりそういうのありました。Raycasterという名前で、座標位置を指定するとその位置にある物体リストを返してくれるようです。

let mouse = new THREE.Vector2;
mouse.x = NaN;
const raycaster = new THREE.Raycaster();
window.addEventListener('click', e => {
  mouse.x = ( e.clientX / window.innerWidth ) * 2 - 1;
  mouse.y = ( e.clientY / window.innerHeight ) * 2 - 1;
});

とりあえずクリックした位置をさっきのmouse変数に入れておきます。座標位置はピクセル位置ではなく、ウィンドウサイズの端から端までを-1.0 - 1.0の範囲にみたてたときの位置です。なお、mouse変数に(0.0, 0.0)が初期座標として入っていると中央にある箱にピッタリ重なってしまうので、X座標をNaNにしときました。Raycasterも変数に入れておきます。

function draw() {
  box.rotation.y += 0.01;
  raycaster.setFromCamera( mouse, camera );
  const intersects = raycaster.intersectObjects( scene.children );
  for ( let i = 0; i < intersects.length; i ++ ) {
    intersects[i].object.scale.x *= 1.1
    mouse.x = NaN;
  }
  renderer.render(scene, camera);
  requestAnimationFrame(draw);
}

raycasterにカメラ情報をセットしたら、intersectObjectsメソッドでmouse座標位置にある物体の一覧情報を取得します。クリックした位置にある物体を全部拾ってくれるみたいですが、箱が一つ置かれてるだけなので、結果は「ある」か「なし」か2パターンですね。「ある」のときだけ箱のX軸スケールを1.1倍に膨らませます。クリックすればするほど横にやたらと広がっていきます。今回のプログラムではmouse変数の座標位置にNaNを詰めなおすのを忘れると描画の度に箱が1.1倍に拡大し続けかねないので要注意です。

Raycasterを使った物体検出を見て真っ先に思いついたのは射撃ゲームでした。的を動かせばちょっとはゲーム性がでそうです。Webサイトで使うようなシーンではRaycasterでかなり用が足せそうですね。これ以上やるとなると物理演算とかも視野に入ってくるかな?

Last-Modified