以前、Three.jsでクリックされたオブジェクトを判定する際に使った、THREE.Raycasterを再び調査しました。
クリックされたオブジェクトの判定では、Raycaster.setFromCameraというメソットを使い、クリックされた点の直線上に存在するオブジェクトを導き出しましたが、今回は、Raycaster.setRaycaster.setに基準点と方向を渡すことで、その直線上にオブジェクトが存在するか調べます。
DEMO
キーボードの矢印でCubeの位置を調整できるのですが、直線上に存在する時のみ左上に「HIT」と表示されます。
赤外線センサに引っかかるスパイのようなイメージです。
iframeで埋め込むとページがスクロールしてしまって使いにくいので、JSFiddleで確認するのがおすすめです。
ソースコード(抜粋)
const renderer = new THREE.WebGLRenderer({ canvas: document.querySelector('canvas'), antialias: true, alpha: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(45) camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); camera.position.set(8, 8, 8); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); const cube = new THREE.Mesh( new THREE.BoxGeometry(1, 1, 1), new THREE.MeshNormalMaterial() ); scene.add(cube); const raycaster = new THREE.Raycaster( // Raycaster.setを使わず、コンストラクタに基準点(第一引数)と方向(第二引数)を渡す new THREE.Vector3(-4, .25, -2), new THREE.Vector3(1, 0, 0), 0, 8 ); const line = new THREE.Line( // 確認用にRaycasterと同じ位置にLineを引く new THREE.BufferGeometry().setFromPoints([ new THREE.Vector3(-4, .25, -2), new THREE.Vector3(4, .25, -2), ]), new THREE.MeshNormalMaterial() ); scene.add(line); renderer.setAnimationLoop(() => { renderer.render(scene, camera); const intersects =raycaster.intersectObjects(scene.children); // Raycaster上にあるインスタンスを取得 if (1 < intersects.length) { // Raycasterには常にLineが存在するので、1以上のときがCubeが存在する時 intersects.forEach(({ object }) => { if (object.type !== 'Line') { // Lineを無視 document.querySelector('p').innerText = 'HIT!'; } }); } else { document.querySelector('p').innerText = ''; } }); document.addEventListener('keydown', ({ key }) => { switch(key) { case 'ArrowLeft': cube.position.x -= .1; break; case 'ArrowRight': cube.position.x += .1; break; case 'ArrowUp': cube.position.z -= .1; break; case 'ArrowDown': cube.position.z += .1; break; } });