feat: 3 scene rendering setup
This commit is contained in:
@@ -1,19 +1,14 @@
|
||||
import * as THREE from "three";
|
||||
import { ACTIVE_SYSTEM_CAPTURE_RADIUS, ACTIVE_SYSTEM_DETAIL_SCALE, GALAXY_PARALLAX_FACTOR } from "./viewerConstants";
|
||||
import { KILOMETERS_PER_AU, computePlanetLocalPosition, currentWorldTimeSeconds, scaleGalaxyVector, scaleLocalVector, toThreeVector } from "./viewerMath";
|
||||
import { ACTIVE_SYSTEM_CAPTURE_RADIUS, ACTIVE_SYSTEM_DETAIL_SCALE } from "./viewerConstants";
|
||||
import { DISPLAY_UNITS_PER_KILOMETER, KILOMETERS_PER_AU, computePlanetLocalPosition, currentWorldTimeSeconds, scaleGalaxyVector, scaleLocalVector, toThreeVector } from "./viewerMath";
|
||||
import { resolveSelectableSystemId } from "./viewerSelection";
|
||||
import type {
|
||||
BubbleVisual,
|
||||
ClaimVisual,
|
||||
ConstructionSiteVisual,
|
||||
NodeVisual,
|
||||
PlanetVisual,
|
||||
Selectable,
|
||||
ShipVisual,
|
||||
SpatialNodeVisual,
|
||||
StructureVisual,
|
||||
WorldState,
|
||||
ZoomLevel,
|
||||
PovLevel,
|
||||
} from "./viewerTypes";
|
||||
|
||||
interface ResolveSelectionPositionParams {
|
||||
@@ -23,14 +18,13 @@ interface ResolveSelectionPositionParams {
|
||||
nodeVisuals: Map<string, NodeVisual>;
|
||||
planetVisuals: PlanetVisual[];
|
||||
computeNodeLocalPosition: (visual: NodeVisual, timeSeconds: number) => THREE.Vector3;
|
||||
resolveBubblePosition: (bubbleId: string) => THREE.Vector3 | undefined;
|
||||
resolvePointPosition: (systemId: string, nodeId?: string | null) => THREE.Vector3;
|
||||
resolvePointPosition: (systemId: string, celestialId?: string | null) => THREE.Vector3;
|
||||
}
|
||||
|
||||
interface FocusOnSelectionParams extends ResolveSelectionPositionParams {
|
||||
activeSystemId?: string;
|
||||
galaxyFocus: THREE.Vector3;
|
||||
systemFocusLocal: THREE.Vector3;
|
||||
galaxyAnchor: THREE.Vector3;
|
||||
systemAnchor: THREE.Vector3;
|
||||
}
|
||||
|
||||
interface DetermineActiveSystemParams {
|
||||
@@ -39,7 +33,7 @@ interface DetermineActiveSystemParams {
|
||||
cameraTargetShipId?: string;
|
||||
currentDistance: number;
|
||||
selectedItems: Selectable[];
|
||||
galaxyFocus: THREE.Vector3;
|
||||
galaxyAnchor: THREE.Vector3;
|
||||
}
|
||||
|
||||
interface SeedSystemFocusParams {
|
||||
@@ -48,38 +42,30 @@ interface SeedSystemFocusParams {
|
||||
cameraMode: "tactical" | "follow";
|
||||
cameraTargetShipId?: string;
|
||||
selectedItems: Selectable[];
|
||||
systemFocusLocal: THREE.Vector3;
|
||||
systemAnchor: THREE.Vector3;
|
||||
worldTimeSyncMs: number;
|
||||
nodeVisuals: Map<string, NodeVisual>;
|
||||
planetVisuals: PlanetVisual[];
|
||||
computeNodeLocalPosition: (visual: NodeVisual, timeSeconds: number) => THREE.Vector3;
|
||||
resolveBubblePosition: (bubbleId: string) => THREE.Vector3 | undefined;
|
||||
resolvePointPosition: (systemId: string, nodeId?: string | null) => THREE.Vector3;
|
||||
resolvePointPosition: (systemId: string, celestialId?: string | null) => THREE.Vector3;
|
||||
}
|
||||
|
||||
interface CameraFocusParams {
|
||||
world: WorldState | undefined;
|
||||
activeSystemId?: string;
|
||||
galaxyFocus: THREE.Vector3;
|
||||
systemFocusLocal: THREE.Vector3;
|
||||
galaxyAnchor: THREE.Vector3;
|
||||
}
|
||||
|
||||
interface DisplayLocalPositionParams {
|
||||
world: WorldState | undefined;
|
||||
systemId?: string;
|
||||
activeSystemId?: string;
|
||||
localPosition: THREE.Vector3;
|
||||
systemFocusLocal: THREE.Vector3;
|
||||
export function getSystemCameraFocus(systemAnchor: THREE.Vector3): THREE.Vector3 {
|
||||
return systemAnchor.clone().multiplyScalar(DISPLAY_UNITS_PER_KILOMETER * ACTIVE_SYSTEM_DETAIL_SCALE);
|
||||
}
|
||||
|
||||
export function updatePanFromKeyboard(
|
||||
keyState: Set<string>,
|
||||
orbitYaw: number,
|
||||
currentDistance: number,
|
||||
zoomLevel: ZoomLevel,
|
||||
povLevel: PovLevel,
|
||||
activeSystemId: string | undefined,
|
||||
systemFocusLocal: THREE.Vector3,
|
||||
galaxyFocus: THREE.Vector3,
|
||||
systemAnchor: THREE.Vector3,
|
||||
galaxyAnchor: THREE.Vector3,
|
||||
delta: number,
|
||||
minimumDistance: number,
|
||||
maximumDistance: number,
|
||||
@@ -106,15 +92,15 @@ export function updatePanFromKeyboard(
|
||||
const right = new THREE.Vector3(-forward.z, 0, forward.x);
|
||||
const pan = right.multiplyScalar(move.x).add(forward.multiplyScalar(move.z));
|
||||
if (activeSystemId) {
|
||||
const speedKilometers = zoomLevel === "system"
|
||||
const speedKilometers = povLevel === "system"
|
||||
? THREE.MathUtils.mapLinear(currentDistance, 80, 4000, KILOMETERS_PER_AU * 0.002, KILOMETERS_PER_AU * 0.35)
|
||||
: THREE.MathUtils.mapLinear(currentDistance, minimumDistance, 120, 40, 180000);
|
||||
systemFocusLocal.addScaledVector(pan, speedKilometers * delta);
|
||||
systemAnchor.addScaledVector(pan, speedKilometers * delta);
|
||||
return;
|
||||
}
|
||||
|
||||
const speed = THREE.MathUtils.mapLinear(currentDistance, minimumDistance, maximumDistance, 320, 6800);
|
||||
galaxyFocus.addScaledVector(pan, speed * delta);
|
||||
galaxyAnchor.addScaledVector(pan, speed * delta);
|
||||
}
|
||||
|
||||
export function determineActiveSystemId(params: DetermineActiveSystemParams): string | undefined {
|
||||
@@ -124,7 +110,7 @@ export function determineActiveSystemId(params: DetermineActiveSystemParams): st
|
||||
cameraTargetShipId,
|
||||
currentDistance,
|
||||
selectedItems,
|
||||
galaxyFocus,
|
||||
galaxyAnchor,
|
||||
} = params;
|
||||
|
||||
if (!world) {
|
||||
@@ -165,7 +151,7 @@ export function determineActiveSystemId(params: DetermineActiveSystemParams): st
|
||||
let nearestDistance = Number.POSITIVE_INFINITY;
|
||||
for (const system of world.systems.values()) {
|
||||
const center = scaleGalaxyVector(toThreeVector(system.galaxyPosition));
|
||||
const distance = center.distanceTo(galaxyFocus);
|
||||
const distance = center.distanceTo(galaxyAnchor);
|
||||
if (distance < nearestDistance) {
|
||||
nearestDistance = distance;
|
||||
nearestSystemId = system.id;
|
||||
@@ -185,7 +171,6 @@ export function resolveSelectionPosition(params: ResolveSelectionPositionParams)
|
||||
nodeVisuals,
|
||||
planetVisuals,
|
||||
computeNodeLocalPosition,
|
||||
resolveBubblePosition,
|
||||
resolvePointPosition,
|
||||
} = params;
|
||||
|
||||
@@ -208,20 +193,17 @@ export function resolveSelectionPosition(params: ResolveSelectionPositionParams)
|
||||
? computeNodeLocalPosition(visual, currentWorldTimeSeconds(world, worldTimeSyncMs))
|
||||
: (node ? toThreeVector(node.localPosition) : undefined);
|
||||
}
|
||||
if (selection.kind === "spatial-node") {
|
||||
const node = world.spatialNodes.get(selection.id);
|
||||
return node ? toThreeVector(node.localPosition) : undefined;
|
||||
}
|
||||
if (selection.kind === "bubble") {
|
||||
return resolveBubblePosition(selection.id);
|
||||
if (selection.kind === "celestial") {
|
||||
const celestial = world.celestials.get(selection.id);
|
||||
return celestial ? toThreeVector(celestial.orbitalAnchor) : undefined;
|
||||
}
|
||||
if (selection.kind === "claim") {
|
||||
const claim = world.claims.get(selection.id);
|
||||
return claim ? resolvePointPosition(claim.systemId, claim.nodeId) : undefined;
|
||||
return claim ? resolvePointPosition(claim.systemId, claim.celestialId) : undefined;
|
||||
}
|
||||
if (selection.kind === "construction-site") {
|
||||
const site = world.constructionSites.get(selection.id);
|
||||
return site ? resolvePointPosition(site.systemId, site.nodeId) : undefined;
|
||||
return site ? resolvePointPosition(site.systemId, site.celestialId) : undefined;
|
||||
}
|
||||
if (selection.kind === "planet") {
|
||||
const system = world.systems.get(selection.systemId);
|
||||
@@ -242,8 +224,8 @@ export function focusOnSelection(params: FocusOnSelectionParams) {
|
||||
world,
|
||||
selection,
|
||||
activeSystemId,
|
||||
galaxyFocus,
|
||||
systemFocusLocal,
|
||||
galaxyAnchor,
|
||||
systemAnchor,
|
||||
} = params;
|
||||
|
||||
const nextFocus = resolveSelectionPosition(params);
|
||||
@@ -252,8 +234,8 @@ export function focusOnSelection(params: FocusOnSelectionParams) {
|
||||
}
|
||||
|
||||
if (selection.kind === "system") {
|
||||
galaxyFocus.copy(nextFocus);
|
||||
systemFocusLocal.set(0, 0, 0);
|
||||
galaxyAnchor.copy(nextFocus);
|
||||
systemAnchor.set(0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -261,18 +243,18 @@ export function focusOnSelection(params: FocusOnSelectionParams) {
|
||||
if (selectionSystemId && world) {
|
||||
const system = world.systems.get(selectionSystemId);
|
||||
if (system) {
|
||||
galaxyFocus.copy(scaleGalaxyVector(toThreeVector(system.galaxyPosition)));
|
||||
systemFocusLocal.copy(nextFocus);
|
||||
galaxyAnchor.copy(scaleGalaxyVector(toThreeVector(system.galaxyPosition)));
|
||||
systemAnchor.copy(nextFocus);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeSystemId && resolveSelectableSystemId(world, selection) === activeSystemId) {
|
||||
systemFocusLocal.copy(nextFocus);
|
||||
systemAnchor.copy(nextFocus);
|
||||
return;
|
||||
}
|
||||
|
||||
galaxyFocus.copy(nextFocus);
|
||||
galaxyAnchor.copy(nextFocus);
|
||||
}
|
||||
|
||||
export function seedSystemFocusLocal(params: SeedSystemFocusParams) {
|
||||
@@ -282,7 +264,7 @@ export function seedSystemFocusLocal(params: SeedSystemFocusParams) {
|
||||
cameraMode,
|
||||
cameraTargetShipId,
|
||||
selectedItems,
|
||||
systemFocusLocal,
|
||||
systemAnchor,
|
||||
} = params;
|
||||
|
||||
if (!world) {
|
||||
@@ -292,7 +274,7 @@ export function seedSystemFocusLocal(params: SeedSystemFocusParams) {
|
||||
if (cameraMode === "follow" && cameraTargetShipId) {
|
||||
const followedShip = world.ships.get(cameraTargetShipId);
|
||||
if (followedShip?.systemId === systemId) {
|
||||
systemFocusLocal.copy(toThreeVector(followedShip.localPosition));
|
||||
systemAnchor.copy(toThreeVector(followedShip.localPosition));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -300,7 +282,7 @@ export function seedSystemFocusLocal(params: SeedSystemFocusParams) {
|
||||
const selected = selectedItems[0];
|
||||
if (selected && resolveSelectableSystemId(world, selected) === systemId) {
|
||||
if (selected.kind === "system") {
|
||||
systemFocusLocal.set(0, 0, 0);
|
||||
systemAnchor.set(0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,62 +293,26 @@ export function seedSystemFocusLocal(params: SeedSystemFocusParams) {
|
||||
nodeVisuals: params.nodeVisuals,
|
||||
planetVisuals: params.planetVisuals,
|
||||
computeNodeLocalPosition: params.computeNodeLocalPosition,
|
||||
resolveBubblePosition: params.resolveBubblePosition,
|
||||
resolvePointPosition: params.resolvePointPosition,
|
||||
});
|
||||
if (selectedPosition) {
|
||||
systemFocusLocal.copy(selectedPosition);
|
||||
systemAnchor.copy(selectedPosition);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
systemFocusLocal.set(0, 0, 0);
|
||||
systemAnchor.set(0, 0, 0);
|
||||
}
|
||||
|
||||
export function getCameraFocusWorldPosition(params: CameraFocusParams): THREE.Vector3 {
|
||||
const {
|
||||
world,
|
||||
activeSystemId,
|
||||
galaxyFocus,
|
||||
systemFocusLocal,
|
||||
} = params;
|
||||
|
||||
if (!activeSystemId || !world) {
|
||||
return galaxyFocus;
|
||||
}
|
||||
|
||||
const system = world.systems.get(activeSystemId);
|
||||
return system
|
||||
? scaleGalaxyVector(toThreeVector(system.galaxyPosition)).add(
|
||||
scaleLocalVector(systemFocusLocal).multiplyScalar(ACTIVE_SYSTEM_DETAIL_SCALE * GALAXY_PARALLAX_FACTOR),
|
||||
)
|
||||
: galaxyFocus;
|
||||
return params.galaxyAnchor;
|
||||
}
|
||||
|
||||
export function toDisplayLocalPosition(params: DisplayLocalPositionParams): THREE.Vector3 {
|
||||
const {
|
||||
world,
|
||||
systemId,
|
||||
activeSystemId,
|
||||
localPosition,
|
||||
systemFocusLocal,
|
||||
} = params;
|
||||
|
||||
if (!world || !systemId) {
|
||||
return scaleLocalVector(localPosition);
|
||||
}
|
||||
|
||||
const system = world.systems.get(systemId);
|
||||
if (!system) {
|
||||
return scaleLocalVector(localPosition);
|
||||
}
|
||||
|
||||
const center = scaleGalaxyVector(toThreeVector(system.galaxyPosition));
|
||||
const scaledLocalPosition = scaleLocalVector(localPosition);
|
||||
const scaledSystemFocus = scaleLocalVector(systemFocusLocal);
|
||||
if (systemId !== activeSystemId) {
|
||||
return center.clone().add(scaledLocalPosition);
|
||||
}
|
||||
|
||||
return center.clone().add(scaledLocalPosition.sub(scaledSystemFocus).multiplyScalar(ACTIVE_SYSTEM_DETAIL_SCALE));
|
||||
/**
|
||||
* Convert a local km position to system-scene display coordinates.
|
||||
* System scene coordinate system: star at origin, all positions scaled by
|
||||
* DISPLAY_UNITS_PER_KILOMETER * ACTIVE_SYSTEM_DETAIL_SCALE.
|
||||
*/
|
||||
export function toDisplayLocalPosition(localPosition: THREE.Vector3): THREE.Vector3 {
|
||||
return localPosition.clone().multiplyScalar(DISPLAY_UNITS_PER_KILOMETER * ACTIVE_SYSTEM_DETAIL_SCALE);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user