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 }
完成したデモになります。レイキャスト機能で球体がクリックできるようになりました。

