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;
}
}