2022年02月26日 - WebVR・Three.js
Three.jsでオブジェクトをクリック
Three.jsでオブジェクトをクリックしてみました。※Three.jsはr134を使用しています。
Three.jsでオブジェクトをクリック
3D空間上のオブジェクトをマウスでクリックするには、レイキャスト機能で光線を飛ばして、交差したオブジェクトを取得します。
● 球体の生成
まずは、球体を生成します。
let sphere; threeWorld(); function threeWorld(){ //球体を生成 const geometry = new THREE.SphereGeometry(2,32,16); const material = new THREE.MeshPhongMaterial({color:0xFFFFFF}); sphere = new THREE.Mesh(geometry,material); scene.add(sphere); //球体のnameを設定 sphere.name = 'spehere'; }
● マウス座標の取得
canvas上のマウス座標を取得します。
//canvasを取得 const container = document.querySelector('#canvas_vr'); let mouse; setControll(); function setControll(){ //マウス座標管理用のベクトル mouse = new THREE.Vector2(); //マウスイベントを登録 container.addEventListener('mousemove',handleMouseMove); function handleMouseMove(event){ const element = event.currentTarget; //canvas上のマウスのXY座標 const x = event.clientX - element.offsetLeft; const y = event.clientY - element.offsetTop; //canvasの幅と高さを取得 const w = element.offsetWidth; const h = element.offsetHeight; //マウス座標を-1〜1の範囲に変換 mouse.x = (x/w)*2-1; mouse.y = -(y/h)*2+1; } }
● オブジェクトをクリック
レイキャスト機能で光線を飛ばし、intersectObjectsで光線と交差したオブジェクトを取得します。
let mouse; let raycaster; let clickFlg = false; let moveFlg = false; setControll(); function setControll(){ mouse = new THREE.Vector2(); //レイキャストを生成 raycaster = new THREE.Raycaster(); container.addEventListener('mousemove',handleMouseMove); //マウスイベントを登録 container.addEventListener('click',handleClick); function handleMouseMove(event){ moveFlg = true; const element = event.currentTarget; const x = event.clientX - element.offsetLeft; const y = event.clientY - element.offsetTop; const w = element.offsetWidth; const h = element.offsetHeight; mouse.x = (x/w)*2-1; mouse.y = -(y/h)*2+1; } function handleClick(event){ if(clickFlg){ window.open('https://www.pentacreation.com/blog/'); } } } function rendering(){ requestAnimationFrame(rendering); //マウス位置からまっすぐに伸びる光線ベクトルを生成 raycaster.setFromCamera(mouse,camera); //光線と交差したオブジェクトを取得 const intersects = raycaster.intersectObjects(scene.children,false); //光線と交差したオブジェクトがある場合 if(intersects.length > 0){ //交差したオブジェクトを取得 const obj = intersects[0].object; //光線が球体と交差していた場合 if(obj.name == 'spehere'){ if(moveFlg){ clickFlg = true; } }else{ clickFlg = false; } }else{ clickFlg = false; } renderer.render(scene,camera); }
● script.js
必要なライブラリを読み込みます。
<script src="js/lib/preloadjs.min.js"></script> <script src="js/lib/TweenMax.min.js"></script> <script src="js/script.js" type="module"></script>
完成したscript.jsです。
//=============================================================== // Import Library //=============================================================== import * as THREE from './lib/three_jsm/three.module.js'; import { OrbitControls } from './lib/three_jsm/OrbitControls.js'; import { scene, camera, container, renderer } from './lib/basescene.js'; //=============================================================== // Main //=============================================================== window.addEventListener('load',function(){ init(); }); let orbitControls; let sphere; let mouse; let raycaster; let clickFlg = false; let moveFlg = false; function init(){ setLoading(); } function setLoading(){ TweenMax.to('.loader',0.1,{opacity:1}); TweenMax.to('#loader_wrapper',1,{ opacity:0, delay:1, onComplete: function(){ document.getElementById('loader_wrapper').style.display='none'; threeWorld(); setLight(); setControll(); rendering(); } }); } function threeWorld(){ const axesHelper = new THREE.AxesHelper(500); const gridHelper = new THREE.GridHelper(500,50); scene.add(axesHelper); scene.add(gridHelper); const geometry = new THREE.SphereGeometry(2,32,16); const material = new THREE.MeshPhongMaterial({color:0xFFFFFF}); sphere = new THREE.Mesh(geometry,material); scene.add(sphere); sphere.position.set(0,5,0); sphere.name = 'spehere'; } function setLight(){ const ambientlight = new THREE.AmbientLight(0xFFFFFF,0.4); scene.add(ambientlight); const pointLight = new THREE.PointLight(0xFFFFFF,1.0,100,1.0); pointLight.position.set(7.5,10,0); scene.add(pointLight); } function setControll(){ document.addEventListener('touchmove',function(e){e.preventDefault();},{passive:false}); orbitControls = new OrbitControls(camera,renderer.domElement); orbitControls.target.set(0,0,0); orbitControls.enableDamping = true; orbitControls.dampingFactor = 0.5; mouse = new THREE.Vector2(); raycaster = new THREE.Raycaster(); container.addEventListener('mousemove',handleMouseMove); container.addEventListener('click',handleClick); function handleMouseMove(event){ moveFlg = true; const element = event.currentTarget; const x = event.clientX - element.offsetLeft; const y = event.clientY - element.offsetTop; const w = element.offsetWidth; const h = element.offsetHeight; mouse.x = (x/w)*2-1; mouse.y = -(y/h)*2+1; } function handleClick(event){ if(clickFlg){ window.open('https://www.pentacreation.com/blog/'); } } } function rendering(){ requestAnimationFrame(rendering); if(orbitControls){ orbitControls.update(); } raycaster.setFromCamera(mouse,camera); const intersects = raycaster.intersectObjects(scene.children,false); if(intersects.length > 0){ const obj = intersects[0].object; if(obj.name == 'spehere'){ if(moveFlg){ clickFlg = true; } }else{ clickFlg = false; } }else{ clickFlg = false; } if(clickFlg){ container.style.cursor = 'pointer'; }else{ container.style.cursor = 'grab'; } renderer.render(scene,camera); }
● basescene.js
sceneやcameraなど基本的な設定を管理するbasescene.jsです。
//=============================================================== // Import Library //=============================================================== import * as THREE from './three_jsm/three.module.js'; //=============================================================== // Base scene //=============================================================== let scene,camera,container,renderer; init(); function init(){ scene = new THREE.Scene(); camera = new THREE.PerspectiveCamera(50,window.innerWidth/window.innerHeight,1,1000); camera.position.set(18,14,18); scene.add(camera); renderer = new THREE.WebGLRenderer({antialias:true}); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth,window.innerHeight); renderer.setClearColor(new THREE.Color(0x000000)); container = document.querySelector('#canvas_vr'); container.appendChild(renderer.domElement); window.addEventListener('resize',function(){ camera.aspect = window.innerWidth/window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth,window.innerHeight); },false); } export { scene, camera, container, renderer }
完成したデモになります。レイキャスト機能で球体がクリックできるようになりました。