88 lines
3.0 KiB
TypeScript
88 lines
3.0 KiB
TypeScript
import * as THREE from "three";
|
|
import { classifyPovLevel } from "./viewerMath";
|
|
import type { PovLevel } from "./viewerTypes";
|
|
import type { UniverseLayer } from "./viewerUniverseLayer";
|
|
import type { GalaxyLayer } from "./viewerGalaxyLayer";
|
|
import type { SystemLayer } from "./viewerSystemLayer";
|
|
import type { LocalLayer } from "./viewerLocalLayer";
|
|
|
|
export interface RenderFrameParams {
|
|
clock: THREE.Clock;
|
|
renderer: THREE.WebGLRenderer;
|
|
universeLayer: UniverseLayer;
|
|
galaxyLayer: GalaxyLayer;
|
|
systemLayer: SystemLayer;
|
|
localLayer: LocalLayer;
|
|
getPovLevel: () => PovLevel;
|
|
updateCamera: (delta: number) => void;
|
|
updateAmbience: (delta: number) => void;
|
|
updatePlanetPresentation: () => void;
|
|
updateShipPresentation: () => void;
|
|
updateNetworkPanel: () => void;
|
|
applyZoomPresentation: () => void;
|
|
recordPerformanceStats: (frameMs: number) => void;
|
|
updatePerformancePanel: () => void;
|
|
}
|
|
|
|
export interface ResizeParams {
|
|
galaxyLayer: GalaxyLayer;
|
|
systemLayer: SystemLayer;
|
|
localLayer: LocalLayer;
|
|
width: number;
|
|
height: number;
|
|
}
|
|
|
|
export interface CameraStepParams {
|
|
currentDistance: number;
|
|
desiredDistance: number;
|
|
orbitPitch: number;
|
|
delta: number;
|
|
}
|
|
|
|
export function renderFrame(params: RenderFrameParams) {
|
|
const frameStartedAtMs = performance.now();
|
|
const delta = Math.min(params.clock.getDelta(), 0.033);
|
|
params.updateCamera(delta);
|
|
params.updateAmbience(delta);
|
|
params.updatePlanetPresentation();
|
|
params.updateShipPresentation();
|
|
params.updateNetworkPanel();
|
|
params.applyZoomPresentation();
|
|
|
|
const povLevel = params.getPovLevel();
|
|
const activeCamera = povLevel === "galaxy" ? params.galaxyLayer.camera : params.systemLayer.camera;
|
|
params.renderer.autoClear = false;
|
|
params.renderer.clear();
|
|
// Universe backdrop — always first, rendered with the active camera so it aligns with the foreground
|
|
params.universeLayer.render(params.renderer, activeCamera);
|
|
params.renderer.clearDepth();
|
|
if (povLevel === "galaxy") {
|
|
// Galaxy map on top of universe backdrop
|
|
params.galaxyLayer.render(params.renderer);
|
|
} else if (povLevel === "system") {
|
|
params.systemLayer.render(params.renderer);
|
|
} else {
|
|
// local: system as mid-ground backdrop, then local on top
|
|
params.systemLayer.render(params.renderer);
|
|
params.renderer.clearDepth();
|
|
params.localLayer.render(params.renderer);
|
|
}
|
|
|
|
params.recordPerformanceStats(performance.now() - frameStartedAtMs);
|
|
params.updatePerformancePanel();
|
|
}
|
|
|
|
export function resizeViewer(params: ResizeParams) {
|
|
const aspect = params.width / params.height;
|
|
params.galaxyLayer.onResize(aspect);
|
|
params.systemLayer.onResize(aspect);
|
|
params.localLayer.onResize(aspect);
|
|
}
|
|
|
|
export function stepCamera(params: CameraStepParams) {
|
|
const currentDistance = THREE.MathUtils.damp(params.currentDistance, params.desiredDistance, 7.5, params.delta);
|
|
const povLevel = classifyPovLevel(currentDistance);
|
|
const orbitPitch = THREE.MathUtils.clamp(params.orbitPitch, 0.18, 1.3);
|
|
return { currentDistance, povLevel, orbitPitch };
|
|
}
|