見出し画像

木を作る、葉を大きくしてそれっぽく修正

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Random Tree</title>
		<style>
			body {
				margin: 0;
				padding: 0;
				overflow: hidden;
			}
		</style>
	</head>
	<body>
		<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r132/three.min.js"></script>
		<script src="https://cdn.rawgit.com/mrdoob/three.js/r132/examples/js/controls/OrbitControls.js"></script>
		<script>
			var controls;
			const NUM_POINTS = 1;	//ツリーの始点の数
			const LINE_MATERIAL = new THREE.LineBasicMaterial({ color: 0x550000 });
			const LINE_LENGTH = 7.5;	// ツリーの各枝の長さ
			const LINE_TAPER = 0.1;	//ツリーの各枝の先端が細くなる割合
			const MAX_DEPTH = 10;	//ツリーの再帰的な成長の最大深度
			const ANGLE_RANGE = 0.5;//ツリーの各枝の方向が変化する角度の範囲
			const BRANCHING_PROBABILITY = 0.5;// 枝分かれする確率
			const SPHERE_RADIUS = 8.0;  // 球体の半径
			const SPHERE_COLOR = 0x308030; // 球体の色
			

			class Branch extends THREE.Object3D {
				constructor(geometry, material, length, taper) {
					super();
					const line = new THREE.Line(geometry, material);
					this.add(line);
					this.length = length;
					this.taper = taper;
				}
			}

			class Tree {
				constructor() {
					this.branches = [];
					this.maxDepth = MAX_DEPTH;
					this.endPoints = [];
				}

				grow(depth, point, angle) {
					if (depth >= this.maxDepth) {
						this.endPoints.push(point);
						return;
					}

					const geometry = new THREE.BufferGeometry();
					const positions = new Float32Array(2 * 3);
					positions.set([point.x, point.y, point.z, point.x, point.y, point.z], 0);
					geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

					const direction = new THREE.Vector3(
						Math.random() - 0.5,
						Math.random() - 0.5,
						Math.random() - 0.5
					).normalize();

					const axis = new THREE.Vector3();
					axis.crossVectors(direction, point).normalize();
					const angleChange = ANGLE_RANGE * Math.random() - ANGLE_RANGE / 2;
					angle += angleChange;

					const endPoint = point.clone().add(direction.clone().applyAxisAngle(axis, angle).multiplyScalar(LINE_LENGTH));
					positions.set([point.x, point.y, point.z, endPoint.x, endPoint.y, endPoint.z], 0);
					geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

					const newBranch = new Branch(geometry, LINE_MATERIAL, LINE_LENGTH, LINE_TAPER);
					this.branches.push(newBranch);
					
					if (Math.random() < BRANCHING_PROBABILITY) {
						// 枝分かれする
						this.grow(depth + 1, endPoint.clone(), angle);
						this.grow(depth + 1, endPoint.clone(), angle);
					} else {
						// 枝分かれしない処理を追加
						this.grow(depth + 1, endPoint.clone(), angle);
					}

					//this.grow(depth + 1, endPoint.clone(), angle);
					//this.grow(depth + 1, endPoint.clone(), angle);
				}

				render(scene) {
					for (let i = 0; i < this.branches.length; i++) {
						scene.add(this.branches[i]);
					}
					for (let i = 0;	i < this.endPoints.length; i++) {
							const sphereGeometry = new THREE.SphereGeometry(SPHERE_RADIUS, 12, 12);
							//const sphereMaterial = new THREE.MeshBasicMaterial({ color: SPHERE_COLOR });
							const sphereMaterial = new THREE.MeshPhongMaterial({ color: SPHERE_COLOR, shininess: 0.1 });

							const sphere = new THREE.Mesh(sphereGeometry, sphereMaterial);
							sphere.castShadow = true;
							sphere.receiveShadow = true;

							sphere.position.copy(this.endPoints[i]);
							scene.add(sphere);
						}
						
					}
				}
				
				function init() {
					const scene = new THREE.Scene();
					
					const camera = new THREE.PerspectiveCamera(
						40, window.innerWidth / window.innerHeight, 0.1, 1000);
					camera.position.y = 40;
					camera.position.z = 120;
					
					
					// Add a point light to the scene
					const sunLight = new THREE.PointLight(0xffffff, 3, 100, 1);
					sunLight.position.set(10, 100, 30);
					sunLight.castShadow = true;
					sunLight.shadow.mapSize.width = 2048;
					sunLight.shadow.mapSize.height = 2048;
					sunLight.shadow.camera.near = 1;
					sunLight.shadow.camera.far = 1000;
					sunLight.shadow.bias = -0.005;

					scene.add(sunLight);
					
					// Add an ambient light to the scene
					const ambientLight = new THREE.AmbientLight(0xeeeeff, 0.7);
					scene.add(ambientLight);
					
					const renderer = new THREE.WebGLRenderer();
					renderer.setClearColor(0xffffff);
					renderer.setSize(window.innerWidth, window.innerHeight);
					renderer.shadowMap.enabled = true; // 影を有効にする
					renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 影の質を設定する

					document.body.appendChild(renderer.domElement);
					
					// OrbitControlsを作成します
					controls = new THREE.OrbitControls(camera, renderer.domElement);
					
					const tree = new Tree();
					const points = [];
					for (let i = 0; i < NUM_POINTS; i++) {
						points.push(
							new THREE.Vector3(
								0,
								10,
								0
							)
						);
					}
					
					for (let i = 0; i < points.length; i++) {
						tree.grow(0, points[i], Math.PI / 2);
					}
					
					tree.render(scene);
					
					function animate() {
						requestAnimationFrame(animate);
						
						scene.rotation.y += 0.002;						
						//sunLight.rotation.y -= 0.1;
						
						// OrbitControlsを更新します
						controls.update();
						camera.lookAt(new THREE.Vector3(0, 50, 0));
						
						// レンダリングします
						renderer.render(scene, camera);
					}
					
					animate();
				}
				
				init();
				
				</script>
				</body>
				</html>

この記事が気に入ったらサポートをしてみませんか?