[Three.js]カメラをマウスで操作して視点変更を可能にする

2021年2月27日

Three.js によって3Dモデルを表示できたので、せっかくなら様々な角度からモデルを眺められるようにしたいです。

Three.js入門 - ブラウザで様々な3Dを表示するサンプル

今回はカメラを操作する方法について紹介します。

あるオブジェクトの周囲軌道上でカメラを移動させ、視点をマウス操作によって変更できるようにするには Controls のひとつである OrbitControls を追加します。動作サンプルはページ下部に表示しています。

サンプルコードと動作例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>カメラ視点を自由に切り替えられるシーン</title>
		<style>
			body { margin: 0; }
		</style>
	</head>
	<body>
		<script type="module">

			import * as THREE from 'https://unpkg.com/three@0.126.0/build/three.module.js';

			const scene = new THREE.Scene();
			// 背景色を灰色にする
			scene.background = new THREE.Color(0x444444);

			const renderer = new THREE.WebGLRenderer();
			// 影に必要
			renderer.shadowMap.enabled = true;			
			renderer.setSize(window.innerWidth, window.innerHeight);
			document.body.appendChild(renderer.domElement);


			// 立方体
			const cube = new THREE.Mesh(
				new THREE.BoxGeometry(), 
				new THREE.MeshStandardMaterial( { color: 0x00ff00 } ));
			cube.castShadow = true;
			cube.position.set(0, 3, 1);
			scene.add(cube);


			// 床となる平面
			const plane = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), new THREE.MeshStandardMaterial());
			// 回転は度ではなくラジアンなので注意
			plane.rotation.x = THREE.MathUtils.degToRad(-90);
			plane.receiveShadow = true;
			scene.add(plane);

			// 四方の壁となる平面
			const wallForward = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), new THREE.MeshStandardMaterial({
				color: 0x0000FF
			}));
			wallForward.position.z = -10;
			wallForward.receiveShadow = true;
			scene.add(wallForward);

			const wallRight = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), new THREE.MeshStandardMaterial({
				color: 0x00FF00
			}));
			wallRight.rotation.y = THREE.MathUtils.degToRad(90);
			wallRight.position.x = -10;
			wallRight.receiveShadow = true;
			scene.add(wallRight);

			const wallLeft = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), new THREE.MeshStandardMaterial({
				color: 0xFF0000
			}));
			wallLeft.rotation.y = THREE.MathUtils.degToRad(-90);
			wallLeft.position.x = 10;
			wallLeft.receiveShadow = true;
			scene.add(wallLeft);

			const wallBack = new THREE.Mesh(new THREE.PlaneGeometry(20, 20), new THREE.MeshStandardMaterial({
				color: 0xFF00FF
			}));
			wallBack.rotation.y = THREE.MathUtils.degToRad(180);
			wallBack.position.z = 10;
			wallBack.receiveShadow = true;
			scene.add(wallBack);


			// ポイントライト
			const pointLight = new THREE.PointLight(0xffffff, 1, 100 );
			pointLight.position.set(0, 10, 0);
			pointLight.castShadow = true;
			scene.add(pointLight);


			// GUI表示
			import { GUI } from 'https://unpkg.com/three@0.126.0/examples/jsm/libs/dat.gui.module.js';

			// カメラ位置をリセットするためのメニュー項目
			const settings = {
				resetCamera: function() {
					controls.update();
					camera.position.set(10, 10, 10);
				}
			};

			// メニューGUI
			const gui = new GUI();
			gui.add(settings, 'resetCamera');
			gui.open();

			// カメラ設定
			const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
			camera.position.set(10, 10, 10);
			camera.lookAt(0, 0, 0);

			import { OrbitControls } from 'https://unpkg.com/three@0.126.0/examples/jsm/controls/OrbitControls.js';			
			const controls = new OrbitControls(camera, renderer.domElement);

			// 毎フレームのレンダリング処理
			function animate() {

				// requestAnimationFrameによる更新処理は他のブラウザタブが選択されると自動的にポーズされる
				requestAnimationFrame(animate);

				// required if controls.enableDamping or controls.autoRotate are set to true
				// controls.update();
				renderer.render(scene, camera);
			}

			// WebGLのサポートチェック
			import { WEBGL } from 'https://unpkg.com/three@0.126.0/examples/jsm/WebGL.js';		
			if (WEBGL.isWebGLAvailable()) {
				animate();
			} else {
				document.getElementById('container').appendChild(WEBGL.getWebGLErrorMessage());
			}
		</script>
	</body>
</html>

このコードを含むHTMLファイルを iframe で以下に埋め込みました。

カメラ視点を自由に切り替えられるシーン

ズームや角度変更、平行移動などカメラを操作して視点を切り替えられます。

以上、Three.js にてカメラを操作する方法についてでした。Controls には、他にも FPS のようなカメラ移動を可能にするものなどがあります。詳細は公式ドキュメントを御覧ください。

FlyControls – three.js docs

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です