X
2022年02月26日 - WebVR・Three.js

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 }

完成したデモになります。レイキャスト機能で球体がクリックできるようになりました。

  • このエントリーをはてなブックマークに追加

関連記事

スポンサーリンク

前の記事へ

Pentacreation Homeを制作

次の記事へ

Blender3.3でレンダリング(Cycles X 編)