@babylonjs/lite 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/index.js +326 -326
  3. package/dist/index.js.map +1 -1
  4. package/index.d.ts +72 -6
  5. package/lib/camera/arc-rotate.js +2 -20
  6. package/lib/camera/arc-rotate.js.map +1 -1
  7. package/lib/camera/camera.js +21 -4
  8. package/lib/camera/camera.js.map +1 -1
  9. package/lib/camera/free-camera.js +2 -19
  10. package/lib/camera/free-camera.js.map +1 -1
  11. package/lib/camera/geospatial-camera.js +2 -19
  12. package/lib/camera/geospatial-camera.js.map +1 -1
  13. package/lib/camera/orthographic.js +70 -0
  14. package/lib/camera/orthographic.js.map +1 -0
  15. package/lib/engine/engine.js +1 -1
  16. package/lib/frame-graph/render-task.js +2 -2
  17. package/lib/frame-graph/render-task.js.map +1 -1
  18. package/lib/index.js +4 -1
  19. package/lib/index.js.map +1 -1
  20. package/lib/light/clustered.js +19 -6
  21. package/lib/light/clustered.js.map +1 -1
  22. package/lib/material/shader/shader-renderable.js +2 -2
  23. package/lib/material/shader/shader-renderable.js.map +1 -1
  24. package/lib/material/standard/enable-standard-mesh-features.js.map +1 -1
  25. package/lib/math/index.js +1 -0
  26. package/lib/math/index.js.map +1 -1
  27. package/lib/math/mat4-look-at-world-lh.js +55 -0
  28. package/lib/math/mat4-look-at-world-lh.js.map +1 -0
  29. package/lib/math/mat4-ortho-lh-to-ref.js +22 -0
  30. package/lib/math/mat4-ortho-lh-to-ref.js.map +1 -0
  31. package/lib/math/mat4.js +1 -0
  32. package/lib/math/mat4.js.map +1 -1
  33. package/lib/navigation/index.js +1 -1
  34. package/lib/navigation/navigation.js +12 -1
  35. package/lib/navigation/navigation.js.map +1 -1
  36. package/lib/post-process/taa.js +2 -1
  37. package/lib/post-process/taa.js.map +1 -1
  38. package/lib/shadow/csm-shadow-task-hooks.js +13 -6
  39. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  40. package/lib/shadow/shadow-base.js +3 -2
  41. package/lib/shadow/shadow-base.js.map +1 -1
  42. package/lib/text/text-renderable.js +2 -2
  43. package/lib/text/text-renderable.js.map +1 -1
  44. package/package.json +3 -11
  45. package/material/standard/enable-standard-mesh-features.d.ts +0 -4
  46. package/material/standard/enable-standard-vertex-colors.d.ts +0 -2
package/index.d.ts CHANGED
@@ -1267,6 +1267,9 @@ export declare interface BoxData {
1267
1267
  indexCount: number;
1268
1268
  }
1269
1269
 
1270
+ /** Build a DDS cube skybox as a complete Renderable (order 0). */
1271
+ export declare function buildDdsSkyboxRenderable(scene: SceneContext, skyHalfSize: number, rootPosition: [number, number, number], primaryColor: [number, number, number], skyboxTextureUrl?: string, enableNoise?: boolean): Promise<Renderable>;
1272
+
1270
1273
  /** Record and initialize one task already present in a live graph without rebuilding existing tasks. */
1271
1274
  export declare function buildFrameGraphTask(fg: FrameGraph, task: Task): void;
1272
1275
 
@@ -1286,7 +1289,11 @@ export declare interface Camera {
1286
1289
  viewport?: NormalizedViewport;
1287
1290
  children: SceneNode[];
1288
1291
  readonly worldMatrix: Mat4;
1289
- readonly worldMatrixVersion: number;
1292
+ readonly worldMatrixVersion: number;
1290
1293
  /** Live orthographic view-volume extents, installed by `enableOrthographicCamera`
1294
+ * and mutable/animatable thereafter. Null or undefined means the camera projects
1295
+ * perspectively through `fov`. */
1296
+ ortho?: OrthographicBounds | null;
1297
+ }
1291
1298
 
1292
1299
  /** Display-only gizmo that visualizes an attached camera body and optional frustum. */
1293
1300
  export declare interface CameraGizmo {
@@ -3312,6 +3319,9 @@ export declare interface DirectionalLight extends LightBase {
3312
3319
  intensity: number;
3313
3320
  }
3314
3321
 
3322
+ /** Switch a camera back to its perspective projection (driven by `camera.fov`). */
3323
+ export declare function disableOrthographicCamera(camera: Camera): void;
3324
+
3315
3325
  /** Options for `createDiscData`. Subset of Babylon's CreateDisc. */
3316
3326
  export declare interface DiscOptions {
3317
3327
  radius?: number;
@@ -3816,6 +3826,16 @@ export declare function enableMaterialTracking(material: Material & {
3816
3826
  /** Enable live morph-target bounds for one shadow generator. */
3817
3827
  export declare function enableMorphTargetShadows(generator: ShadowGenerator): void;
3818
3828
 
3829
+ /** Switch a camera to an orthographic projection, and return its live `ortho` bounds.
3830
+ *
3831
+ * Depth still comes from `camera.nearPlane` / `camera.farPlane`; `camera.fov` has no
3832
+ * effect in this mode — an orthographic camera zooms by changing `halfHeight`.
3833
+ *
3834
+ * The returned object is also reachable as `camera.ortho`, and stays mutable (see
3835
+ * `OrthographicBounds`), so this only needs to be called once per camera. Calling it
3836
+ * again replaces the bounds with a fresh object. */
3837
+ export declare function enableOrthographicCamera(camera: Camera, bounds?: OrthographicBoundsOptions): OrthographicBounds;
3838
+
3819
3839
  /** Enables weighted property-animation blending on `manager` by registering its category handler. */
3820
3840
  export declare function enablePropertyAnimationBlending(manager: AnimationManager): void;
3821
3841
 
@@ -3841,11 +3861,11 @@ export declare function enableSpatial(host: AudioGraphHost, options?: SpatialSou
3841
3861
 
3842
3862
  /**
3843
3863
  * Published opt-ins for Standard skeletal skinning and UV translation. Import
3844
- * from `@babylonjs/lite/material/standard/enable-standard-mesh-features`.
3864
+ * from the `@babylonjs/lite` root entry.
3845
3865
  *
3846
3866
  * RGBA vertex colours are enabled separately through the canonical
3847
3867
  * `enableStandardVertexColors()` from
3848
- * `@babylonjs/lite/material/standard/enable-standard-vertex-colors`.
3868
+ * the `@babylonjs/lite` root entry.
3849
3869
  */
3850
3870
  /** Enable four/eight-influence skeletal skinning for Standard meshes. */
3851
3871
  export declare function enableStandardSkeleton(): void;
@@ -4109,6 +4129,8 @@ export declare interface Font {
4109
4129
 
4110
4130
  declare const fontBrand: unique symbol;
4111
4131
 
4132
+ export declare function forceWebGpuDeviceLossForTesting(engine: EngineContext): void;
4133
+
4112
4134
  /** The frame graph — an ordered list of tasks. */
4113
4135
  export declare interface FrameGraph {
4114
4136
  /** Build (or rebuild) every task in execute order. */
4115
4137
  build(): void;
@@ -4657,7 +4679,7 @@ export declare function getPickedNormal(info: PickingInfo, useWorldCoordinates?:
4657
4679
  */
4658
4680
  export declare function getPickedUV(info: PickingInfo): [number, number] | null;
4659
4681
 
4660
- /** Compute the projection matrix for a camera. Cached per worldMatrixVersion + aspect. */
4682
+ /** Compute the projection matrix for a camera. Cached per `_cameraChangeKey` + aspect. */
4661
4683
  export declare function getProjectionMatrix(camera: Camera, aspectRatio: number): Mat4;
4662
4684
 
4663
4685
  /** Return the latest task GPU timing snapshot without stalling the GPU or CPU. */
@@ -4692,7 +4714,7 @@ export declare function getVariantNames(container: AssetContainer): readonly str
4692
4714
  * bit-identical to a normal `R_inv * -cameraPos` view matrix. */
4693
4715
  export declare function getViewMatrix(camera: Camera): Mat4;
4694
4716
 
4695
- /** Compute the view-projection matrix for a camera. Cached per worldMatrixVersion + aspect. */
4717
+ /** Compute the view-projection matrix for a camera. Cached per `_cameraChangeKey` + aspect. */
4696
4718
  export declare function getViewProjectionMatrix(camera: Camera, aspectRatio: number): Mat4;
4697
4719
 
4698
4720
  declare interface GizmoMaterialSet {
@@ -5133,7 +5155,9 @@ export declare interface IWorldMatrixProvider {
5133
5155
  /** World-space 4×4 column-major matrix. May trigger lazy recomputation. */
5134
5156
  readonly worldMatrix: Mat4;
5135
5157
  /** Monotonically increasing counter — bumped each time worldMatrix recomputes.
5136
- * Children snapshot this value to detect when their parent has changed. */
5158
+ * Children snapshot this value to detect when their parent has changed.
5159
+ * Must never decrease: `_cameraChangeKey` sums it with the projection revision
5160
+ * and relies on that to detect every change without aliasing. */
5137
5161
  readonly worldMatrixVersion: number;
5138
5162
  }
5139
5163
 
@@ -5710,6 +5734,15 @@ export declare interface NavMeshSource {
5710
5734
  indices: ArrayLike<number>;
5711
5735
  }
5712
5736
 
5737
+ /**
5738
+ * Strict walkability ray: `true` when the straight segment from `start` to `end` is NOT provably
5739
+ * clear on the navmesh. Unlike {@link raycast} (BJS Addons parity: `hit` only for `0 < t < 1`),
5740
+ * an unresolvable start polygon and a wall at the very origin (Detour reports `t = 0`, which
5741
+ * happens whenever the probe origin lies on a boundary edge - e.g. a funnel corner) are BLOCKED:
5742
+ * "cannot prove clear" is blocked. Recast's raycast ignores the y component (2D check).
5743
+ */
5744
+ export declare function navRayBlocked(plugin: NavigationPlugin, start: Vec3, end: Vec3): boolean;
5745
+
5713
5746
  /** Negate every vector component. */
5714
5747
  export declare function negateVec3(v: Vec3): Vec3;
5715
5748
 
@@ -6099,6 +6132,39 @@ export declare function onPhysicsTrigger(world: PhysicsWorld, cb: (info: Physics
6099
6132
  * user-owned GPU resources (e.g. a `SpriteRenderer`) to the scene's lifetime. */
6100
6133
  export declare function onSceneDispose(scene: SceneContext, cb: () => void): void;
6101
6134
 
6135
+ /** Live orthographic view-volume extents, in world units. Mutable and animatable:
6136
+ * every setter invalidates the camera's projection cache, so assigning a field —
6137
+ * by hand, from a render loop, or through a property animation targeting
6138
+ * `"ortho.halfHeight"` — takes effect on the next frame.
6139
+ *
6140
+ * A plane left `null` is derived from `halfHeight`: vertically as `±halfHeight`,
6141
+ * horizontally as `±halfHeight * aspectRatio`, so the volume tracks the render
6142
+ * target's aspect ratio and never squashes the image. Set a plane to a number for
6143
+ * an off-center volume (Babylon's `orthoLeft` / `orthoRight` / `orthoBottom` /
6144
+ * `orthoTop`); set it back to `null` to return to the derived extent. */
6145
+ export declare interface OrthographicBounds {
6146
+ /** Vertical half-extent of the view volume. Halving it doubles the zoom. */
6147
+ halfHeight: number;
6148
+ /** Left clip plane, or null to derive `-halfHeight * aspectRatio`. */
6149
+ left: number | null;
6150
+ /** Right clip plane, or null to derive `halfHeight * aspectRatio`. */
6151
+ right: number | null;
6152
+ /** Bottom clip plane, or null to derive `-halfHeight`. */
6153
+ bottom: number | null;
6154
+ /** Top clip plane, or null to derive `halfHeight`. */
6155
+ top: number | null;
6156
+ }
6157
+
6158
+ /** Initial extents accepted by `enableOrthographicCamera`. Every field is optional;
6159
+ * omitted planes are derived from `halfHeight` (default 1). */
6160
+ export declare interface OrthographicBoundsOptions {
6161
+ halfHeight?: number;
6162
+ left?: number | null;
6163
+ right?: number | null;
6164
+ bottom?: number | null;
6165
+ top?: number | null;
6166
+ }
6167
+
6102
6168
  /** Convert a packed 0xRRGGBB sRGB color to a linear-RGBA tuple suitable for
6103
6169
  * text-renderer `defaultColor` / `PlacedGlyph.color`. */
6104
6170
  export declare function packedSrgbToLinearRgba(packed: number, alpha?: number): readonly [number, number, number, number];
@@ -1,4 +1,4 @@
1
- import { mat4LookAtLH } from '../math/mat4-look-at-lh.js';
1
+ import { mat4LookAtWorldLHToRef } from '../math/mat4-look-at-world-lh.js';
2
2
  import { Vec3Up } from '../math/vec3-up.js';
3
3
  import { attachWorldMatrixState, createWorldMatrixState } from '../scene/world-matrix-state.js';
4
4
  import { ObservableVec3 } from '../math/observable-vec3.js';
@@ -20,25 +20,7 @@ function createArcRotateCamera(alpha, beta, radius, target) {
20
20
  }
21
21
  const _localMat = allocateMat4();
22
22
  function cameraLocalWorldMatrix() {
23
- const eye = localEyePosition();
24
- const v = mat4LookAtLH(eye, cam.target, Vec3Up);
25
- const m = _localMat;
26
- m[0] = v[0];
27
- m[1] = v[4];
28
- m[2] = v[8];
29
- m[3] = 0;
30
- m[4] = v[1];
31
- m[5] = v[5];
32
- m[6] = v[9];
33
- m[7] = 0;
34
- m[8] = v[2];
35
- m[9] = v[6];
36
- m[10] = v[10];
37
- m[11] = 0;
38
- m[12] = eye.x;
39
- m[13] = eye.y;
40
- m[14] = eye.z;
41
- m[15] = 1;
23
+ mat4LookAtWorldLHToRef(_localMat, localEyePosition(), cam.target, Vec3Up);
42
24
  return _localMat;
43
25
  }
44
26
  const wm = createWorldMatrixState(cameraLocalWorldMatrix);
@@ -1 +1 @@
1
- {"version":3,"file":"arc-rotate.js","sources":["../../../src/camera/arc-rotate.ts"],"sourcesContent":["import type { Camera, NormalizedViewport } from \"./camera.js\";\nimport type { Vec3, Mat4 } from \"../math/types.js\";\nimport { mat4LookAtLH } from \"../math/mat4-look-at-lh.js\";\nimport { Vec3Up } from \"../math/vec3-up.js\";\nimport type { IWorldMatrixProvider, IParentable } from \"../scene/parentable.js\";\nimport { createWorldMatrixState, attachWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport { ObservableVec3 } from \"../math/observable-vec3.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport { allocateMat4 } from \"../math/_matrix-allocator.js\";\n\n/** ArcRotateCamera — orbits around a target point.\n * Uses Babylon.js convention: left-handed, alpha=rotation around Y, beta=elevation.\n * Plain data + methods. Does NOT know about the scene.\n *\n * Push-based dirty tracking: alpha/beta/radius use Object.defineProperty,\n * target uses ObservableVec3. Changes call wm.markLocalDirty() immediately.\n *\n * Inertia follows the Babylon.js model: input handlers accumulate per-frame\n * offsets (inertialAlphaOffset, etc.) which are applied and exponentially\n * decayed each frame by the controls module. */\nexport interface ArcRotateCamera extends Camera, IWorldMatrixProvider, IParentable {\n alpha: number;\n beta: number;\n radius: number;\n target: Vec3;\n fov: number;\n nearPlane: number;\n farPlane: number;\n viewport?: NormalizedViewport;\n children: SceneNode[];\n\n /** Inertia coefficient for rotation and zoom (0 = instant stop, 0.9 = default, 1 = no decay). */\n inertia: number;\n /** Inertia coefficient for panning (0 = instant stop, 0.9 = default). */\n panningInertia: number;\n\n /** Mouse-drag orbit sensitivity (HIGHER = slower rotation). Babylon default 1000. */\n angularSensibility: number;\n /** Right-drag panning sensitivity in pixels-per-unit (LOWER = faster pan). Babylon default 50. */\n panningSensibility: number;\n /** Wheel-zoom sensitivity (HIGHER = slower zoom). Babylon default 3. */\n wheelPrecision: number;\n\n /** Per-frame inertial offsets — accumulated by input, applied & decayed each frame. */\n inertialAlphaOffset: number;\n inertialBetaOffset: number;\n inertialRadiusOffset: number;\n inertialPanningX: number;\n inertialPanningY: number;\n\n /**\n * Optional orbit limits enforced by {@link attachControl}'s per-frame loop.\n * `undefined` means unbounded on that side. Set these via {@link setCameraLimits}\n * so the current pose is clamped immediately (and inertia zeroed at the wall),\n * avoiding any overshoot-then-snap jiggle. Angles are in radians.\n */\n lowerAlphaLimit?: number;\n upperAlphaLimit?: number;\n lowerBetaLimit?: number;\n upperBetaLimit?: number;\n lowerRadiusLimit?: number;\n upperRadiusLimit?: number;\n\n /** @internal Self-clamp hook installed by {@link setCameraLimits}. The\n * alpha/beta/radius setters invoke it immediately after every mutation, so\n * the camera is never observably out of its orbit limits — at any point a\n * per-frame callback (e.g. a camera-pinned skybox) reads it. This is what\n * makes a direct pinch write or inertial overshoot snap to the wall in the\n * same statement that caused it, with no one-frame \"blink\". Undefined until\n * limits are set, so cameras that never call setCameraLimits carry none of\n * the clamp code and the setters' `?.()` call is a single dead check. */\n _clampToLimits?: () => void;\n\n parent: IWorldMatrixProvider | null;\n readonly worldMatrix: Mat4;\n readonly worldMatrixVersion: number;\n}\n\n/** Create a bare ArcRotateCamera with given params. Pure data, no scene knowledge. */\nexport function createArcRotateCamera(alpha: number, beta: number, radius: number, target: Vec3): ArcRotateCamera {\n function localEyePosition(): Vec3 {\n const cosA = Math.cos(cam.alpha),\n sinA = Math.sin(cam.alpha);\n const cosB = Math.cos(cam.beta);\n let sinB = Math.sin(cam.beta);\n if (sinB === 0) {\n sinB = 0.0001;\n }\n return {\n x: cam.target.x + cam.radius * cosA * sinB,\n y: cam.target.y + cam.radius * cosB,\n z: cam.target.z + cam.radius * sinA * sinB,\n };\n }\n\n // Reusable local-world matrix.\n const _localMat: Mat4 = allocateMat4();\n\n function cameraLocalWorldMatrix(): Mat4 {\n const eye = localEyePosition();\n const v = mat4LookAtLH(eye, cam.target, Vec3Up);\n const m = _localMat as unknown as Mat4Storage;\n // Transpose upper 3×3 of view = camera-to-world rotation; translation = eye.\n m[0] = v[0]!;\n m[1] = v[4]!;\n m[2] = v[8]!;\n m[3] = 0;\n m[4] = v[1]!;\n m[5] = v[5]!;\n m[6] = v[9]!;\n m[7] = 0;\n m[8] = v[2]!;\n m[9] = v[6]!;\n m[10] = v[10]!;\n m[11] = 0;\n m[12] = eye.x;\n m[13] = eye.y;\n m[14] = eye.z;\n m[15] = 1;\n return _localMat;\n }\n\n const wm = createWorldMatrixState(cameraLocalWorldMatrix);\n const onDirty = (): void => wm.markLocalDirty();\n\n const scalars = { alpha, beta, radius };\n\n const cam: ArcRotateCamera = {\n alpha: 0 as number, // placeholder — overridden by defineProperty below\n beta: 0 as number,\n radius: 0 as number,\n target: new ObservableVec3(target.x, target.y, target.z, onDirty) as unknown as Vec3,\n fov: 0.8,\n nearPlane: 0.1,\n farPlane: 1000,\n children: [] as SceneNode[],\n\n inertia: 0.9,\n panningInertia: 0.9,\n angularSensibility: 1000,\n panningSensibility: 50,\n wheelPrecision: 3,\n inertialAlphaOffset: 0,\n inertialBetaOffset: 0,\n inertialRadiusOffset: 0,\n inertialPanningX: 0,\n inertialPanningY: 0,\n\n // Matrix caches use the process-global allocator — F32 by default,\n // F64 after an HPM engine is created. Same backing as the camera world\n // matrix above, so the camera's storage precision is uniform.\n _viewCache: allocateMat4() as unknown as Mat4Storage,\n _projCache: allocateMat4() as unknown as Mat4Storage,\n _vpCache: allocateMat4() as unknown as Mat4Storage,\n\n get parent() {\n return wm.parent;\n },\n set parent(v) {\n wm.parent = v;\n },\n get worldMatrix() {\n return wm.getWorldMatrix();\n },\n get worldMatrixVersion() {\n return wm.getWorldMatrixVersion();\n },\n };\n\n // Push-based dirty tracking for scalar camera params that affect worldMatrix.\n for (const key of [\"alpha\", \"beta\", \"radius\"] as const) {\n Object.defineProperty(cam, key, {\n get: () => scalars[key],\n set: (v: number) => {\n if (scalars[key] !== v) {\n scalars[key] = v;\n onDirty();\n // Self-clamp into orbit limits the instant a value changes, so\n // no caller (pinch direct-write, inertia, auto-rotate) can leave\n // the camera transiently out of bounds for any per-frame reader.\n // No-op (and no clamp code bundled) until setCameraLimits runs.\n cam._clampToLimits?.();\n }\n },\n configurable: true,\n enumerable: true,\n });\n }\n\n // Tag so children parented to this camera get push invalidation (O(1) reads).\n attachWorldMatrixState(cam, wm);\n\n return cam;\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"arc-rotate.js","sources":["../../../src/camera/arc-rotate.ts"],"sourcesContent":["import type { Camera, NormalizedViewport } from \"./camera.js\";\nimport type { Vec3, Mat4 } from \"../math/types.js\";\nimport { mat4LookAtWorldLHToRef } from \"../math/mat4-look-at-world-lh.js\";\nimport { Vec3Up } from \"../math/vec3-up.js\";\nimport type { IWorldMatrixProvider, IParentable } from \"../scene/parentable.js\";\nimport { createWorldMatrixState, attachWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport { ObservableVec3 } from \"../math/observable-vec3.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport { allocateMat4 } from \"../math/_matrix-allocator.js\";\n\n/** ArcRotateCamera — orbits around a target point.\n * Uses Babylon.js convention: left-handed, alpha=rotation around Y, beta=elevation.\n * Plain data + methods. Does NOT know about the scene.\n *\n * Push-based dirty tracking: alpha/beta/radius use Object.defineProperty,\n * target uses ObservableVec3. Changes call wm.markLocalDirty() immediately.\n *\n * Inertia follows the Babylon.js model: input handlers accumulate per-frame\n * offsets (inertialAlphaOffset, etc.) which are applied and exponentially\n * decayed each frame by the controls module. */\nexport interface ArcRotateCamera extends Camera, IWorldMatrixProvider, IParentable {\n alpha: number;\n beta: number;\n radius: number;\n target: Vec3;\n fov: number;\n nearPlane: number;\n farPlane: number;\n viewport?: NormalizedViewport;\n children: SceneNode[];\n\n /** Inertia coefficient for rotation and zoom (0 = instant stop, 0.9 = default, 1 = no decay). */\n inertia: number;\n /** Inertia coefficient for panning (0 = instant stop, 0.9 = default). */\n panningInertia: number;\n\n /** Mouse-drag orbit sensitivity (HIGHER = slower rotation). Babylon default 1000. */\n angularSensibility: number;\n /** Right-drag panning sensitivity in pixels-per-unit (LOWER = faster pan). Babylon default 50. */\n panningSensibility: number;\n /** Wheel-zoom sensitivity (HIGHER = slower zoom). Babylon default 3. */\n wheelPrecision: number;\n\n /** Per-frame inertial offsets — accumulated by input, applied & decayed each frame. */\n inertialAlphaOffset: number;\n inertialBetaOffset: number;\n inertialRadiusOffset: number;\n inertialPanningX: number;\n inertialPanningY: number;\n\n /**\n * Optional orbit limits enforced by {@link attachControl}'s per-frame loop.\n * `undefined` means unbounded on that side. Set these via {@link setCameraLimits}\n * so the current pose is clamped immediately (and inertia zeroed at the wall),\n * avoiding any overshoot-then-snap jiggle. Angles are in radians.\n */\n lowerAlphaLimit?: number;\n upperAlphaLimit?: number;\n lowerBetaLimit?: number;\n upperBetaLimit?: number;\n lowerRadiusLimit?: number;\n upperRadiusLimit?: number;\n\n /** @internal Self-clamp hook installed by {@link setCameraLimits}. The\n * alpha/beta/radius setters invoke it immediately after every mutation, so\n * the camera is never observably out of its orbit limits — at any point a\n * per-frame callback (e.g. a camera-pinned skybox) reads it. This is what\n * makes a direct pinch write or inertial overshoot snap to the wall in the\n * same statement that caused it, with no one-frame \"blink\". Undefined until\n * limits are set, so cameras that never call setCameraLimits carry none of\n * the clamp code and the setters' `?.()` call is a single dead check. */\n _clampToLimits?: () => void;\n\n parent: IWorldMatrixProvider | null;\n readonly worldMatrix: Mat4;\n readonly worldMatrixVersion: number;\n}\n\n/** Create a bare ArcRotateCamera with given params. Pure data, no scene knowledge. */\nexport function createArcRotateCamera(alpha: number, beta: number, radius: number, target: Vec3): ArcRotateCamera {\n function localEyePosition(): Vec3 {\n const cosA = Math.cos(cam.alpha),\n sinA = Math.sin(cam.alpha);\n const cosB = Math.cos(cam.beta);\n let sinB = Math.sin(cam.beta);\n if (sinB === 0) {\n sinB = 0.0001;\n }\n return {\n x: cam.target.x + cam.radius * cosA * sinB,\n y: cam.target.y + cam.radius * cosB,\n z: cam.target.z + cam.radius * sinA * sinB,\n };\n }\n\n // Reusable local-world matrix.\n const _localMat: Mat4 = allocateMat4();\n\n function cameraLocalWorldMatrix(): Mat4 {\n mat4LookAtWorldLHToRef(_localMat as unknown as Mat4Storage, localEyePosition(), cam.target, Vec3Up);\n return _localMat;\n }\n\n const wm = createWorldMatrixState(cameraLocalWorldMatrix);\n const onDirty = (): void => wm.markLocalDirty();\n\n const scalars = { alpha, beta, radius };\n\n const cam: ArcRotateCamera = {\n alpha: 0 as number, // placeholder — overridden by defineProperty below\n beta: 0 as number,\n radius: 0 as number,\n target: new ObservableVec3(target.x, target.y, target.z, onDirty) as unknown as Vec3,\n fov: 0.8,\n nearPlane: 0.1,\n farPlane: 1000,\n children: [] as SceneNode[],\n\n inertia: 0.9,\n panningInertia: 0.9,\n angularSensibility: 1000,\n panningSensibility: 50,\n wheelPrecision: 3,\n inertialAlphaOffset: 0,\n inertialBetaOffset: 0,\n inertialRadiusOffset: 0,\n inertialPanningX: 0,\n inertialPanningY: 0,\n\n // Matrix caches use the process-global allocator — F32 by default,\n // F64 after an HPM engine is created. Same backing as the camera world\n // matrix above, so the camera's storage precision is uniform.\n _viewCache: allocateMat4() as unknown as Mat4Storage,\n _projCache: allocateMat4() as unknown as Mat4Storage,\n _vpCache: allocateMat4() as unknown as Mat4Storage,\n\n get parent() {\n return wm.parent;\n },\n set parent(v) {\n wm.parent = v;\n },\n get worldMatrix() {\n return wm.getWorldMatrix();\n },\n get worldMatrixVersion() {\n return wm.getWorldMatrixVersion();\n },\n };\n\n // Push-based dirty tracking for scalar camera params that affect worldMatrix.\n for (const key of [\"alpha\", \"beta\", \"radius\"] as const) {\n Object.defineProperty(cam, key, {\n get: () => scalars[key],\n set: (v: number) => {\n if (scalars[key] !== v) {\n scalars[key] = v;\n onDirty();\n // Self-clamp into orbit limits the instant a value changes, so\n // no caller (pinch direct-write, inertia, auto-rotate) can leave\n // the camera transiently out of bounds for any per-frame reader.\n // No-op (and no clamp code bundled) until setCameraLimits runs.\n cam._clampToLimits?.();\n }\n },\n configurable: true,\n enumerable: true,\n });\n }\n\n // Tag so children parented to this camera get push invalidation (O(1) reads).\n attachWorldMatrixState(cam, wm);\n\n return cam;\n}\n"],"names":[],"mappings":"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"}
@@ -31,19 +31,36 @@ function getViewMatrix(camera) {
31
31
  camera._viewVer = ver;
32
32
  return v;
33
33
  }
34
+ let _orthoProjector = null;
35
+ function _installOrthographicProjector(write) {
36
+ _orthoProjector = write;
37
+ }
38
+ function _cameraChangeKey(camera) {
39
+ if (camera._projFov !== camera.fov || camera._projNear !== camera.nearPlane || camera._projFar !== camera.farPlane) {
40
+ camera._projFov = camera.fov;
41
+ camera._projNear = camera.nearPlane;
42
+ camera._projFar = camera.farPlane;
43
+ camera._projRev = (camera._projRev ?? 0) + 1;
44
+ }
45
+ return camera.worldMatrixVersion + (camera._projRev ?? 0);
46
+ }
34
47
  function getProjectionMatrix(camera, aspectRatio) {
35
- const ver = camera.worldMatrixVersion;
48
+ const ver = _cameraChangeKey(camera);
36
49
  if (camera._projVer === ver && camera._projAspect === aspectRatio) {
37
50
  return camera._projCache;
38
51
  }
39
52
  const p = camera._projCache;
40
- mat4PerspectiveLHToRef(p, camera.fov, aspectRatio, camera.nearPlane, camera.farPlane);
53
+ if (_orthoProjector !== null && camera.ortho) {
54
+ _orthoProjector(camera, aspectRatio, p);
55
+ } else {
56
+ mat4PerspectiveLHToRef(p, camera.fov, aspectRatio, camera.nearPlane, camera.farPlane);
57
+ }
41
58
  camera._projVer = ver;
42
59
  camera._projAspect = aspectRatio;
43
60
  return p;
44
61
  }
45
62
  function getViewProjectionMatrix(camera, aspectRatio) {
46
- const ver = camera.worldMatrixVersion;
63
+ const ver = _cameraChangeKey(camera);
47
64
  if (camera._vpVer === ver && camera._vpAspect === aspectRatio) {
48
65
  return camera._vpCache;
49
66
  }
@@ -62,5 +79,5 @@ function getEffectiveAspectRatio(camera, targetWidth, targetHeight) {
62
79
  return targetWidth / targetHeight * (v ? v.width / v.height : 1);
63
80
  }
64
81
 
65
- export { getCameraPosition, getEffectiveAspectRatio, getProjectionMatrix, getViewMatrix, getViewProjectionMatrix };
82
+ export { _cameraChangeKey, _installOrthographicProjector, getCameraPosition, getEffectiveAspectRatio, getProjectionMatrix, getViewMatrix, getViewProjectionMatrix };
66
83
  //# sourceMappingURL=camera.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"camera.js","sources":["../../../src/camera/camera.ts"],"sourcesContent":["import type { Vec3, Mat4 } from \"../math/types.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport { mat4MultiplyInto } from \"../math/mat4-multiply-into.js\";\nimport { mat4PerspectiveLHToRef } from \"../math/mat4-perspective-lh-to-ref.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\n\n/** Minimal camera contract — any camera that can provide view/projection matrices.\n * Both ArcRotateCamera and FreeCamera implement this interface.\n * Pure state, no scene knowledge (pillar 4b).\n *\n * The view/projection matrix caches below are allocated by the camera factory\n * via the process-global `allocateMat4()` singleton — F32 by default, F64\n * after any HPM engine is constructed (see\n * `docs/lite/architecture/36-high-precision-matrix.md`). The storage\n * type is fixed at construction and never changes. */\nexport interface Camera {\n fov: number;\n nearPlane: number;\n farPlane: number;\n viewport?: NormalizedViewport;\n children: SceneNode[];\n readonly worldMatrix: Mat4;\n readonly worldMatrixVersion: number;\n /** @internal View matrix cache. Pre-allocated by the camera factory via\n * `allocateMat4()`. F32 by default, F64 after an HPM engine is created. */\n _viewCache: Mat4Storage;\n /** @internal */\n _viewVer?: number;\n /** @internal Projection matrix cache. Same allocator as `_viewCache`. */\n _projCache: Mat4Storage;\n /** @internal */\n _projVer?: number;\n /** @internal */\n _projAspect?: number;\n /** @internal View-projection matrix cache. Same allocator. */\n _vpCache: Mat4Storage;\n /** @internal */\n _vpVer?: number;\n /** @internal */\n _vpAspect?: number;\n /** @internal Marker: when set by an LWR-enabled scene, `getViewMatrix`\n * zeros the view matrix translation column (the GPU sees the camera at\n * the origin in the eye-relative frame, matching the mesh-world UBO\n * pack that subtracted the camera position). Set by scene `_update` when\n * the engine has `useFloatingOrigin: true`; never unset. Non-LWR cameras\n * leave the field undefined and `getViewMatrix` produces a standard view\n * matrix. */\n _useFloatingOrigin?: boolean;\n}\n\n/** Babylon-compatible normalized camera viewport. x/y/width/height are fractions of the render target. */\nexport interface NormalizedViewport {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Compute the view matrix for a camera. Cached per worldMatrixVersion.\n *\n * Floating-origin awareness: when `camera._useFloatingOrigin` is set\n * (LWR — wired by the scene's `_update` when the active scene camera is\n * bound to an LWR engine), the view matrix translation column is forced\n * to zero. The GPU vertex shader then sees the camera at the origin in\n * the eye-relative frame, matching the mesh-world UBO pack which\n * subtracted the camera position from world translations. View × world\n * in the shader produces eye-relative vertex coordinates at full\n * precision regardless of how far from world-origin the scene is.\n *\n * When the flag is unset (standard non-LWR rendering), this path is\n * bit-identical to a normal `R_inv * -cameraPos` view matrix. */\nexport function getViewMatrix(camera: Camera): Mat4 {\n const ver = camera.worldMatrixVersion;\n if (camera._viewVer === ver) {\n return camera._viewCache as unknown as Mat4;\n }\n const v = camera._viewCache;\n const w = camera.worldMatrix;\n const useFO = camera._useFloatingOrigin;\n const cx = useFO ? 0 : w[12]!;\n const cy = useFO ? 0 : w[13]!;\n const cz = useFO ? 0 : w[14]!;\n v[0] = w[0]!;\n v[1] = w[4]!;\n v[2] = w[8]!;\n v[3] = 0;\n v[4] = w[1]!;\n v[5] = w[5]!;\n v[6] = w[9]!;\n v[7] = 0;\n v[8] = w[2]!;\n v[9] = w[6]!;\n v[10] = w[10]!;\n v[11] = 0;\n v[12] = -(w[0]! * cx + w[1]! * cy + w[2]! * cz);\n v[13] = -(w[4]! * cx + w[5]! * cy + w[6]! * cz);\n v[14] = -(w[8]! * cx + w[9]! * cy + w[10]! * cz);\n v[15] = 1;\n camera._viewVer = ver;\n return v as unknown as Mat4;\n}\n\n/** Compute the projection matrix for a camera. Cached per worldMatrixVersion + aspect. */\nexport function getProjectionMatrix(camera: Camera, aspectRatio: number): Mat4 {\n const ver = camera.worldMatrixVersion;\n if (camera._projVer === ver && camera._projAspect === aspectRatio) {\n return camera._projCache as unknown as Mat4;\n }\n const p = camera._projCache;\n mat4PerspectiveLHToRef(p, camera.fov, aspectRatio, camera.nearPlane, camera.farPlane);\n camera._projVer = ver;\n camera._projAspect = aspectRatio;\n return p as unknown as Mat4;\n}\n\n/** Compute the view-projection matrix for a camera. Cached per worldMatrixVersion + aspect. */\nexport function getViewProjectionMatrix(camera: Camera, aspectRatio: number): Mat4 {\n const ver = camera.worldMatrixVersion;\n if (camera._vpVer === ver && camera._vpAspect === aspectRatio) {\n return camera._vpCache as unknown as Mat4;\n }\n const vp = camera._vpCache;\n mat4MultiplyInto(vp, 0, getProjectionMatrix(camera, aspectRatio) as unknown as Mat4Storage, 0, getViewMatrix(camera) as unknown as Mat4Storage, 0);\n camera._vpVer = ver;\n camera._vpAspect = aspectRatio;\n return vp as unknown as Mat4;\n}\n\n/** Get the world-space position of a camera. */\nexport function getCameraPosition(camera: Camera): Vec3 {\n const w = camera.worldMatrix;\n return { x: w[12]!, y: w[13]!, z: w[14]! };\n}\n\n/** Returns the render-target aspect ratio adjusted for the camera's normalized viewport, or the raw ratio if none. */\nexport function getEffectiveAspectRatio(camera: Camera | null | undefined, targetWidth: number, targetHeight: number): number {\n const v = camera?.viewport;\n return (targetWidth / targetHeight) * (v ? v.width / v.height : 1);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"camera.js","sources":["../../../src/camera/camera.ts"],"sourcesContent":["import type { Vec3, Mat4 } from \"../math/types.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport { mat4MultiplyInto } from \"../math/mat4-multiply-into.js\";\nimport { mat4PerspectiveLHToRef } from \"../math/mat4-perspective-lh-to-ref.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport type { OrthographicBounds } from \"./orthographic.js\";\n\n/** Minimal camera contract — any camera that can provide view/projection matrices.\n * Both ArcRotateCamera and FreeCamera implement this interface.\n * Pure state, no scene knowledge (pillar 4b).\n *\n * The view/projection matrix caches below are allocated by the camera factory\n * via the process-global `allocateMat4()` singleton — F32 by default, F64\n * after any HPM engine is constructed (see\n * `docs/lite/architecture/36-high-precision-matrix.md`). The storage\n * type is fixed at construction and never changes. */\nexport interface Camera {\n fov: number;\n nearPlane: number;\n farPlane: number;\n viewport?: NormalizedViewport;\n children: SceneNode[];\n readonly worldMatrix: Mat4;\n readonly worldMatrixVersion: number;\n /** @internal View matrix cache. Pre-allocated by the camera factory via\n * `allocateMat4()`. F32 by default, F64 after an HPM engine is created. */\n _viewCache: Mat4Storage;\n /** @internal */\n _viewVer?: number;\n /** @internal Projection matrix cache. Same allocator as `_viewCache`. */\n _projCache: Mat4Storage;\n /** @internal */\n _projVer?: number;\n /** @internal */\n _projAspect?: number;\n /** @internal View-projection matrix cache. Same allocator. */\n _vpCache: Mat4Storage;\n /** @internal */\n _vpVer?: number;\n /** @internal */\n _vpAspect?: number;\n /** @internal Marker: when set by an LWR-enabled scene, `getViewMatrix`\n * zeros the view matrix translation column (the GPU sees the camera at\n * the origin in the eye-relative frame, matching the mesh-world UBO\n * pack that subtracted the camera position). Set by scene `_update` when\n * the engine has `useFloatingOrigin: true`; never unset. Non-LWR cameras\n * leave the field undefined and `getViewMatrix` produces a standard view\n * matrix. */\n _useFloatingOrigin?: boolean;\n /** @internal Monotonic counter bumped whenever the *projection* changes\n * independently of the camera transform: by `_cameraChangeKey` when it\n * observes a `fov` / `nearPlane` / `farPlane` write, and by the orthographic\n * feature module (`enableOrthographicCamera` / `disableOrthographicCamera`\n * and every `ortho` bounds setter).\n *\n * Projection-dependent per-frame consumers gate their GPU uploads on the\n * camera's `worldMatrixVersion`, which does not move when only the view\n * volume does; they fold this counter into the same key so the change\n * reaches the GPU. It is deliberately separate from `worldMatrixVersion`:\n * a projection change must NOT be mistaken for camera motion, which would\n * additionally invalidate the camera's children and — under floating\n * origin — retrigger origin rebasing across every renderable.\n *\n * Initialized on the first `_cameraChangeKey` call: the `fov` / `nearPlane` /\n * `farPlane` snapshot below starts `undefined`, so that first call always\n * observes a drift and bumps this to 1. Consumers therefore never read it\n * as `undefined` — they reach it only through `_cameraChangeKey`. */\n _projRev?: number;\n /** @internal Last `fov` / `nearPlane` / `farPlane` observed by `_cameraChangeKey`.\n * These are plain writable fields on a plain-data camera (pillar 4b′), so a write\n * cannot notify anyone; the change key polls them by value instead and bumps\n * `_projRev` when they drift. See `_cameraChangeKey`. */\n _projFov?: number;\n /** @internal See `_projFov`. */\n _projNear?: number;\n /** @internal See `_projFov`. */\n _projFar?: number;\n /** Live orthographic view-volume extents, installed by `enableOrthographicCamera`\n * and mutable/animatable thereafter. Null or undefined means the camera projects\n * perspectively through `fov`. */\n ortho?: OrthographicBounds | null;\n}\n\n/** Babylon-compatible normalized camera viewport. x/y/width/height are fractions of the render target. */\nexport interface NormalizedViewport {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/** Compute the view matrix for a camera. Cached per worldMatrixVersion.\n *\n * Floating-origin awareness: when `camera._useFloatingOrigin` is set\n * (LWR — wired by the scene's `_update` when the active scene camera is\n * bound to an LWR engine), the view matrix translation column is forced\n * to zero. The GPU vertex shader then sees the camera at the origin in\n * the eye-relative frame, matching the mesh-world UBO pack which\n * subtracted the camera position from world translations. View × world\n * in the shader produces eye-relative vertex coordinates at full\n * precision regardless of how far from world-origin the scene is.\n *\n * When the flag is unset (standard non-LWR rendering), this path is\n * bit-identical to a normal `R_inv * -cameraPos` view matrix. */\nexport function getViewMatrix(camera: Camera): Mat4 {\n const ver = camera.worldMatrixVersion;\n if (camera._viewVer === ver) {\n return camera._viewCache as unknown as Mat4;\n }\n const v = camera._viewCache;\n const w = camera.worldMatrix;\n const useFO = camera._useFloatingOrigin;\n const cx = useFO ? 0 : w[12]!;\n const cy = useFO ? 0 : w[13]!;\n const cz = useFO ? 0 : w[14]!;\n v[0] = w[0]!;\n v[1] = w[4]!;\n v[2] = w[8]!;\n v[3] = 0;\n v[4] = w[1]!;\n v[5] = w[5]!;\n v[6] = w[9]!;\n v[7] = 0;\n v[8] = w[2]!;\n v[9] = w[6]!;\n v[10] = w[10]!;\n v[11] = 0;\n v[12] = -(w[0]! * cx + w[1]! * cy + w[2]! * cz);\n v[13] = -(w[4]! * cx + w[5]! * cy + w[6]! * cz);\n v[14] = -(w[8]! * cx + w[9]! * cy + w[10]! * cz);\n v[15] = 1;\n camera._viewVer = ver;\n return v as unknown as Mat4;\n}\n\n/** Orthographic projection writer, installed only by `enableOrthographicCamera`. Module-local with a\n * single exported setter: when `enableOrthographicCamera` is absent from the bundle the setter\n * tree-shakes, the bundler proves this is always null, and the orthographic branch below folds away —\n * perspective-only scenes stay byte-identical. */\nlet _orthoProjector: ((camera: Camera, aspectRatio: number, out: Mat4Storage) => void) | null = null;\n\n/** @internal Install orthographic projection support (called by `enableOrthographicCamera`). */\nexport function _installOrthographicProjector(write: (camera: Camera, aspectRatio: number, out: Mat4Storage) => void): void {\n _orthoProjector = write;\n}\n\n/** @internal Change key for every projection-dependent per-frame consumer, and for the\n * projection matrix caches themselves.\n *\n * Consumers gate their GPU uploads on a version number. `camera.worldMatrixVersion` alone\n * is not that number: it does not move when only the view volume changes, so a steady-state\n * scene keeps rendering a stale view-projection after a `fov`, `nearPlane`, `farPlane` or\n * orthographic-bounds write.\n *\n * `fov` / `nearPlane` / `farPlane` are plain writable fields on a plain-data camera\n * (pillar 4b′) — a write cannot notify anyone — so this polls them by value and folds a\n * drift into `_projRev`. Polling here rather than installing accessors in every camera\n * factory keeps the projection contract in ONE place, costs nothing per camera type, and\n * works for a hand-rolled object satisfying `Camera` (the same reason\n * `world-matrix-state.ts` polls a foreign parent's version instead of pushing to it).\n * Orthographic bounds are pushed, not polled: that module owns setters already.\n *\n * Both terms of the returned sum are monotonically non-decreasing, so the sum is too and\n * any change in either strictly increases it — it cannot alias. (Same version-summing idiom\n * as `shadow-base.ts` and `gltf-feature-lights-punctual.ts`.) This relies on the `Camera`\n * contract that `worldMatrixVersion` never decreases; every in-engine camera satisfies it\n * (the counter only ever increments, including across reparenting), and a custom `Camera`\n * implementation must too or a change can be missed.\n *\n * Deliberately NOT folded into `worldMatrixVersion` itself: a projection change must not be\n * mistaken for camera motion, which would invalidate the camera's children and, under\n * floating origin, retrigger origin rebasing across every renderable (`wrapRenderableForFO`).\n * Those consumers keep reading `worldMatrixVersion`. */\nexport function _cameraChangeKey(camera: Camera): number {\n if (camera._projFov !== camera.fov || camera._projNear !== camera.nearPlane || camera._projFar !== camera.farPlane) {\n camera._projFov = camera.fov;\n camera._projNear = camera.nearPlane;\n camera._projFar = camera.farPlane;\n camera._projRev = (camera._projRev ?? 0) + 1;\n }\n return camera.worldMatrixVersion + (camera._projRev ?? 0);\n}\n\n/** Compute the projection matrix for a camera. Cached per `_cameraChangeKey` + aspect. */\nexport function getProjectionMatrix(camera: Camera, aspectRatio: number): Mat4 {\n const ver = _cameraChangeKey(camera);\n if (camera._projVer === ver && camera._projAspect === aspectRatio) {\n return camera._projCache as unknown as Mat4;\n }\n const p = camera._projCache;\n if (_orthoProjector !== null && camera.ortho) {\n _orthoProjector(camera, aspectRatio, p);\n } else {\n mat4PerspectiveLHToRef(p, camera.fov, aspectRatio, camera.nearPlane, camera.farPlane);\n }\n camera._projVer = ver;\n camera._projAspect = aspectRatio;\n return p as unknown as Mat4;\n}\n\n/** Compute the view-projection matrix for a camera. Cached per `_cameraChangeKey` + aspect. */\nexport function getViewProjectionMatrix(camera: Camera, aspectRatio: number): Mat4 {\n const ver = _cameraChangeKey(camera);\n if (camera._vpVer === ver && camera._vpAspect === aspectRatio) {\n return camera._vpCache as unknown as Mat4;\n }\n const vp = camera._vpCache;\n mat4MultiplyInto(vp, 0, getProjectionMatrix(camera, aspectRatio) as unknown as Mat4Storage, 0, getViewMatrix(camera) as unknown as Mat4Storage, 0);\n camera._vpVer = ver;\n camera._vpAspect = aspectRatio;\n return vp as unknown as Mat4;\n}\n\n/** Get the world-space position of a camera. */\nexport function getCameraPosition(camera: Camera): Vec3 {\n const w = camera.worldMatrix;\n return { x: w[12]!, y: w[13]!, z: w[14]! };\n}\n\n/** Returns the render-target aspect ratio adjusted for the camera's normalized viewport, or the raw ratio if none. */\nexport function getEffectiveAspectRatio(camera: Camera | null | undefined, targetWidth: number, targetHeight: number): number {\n const v = camera?.viewport;\n return (targetWidth / targetHeight) * (v ? v.width / v.height : 1);\n}\n"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { mat4LookAtLH } from '../math/mat4-look-at-lh.js';
1
+ import { mat4LookAtWorldLHToRef } from '../math/mat4-look-at-world-lh.js';
2
2
  import { Vec3Up } from '../math/vec3-up.js';
3
3
  import { attachWorldMatrixState, createWorldMatrixState } from '../scene/world-matrix-state.js';
4
4
  import { ObservableVec3 } from '../math/observable-vec3.js';
@@ -10,24 +10,7 @@ function createFreeCamera(position, target) {
10
10
  const dz = target.z - position.z;
11
11
  const _localMat = allocateMat4();
12
12
  function cameraLocalWorldMatrix() {
13
- const view = mat4LookAtLH(cam.position, cam.target, Vec3Up);
14
- const m = _localMat;
15
- m[0] = view[0];
16
- m[1] = view[4];
17
- m[2] = view[8];
18
- m[3] = 0;
19
- m[4] = view[1];
20
- m[5] = view[5];
21
- m[6] = view[9];
22
- m[7] = 0;
23
- m[8] = view[2];
24
- m[9] = view[6];
25
- m[10] = view[10];
26
- m[11] = 0;
27
- m[12] = cam.position.x;
28
- m[13] = cam.position.y;
29
- m[14] = cam.position.z;
30
- m[15] = 1;
13
+ mat4LookAtWorldLHToRef(_localMat, cam.position, cam.target, Vec3Up);
31
14
  return _localMat;
32
15
  }
33
16
  const wm = createWorldMatrixState(cameraLocalWorldMatrix);
@@ -1 +1 @@
1
- {"version":3,"file":"free-camera.js","sources":["../../../src/camera/free-camera.ts"],"sourcesContent":["import type { Camera } from \"./camera.js\";\nimport type { Vec3, Mat4 } from \"../math/types.js\";\nimport { mat4LookAtLH } from \"../math/mat4-look-at-lh.js\";\nimport { Vec3Up } from \"../math/vec3-up.js\";\nimport type { IWorldMatrixProvider, IParentable } from \"../scene/parentable.js\";\nimport { createWorldMatrixState, attachWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport { ObservableVec3 } from \"../math/observable-vec3.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport { allocateMat4 } from \"../math/_matrix-allocator.js\";\n\n/** FreeCamera — positioned in world space, looking at a target point.\n * Matches Babylon.js FreeCamera: position + target, left-handed.\n * Plain data + methods. Does NOT know about the scene.\n *\n * Push-based dirty tracking: position and target use ObservableVec3,\n * _yaw/_pitch use Object.defineProperty. */\nexport interface FreeCamera extends Camera, IWorldMatrixProvider, IParentable {\n position: ObservableVec3;\n target: ObservableVec3;\n /** Movement speed. Default 2.0 (matches BJS). */\n speed: number;\n /** Mouse rotation sensitivity (higher = less sensitive). Default 2000 (matches BJS). */\n angularSensitivity: number;\n /** Inertia damping factor (0 = instant stop, 0.9 = smooth). Default 0.9 (matches BJS). */\n inertia: number;\n parent: IWorldMatrixProvider | null;\n readonly worldMatrix: Mat4;\n readonly worldMatrixVersion: number;\n /** @internal */\n _yaw: number;\n /** @internal */\n _pitch: number;\n}\n\n/** Create a FreeCamera at the given position looking at target. Pure data, no scene knowledge. */\nexport function createFreeCamera(position: Vec3, target: Vec3): FreeCamera {\n // Compute initial yaw/pitch from position→target direction\n const dx = target.x - position.x;\n const dy = target.y - position.y;\n const dz = target.z - position.z;\n\n // Reusable local-world matrix.\n const _localMat: Mat4 = allocateMat4();\n\n function cameraLocalWorldMatrix(): Mat4 {\n const view = mat4LookAtLH(cam.position, cam.target, Vec3Up);\n const m = _localMat as unknown as Mat4Storage;\n // Camera-to-world = transpose upper 3×3 of view + eye position\n m[0] = view[0]!;\n m[1] = view[4]!;\n m[2] = view[8]!;\n m[3] = 0;\n m[4] = view[1]!;\n m[5] = view[5]!;\n m[6] = view[9]!;\n m[7] = 0;\n m[8] = view[2]!;\n m[9] = view[6]!;\n m[10] = view[10]!;\n m[11] = 0;\n m[12] = cam.position.x;\n m[13] = cam.position.y;\n m[14] = cam.position.z;\n m[15] = 1;\n return _localMat;\n }\n\n const wm = createWorldMatrixState(cameraLocalWorldMatrix);\n const onDirty = () => wm.markLocalDirty();\n\n let _yaw = Math.atan2(dx, dz);\n let _pitch = Math.atan2(dy, Math.sqrt(dx * dx + dz * dz));\n\n const cam: FreeCamera = {\n position: new ObservableVec3(position.x, position.y, position.z, onDirty),\n target: new ObservableVec3(target.x, target.y, target.z, onDirty),\n fov: 0.8,\n nearPlane: 1,\n farPlane: 10000,\n speed: 2.0,\n angularSensitivity: 2000,\n inertia: 0.9,\n children: [] as SceneNode[],\n\n // Matrix caches use the process-global allocator.\n _viewCache: allocateMat4() as unknown as Mat4Storage,\n _projCache: allocateMat4() as unknown as Mat4Storage,\n _vpCache: allocateMat4() as unknown as Mat4Storage,\n\n get parent() {\n return wm.parent;\n },\n set parent(v) {\n wm.parent = v;\n },\n get worldMatrix() {\n return wm.getWorldMatrix();\n },\n get worldMatrixVersion() {\n return wm.getWorldMatrixVersion();\n },\n } as FreeCamera;\n\n // Push-based dirty for yaw/pitch\n Object.defineProperty(cam, \"_yaw\", {\n get() {\n return _yaw;\n },\n set(v: number) {\n if (_yaw !== v) {\n _yaw = v;\n onDirty();\n }\n },\n configurable: true,\n enumerable: true,\n });\n Object.defineProperty(cam, \"_pitch\", {\n get() {\n return _pitch;\n },\n set(v: number) {\n if (_pitch !== v) {\n _pitch = v;\n onDirty();\n }\n },\n configurable: true,\n enumerable: true,\n });\n\n // Tag so children parented to this camera get push invalidation (O(1) reads).\n attachWorldMatrixState(cam, wm);\n\n return cam;\n}\n"],"names":[],"mappings":";;;;;;AAoCO,SAAS,gBAAA,CAAiB,UAAgB,MAAA,EAA0B;AAEvE,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,CAAA,GAAI,QAAA,CAAS,CAAA;AAC/B,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,CAAA,GAAI,QAAA,CAAS,CAAA;AAC/B,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,CAAA,GAAI,QAAA,CAAS,CAAA;AAG/B,EAAA,MAAM,YAAkB,YAAA,EAAa;AAErC,EAAA,SAAS,sBAAA,GAA+B;AACpC,IAAA,MAAM,OAAO,YAAA,CAAa,GAAA,CAAI,QAAA,EAAU,GAAA,CAAI,QAAQ,MAAM,CAAA;AAC1D,IAAA,MAAM,CAAA,GAAI,SAAA;AAEV,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACP,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACP,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,IAAA,CAAK,EAAE,CAAA;AACf,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA;AACR,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,GAAA,CAAI,QAAA,CAAS,CAAA;AACrB,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,GAAA,CAAI,QAAA,CAAS,CAAA;AACrB,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,GAAA,CAAI,QAAA,CAAS,CAAA;AACrB,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA;AACR,IAAA,OAAO,SAAA;AAAA,EACX;AAEA,EAAA,MAAM,EAAA,GAAK,uBAAuB,sBAAsB,CAAA;AACxD,EAAA,MAAM,OAAA,GAAU,MAAM,EAAA,CAAG,cAAA,EAAe;AAExC,EAAA,IAAI,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,EAAE,CAAA;AAC5B,EAAA,IAAI,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,IAAA,CAAK,KAAK,EAAA,GAAK,EAAA,GAAK,EAAA,GAAK,EAAE,CAAC,CAAA;AAExD,EAAA,MAAM,GAAA,GAAkB;AAAA,IACpB,QAAA,EAAU,IAAI,cAAA,CAAe,QAAA,CAAS,GAAG,QAAA,CAAS,CAAA,EAAG,QAAA,CAAS,CAAA,EAAG,OAAO,CAAA;AAAA,IACxE,MAAA,EAAQ,IAAI,cAAA,CAAe,MAAA,CAAO,GAAG,MAAA,CAAO,CAAA,EAAG,MAAA,CAAO,CAAA,EAAG,OAAO,CAAA;AAAA,IAChE,GAAA,EAAK,GAAA;AAAA,IACL,SAAA,EAAW,CAAA;AAAA,IACX,QAAA,EAAU,GAAA;AAAA,IACV,KAAA,EAAO,CAAA;AAAA,IACP,kBAAA,EAAoB,GAAA;AAAA,IACpB,OAAA,EAAS,GAAA;AAAA,IACT,UAAU,EAAC;AAAA;AAAA,IAGX,YAAY,YAAA,EAAa;AAAA,IACzB,YAAY,YAAA,EAAa;AAAA,IACzB,UAAU,YAAA,EAAa;AAAA,IAEvB,IAAI,MAAA,GAAS;AACT,MAAA,OAAO,EAAA,CAAG,MAAA;AAAA,IACd,CAAA;AAAA,IACA,IAAI,OAAO,CAAA,EAAG;AACV,MAAA,EAAA,CAAG,MAAA,GAAS,CAAA;AAAA,IAChB,CAAA;AAAA,IACA,IAAI,WAAA,GAAc;AACd,MAAA,OAAO,GAAG,cAAA,EAAe;AAAA,IAC7B,CAAA;AAAA,IACA,IAAI,kBAAA,GAAqB;AACrB,MAAA,OAAO,GAAG,qBAAA,EAAsB;AAAA,IACpC;AAAA,GACJ;AAGA,EAAA,MAAA,CAAO,cAAA,CAAe,KAAK,MAAA,EAAQ;AAAA,IAC/B,GAAA,GAAM;AACF,MAAA,OAAO,IAAA;AAAA,IACX,CAAA;AAAA,IACA,IAAI,CAAA,EAAW;AACX,MAAA,IAAI,SAAS,CAAA,EAAG;AACZ,QAAA,IAAA,GAAO,CAAA;AACP,QAAA,OAAA,EAAQ;AAAA,MACZ;AAAA,IACJ,CAAA;AAAA,IACA,YAAA,EAAc,IAAA;AAAA,IACd,UAAA,EAAY;AAAA,GACf,CAAA;AACD,EAAA,MAAA,CAAO,cAAA,CAAe,KAAK,QAAA,EAAU;AAAA,IACjC,GAAA,GAAM;AACF,MAAA,OAAO,MAAA;AAAA,IACX,CAAA;AAAA,IACA,IAAI,CAAA,EAAW;AACX,MAAA,IAAI,WAAW,CAAA,EAAG;AACd,QAAA,MAAA,GAAS,CAAA;AACT,QAAA,OAAA,EAAQ;AAAA,MACZ;AAAA,IACJ,CAAA;AAAA,IACA,YAAA,EAAc,IAAA;AAAA,IACd,UAAA,EAAY;AAAA,GACf,CAAA;AAGD,EAAA,sBAAA,CAAuB,KAAK,EAAE,CAAA;AAE9B,EAAA,OAAO,GAAA;AACX;;;;"}
1
+ {"version":3,"file":"free-camera.js","sources":["../../../src/camera/free-camera.ts"],"sourcesContent":["import type { Camera } from \"./camera.js\";\nimport type { Vec3, Mat4 } from \"../math/types.js\";\nimport { mat4LookAtWorldLHToRef } from \"../math/mat4-look-at-world-lh.js\";\nimport { Vec3Up } from \"../math/vec3-up.js\";\nimport type { IWorldMatrixProvider, IParentable } from \"../scene/parentable.js\";\nimport { createWorldMatrixState, attachWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport { ObservableVec3 } from \"../math/observable-vec3.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport type { Mat4Storage } from \"../math/types.js\";\nimport { allocateMat4 } from \"../math/_matrix-allocator.js\";\n\n/** FreeCamera — positioned in world space, looking at a target point.\n * Matches Babylon.js FreeCamera: position + target, left-handed.\n * Plain data + methods. Does NOT know about the scene.\n *\n * Push-based dirty tracking: position and target use ObservableVec3,\n * _yaw/_pitch use Object.defineProperty. */\nexport interface FreeCamera extends Camera, IWorldMatrixProvider, IParentable {\n position: ObservableVec3;\n target: ObservableVec3;\n /** Movement speed. Default 2.0 (matches BJS). */\n speed: number;\n /** Mouse rotation sensitivity (higher = less sensitive). Default 2000 (matches BJS). */\n angularSensitivity: number;\n /** Inertia damping factor (0 = instant stop, 0.9 = smooth). Default 0.9 (matches BJS). */\n inertia: number;\n parent: IWorldMatrixProvider | null;\n readonly worldMatrix: Mat4;\n readonly worldMatrixVersion: number;\n /** @internal */\n _yaw: number;\n /** @internal */\n _pitch: number;\n}\n\n/** Create a FreeCamera at the given position looking at target. Pure data, no scene knowledge. */\nexport function createFreeCamera(position: Vec3, target: Vec3): FreeCamera {\n // Compute initial yaw/pitch from position→target direction\n const dx = target.x - position.x;\n const dy = target.y - position.y;\n const dz = target.z - position.z;\n\n // Reusable local-world matrix.\n const _localMat: Mat4 = allocateMat4();\n\n function cameraLocalWorldMatrix(): Mat4 {\n mat4LookAtWorldLHToRef(_localMat as unknown as Mat4Storage, cam.position, cam.target, Vec3Up);\n return _localMat;\n }\n\n const wm = createWorldMatrixState(cameraLocalWorldMatrix);\n const onDirty = () => wm.markLocalDirty();\n\n let _yaw = Math.atan2(dx, dz);\n let _pitch = Math.atan2(dy, Math.sqrt(dx * dx + dz * dz));\n\n const cam: FreeCamera = {\n position: new ObservableVec3(position.x, position.y, position.z, onDirty),\n target: new ObservableVec3(target.x, target.y, target.z, onDirty),\n fov: 0.8,\n nearPlane: 1,\n farPlane: 10000,\n speed: 2.0,\n angularSensitivity: 2000,\n inertia: 0.9,\n children: [] as SceneNode[],\n\n // Matrix caches use the process-global allocator.\n _viewCache: allocateMat4() as unknown as Mat4Storage,\n _projCache: allocateMat4() as unknown as Mat4Storage,\n _vpCache: allocateMat4() as unknown as Mat4Storage,\n\n get parent() {\n return wm.parent;\n },\n set parent(v) {\n wm.parent = v;\n },\n get worldMatrix() {\n return wm.getWorldMatrix();\n },\n get worldMatrixVersion() {\n return wm.getWorldMatrixVersion();\n },\n } as FreeCamera;\n\n // Push-based dirty for yaw/pitch\n Object.defineProperty(cam, \"_yaw\", {\n get() {\n return _yaw;\n },\n set(v: number) {\n if (_yaw !== v) {\n _yaw = v;\n onDirty();\n }\n },\n configurable: true,\n enumerable: true,\n });\n Object.defineProperty(cam, \"_pitch\", {\n get() {\n return _pitch;\n },\n set(v: number) {\n if (_pitch !== v) {\n _pitch = v;\n onDirty();\n }\n },\n configurable: true,\n enumerable: true,\n });\n\n // Tag so children parented to this camera get push invalidation (O(1) reads).\n attachWorldMatrixState(cam, wm);\n\n return cam;\n}\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { attachWorldMatrixState, createWorldMatrixState } from '../scene/world-matrix-state.js';
2
2
  import { allocateMat4 } from '../math/_matrix-allocator.js';
3
- import { mat4LookAtLH } from '../math/mat4-look-at-lh.js';
3
+ import { mat4LookAtWorldLHToRef } from '../math/mat4-look-at-world-lh.js';
4
4
  import { GEO_EPSILON, createGeospatialLimits, getEffectivePitchMax } from './geospatial-limits.js';
5
5
 
6
6
  const TWO_PI = Math.PI * 2;
@@ -98,24 +98,7 @@ function createGeospatialCamera(options) {
98
98
  const _localMat = allocateMat4();
99
99
  function cameraLocalWorldMatrix() {
100
100
  const center3 = { x: position.x + lookAt.x, y: position.y + lookAt.y, z: position.z + lookAt.z };
101
- const view = mat4LookAtLH(position, center3, upVector);
102
- const m = _localMat;
103
- m[0] = view[0];
104
- m[1] = view[4];
105
- m[2] = view[8];
106
- m[3] = 0;
107
- m[4] = view[1];
108
- m[5] = view[5];
109
- m[6] = view[9];
110
- m[7] = 0;
111
- m[8] = view[2];
112
- m[9] = view[6];
113
- m[10] = view[10];
114
- m[11] = 0;
115
- m[12] = position.x;
116
- m[13] = position.y;
117
- m[14] = position.z;
118
- m[15] = 1;
101
+ mat4LookAtWorldLHToRef(_localMat, position, center3, upVector);
119
102
  return _localMat;
120
103
  }
121
104
  const wm = createWorldMatrixState(cameraLocalWorldMatrix);
@@ -1 +1 @@
1
- {"version":3,"file":"geospatial-camera.js","sources":["../../../src/camera/geospatial-camera.ts"],"sourcesContent":["import type { Camera, NormalizedViewport } from \"./camera.js\";\nimport type { Vec3, Mat4, Mat4Storage } from \"../math/types.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport type { IWorldMatrixProvider, IParentable } from \"../scene/parentable.js\";\nimport { createWorldMatrixState, attachWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport { allocateMat4 } from \"../math/_matrix-allocator.js\";\nimport { mat4LookAtLH } from \"../math/mat4-look-at-lh.js\";\nimport type { GeospatialLimits } from \"./geospatial-limits.js\";\nimport { createGeospatialLimits, getEffectivePitchMax, GEO_EPSILON } from \"./geospatial-limits.js\";\n\nconst TWO_PI = Math.PI * 2;\n/** Babylon.js world \"north\" axis in a left-handed scene = +Z (LeftHandedForward). */\nconst WORLD_NORTH: Vec3 = { x: 0, y: 0, z: 1 };\nconst WORLD_RIGHT: Vec3 = { x: 1, y: 0, z: 0 };\n/** sin of the spherical-latitude limit (~89.96°) used to keep the centre off the poles. */\nconst POLE_SINE_LIMIT = 0.998749218;\n\n/** Options for {@link createGeospatialCamera}. */\nexport interface GeospatialCameraOptions {\n /** Radius of the planet being orbited. */\n planetRadius: number;\n}\n\n/** A delta to apply via {@link setGeospatialOrientation}; omitted fields keep their current value. */\nexport interface GeospatialOrientation {\n /** Yaw in radians (0 = north, π/2 = east). */\n yaw?: number;\n /** Pitch in radians (0 = looking straight down at the planet centre, π/2 = horizon). */\n pitch?: number;\n /** Distance from the camera to its centre point. */\n radius?: number;\n /** Anchor point on the globe (ECEF) that the camera orbits. */\n center?: Vec3;\n}\n\n/** Camera that orbits a spherical planet centred at the world origin (Babylon.js `GeospatialCamera`).\n *\n * Orientation is fully described by `center` (the anchored point on the globe in\n * ECEF coordinates), `yaw`, `pitch`, and `radius`. Setting any of these\n * recomputes the derived `position` / `upVector` and the view matrix.\n *\n * Pure state — behaviour is provided by standalone functions\n * ({@link setGeospatialOrientation}, `attachGeospatialControls`,\n * `flyGeospatialCameraToAsync`). The camera never references the scene. */\nexport interface GeospatialCamera extends Camera, IWorldMatrixProvider, IParentable {\n /** The anchored point on the globe (ECEF). Assigning re-orbits around the new centre. */\n center: Vec3;\n /** Yaw about the geocentric up axis. Wrapped to [-π, π). 0 = north, π/2 = east. */\n yaw: number;\n /** Pitch from looking straight down (0) to the horizon (π/2). Wrapped to [-π, π). */\n pitch: number;\n /** Distance from the camera to its centre point (distinct from `planetRadius`). */\n radius: number;\n /** Limits governing yaw/pitch/radius clamping. Mutable; clamping applies on the next orientation change. */\n limits: GeospatialLimits;\n /** Derived world-space eye position. Read-only — driven by center/yaw/pitch/radius. */\n readonly position: Vec3;\n /** Derived camera up vector. Read-only. */\n readonly upVector: Vec3;\n\n fov: number;\n nearPlane: number;\n farPlane: number;\n viewport?: NormalizedViewport;\n children: SceneNode[];\n parent: IWorldMatrixProvider | null;\n readonly worldMatrix: Mat4;\n readonly worldMatrixVersion: number;\n\n /** @internal Current normalized lookAt (unit) direction. */\n _lookAt: Vec3;\n /** @internal Recompute orientation from raw yaw/pitch/radius/center, applying limits.\n * Used by the controls/flyTo modules to drive the camera in one shot. */\n _setOrientation: (yaw: number, pitch: number, radius: number, center: Vec3) => void;\n /** @internal Cancels an in-flight `flyGeospatialCameraToAsync` animation. Set while a\n * flight is active; the controls loop calls it when user input arrives. */\n _cancelFly?: () => void;\n}\n\n/** Wrap an angle to [-π, π), matching Babylon.js `Scalar.NormalizeRadians`. */\nexport function normalizeRadians(angle: number): number {\n return angle - TWO_PI * Math.floor((angle + Math.PI) / TWO_PI);\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return v < min ? min : v > max ? max : v;\n}\n\n/**\n * Build the east/north/up orthonormal basis at a point on the globe (left-handed\n * convention). `up` is the geocentric normal (normalized position); `east` and\n * `north` complete a right-handed-looking tangent frame given the LH world.\n * Writes into the provided result objects and returns nothing.\n */\nexport function computeLocalBasis(worldPos: Vec3, refEast: Vec3, refNorth: Vec3, refUp: Vec3): void {\n // up = normalized position (geocentric normal)\n const upLen = Math.hypot(worldPos.x, worldPos.y, worldPos.z) || 1;\n refUp.x = worldPos.x / upLen;\n refUp.y = worldPos.y / upLen;\n refUp.z = worldPos.z / upLen;\n\n // east = cross(up, worldNorth)\n cross(refUp, WORLD_NORTH, refEast);\n if (lengthSq(refEast) < GEO_EPSILON) {\n // At a pole, cross with worldRight instead.\n cross(refUp, WORLD_RIGHT, refEast);\n }\n normalizeInPlace(refEast);\n\n // north = cross(east, up)\n cross(refEast, refUp, refNorth);\n normalizeInPlace(refNorth);\n}\n\n/**\n * Compute the lookAt direction from yaw/pitch at a centre point (forward formula).\n * Writes the normalized direction into `result`.\n */\nexport function computeLookAtFromYawPitch(yaw: number, pitch: number, center: Vec3, result: Vec3): Vec3 {\n const east = { x: 0, y: 0, z: 0 };\n const north = { x: 0, y: 0, z: 0 };\n const up = { x: 0, y: 0, z: 0 };\n computeLocalBasis(center, east, north, up);\n\n const sinPitch = Math.sin(pitch);\n const cosPitch = Math.cos(pitch);\n const cosYaw = Math.cos(yaw);\n const sinYaw = Math.sin(yaw);\n\n // horiz = north*cos(yaw) + east*sin(yaw)\n const hx = north.x * cosYaw + east.x * sinYaw;\n const hy = north.y * cosYaw + east.y * sinYaw;\n const hz = north.z * cosYaw + east.z * sinYaw;\n\n // lookAt = horiz*sinPitch - up*cosPitch\n result.x = hx * sinPitch - up.x * cosPitch;\n result.y = hy * sinPitch - up.y * cosPitch;\n result.z = hz * sinPitch - up.z * cosPitch;\n return normalizeInPlace(result);\n}\n\n/**\n * Inverse of {@link computeLookAtFromYawPitch}: given a lookAt direction and centre,\n * recover the yaw/pitch that would produce it. Writes `[yaw, pitch]` into `result`.\n * `currentYaw` is used as a fallback when looking straight down/up (yaw undefined).\n */\nexport function computeYawPitchFromLookAt(lookAt: Vec3, center: Vec3, currentYaw: number, result: { x: number; y: number }): { x: number; y: number } {\n const east = { x: 0, y: 0, z: 0 };\n const north = { x: 0, y: 0, z: 0 };\n const up = { x: 0, y: 0, z: 0 };\n computeLocalBasis(center, east, north, up);\n\n const lookDotUp = lookAt.x * up.x + lookAt.y * up.y + lookAt.z * up.z;\n const cosPitch = -lookDotUp;\n const pitch = Math.acos(clamp(cosPitch, -1, 1));\n\n // lookHorizontal = lookAt + up*cosPitch = horiz*sinPitch\n const lhx = lookAt.x + up.x * cosPitch;\n const lhy = lookAt.y + up.y * cosPitch;\n const lhz = lookAt.z + up.z * cosPitch;\n\n const sinPitch = Math.sin(pitch);\n if (Math.abs(sinPitch) < GEO_EPSILON) {\n result.x = currentYaw;\n result.y = pitch;\n return result;\n }\n const inv = 1 / sinPitch;\n const hx = lhx * inv;\n const hy = lhy * inv;\n const hz = lhz * inv;\n\n const cosYaw = hx * north.x + hy * north.y + hz * north.z;\n const sinYaw = hx * east.x + hy * east.y + hz * east.z;\n result.x = Math.atan2(sinYaw, cosYaw);\n result.y = pitch;\n return result;\n}\n\n/**\n * Clamp the camera centre away from the geographic poles (in place), so the\n * tangent basis stays well-defined. Mirrors Babylon.js `ClampCenterFromPolesInPlace`.\n */\nexport function clampCenterFromPoles(center: Vec3): Vec3 {\n const mag = Math.hypot(center.x, center.y, center.z);\n if (mag > GEO_EPSILON) {\n const sinLat = center.z / mag;\n if (Math.abs(sinLat) > POLE_SINE_LIMIT) {\n const sinClamped = clamp(sinLat, -POLE_SINE_LIMIT, POLE_SINE_LIMIT);\n const cosClamped = Math.sqrt(1 - sinClamped * sinClamped);\n const lon = Math.atan2(center.y, center.x);\n center.x = mag * Math.cos(lon) * cosClamped;\n center.y = mag * Math.sin(lon) * cosClamped;\n center.z = mag * sinClamped;\n }\n }\n return center;\n}\n\n/** Set one or more orientation fields at once (single recompute). Omitted fields keep their value. */\nexport function setGeospatialOrientation(camera: GeospatialCamera, orientation: GeospatialOrientation): void {\n camera._setOrientation(orientation.yaw ?? camera.yaw, orientation.pitch ?? camera.pitch, orientation.radius ?? camera.radius, orientation.center ?? camera.center);\n}\n\n/** Create a {@link GeospatialCamera} for a planet of the given radius. Pure data, no scene knowledge. */\nexport function createGeospatialCamera(options: GeospatialCameraOptions): GeospatialCamera {\n const limits = createGeospatialLimits(options.planetRadius);\n\n const center: Vec3 = { x: options.planetRadius, y: 0, z: 0 };\n const position: Vec3 = { x: 0, y: 0, z: 0 };\n const upVector: Vec3 = { x: 0, y: 1, z: 0 };\n const lookAt: Vec3 = { x: 0, y: 0, z: 0 };\n const scalars = { yaw: 0, pitch: 0, radius: 0 };\n\n const _localMat: Mat4 = allocateMat4();\n\n function cameraLocalWorldMatrix(): Mat4 {\n // camera-to-world = transpose(view R) + eye, like FreeCamera.\n const center3: Vec3 = { x: position.x + lookAt.x, y: position.y + lookAt.y, z: position.z + lookAt.z };\n const view = mat4LookAtLH(position, center3, upVector);\n const m = _localMat as unknown as Mat4Storage;\n m[0] = view[0]!;\n m[1] = view[4]!;\n m[2] = view[8]!;\n m[3] = 0;\n m[4] = view[1]!;\n m[5] = view[5]!;\n m[6] = view[9]!;\n m[7] = 0;\n m[8] = view[2]!;\n m[9] = view[6]!;\n m[10] = view[10]!;\n m[11] = 0;\n m[12] = position.x;\n m[13] = position.y;\n m[14] = position.z;\n m[15] = 1;\n return _localMat;\n }\n\n const wm = createWorldMatrixState(cameraLocalWorldMatrix);\n\n function applyOrientation(yaw: number, pitch: number, radius: number, newCenter: Vec3): void {\n scalars.yaw = normalizeRadians(yaw);\n scalars.pitch = normalizeRadians(pitch);\n scalars.radius = radius;\n center.x = newCenter.x;\n center.y = newCenter.y;\n center.z = newCenter.z;\n\n // Clamp to limits.\n scalars.yaw = clamp(scalars.yaw, limits.yawMin, limits.yawMax);\n scalars.pitch = clamp(scalars.pitch, limits.pitchMin, getEffectivePitchMax(limits, scalars.radius));\n scalars.radius = clamp(scalars.radius, limits.radiusMin, limits.radiusMax);\n clampCenterFromPoles(center);\n\n // Tangent basis at the (clamped) centre.\n const east = { x: 0, y: 0, z: 0 };\n const north = { x: 0, y: 0, z: 0 };\n const up = { x: 0, y: 0, z: 0 };\n computeLocalBasis(center, east, north, up);\n\n // lookAt from yaw/pitch.\n computeLookAtFromYawPitch(scalars.yaw, scalars.pitch, center, lookAt);\n\n // Build an orthonormal camera up aligned with geocentric up.\n const right = { x: 0, y: 0, z: 0 };\n cross(up, lookAt, right);\n if (lengthSq(right) < GEO_EPSILON) {\n // Looking straight down: lookAt ∥ up → use the horizontal direction.\n const cy = Math.cos(scalars.yaw);\n const sy = Math.sin(scalars.yaw);\n const horiz = { x: north.x * cy + east.x * sy, y: north.y * cy + east.y * sy, z: north.z * cy + east.z * sy };\n cross(horiz, lookAt, right);\n }\n normalizeInPlace(right);\n\n // up = normalize(cross(look, right))\n cross(lookAt, right, upVector);\n normalizeInPlace(upVector);\n\n // position = center - look*radius\n position.x = center.x - lookAt.x * scalars.radius;\n position.y = center.y - lookAt.y * scalars.radius;\n position.z = center.z - lookAt.z * scalars.radius;\n\n wm.markLocalDirty();\n }\n\n const cam = {\n fov: 0.8,\n nearPlane: 1,\n farPlane: options.planetRadius * 16,\n children: [] as SceneNode[],\n limits,\n position,\n upVector,\n\n _lookAt: lookAt,\n _setOrientation: applyOrientation,\n\n _viewCache: allocateMat4() as unknown as Mat4Storage,\n _projCache: allocateMat4() as unknown as Mat4Storage,\n _vpCache: allocateMat4() as unknown as Mat4Storage,\n\n get parent() {\n return wm.parent;\n },\n set parent(v: IWorldMatrixProvider | null) {\n wm.parent = v;\n },\n get worldMatrix() {\n return wm.getWorldMatrix();\n },\n get worldMatrixVersion() {\n return wm.getWorldMatrixVersion();\n },\n\n get center() {\n return center;\n },\n set center(v: Vec3) {\n applyOrientation(scalars.yaw, scalars.pitch, scalars.radius, v);\n },\n get yaw() {\n return scalars.yaw;\n },\n set yaw(v: number) {\n if (v !== scalars.yaw) {\n applyOrientation(v, scalars.pitch, scalars.radius, center);\n }\n },\n get pitch() {\n return scalars.pitch;\n },\n set pitch(v: number) {\n if (v !== scalars.pitch) {\n applyOrientation(scalars.yaw, v, scalars.radius, center);\n }\n },\n get radius() {\n return scalars.radius;\n },\n set radius(v: number) {\n if (v !== scalars.radius) {\n applyOrientation(scalars.yaw, scalars.pitch, v, center);\n }\n },\n } as unknown as GeospatialCamera;\n\n attachWorldMatrixState(cam, wm);\n\n // Default resting pose: looking straight down at (planetRadius,0,0) from radiusMax.\n const restingRadius = limits.radiusMax !== Infinity ? limits.radiusMax : options.planetRadius * 4;\n applyOrientation(0, 0, restingRadius, center);\n\n return cam;\n}\n\n// ── small local vector helpers (no per-frame allocation) ───────────────────\n\nfunction cross(a: Vec3, b: Vec3, out: Vec3): void {\n const x = a.y * b.z - a.z * b.y;\n const y = a.z * b.x - a.x * b.z;\n const z = a.x * b.y - a.y * b.x;\n out.x = x;\n out.y = y;\n out.z = z;\n}\n\nfunction lengthSq(v: Vec3): number {\n return v.x * v.x + v.y * v.y + v.z * v.z;\n}\n\nfunction normalizeInPlace(v: Vec3): Vec3 {\n const len = Math.hypot(v.x, v.y, v.z);\n if (len > 1e-10) {\n const inv = 1 / len;\n v.x *= inv;\n v.y *= inv;\n v.z *= inv;\n }\n return v;\n}\n"],"names":[],"mappings":";;;;;AAUA,MAAM,MAAA,GAAS,KAAK,EAAA,GAAK,CAAA;AAEzB,MAAM,cAAoB,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAC7C,MAAM,cAAoB,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAE7C,MAAM,eAAA,GAAkB,WAAA;AAiEjB,SAAS,iBAAiB,KAAA,EAAuB;AACpD,EAAA,OAAO,QAAQ,MAAA,GAAS,IAAA,CAAK,OAAO,KAAA,GAAQ,IAAA,CAAK,MAAM,MAAM,CAAA;AACjE;AAEA,SAAS,KAAA,CAAM,CAAA,EAAW,GAAA,EAAa,GAAA,EAAqB;AACxD,EAAA,OAAO,CAAA,GAAI,GAAA,GAAM,GAAA,GAAM,CAAA,GAAI,MAAM,GAAA,GAAM,CAAA;AAC3C;AAQO,SAAS,iBAAA,CAAkB,QAAA,EAAgB,OAAA,EAAe,QAAA,EAAgB,KAAA,EAAmB;AAEhG,EAAA,MAAM,KAAA,GAAQ,KAAK,KAAA,CAAM,QAAA,CAAS,GAAG,QAAA,CAAS,CAAA,EAAG,QAAA,CAAS,CAAC,CAAA,IAAK,CAAA;AAChE,EAAA,KAAA,CAAM,CAAA,GAAI,SAAS,CAAA,GAAI,KAAA;AACvB,EAAA,KAAA,CAAM,CAAA,GAAI,SAAS,CAAA,GAAI,KAAA;AACvB,EAAA,KAAA,CAAM,CAAA,GAAI,SAAS,CAAA,GAAI,KAAA;AAGvB,EAAA,KAAA,CAAM,KAAA,EAAO,aAAa,OAAO,CAAA;AACjC,EAAA,IAAI,QAAA,CAAS,OAAO,CAAA,GAAI,WAAA,EAAa;AAEjC,IAAA,KAAA,CAAM,KAAA,EAAO,aAAa,OAAO,CAAA;AAAA,EACrC;AACA,EAAA,gBAAA,CAAiB,OAAO,CAAA;AAGxB,EAAA,KAAA,CAAM,OAAA,EAAS,OAAO,QAAQ,CAAA;AAC9B,EAAA,gBAAA,CAAiB,QAAQ,CAAA;AAC7B;AAMO,SAAS,yBAAA,CAA0B,GAAA,EAAa,KAAA,EAAe,MAAA,EAAc,MAAA,EAAoB;AACpG,EAAA,MAAM,OAAO,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAChC,EAAA,MAAM,QAAQ,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AACjC,EAAA,MAAM,KAAK,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAC9B,EAAA,iBAAA,CAAkB,MAAA,EAAQ,IAAA,EAAM,KAAA,EAAO,EAAE,CAAA;AAEzC,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAC3B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA;AAG3B,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,CAAA,GAAI,MAAA,GAAS,KAAK,CAAA,GAAI,MAAA;AACvC,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,CAAA,GAAI,MAAA,GAAS,KAAK,CAAA,GAAI,MAAA;AACvC,EAAA,MAAM,EAAA,GAAK,KAAA,CAAM,CAAA,GAAI,MAAA,GAAS,KAAK,CAAA,GAAI,MAAA;AAGvC,EAAA,MAAA,CAAO,CAAA,GAAI,EAAA,GAAK,QAAA,GAAW,EAAA,CAAG,CAAA,GAAI,QAAA;AAClC,EAAA,MAAA,CAAO,CAAA,GAAI,EAAA,GAAK,QAAA,GAAW,EAAA,CAAG,CAAA,GAAI,QAAA;AAClC,EAAA,MAAA,CAAO,CAAA,GAAI,EAAA,GAAK,QAAA,GAAW,EAAA,CAAG,CAAA,GAAI,QAAA;AAClC,EAAA,OAAO,iBAAiB,MAAM,CAAA;AAClC;AAOO,SAAS,yBAAA,CAA0B,MAAA,EAAc,MAAA,EAAc,UAAA,EAAoB,MAAA,EAA4D;AAClJ,EAAA,MAAM,OAAO,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAChC,EAAA,MAAM,QAAQ,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AACjC,EAAA,MAAM,KAAK,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAC9B,EAAA,iBAAA,CAAkB,MAAA,EAAQ,IAAA,EAAM,KAAA,EAAO,EAAE,CAAA;AAEzC,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,CAAA,GAAI,EAAA,CAAG,CAAA,GAAI,MAAA,CAAO,CAAA,GAAI,EAAA,CAAG,CAAA,GAAI,MAAA,CAAO,CAAA,GAAI,EAAA,CAAG,CAAA;AACpE,EAAA,MAAM,WAAW,CAAC,SAAA;AAClB,EAAA,MAAM,QAAQ,IAAA,CAAK,IAAA,CAAK,MAAM,QAAA,EAAU,EAAA,EAAI,CAAC,CAAC,CAAA;AAG9C,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,CAAA,GAAI,EAAA,CAAG,CAAA,GAAI,QAAA;AAC9B,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,CAAA,GAAI,EAAA,CAAG,CAAA,GAAI,QAAA;AAC9B,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,CAAA,GAAI,EAAA,CAAG,CAAA,GAAI,QAAA;AAE9B,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,KAAK,CAAA;AAC/B,EAAA,IAAI,IAAA,CAAK,GAAA,CAAI,QAAQ,CAAA,GAAI,WAAA,EAAa;AAClC,IAAA,MAAA,CAAO,CAAA,GAAI,UAAA;AACX,IAAA,MAAA,CAAO,CAAA,GAAI,KAAA;AACX,IAAA,OAAO,MAAA;AAAA,EACX;AACA,EAAA,MAAM,MAAM,CAAA,GAAI,QAAA;AAChB,EAAA,MAAM,KAAK,GAAA,GAAM,GAAA;AACjB,EAAA,MAAM,KAAK,GAAA,GAAM,GAAA;AACjB,EAAA,MAAM,KAAK,GAAA,GAAM,GAAA;AAEjB,EAAA,MAAM,MAAA,GAAS,KAAK,KAAA,CAAM,CAAA,GAAI,KAAK,KAAA,CAAM,CAAA,GAAI,KAAK,KAAA,CAAM,CAAA;AACxD,EAAA,MAAM,MAAA,GAAS,KAAK,IAAA,CAAK,CAAA,GAAI,KAAK,IAAA,CAAK,CAAA,GAAI,KAAK,IAAA,CAAK,CAAA;AACrD,EAAA,MAAA,CAAO,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,MAAA,EAAQ,MAAM,CAAA;AACpC,EAAA,MAAA,CAAO,CAAA,GAAI,KAAA;AACX,EAAA,OAAO,MAAA;AACX;AAMO,SAAS,qBAAqB,MAAA,EAAoB;AACrD,EAAA,MAAM,GAAA,GAAM,KAAK,KAAA,CAAM,MAAA,CAAO,GAAG,MAAA,CAAO,CAAA,EAAG,OAAO,CAAC,CAAA;AACnD,EAAA,IAAI,MAAM,WAAA,EAAa;AACnB,IAAA,MAAM,MAAA,GAAS,OAAO,CAAA,GAAI,GAAA;AAC1B,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,GAAI,eAAA,EAAiB;AACpC,MAAA,MAAM,UAAA,GAAa,KAAA,CAAM,MAAA,EAAQ,CAAC,iBAAiB,eAAe,CAAA;AAClE,MAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,CAAA,GAAI,aAAa,UAAU,CAAA;AACxD,MAAA,MAAM,MAAM,IAAA,CAAK,KAAA,CAAM,MAAA,CAAO,CAAA,EAAG,OAAO,CAAC,CAAA;AACzC,MAAA,MAAA,CAAO,CAAA,GAAI,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,GAAI,UAAA;AACjC,MAAA,MAAA,CAAO,CAAA,GAAI,GAAA,GAAM,IAAA,CAAK,GAAA,CAAI,GAAG,CAAA,GAAI,UAAA;AACjC,MAAA,MAAA,CAAO,IAAI,GAAA,GAAM,UAAA;AAAA,IACrB;AAAA,EACJ;AACA,EAAA,OAAO,MAAA;AACX;AAGO,SAAS,wBAAA,CAAyB,QAA0B,WAAA,EAA0C;AACzG,EAAA,MAAA,CAAO,gBAAgB,WAAA,CAAY,GAAA,IAAO,MAAA,CAAO,GAAA,EAAK,YAAY,KAAA,IAAS,MAAA,CAAO,KAAA,EAAO,WAAA,CAAY,UAAU,MAAA,CAAO,MAAA,EAAQ,WAAA,CAAY,MAAA,IAAU,OAAO,MAAM,CAAA;AACrK;AAGO,SAAS,uBAAuB,OAAA,EAAoD;AACvF,EAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,OAAA,CAAQ,YAAY,CAAA;AAE1D,EAAA,MAAM,MAAA,GAAe,EAAE,CAAA,EAAG,OAAA,CAAQ,cAAc,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAC3D,EAAA,MAAM,WAAiB,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAC1C,EAAA,MAAM,WAAiB,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAC1C,EAAA,MAAM,SAAe,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AACxC,EAAA,MAAM,UAAU,EAAE,GAAA,EAAK,GAAG,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,EAAE;AAE9C,EAAA,MAAM,YAAkB,YAAA,EAAa;AAErC,EAAA,SAAS,sBAAA,GAA+B;AAEpC,IAAA,MAAM,UAAgB,EAAE,CAAA,EAAG,QAAA,CAAS,CAAA,GAAI,OAAO,CAAA,EAAG,CAAA,EAAG,QAAA,CAAS,CAAA,GAAI,OAAO,CAAA,EAAG,CAAA,EAAG,QAAA,CAAS,CAAA,GAAI,OAAO,CAAA,EAAE;AACrG,IAAA,MAAM,IAAA,GAAO,YAAA,CAAa,QAAA,EAAU,OAAA,EAAS,QAAQ,CAAA;AACrD,IAAA,MAAM,CAAA,GAAI,SAAA;AACV,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACP,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACP,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,CAAC,CAAA,GAAI,IAAA,CAAK,CAAC,CAAA;AACb,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,IAAA,CAAK,EAAE,CAAA;AACf,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA;AACR,IAAA,CAAA,CAAE,EAAE,IAAI,QAAA,CAAS,CAAA;AACjB,IAAA,CAAA,CAAE,EAAE,IAAI,QAAA,CAAS,CAAA;AACjB,IAAA,CAAA,CAAE,EAAE,IAAI,QAAA,CAAS,CAAA;AACjB,IAAA,CAAA,CAAE,EAAE,CAAA,GAAI,CAAA;AACR,IAAA,OAAO,SAAA;AAAA,EACX;AAEA,EAAA,MAAM,EAAA,GAAK,uBAAuB,sBAAsB,CAAA;AAExD,EAAA,SAAS,gBAAA,CAAiB,GAAA,EAAa,KAAA,EAAe,MAAA,EAAgB,SAAA,EAAuB;AACzF,IAAA,OAAA,CAAQ,GAAA,GAAM,iBAAiB,GAAG,CAAA;AAClC,IAAA,OAAA,CAAQ,KAAA,GAAQ,iBAAiB,KAAK,CAAA;AACtC,IAAA,OAAA,CAAQ,MAAA,GAAS,MAAA;AACjB,IAAA,MAAA,CAAO,IAAI,SAAA,CAAU,CAAA;AACrB,IAAA,MAAA,CAAO,IAAI,SAAA,CAAU,CAAA;AACrB,IAAA,MAAA,CAAO,IAAI,SAAA,CAAU,CAAA;AAGrB,IAAA,OAAA,CAAQ,MAAM,KAAA,CAAM,OAAA,CAAQ,KAAK,MAAA,CAAO,MAAA,EAAQ,OAAO,MAAM,CAAA;AAC7D,IAAA,OAAA,CAAQ,KAAA,GAAQ,KAAA,CAAM,OAAA,CAAQ,KAAA,EAAO,MAAA,CAAO,UAAU,oBAAA,CAAqB,MAAA,EAAQ,OAAA,CAAQ,MAAM,CAAC,CAAA;AAClG,IAAA,OAAA,CAAQ,SAAS,KAAA,CAAM,OAAA,CAAQ,QAAQ,MAAA,CAAO,SAAA,EAAW,OAAO,SAAS,CAAA;AACzE,IAAA,oBAAA,CAAqB,MAAM,CAAA;AAG3B,IAAA,MAAM,OAAO,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAChC,IAAA,MAAM,QAAQ,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AACjC,IAAA,MAAM,KAAK,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AAC9B,IAAA,iBAAA,CAAkB,MAAA,EAAQ,IAAA,EAAM,KAAA,EAAO,EAAE,CAAA;AAGzC,IAAA,yBAAA,CAA0B,OAAA,CAAQ,GAAA,EAAK,OAAA,CAAQ,KAAA,EAAO,QAAQ,MAAM,CAAA;AAGpE,IAAA,MAAM,QAAQ,EAAE,CAAA,EAAG,GAAG,CAAA,EAAG,CAAA,EAAG,GAAG,CAAA,EAAE;AACjC,IAAA,KAAA,CAAM,EAAA,EAAI,QAAQ,KAAK,CAAA;AACvB,IAAA,IAAI,QAAA,CAAS,KAAK,CAAA,GAAI,WAAA,EAAa;AAE/B,MAAA,MAAM,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,MAAA,MAAM,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,MAAA,MAAM,KAAA,GAAQ,EAAE,CAAA,EAAG,KAAA,CAAM,IAAI,EAAA,GAAK,IAAA,CAAK,CAAA,GAAI,EAAA,EAAI,CAAA,EAAG,KAAA,CAAM,IAAI,EAAA,GAAK,IAAA,CAAK,IAAI,EAAA,EAAI,CAAA,EAAG,MAAM,CAAA,GAAI,EAAA,GAAK,IAAA,CAAK,CAAA,GAAI,EAAA,EAAG;AAC5G,MAAA,KAAA,CAAM,KAAA,EAAO,QAAQ,KAAK,CAAA;AAAA,IAC9B;AACA,IAAA,gBAAA,CAAiB,KAAK,CAAA;AAGtB,IAAA,KAAA,CAAM,MAAA,EAAQ,OAAO,QAAQ,CAAA;AAC7B,IAAA,gBAAA,CAAiB,QAAQ,CAAA;AAGzB,IAAA,QAAA,CAAS,CAAA,GAAI,MAAA,CAAO,CAAA,GAAI,MAAA,CAAO,IAAI,OAAA,CAAQ,MAAA;AAC3C,IAAA,QAAA,CAAS,CAAA,GAAI,MAAA,CAAO,CAAA,GAAI,MAAA,CAAO,IAAI,OAAA,CAAQ,MAAA;AAC3C,IAAA,QAAA,CAAS,CAAA,GAAI,MAAA,CAAO,CAAA,GAAI,MAAA,CAAO,IAAI,OAAA,CAAQ,MAAA;AAE3C,IAAA,EAAA,CAAG,cAAA,EAAe;AAAA,EACtB;AAEA,EAAA,MAAM,GAAA,GAAM;AAAA,IACR,GAAA,EAAK,GAAA;AAAA,IACL,SAAA,EAAW,CAAA;AAAA,IACX,QAAA,EAAU,QAAQ,YAAA,GAAe,EAAA;AAAA,IACjC,UAAU,EAAC;AAAA,IACX,MAAA;AAAA,IACA,QAAA;AAAA,IACA,QAAA;AAAA,IAEA,OAAA,EAAS,MAAA;AAAA,IACT,eAAA,EAAiB,gBAAA;AAAA,IAEjB,YAAY,YAAA,EAAa;AAAA,IACzB,YAAY,YAAA,EAAa;AAAA,IACzB,UAAU,YAAA,EAAa;AAAA,IAEvB,IAAI,MAAA,GAAS;AACT,MAAA,OAAO,EAAA,CAAG,MAAA;AAAA,IACd,CAAA;AAAA,IACA,IAAI,OAAO,CAAA,EAAgC;AACvC,MAAA,EAAA,CAAG,MAAA,GAAS,CAAA;AAAA,IAChB,CAAA;AAAA,IACA,IAAI,WAAA,GAAc;AACd,MAAA,OAAO,GAAG,cAAA,EAAe;AAAA,IAC7B,CAAA;AAAA,IACA,IAAI,kBAAA,GAAqB;AACrB,MAAA,OAAO,GAAG,qBAAA,EAAsB;AAAA,IACpC,CAAA;AAAA,IAEA,IAAI,MAAA,GAAS;AACT,MAAA,OAAO,MAAA;AAAA,IACX,CAAA;AAAA,IACA,IAAI,OAAO,CAAA,EAAS;AAChB,MAAA,gBAAA,CAAiB,QAAQ,GAAA,EAAK,OAAA,CAAQ,KAAA,EAAO,OAAA,CAAQ,QAAQ,CAAC,CAAA;AAAA,IAClE,CAAA;AAAA,IACA,IAAI,GAAA,GAAM;AACN,MAAA,OAAO,OAAA,CAAQ,GAAA;AAAA,IACnB,CAAA;AAAA,IACA,IAAI,IAAI,CAAA,EAAW;AACf,MAAA,IAAI,CAAA,KAAM,QAAQ,GAAA,EAAK;AACnB,QAAA,gBAAA,CAAiB,CAAA,EAAG,OAAA,CAAQ,KAAA,EAAO,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,MAC7D;AAAA,IACJ,CAAA;AAAA,IACA,IAAI,KAAA,GAAQ;AACR,MAAA,OAAO,OAAA,CAAQ,KAAA;AAAA,IACnB,CAAA;AAAA,IACA,IAAI,MAAM,CAAA,EAAW;AACjB,MAAA,IAAI,CAAA,KAAM,QAAQ,KAAA,EAAO;AACrB,QAAA,gBAAA,CAAiB,OAAA,CAAQ,GAAA,EAAK,CAAA,EAAG,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,MAC3D;AAAA,IACJ,CAAA;AAAA,IACA,IAAI,MAAA,GAAS;AACT,MAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,IACnB,CAAA;AAAA,IACA,IAAI,OAAO,CAAA,EAAW;AAClB,MAAA,IAAI,CAAA,KAAM,QAAQ,MAAA,EAAQ;AACtB,QAAA,gBAAA,CAAiB,OAAA,CAAQ,GAAA,EAAK,OAAA,CAAQ,KAAA,EAAO,GAAG,MAAM,CAAA;AAAA,MAC1D;AAAA,IACJ;AAAA,GACJ;AAEA,EAAA,sBAAA,CAAuB,KAAK,EAAE,CAAA;AAG9B,EAAA,MAAM,gBAAgB,MAAA,CAAO,SAAA,KAAc,WAAW,MAAA,CAAO,SAAA,GAAY,QAAQ,YAAA,GAAe,CAAA;AAChG,EAAA,gBAAA,CAAiB,CAAA,EAAG,CAAA,EAAG,aAAA,EAAe,MAAM,CAAA;AAE5C,EAAA,OAAO,GAAA;AACX;AAIA,SAAS,KAAA,CAAM,CAAA,EAAS,CAAA,EAAS,GAAA,EAAiB;AAC9C,EAAA,MAAM,IAAI,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,GAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AAC9B,EAAA,MAAM,IAAI,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,GAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AAC9B,EAAA,MAAM,IAAI,CAAA,CAAE,CAAA,GAAI,EAAE,CAAA,GAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA;AAC9B,EAAA,GAAA,CAAI,CAAA,GAAI,CAAA;AACR,EAAA,GAAA,CAAI,CAAA,GAAI,CAAA;AACR,EAAA,GAAA,CAAI,CAAA,GAAI,CAAA;AACZ;AAEA,SAAS,SAAS,CAAA,EAAiB;AAC/B,EAAA,OAAO,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,IAAI,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAA;AAC3C;AAEA,SAAS,iBAAiB,CAAA,EAAe;AACrC,EAAA,MAAM,GAAA,GAAM,KAAK,KAAA,CAAM,CAAA,CAAE,GAAG,CAAA,CAAE,CAAA,EAAG,EAAE,CAAC,CAAA;AACpC,EAAA,IAAI,MAAM,KAAA,EAAO;AACb,IAAA,MAAM,MAAM,CAAA,GAAI,GAAA;AAChB,IAAA,CAAA,CAAE,CAAA,IAAK,GAAA;AACP,IAAA,CAAA,CAAE,CAAA,IAAK,GAAA;AACP,IAAA,CAAA,CAAE,CAAA,IAAK,GAAA;AAAA,EACX;AACA,EAAA,OAAO,CAAA;AACX;;;;"}
1
+ {"version":3,"file":"geospatial-camera.js","sources":["../../../src/camera/geospatial-camera.ts"],"sourcesContent":["import type { Camera, NormalizedViewport } from \"./camera.js\";\nimport type { Vec3, Mat4, Mat4Storage } from \"../math/types.js\";\nimport type { SceneNode } from \"../scene/scene-node.js\";\nimport type { IWorldMatrixProvider, IParentable } from \"../scene/parentable.js\";\nimport { createWorldMatrixState, attachWorldMatrixState } from \"../scene/world-matrix-state.js\";\nimport { allocateMat4 } from \"../math/_matrix-allocator.js\";\nimport { mat4LookAtWorldLHToRef } from \"../math/mat4-look-at-world-lh.js\";\nimport type { GeospatialLimits } from \"./geospatial-limits.js\";\nimport { createGeospatialLimits, getEffectivePitchMax, GEO_EPSILON } from \"./geospatial-limits.js\";\n\nconst TWO_PI = Math.PI * 2;\n/** Babylon.js world \"north\" axis in a left-handed scene = +Z (LeftHandedForward). */\nconst WORLD_NORTH: Vec3 = { x: 0, y: 0, z: 1 };\nconst WORLD_RIGHT: Vec3 = { x: 1, y: 0, z: 0 };\n/** sin of the spherical-latitude limit (~89.96°) used to keep the centre off the poles. */\nconst POLE_SINE_LIMIT = 0.998749218;\n\n/** Options for {@link createGeospatialCamera}. */\nexport interface GeospatialCameraOptions {\n /** Radius of the planet being orbited. */\n planetRadius: number;\n}\n\n/** A delta to apply via {@link setGeospatialOrientation}; omitted fields keep their current value. */\nexport interface GeospatialOrientation {\n /** Yaw in radians (0 = north, π/2 = east). */\n yaw?: number;\n /** Pitch in radians (0 = looking straight down at the planet centre, π/2 = horizon). */\n pitch?: number;\n /** Distance from the camera to its centre point. */\n radius?: number;\n /** Anchor point on the globe (ECEF) that the camera orbits. */\n center?: Vec3;\n}\n\n/** Camera that orbits a spherical planet centred at the world origin (Babylon.js `GeospatialCamera`).\n *\n * Orientation is fully described by `center` (the anchored point on the globe in\n * ECEF coordinates), `yaw`, `pitch`, and `radius`. Setting any of these\n * recomputes the derived `position` / `upVector` and the view matrix.\n *\n * Pure state — behaviour is provided by standalone functions\n * ({@link setGeospatialOrientation}, `attachGeospatialControls`,\n * `flyGeospatialCameraToAsync`). The camera never references the scene. */\nexport interface GeospatialCamera extends Camera, IWorldMatrixProvider, IParentable {\n /** The anchored point on the globe (ECEF). Assigning re-orbits around the new centre. */\n center: Vec3;\n /** Yaw about the geocentric up axis. Wrapped to [-π, π). 0 = north, π/2 = east. */\n yaw: number;\n /** Pitch from looking straight down (0) to the horizon (π/2). Wrapped to [-π, π). */\n pitch: number;\n /** Distance from the camera to its centre point (distinct from `planetRadius`). */\n radius: number;\n /** Limits governing yaw/pitch/radius clamping. Mutable; clamping applies on the next orientation change. */\n limits: GeospatialLimits;\n /** Derived world-space eye position. Read-only — driven by center/yaw/pitch/radius. */\n readonly position: Vec3;\n /** Derived camera up vector. Read-only. */\n readonly upVector: Vec3;\n\n fov: number;\n nearPlane: number;\n farPlane: number;\n viewport?: NormalizedViewport;\n children: SceneNode[];\n parent: IWorldMatrixProvider | null;\n readonly worldMatrix: Mat4;\n readonly worldMatrixVersion: number;\n\n /** @internal Current normalized lookAt (unit) direction. */\n _lookAt: Vec3;\n /** @internal Recompute orientation from raw yaw/pitch/radius/center, applying limits.\n * Used by the controls/flyTo modules to drive the camera in one shot. */\n _setOrientation: (yaw: number, pitch: number, radius: number, center: Vec3) => void;\n /** @internal Cancels an in-flight `flyGeospatialCameraToAsync` animation. Set while a\n * flight is active; the controls loop calls it when user input arrives. */\n _cancelFly?: () => void;\n}\n\n/** Wrap an angle to [-π, π), matching Babylon.js `Scalar.NormalizeRadians`. */\nexport function normalizeRadians(angle: number): number {\n return angle - TWO_PI * Math.floor((angle + Math.PI) / TWO_PI);\n}\n\nfunction clamp(v: number, min: number, max: number): number {\n return v < min ? min : v > max ? max : v;\n}\n\n/**\n * Build the east/north/up orthonormal basis at a point on the globe (left-handed\n * convention). `up` is the geocentric normal (normalized position); `east` and\n * `north` complete a right-handed-looking tangent frame given the LH world.\n * Writes into the provided result objects and returns nothing.\n */\nexport function computeLocalBasis(worldPos: Vec3, refEast: Vec3, refNorth: Vec3, refUp: Vec3): void {\n // up = normalized position (geocentric normal)\n const upLen = Math.hypot(worldPos.x, worldPos.y, worldPos.z) || 1;\n refUp.x = worldPos.x / upLen;\n refUp.y = worldPos.y / upLen;\n refUp.z = worldPos.z / upLen;\n\n // east = cross(up, worldNorth)\n cross(refUp, WORLD_NORTH, refEast);\n if (lengthSq(refEast) < GEO_EPSILON) {\n // At a pole, cross with worldRight instead.\n cross(refUp, WORLD_RIGHT, refEast);\n }\n normalizeInPlace(refEast);\n\n // north = cross(east, up)\n cross(refEast, refUp, refNorth);\n normalizeInPlace(refNorth);\n}\n\n/**\n * Compute the lookAt direction from yaw/pitch at a centre point (forward formula).\n * Writes the normalized direction into `result`.\n */\nexport function computeLookAtFromYawPitch(yaw: number, pitch: number, center: Vec3, result: Vec3): Vec3 {\n const east = { x: 0, y: 0, z: 0 };\n const north = { x: 0, y: 0, z: 0 };\n const up = { x: 0, y: 0, z: 0 };\n computeLocalBasis(center, east, north, up);\n\n const sinPitch = Math.sin(pitch);\n const cosPitch = Math.cos(pitch);\n const cosYaw = Math.cos(yaw);\n const sinYaw = Math.sin(yaw);\n\n // horiz = north*cos(yaw) + east*sin(yaw)\n const hx = north.x * cosYaw + east.x * sinYaw;\n const hy = north.y * cosYaw + east.y * sinYaw;\n const hz = north.z * cosYaw + east.z * sinYaw;\n\n // lookAt = horiz*sinPitch - up*cosPitch\n result.x = hx * sinPitch - up.x * cosPitch;\n result.y = hy * sinPitch - up.y * cosPitch;\n result.z = hz * sinPitch - up.z * cosPitch;\n return normalizeInPlace(result);\n}\n\n/**\n * Inverse of {@link computeLookAtFromYawPitch}: given a lookAt direction and centre,\n * recover the yaw/pitch that would produce it. Writes `[yaw, pitch]` into `result`.\n * `currentYaw` is used as a fallback when looking straight down/up (yaw undefined).\n */\nexport function computeYawPitchFromLookAt(lookAt: Vec3, center: Vec3, currentYaw: number, result: { x: number; y: number }): { x: number; y: number } {\n const east = { x: 0, y: 0, z: 0 };\n const north = { x: 0, y: 0, z: 0 };\n const up = { x: 0, y: 0, z: 0 };\n computeLocalBasis(center, east, north, up);\n\n const lookDotUp = lookAt.x * up.x + lookAt.y * up.y + lookAt.z * up.z;\n const cosPitch = -lookDotUp;\n const pitch = Math.acos(clamp(cosPitch, -1, 1));\n\n // lookHorizontal = lookAt + up*cosPitch = horiz*sinPitch\n const lhx = lookAt.x + up.x * cosPitch;\n const lhy = lookAt.y + up.y * cosPitch;\n const lhz = lookAt.z + up.z * cosPitch;\n\n const sinPitch = Math.sin(pitch);\n if (Math.abs(sinPitch) < GEO_EPSILON) {\n result.x = currentYaw;\n result.y = pitch;\n return result;\n }\n const inv = 1 / sinPitch;\n const hx = lhx * inv;\n const hy = lhy * inv;\n const hz = lhz * inv;\n\n const cosYaw = hx * north.x + hy * north.y + hz * north.z;\n const sinYaw = hx * east.x + hy * east.y + hz * east.z;\n result.x = Math.atan2(sinYaw, cosYaw);\n result.y = pitch;\n return result;\n}\n\n/**\n * Clamp the camera centre away from the geographic poles (in place), so the\n * tangent basis stays well-defined. Mirrors Babylon.js `ClampCenterFromPolesInPlace`.\n */\nexport function clampCenterFromPoles(center: Vec3): Vec3 {\n const mag = Math.hypot(center.x, center.y, center.z);\n if (mag > GEO_EPSILON) {\n const sinLat = center.z / mag;\n if (Math.abs(sinLat) > POLE_SINE_LIMIT) {\n const sinClamped = clamp(sinLat, -POLE_SINE_LIMIT, POLE_SINE_LIMIT);\n const cosClamped = Math.sqrt(1 - sinClamped * sinClamped);\n const lon = Math.atan2(center.y, center.x);\n center.x = mag * Math.cos(lon) * cosClamped;\n center.y = mag * Math.sin(lon) * cosClamped;\n center.z = mag * sinClamped;\n }\n }\n return center;\n}\n\n/** Set one or more orientation fields at once (single recompute). Omitted fields keep their value. */\nexport function setGeospatialOrientation(camera: GeospatialCamera, orientation: GeospatialOrientation): void {\n camera._setOrientation(orientation.yaw ?? camera.yaw, orientation.pitch ?? camera.pitch, orientation.radius ?? camera.radius, orientation.center ?? camera.center);\n}\n\n/** Create a {@link GeospatialCamera} for a planet of the given radius. Pure data, no scene knowledge. */\nexport function createGeospatialCamera(options: GeospatialCameraOptions): GeospatialCamera {\n const limits = createGeospatialLimits(options.planetRadius);\n\n const center: Vec3 = { x: options.planetRadius, y: 0, z: 0 };\n const position: Vec3 = { x: 0, y: 0, z: 0 };\n const upVector: Vec3 = { x: 0, y: 1, z: 0 };\n const lookAt: Vec3 = { x: 0, y: 0, z: 0 };\n const scalars = { yaw: 0, pitch: 0, radius: 0 };\n\n const _localMat: Mat4 = allocateMat4();\n\n function cameraLocalWorldMatrix(): Mat4 {\n const center3: Vec3 = { x: position.x + lookAt.x, y: position.y + lookAt.y, z: position.z + lookAt.z };\n mat4LookAtWorldLHToRef(_localMat as unknown as Mat4Storage, position, center3, upVector);\n return _localMat;\n }\n\n const wm = createWorldMatrixState(cameraLocalWorldMatrix);\n\n function applyOrientation(yaw: number, pitch: number, radius: number, newCenter: Vec3): void {\n scalars.yaw = normalizeRadians(yaw);\n scalars.pitch = normalizeRadians(pitch);\n scalars.radius = radius;\n center.x = newCenter.x;\n center.y = newCenter.y;\n center.z = newCenter.z;\n\n // Clamp to limits.\n scalars.yaw = clamp(scalars.yaw, limits.yawMin, limits.yawMax);\n scalars.pitch = clamp(scalars.pitch, limits.pitchMin, getEffectivePitchMax(limits, scalars.radius));\n scalars.radius = clamp(scalars.radius, limits.radiusMin, limits.radiusMax);\n clampCenterFromPoles(center);\n\n // Tangent basis at the (clamped) centre.\n const east = { x: 0, y: 0, z: 0 };\n const north = { x: 0, y: 0, z: 0 };\n const up = { x: 0, y: 0, z: 0 };\n computeLocalBasis(center, east, north, up);\n\n // lookAt from yaw/pitch.\n computeLookAtFromYawPitch(scalars.yaw, scalars.pitch, center, lookAt);\n\n // Build an orthonormal camera up aligned with geocentric up.\n const right = { x: 0, y: 0, z: 0 };\n cross(up, lookAt, right);\n if (lengthSq(right) < GEO_EPSILON) {\n // Looking straight down: lookAt ∥ up → use the horizontal direction.\n const cy = Math.cos(scalars.yaw);\n const sy = Math.sin(scalars.yaw);\n const horiz = { x: north.x * cy + east.x * sy, y: north.y * cy + east.y * sy, z: north.z * cy + east.z * sy };\n cross(horiz, lookAt, right);\n }\n normalizeInPlace(right);\n\n // up = normalize(cross(look, right))\n cross(lookAt, right, upVector);\n normalizeInPlace(upVector);\n\n // position = center - look*radius\n position.x = center.x - lookAt.x * scalars.radius;\n position.y = center.y - lookAt.y * scalars.radius;\n position.z = center.z - lookAt.z * scalars.radius;\n\n wm.markLocalDirty();\n }\n\n const cam = {\n fov: 0.8,\n nearPlane: 1,\n farPlane: options.planetRadius * 16,\n children: [] as SceneNode[],\n limits,\n position,\n upVector,\n\n _lookAt: lookAt,\n _setOrientation: applyOrientation,\n\n _viewCache: allocateMat4() as unknown as Mat4Storage,\n _projCache: allocateMat4() as unknown as Mat4Storage,\n _vpCache: allocateMat4() as unknown as Mat4Storage,\n\n get parent() {\n return wm.parent;\n },\n set parent(v: IWorldMatrixProvider | null) {\n wm.parent = v;\n },\n get worldMatrix() {\n return wm.getWorldMatrix();\n },\n get worldMatrixVersion() {\n return wm.getWorldMatrixVersion();\n },\n\n get center() {\n return center;\n },\n set center(v: Vec3) {\n applyOrientation(scalars.yaw, scalars.pitch, scalars.radius, v);\n },\n get yaw() {\n return scalars.yaw;\n },\n set yaw(v: number) {\n if (v !== scalars.yaw) {\n applyOrientation(v, scalars.pitch, scalars.radius, center);\n }\n },\n get pitch() {\n return scalars.pitch;\n },\n set pitch(v: number) {\n if (v !== scalars.pitch) {\n applyOrientation(scalars.yaw, v, scalars.radius, center);\n }\n },\n get radius() {\n return scalars.radius;\n },\n set radius(v: number) {\n if (v !== scalars.radius) {\n applyOrientation(scalars.yaw, scalars.pitch, v, center);\n }\n },\n } as unknown as GeospatialCamera;\n\n attachWorldMatrixState(cam, wm);\n\n // Default resting pose: looking straight down at (planetRadius,0,0) from radiusMax.\n const restingRadius = limits.radiusMax !== Infinity ? limits.radiusMax : options.planetRadius * 4;\n applyOrientation(0, 0, restingRadius, center);\n\n return cam;\n}\n\n// ── small local vector helpers (no per-frame allocation) ───────────────────\n\nfunction cross(a: Vec3, b: Vec3, out: Vec3): void {\n const x = a.y * b.z - a.z * b.y;\n const y = a.z * b.x - a.x * b.z;\n const z = a.x * b.y - a.y * b.x;\n out.x = x;\n out.y = y;\n out.z = z;\n}\n\nfunction lengthSq(v: Vec3): number {\n return v.x * v.x + v.y * v.y + v.z * v.z;\n}\n\nfunction normalizeInPlace(v: Vec3): Vec3 {\n const len = Math.hypot(v.x, v.y, v.z);\n if (len > 1e-10) {\n const inv = 1 / len;\n v.x *= inv;\n v.y *= inv;\n v.z *= inv;\n }\n return v;\n}\n"],"names":[],"mappings":"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"}