1
0
Files
vrm/src/worldState.js
2026-03-07 23:16:35 +09:00

77 lines
2.4 KiB
JavaScript

import { Vector3, Quaternion } from 'three';
import { Geodetic, PointOfView, radians } from '@takram/three-geospatial';
const EARTH_RADIUS = 6378137;
export const worldState = {
position: new Vector3(0, EARTH_RADIUS + 100000, 0),
quaternion: new Quaternion(),
speed: 1000.0,
stageRotationY: 0,
currentHour: 12,
currentLocation: 'Tokyo',
};
// Pre-allocated temp objects (avoid GC in useFrame)
const _up = new Vector3();
const _quat = new Quaternion();
const _unitY = new Vector3(0, 1, 0);
export function getSurfaceBasis(position) {
if (!position) return _quat.identity();
_up.copy(position).normalize();
if (_up.lengthSq() < 0.1) return _quat.identity();
return _quat.setFromUnitVectors(_unitY, _up);
}
// Non-mutating version for cases that need a copy
const _basisOut = new Quaternion();
export function getSurfaceBasisCopy(position) {
getSurfaceBasis(position);
return _basisOut.copy(_quat);
}
export function getEllipsoidRadius(position) {
const a = 6378137.0;
const b = 6356752.314245;
const r = position.length();
if (r < 100) return a;
const sinPhi = position.z / r;
const cosPhi = Math.sqrt(1 - sinPhi * sinPhi);
const aCos = a * cosPhi;
const bSin = b * sinPhi;
return Math.sqrt(
((a * aCos) ** 2 + (b * bSin) ** 2) / (aCos ** 2 + bSin ** 2)
);
}
export const LOCATIONS = [
{ name: 'Tokyo', longitude: 139.7671, latitude: 35.6812, heading: 180, pitch: -5, distance: 1100 },
{ name: 'Fuji', longitude: 138.7278, latitude: 35.3206, heading: 0, pitch: -10, distance: 4000 },
{ name: 'Space', longitude: 139.7671, latitude: 35.6812, heading: 0, pitch: -90, distance: 100000 },
];
const LOCATION_MULT = { Tokyo: 1, Fuji: 2, Space: 3 };
export function teleportTo(location) {
worldState.currentLocation = location.name;
const { longitude, latitude, heading, pitch, distance } = location;
const position = new Vector3();
const globalQuaternion = new Quaternion();
const up = new Vector3(0, 1, 0);
const truePosition = new Geodetic(radians(longitude), radians(latitude), distance).toECEF();
new PointOfView(distance, radians(heading), radians(pitch)).decompose(
new Geodetic(radians(longitude), radians(latitude)).toECEF(),
position,
globalQuaternion,
up
);
worldState.position.copy(truePosition);
const basis = getSurfaceBasisCopy(truePosition);
worldState.quaternion.copy(basis.invert().multiply(globalQuaternion));
}