feat: 3 scene rendering setup

This commit is contained in:
2026-03-18 08:49:51 -04:00
parent 933c6afd08
commit 358122a74a
33 changed files with 1094 additions and 1132 deletions

View File

@@ -1,12 +1,18 @@
import * as THREE from "three";
import { classifyZoomLevel } from "./viewerMath";
import type { PerformanceStats } from "./viewerTypes";
import { classifyPovLevel } from "./viewerMath";
import type { PovLevel, PerformanceStats } from "./viewerTypes";
export interface RenderFrameParams {
clock: THREE.Clock;
renderer: THREE.WebGLRenderer;
scene: THREE.Scene;
camera: THREE.PerspectiveCamera;
universeScene: THREE.Scene;
galaxyScene: THREE.Scene;
galaxyCamera: THREE.PerspectiveCamera;
systemScene: THREE.Scene;
systemCamera: THREE.PerspectiveCamera;
localScene: THREE.Scene;
localCamera: THREE.PerspectiveCamera;
getPovLevel: () => PovLevel;
updateCamera: (delta: number) => void;
updateAmbience: (delta: number) => void;
updatePlanetPresentation: () => void;
@@ -19,7 +25,9 @@ export interface RenderFrameParams {
export interface ResizeParams {
renderer: THREE.WebGLRenderer;
camera: THREE.PerspectiveCamera;
galaxyCamera: THREE.PerspectiveCamera;
systemCamera: THREE.PerspectiveCamera;
localCamera: THREE.PerspectiveCamera;
}
export interface CameraStepParams {
@@ -38,7 +46,26 @@ export function renderFrame(params: RenderFrameParams) {
params.updateShipPresentation();
params.updateNetworkPanel();
params.applyZoomPresentation();
params.renderer.render(params.scene, params.camera);
const povLevel = params.getPovLevel();
const activeCamera = povLevel === "galaxy" ? params.galaxyCamera : params.systemCamera;
params.renderer.autoClear = false;
params.renderer.clear();
// Universe backdrop — always first, rendered with the active camera so it aligns with the foreground
params.renderer.render(params.universeScene, activeCamera);
params.renderer.clearDepth();
if (povLevel === "galaxy") {
// Galaxy map on top of universe backdrop
params.renderer.render(params.galaxyScene, params.galaxyCamera);
} else if (povLevel === "system") {
params.renderer.render(params.systemScene, params.systemCamera);
} else {
// local: system as mid-ground backdrop, then local on top
params.renderer.render(params.systemScene, params.systemCamera);
params.renderer.clearDepth();
params.renderer.render(params.localScene, params.localCamera);
}
params.recordPerformanceStats(performance.now() - frameStartedAtMs);
params.updatePerformancePanel();
}
@@ -46,14 +73,16 @@ export function renderFrame(params: RenderFrameParams) {
export function resizeViewer(params: ResizeParams) {
const width = window.innerWidth;
const height = window.innerHeight;
params.camera.aspect = width / height;
params.camera.updateProjectionMatrix();
for (const camera of [params.galaxyCamera, params.systemCamera, params.localCamera]) {
camera.aspect = width / height;
camera.updateProjectionMatrix();
}
params.renderer.setSize(width, height);
}
export function stepCamera(params: CameraStepParams) {
const currentDistance = THREE.MathUtils.damp(params.currentDistance, params.desiredDistance, 7.5, params.delta);
const zoomLevel = classifyZoomLevel(currentDistance);
const povLevel = classifyPovLevel(currentDistance);
const orbitPitch = THREE.MathUtils.clamp(params.orbitPitch, 0.18, 1.3);
return { currentDistance, zoomLevel, orbitPitch };
return { currentDistance, povLevel, orbitPitch };
}