Optimize rendering performance and scene management in main.js. Updated WebGLRenderer settings for lower power consumption, adjusted pixel ratio, and improved shadow map handling. Enhanced animation frame control for smoother transitions and reduced unnecessary computations in static scene objects.
Browse files- frontend/main.js +35 -4
frontend/main.js
CHANGED
|
@@ -11,11 +11,19 @@ import { initUI } from "/static/ui.js";
|
|
| 11 |
// ---------------------------------------------------------------------------
|
| 12 |
|
| 13 |
const canvas = document.getElementById("scene");
|
| 14 |
-
const renderer = new THREE.WebGLRenderer({
|
| 15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
renderer.setSize(window.innerWidth, window.innerHeight);
|
| 17 |
renderer.shadowMap.enabled = true;
|
| 18 |
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
|
|
|
|
|
|
|
|
|
| 19 |
|
| 20 |
const scene = new THREE.Scene();
|
| 21 |
scene.fog = new THREE.Fog(0xbfe3ff, 90, 420);
|
|
@@ -106,6 +114,14 @@ scene.add(sun);
|
|
| 106 |
|
| 107 |
const world = buildWorld(scene);
|
| 108 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
// ---------------------------------------------------------------------------
|
| 110 |
// Vending machine interaction: hover outline + floating label, click hook
|
| 111 |
// ---------------------------------------------------------------------------
|
|
@@ -299,6 +315,9 @@ window.lofinityDebug = {
|
|
| 299 |
closeMachine() {
|
| 300 |
closeMachineView();
|
| 301 |
},
|
|
|
|
|
|
|
|
|
|
| 302 |
};
|
| 303 |
|
| 304 |
// ---------------------------------------------------------------------------
|
|
@@ -307,12 +326,24 @@ window.lofinityDebug = {
|
|
| 307 |
|
| 308 |
const clock = new THREE.Clock();
|
| 309 |
|
| 310 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 311 |
requestAnimationFrame(animate);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 312 |
const elapsed = clock.getElapsedTime();
|
| 313 |
|
| 314 |
for (const cloud of world.clouds) {
|
| 315 |
-
cloud.position.x += cloud.userData.speed *
|
| 316 |
if (cloud.position.x > 170) cloud.position.x = -170;
|
| 317 |
}
|
| 318 |
|
|
|
|
| 11 |
// ---------------------------------------------------------------------------
|
| 12 |
|
| 13 |
const canvas = document.getElementById("scene");
|
| 14 |
+
const renderer = new THREE.WebGLRenderer({
|
| 15 |
+
canvas,
|
| 16 |
+
antialias: true,
|
| 17 |
+
powerPreference: "low-power",
|
| 18 |
+
});
|
| 19 |
+
// 1.5x is visually identical to 2x at this flat-shaded art style, ~44% fewer pixels
|
| 20 |
+
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 1.5));
|
| 21 |
renderer.setSize(window.innerWidth, window.innerHeight);
|
| 22 |
renderer.shadowMap.enabled = true;
|
| 23 |
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
|
| 24 |
+
// nothing that casts shadows ever moves: bake the shadow map once
|
| 25 |
+
renderer.shadowMap.autoUpdate = false;
|
| 26 |
+
renderer.shadowMap.needsUpdate = true;
|
| 27 |
|
| 28 |
const scene = new THREE.Scene();
|
| 29 |
scene.fog = new THREE.Fog(0xbfe3ff, 90, 420);
|
|
|
|
| 114 |
|
| 115 |
const world = buildWorld(scene);
|
| 116 |
|
| 117 |
+
// Freeze transform recomputation for the (almost entirely) static scene;
|
| 118 |
+
// only the clouds and the camera move.
|
| 119 |
+
scene.traverse((obj) => {
|
| 120 |
+
obj.updateMatrix();
|
| 121 |
+
obj.matrixAutoUpdate = false;
|
| 122 |
+
});
|
| 123 |
+
for (const cloud of world.clouds) cloud.matrixAutoUpdate = true;
|
| 124 |
+
|
| 125 |
// ---------------------------------------------------------------------------
|
| 126 |
// Vending machine interaction: hover outline + floating label, click hook
|
| 127 |
// ---------------------------------------------------------------------------
|
|
|
|
| 315 |
closeMachine() {
|
| 316 |
closeMachineView();
|
| 317 |
},
|
| 318 |
+
stats() {
|
| 319 |
+
return { ...renderer.info.render, ...renderer.info.memory };
|
| 320 |
+
},
|
| 321 |
};
|
| 322 |
|
| 323 |
// ---------------------------------------------------------------------------
|
|
|
|
| 326 |
|
| 327 |
const clock = new THREE.Clock();
|
| 328 |
|
| 329 |
+
// Frame governor: a chill scene doesn't need 120fps. Idle runs at 30fps;
|
| 330 |
+
// camera transitions get 60 so they stay silky.
|
| 331 |
+
let lastRender = 0;
|
| 332 |
+
|
| 333 |
+
function animate(now = 0) {
|
| 334 |
requestAnimationFrame(animate);
|
| 335 |
+
const transitioning =
|
| 336 |
+
intro.phase === "descending" ||
|
| 337 |
+
view.mode === "zoom-in" ||
|
| 338 |
+
view.mode === "zoom-out";
|
| 339 |
+
const interval = transitioning ? 1000 / 60 : 1000 / 30;
|
| 340 |
+
if (now - lastRender < interval - 1) return;
|
| 341 |
+
const dt = Math.min((now - lastRender) / 1000, 0.1);
|
| 342 |
+
lastRender = now;
|
| 343 |
const elapsed = clock.getElapsedTime();
|
| 344 |
|
| 345 |
for (const cloud of world.clouds) {
|
| 346 |
+
cloud.position.x += cloud.userData.speed * dt;
|
| 347 |
if (cloud.position.x > 170) cloud.position.x = -170;
|
| 348 |
}
|
| 349 |
|