[READ-ONLY] Mirror of https://github.com/flo-bit/tiny-planets. procedurally generated tiny planets in the browsers
flo-bit.dev/tiny-planets/
low-poly
planets
procedural-generation
threejs
3.5 kB
141 lines
1import * as THREE from "three";
2import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
3import { Planet } from "./worlds/planet";
4import { Stars } from "./worlds/stars";
5import { planetPresets } from "./worlds/presets";
6
7const presets = ["beach", "forest", "snowForest"];
8
9const width = window.innerWidth,
10 height = window.innerHeight;
11
12const canvas = document.getElementById("root");
13
14if (!canvas) {
15 throw new Error("Canvas not found");
16}
17const scene = new THREE.Scene();
18const camera = new THREE.PerspectiveCamera(70, width / height, 0.01, 30);
19camera.position.set(0, 0, 2.5);
20
21const renderer = new THREE.WebGLRenderer({
22 antialias: true,
23 canvas,
24 alpha: true,
25});
26
27renderer.toneMapping = THREE.ACESFilmicToneMapping;
28renderer.shadowMap.enabled = true;
29
30const _ = new OrbitControls(camera, renderer.domElement);
31
32let hasPlanet = false;
33
34let sphereGeometry = new THREE.IcosahedronGeometry(1, 20);
35let sphereMaterial = new THREE.MeshStandardMaterial({
36 color: "white",
37 wireframe: true,
38 wireframeLinewidth: 10,
39});
40let planetMesh: THREE.Mesh = new THREE.Mesh(sphereGeometry, sphereMaterial);
41scene.add(planetMesh);
42
43const light = new THREE.DirectionalLight();
44light.intensity = 2;
45light.position.set(2, 1, 0);
46scene.add(light);
47light.castShadow = true;
48light.shadow.mapSize.width = 512;
49light.shadow.mapSize.height = 512;
50light.shadow.camera.far = 10;
51light.shadow.camera.near = 0.1;
52
53light.shadow.bias = 0.01;
54light.shadow.camera.top = 2;
55light.shadow.camera.right = 2;
56light.shadow.camera.bottom = -2;
57light.shadow.camera.left = -2;
58
59const ambientLight = new THREE.AmbientLight(0xffffff, 0.1);
60scene.add(ambientLight);
61
62let total = 0;
63let lastDelta = 0;
64
65let rotate = true;
66renderer.setAnimationLoop((delta) => {
67 renderer.render(scene, camera);
68
69 if (rotate) planetMesh.rotation.y += 0.001;
70
71 if (lastDelta > 0) {
72 total += delta - lastDelta;
73 }
74 lastDelta = delta;
75
76 if (!hasPlanet) {
77 console.log("Creating planet");
78 createPlanet("beach");
79 hasPlanet = true;
80 }
81});
82
83let stars = new Stars();
84
85scene.add(stars);
86
87// add keydown event listener
88document.addEventListener("keydown", (event) => {
89 if (event.key === "1") {
90 createPlanet("beach");
91 } else if (event.key === "2") {
92 createPlanet("forest");
93 } else if (event.key === "3") {
94 createPlanet("snowForest");
95 }
96
97 if (event.key === " ") {
98 rotate = !rotate;
99 }
100});
101
102// button press
103let button = document.getElementById("button");
104if (button) {
105 console.log("Button found");
106 button.addEventListener("click", () => {
107 let randomPreset = presets[Math.floor(Math.random() * presets.length)];
108 createPlanet(randomPreset);
109 });
110}
111
112async function createPlanet(preset: string | undefined = undefined) {
113 if (!preset) {
114 preset = presets[Math.floor(Math.random() * presets.length)];
115 }
116
117 console.time("planet");
118 const planet = new Planet({
119 detail: 50,
120 ...planetPresets[preset],
121 });
122 let mesh = await planet.create();
123 scene.remove(planetMesh);
124 scene.add(mesh);
125 planetMesh = mesh;
126
127 // planetMesh.add(camera);
128 // planet.updatePosition(camera, new THREE.Vector3(0, 0, 1.1));
129
130 console.timeEnd("planet");
131}
132
133function updateSize() {
134 renderer.setSize(window.innerWidth, window.innerHeight);
135 renderer.setPixelRatio(window.devicePixelRatio);
136 camera.aspect = window.innerWidth / window.innerHeight;
137 camera.updateProjectionMatrix();
138}
139
140updateSize();
141window.addEventListener("resize", updateSize);