Three.jsを学ぶ その2 いろいろなジオメトリ

前回の発展型。

いろいろな形状の3Dオブジェクトを置いてみる。

まずは、基本となるレンダラーやカメラなどを制御するコード。
今回はカメラも移動させています。

import * as THREE from "three"
import { RandomMesh } from "./Mesh/RandomMesh";


(function(window, document) {

	class Main {

		/**
		 * メイン
		 * @constructor
		 */
		constructor() {

			this.scene = null;
			this.camera = null;
			this.renderer = null;

			// カメラの距離
			this.cameraLength = 100;
			this.cameraRadiusX = this.cameraLength;
			this.cameraRadiusZ = this.cameraLength * 0.8; 	// 楕円移動のため少し半径減らす

			this.rotate = 0;

			this.geometries = [];

			this.init();

		}



		/**
		 * 初期化
		 */
		init = () => {

			// シーンの生成
			this.scene = new THREE.Scene();

			// カメラ
			this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);

			// レンダラーの生成と追加(要するにcanvas要素である)
			this.renderer = new THREE.WebGLRenderer();
			this.renderer.setSize( window.innerWidth, window.innerHeight );
			document.body.appendChild( this.renderer.domElement );

			// ライトの追加(環境光)
			const light = new THREE.AmbientLight(0xFFFFFF, 1.0);
			this.scene.add(light);

			// ライトの追加(特定方向に照射される光源)
			const directLight = new THREE.DirectionalLight(0xFFFFFF, 1);
			this.scene.add(directLight);

			for(let i = 0; i < 20; i++) {
				const geometry = new RandomMesh();
				this.scene.add(geometry);

				this.geometries.push(geometry);
			}

			this.camera.position.z = 100;

			this.animate();

		}


		animate = () => {

			this.geometries.forEach((geometry) => {
				geometry.update();
			});

			this.rotate += 0.5;
			const radian = (this.rotate * Math.PI) / 180;

			this.camera.position.x = this.cameraLength * Math.sin(radian);
			this.camera.position.z = this.cameraRadiusZ * Math.cos(radian);
			this.camera.lookAt(new THREE.Vector3(0, 0, 0));

			requestAnimationFrame(this.animate);

			this.renderer.render(this.scene, this.camera);

		}

	}



	new Main();

})(window, document);

次に、3Dオブジェクト自体のコード。

THREE.Meshを継承したRandomMeshクラスを用意して、クラス内で表面に反映されるカラーと形状となるジオメトリを設定しています。(少々泥臭いコードですが)

import * as THREE from "three";



/**
 * ページトップボタン
 * @class
 */

export class RandomMesh extends THREE.Mesh {

	/**
	 *
	 * @constructor
	 */
	constructor(url) {

		super();

		// this.geometries = [
		// 	THREE.BoxGeometry,
		// 	THREE.SphereGeometry,
		// 	THREE.PlaneGeometry,
		// 	THREE.ConeGeometry,
		// 	THREE.CylinderGeometry,
		// 	THREE.TorusGeometry
		// ];

		this.geometry = this.randomGeometry();
		let color = this.randomColor();
		this.material = new THREE.MeshLambertMaterial( { color: this.randomColor() } );

		this.position.x = 100 * Math.random() - 50;
		this.position.y = 100 * Math.random() - 50;
		this.position.z = 100 * Math.random() - 50;

		this.rotation.x = Math.random();
		this.rotation.y += Math.random();

	}



	/**
	 * ランダムジオメトリ
	 */
	randomGeometry = () => {

		let r = Math.floor(Math.random() * 8);

		const radius = Math.random() * 3 + 4;
		const length = Math.random() + 4 + 4;
		const width = Math.random() + 5 + 5;
		const height = Math.random() + 5 + 5;
		const depth = Math.random() + 5 + 5;

		if(r === 0) {
			return new THREE.PlaneGeometry(16, 9);
		}
		else if(r === 1) {
			return new THREE.SphereGeometry(radius, 32, 32);
		}
		else if(r === 2) {
			return new THREE.BoxGeometry(width, height, depth);
		}
		else if(r === 3) {
			return new THREE.ConeGeometry(radius, height, 32);
		}
		else if(r === 4) {
			return new THREE.CapsuleGeometry(radius, length, 4, 12);
		}
		else if(r === 5) {
			return new THREE.DodecahedronGeometry(radius, 0);
		}
		else if(r === 6) {
			return new THREE.IcosahedronGeometry(radius, 0);
		}
		else if(r === 7) {
			return new THREE.CylinderGeometry( 5, 5, 20, 32 );
		}
		else {
			return new THREE.TorusGeometry( 10, 3, 16, 100 );
		}

	}



	randomColor = () => {
		const h = Math.floor(Math.random() * 360);
		const s = Math.floor(Math.random() * 70) + 30;
		const l = Math.floor(Math.random() * 255);

		return `hsl(${h}, ${s}%, 50%)`;
	}


	update = () => {

		this.rotation.x += 0.01;
		this.rotation.y += 0.01;

	}

}

デモはこちら