77 lines
2.4 KiB
JavaScript
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));
|
|
}
|