perf(nexus): implement performance tier optimization for low-end devices

This commit is contained in:
Allegro (Burn Mode)
2026-04-05 11:36:40 +00:00
parent 9a22d26b9c
commit ae9b51c3f1

65
app.js
View File

@@ -644,19 +644,31 @@ async function init() {
playerPos = new THREE.Vector3(0, 2, 12); playerPos = new THREE.Vector3(0, 2, 12);
playerRot = new THREE.Euler(0, 0, 0, 'YXZ'); playerRot = new THREE.Euler(0, 0, 0, 'YXZ');
// Detect performance tier BEFORE creating renderer (antialias cannot be changed after)
performanceTier = detectPerformanceTier();
const canvas = document.getElementById('nexus-canvas'); const canvas = document.getElementById('nexus-canvas');
renderer = new THREE.WebGLRenderer({ canvas, antialias: true }); const antialias = performanceTier !== 'low';
renderer = new THREE.WebGLRenderer({ canvas, antialias });
renderer.setSize(window.innerWidth, window.innerHeight); renderer.setSize(window.innerWidth, window.innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.toneMappingExposure = 1.2; renderer.toneMappingExposure = 1.2;
renderer.shadowMap.enabled = true; renderer.shadowMap.enabled = performanceTier !== 'low';
renderer.shadowMap.type = THREE.PCFSoftShadowMap; renderer.shadowMap.type = performanceTier === 'high' ? THREE.PCFSoftShadowMap : THREE.BasicShadowMap;
performanceTier = detectPerformanceTier();
updateLoad(10); updateLoad(10);
scene = new THREE.Scene(); scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x050510, 0.012);
// Fog density based on performance tier
if (performanceTier === 'low') {
// No fog for low tier
scene.fog = null;
} else if (performanceTier === 'medium') {
scene.fog = new THREE.FogExp2(0x050510, 0.008);
} else {
scene.fog = new THREE.FogExp2(0x050510, 0.012);
}
setupGOFAI(); setupGOFAI();
camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 1000); camera = new THREE.PerspectiveCamera(65, window.innerWidth / window.innerHeight, 0.1, 1000);
@@ -710,14 +722,29 @@ async function init() {
fetchGiteaData(); fetchGiteaData();
setInterval(fetchGiteaData, 30000); // Refresh every 30s setInterval(fetchGiteaData, 30000); // Refresh every 30s
composer = new EffectComposer(renderer); // Initialize post-processing based on performance tier
composer.addPass(new RenderPass(scene, camera)); // Low tier: No post-processing (avoids GPU stalls from readPixels)
const bloom = new UnrealBloomPass( // Medium tier: RenderPass + SMAA only (no bloom)
new THREE.Vector2(window.innerWidth, window.innerHeight), // High tier: Full post-processing with bloom
0.6, 0.4, 0.85 if (performanceTier === 'low') {
); // No composer for low tier - use direct renderer.render()
composer.addPass(bloom); composer = null;
composer.addPass(new SMAAPass(window.innerWidth, window.innerHeight)); } else if (performanceTier === 'medium') {
composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
// Skip UnrealBloomPass to avoid GPU stalls from readPixels
composer.addPass(new SMAAPass(window.innerWidth, window.innerHeight));
} else {
// High tier: Full post-processing with bloom
composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));
const bloom = new UnrealBloomPass(
new THREE.Vector2(window.innerWidth, window.innerHeight),
0.6, 0.4, 0.85
);
composer.addPass(bloom);
composer.addPass(new SMAAPass(window.innerWidth, window.innerHeight));
}
updateLoad(95); updateLoad(95);
@@ -2495,7 +2522,12 @@ function gameLoop() {
core.material.emissiveIntensity = 1.5 + Math.sin(elapsed * 2) * 0.5; core.material.emissiveIntensity = 1.5 + Math.sin(elapsed * 2) * 0.5;
} }
composer.render(); // Render based on performance tier (low tier bypasses composer to avoid GPU stalls)
if (composer) {
composer.render();
} else {
renderer.render(scene, camera);
}
updateAshStorm(delta, elapsed); updateAshStorm(delta, elapsed);
updatePortalTunnel(delta, elapsed); updatePortalTunnel(delta, elapsed);
@@ -2528,7 +2560,10 @@ function onResize() {
camera.aspect = w / h; camera.aspect = w / h;
camera.updateProjectionMatrix(); camera.updateProjectionMatrix();
renderer.setSize(w, h); renderer.setSize(w, h);
composer.setSize(w, h); // Only resize composer if it exists (low tier has no composer)
if (composer) {
composer.setSize(w, h);
}
} }
// ═══ AGENT SIMULATION ═══ // ═══ AGENT SIMULATION ═══