@babylonjs/core 8.37.3 → 8.39.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 (127) hide show
  1. package/Animations/animation.d.ts +3 -1
  2. package/Animations/animation.js +5 -4
  3. package/Animations/animation.js.map +1 -1
  4. package/Behaviors/Cameras/autoRotationBehavior.d.ts +4 -0
  5. package/Behaviors/Cameras/autoRotationBehavior.js +7 -0
  6. package/Behaviors/Cameras/autoRotationBehavior.js.map +1 -1
  7. package/Behaviors/Cameras/bouncingBehavior.d.ts +5 -0
  8. package/Behaviors/Cameras/bouncingBehavior.js +8 -0
  9. package/Behaviors/Cameras/bouncingBehavior.js.map +1 -1
  10. package/Behaviors/Cameras/framingBehavior.d.ts +4 -0
  11. package/Behaviors/Cameras/framingBehavior.js +7 -0
  12. package/Behaviors/Cameras/framingBehavior.js.map +1 -1
  13. package/Behaviors/Cameras/interpolatingBehavior.d.ts +7 -1
  14. package/Behaviors/Cameras/interpolatingBehavior.js +21 -6
  15. package/Behaviors/Cameras/interpolatingBehavior.js.map +1 -1
  16. package/Behaviors/Meshes/attachToBoxBehavior.d.ts +5 -0
  17. package/Behaviors/Meshes/attachToBoxBehavior.js +8 -1
  18. package/Behaviors/Meshes/attachToBoxBehavior.js.map +1 -1
  19. package/Behaviors/Meshes/baseSixDofDragBehavior.d.ts +5 -2
  20. package/Behaviors/Meshes/baseSixDofDragBehavior.js +8 -0
  21. package/Behaviors/Meshes/baseSixDofDragBehavior.js.map +1 -1
  22. package/Behaviors/Meshes/fadeInOutBehavior.d.ts +5 -0
  23. package/Behaviors/Meshes/fadeInOutBehavior.js +6 -0
  24. package/Behaviors/Meshes/fadeInOutBehavior.js.map +1 -1
  25. package/Behaviors/Meshes/handConstraintBehavior.d.ts +5 -0
  26. package/Behaviors/Meshes/handConstraintBehavior.js +8 -0
  27. package/Behaviors/Meshes/handConstraintBehavior.js.map +1 -1
  28. package/Behaviors/Meshes/multiPointerScaleBehavior.d.ts +5 -0
  29. package/Behaviors/Meshes/multiPointerScaleBehavior.js +8 -0
  30. package/Behaviors/Meshes/multiPointerScaleBehavior.js.map +1 -1
  31. package/Behaviors/Meshes/sixDofDragBehavior.js +1 -1
  32. package/Behaviors/Meshes/sixDofDragBehavior.js.map +1 -1
  33. package/Behaviors/Meshes/surfaceMagnetismBehavior.d.ts +5 -0
  34. package/Behaviors/Meshes/surfaceMagnetismBehavior.js +7 -0
  35. package/Behaviors/Meshes/surfaceMagnetismBehavior.js.map +1 -1
  36. package/Behaviors/behavior.d.ts +4 -0
  37. package/Behaviors/behavior.js.map +1 -1
  38. package/Cameras/Inputs/geospatialCameraPointersInput.js +3 -5
  39. package/Cameras/Inputs/geospatialCameraPointersInput.js.map +1 -1
  40. package/Cameras/geospatialCamera.d.ts +19 -1
  41. package/Cameras/geospatialCamera.js +117 -28
  42. package/Cameras/geospatialCamera.js.map +1 -1
  43. package/Cameras/geospatialCameraMovement.d.ts +7 -2
  44. package/Cameras/geospatialCameraMovement.js +46 -10
  45. package/Cameras/geospatialCameraMovement.js.map +1 -1
  46. package/Engines/WebGPU/Extensions/engine.multiRender.d.ts +2 -1
  47. package/Engines/WebGPU/Extensions/engine.multiRender.js +5 -2
  48. package/Engines/WebGPU/Extensions/engine.multiRender.js.map +1 -1
  49. package/Engines/WebGPU/webgpuTextureHelper.d.ts +1 -0
  50. package/Engines/WebGPU/webgpuTextureHelper.js +11 -0
  51. package/Engines/WebGPU/webgpuTextureHelper.js.map +1 -1
  52. package/Engines/WebGPU/webgpuTextureManager.d.ts +1 -0
  53. package/Engines/WebGPU/webgpuTextureManager.js +100 -9
  54. package/Engines/WebGPU/webgpuTextureManager.js.map +1 -1
  55. package/Engines/abstractEngine.js +2 -2
  56. package/Engines/abstractEngine.js.map +1 -1
  57. package/Engines/renderTargetWrapper.js +6 -1
  58. package/Engines/renderTargetWrapper.js.map +1 -1
  59. package/Engines/thinEngine.js +1 -1
  60. package/Engines/thinEngine.js.map +1 -1
  61. package/Engines/webgpuEngine.d.ts +7 -4
  62. package/Engines/webgpuEngine.js +45 -16
  63. package/Engines/webgpuEngine.js.map +1 -1
  64. package/FrameGraph/Node/nodeRenderGraph.d.ts +22 -5
  65. package/FrameGraph/Node/nodeRenderGraph.js +39 -18
  66. package/FrameGraph/Node/nodeRenderGraph.js.map +1 -1
  67. package/FrameGraph/Passes/pass.d.ts +2 -0
  68. package/FrameGraph/Passes/pass.js +2 -0
  69. package/FrameGraph/Passes/pass.js.map +1 -1
  70. package/FrameGraph/Passes/renderPass.d.ts +2 -0
  71. package/FrameGraph/Passes/renderPass.js +4 -0
  72. package/FrameGraph/Passes/renderPass.js.map +1 -1
  73. package/FrameGraph/frameGraph.d.ts +13 -4
  74. package/FrameGraph/frameGraph.js +45 -5
  75. package/FrameGraph/frameGraph.js.map +1 -1
  76. package/FrameGraph/frameGraphRenderTarget.d.ts +1 -0
  77. package/FrameGraph/frameGraphRenderTarget.js +3 -0
  78. package/FrameGraph/frameGraphRenderTarget.js.map +1 -1
  79. package/FrameGraph/frameGraphTask.d.ts +6 -0
  80. package/FrameGraph/frameGraphTask.js +15 -0
  81. package/FrameGraph/frameGraphTask.js.map +1 -1
  82. package/FrameGraph/frameGraphTypes.d.ts +2 -0
  83. package/FrameGraph/frameGraphTypes.js.map +1 -1
  84. package/Helpers/sceneHelpers.js +1 -1
  85. package/Helpers/sceneHelpers.js.map +1 -1
  86. package/Lights/index.d.ts +1 -0
  87. package/Lights/index.js +1 -0
  88. package/Lights/index.js.map +1 -1
  89. package/Lights/lightingVolume.d.ts +89 -0
  90. package/Lights/lightingVolume.js +426 -0
  91. package/Lights/lightingVolume.js.map +1 -0
  92. package/Materials/Node/nodeMaterial.js +8 -2
  93. package/Materials/Node/nodeMaterial.js.map +1 -1
  94. package/Materials/floatingOriginMatrixOverrides.js +6 -5
  95. package/Materials/floatingOriginMatrixOverrides.js.map +1 -1
  96. package/Meshes/mesh.js +1 -1
  97. package/Meshes/mesh.js.map +1 -1
  98. package/Misc/screenshotTools.js +2 -8
  99. package/Misc/screenshotTools.js.map +1 -1
  100. package/Particles/Node/Blocks/index.d.ts +1 -0
  101. package/Particles/Node/Blocks/index.js +1 -0
  102. package/Particles/Node/Blocks/index.js.map +1 -1
  103. package/Particles/Node/Blocks/particleFloatToIntBlock.d.ts +46 -0
  104. package/Particles/Node/Blocks/particleFloatToIntBlock.js +120 -0
  105. package/Particles/Node/Blocks/particleFloatToIntBlock.js.map +1 -0
  106. package/Particles/Node/Blocks/systemBlock.d.ts +4 -4
  107. package/Particles/Node/Blocks/systemBlock.js +22 -16
  108. package/Particles/Node/Blocks/systemBlock.js.map +1 -1
  109. package/Particles/Node/nodeParticleBuildState.js +1 -1
  110. package/Particles/Node/nodeParticleBuildState.js.map +1 -1
  111. package/Particles/Node/nodeParticleSystemSet.helper.js +61 -30
  112. package/Particles/Node/nodeParticleSystemSet.helper.js.map +1 -1
  113. package/Particles/solidParticle.d.ts +9 -0
  114. package/Particles/solidParticle.js +11 -0
  115. package/Particles/solidParticle.js.map +1 -1
  116. package/Particles/solidParticleSystem.d.ts +28 -0
  117. package/Particles/solidParticleSystem.js +75 -0
  118. package/Particles/solidParticleSystem.js.map +1 -1
  119. package/Particles/thinParticleSystem.d.ts +6 -0
  120. package/Particles/thinParticleSystem.js +21 -12
  121. package/Particles/thinParticleSystem.js.map +1 -1
  122. package/ShadersWGSL/lightingVolume.compute.d.ts +5 -0
  123. package/ShadersWGSL/lightingVolume.compute.js +27 -0
  124. package/ShadersWGSL/lightingVolume.compute.js.map +1 -0
  125. package/package.json +1 -1
  126. package/scene.js +6 -4
  127. package/scene.js.map +1 -1
@@ -3,8 +3,8 @@ import { Vector3, Matrix, TmpVectors } from "../Maths/math.vector.js";
3
3
  import { Epsilon } from "../Maths/math.constants.js";
4
4
  import { Camera } from "./camera.js";
5
5
  import { GeospatialLimits } from "./Limits/geospatialLimits.js";
6
- import { ComputeLocalBasisToRefs, GeospatialCameraMovement } from "./geospatialCameraMovement.js";
7
- import { Vector3CopyToRef, Vector3Dot } from "../Maths/math.vector.functions.js";
6
+ import { ClampCenterFromPolesInPlace, ComputeLocalBasisToRefs, GeospatialCameraMovement } from "./geospatialCameraMovement.js";
7
+ import { Vector3CopyToRef, Vector3Distance } from "../Maths/math.vector.functions.js";
8
8
  import { Clamp } from "../Maths/math.scalar.functions.js";
9
9
  import { InterpolatingBehavior } from "../Behaviors/Cameras/interpolatingBehavior.js";
10
10
  /**
@@ -18,6 +18,7 @@ export class GeospatialCamera extends Camera {
18
18
  super(name, new Vector3(), scene);
19
19
  // Temp vars
20
20
  this._tempPosition = new Vector3();
21
+ this._tempCenter = new Vector3();
21
22
  this._viewMatrix = new Matrix();
22
23
  this._lookAtVector = new Vector3();
23
24
  this._flyToTargets = new Map();
@@ -33,7 +34,7 @@ export class GeospatialCamera extends Camera {
33
34
  this._resetToDefault(this._limits);
34
35
  this._flyingBehavior = new InterpolatingBehavior();
35
36
  this.addBehavior(this._flyingBehavior);
36
- this.movement = new GeospatialCameraMovement(scene, this._limits, this.position, this.center, this._lookAtVector, pickPredicate);
37
+ this.movement = new GeospatialCameraMovement(scene, this._limits, this.position, this.center, this._lookAtVector, pickPredicate, this._flyingBehavior);
37
38
  this.pickPredicate = pickPredicate;
38
39
  this.inputs = new GeospatialCameraInputsManager(this);
39
40
  this.inputs.addMouse().addMouseWheel().addKeyboard();
@@ -95,6 +96,7 @@ export class GeospatialCamera extends Camera {
95
96
  this._yaw = Clamp(this._yaw, limits.yawMin, limits.yawMax);
96
97
  this._pitch = Clamp(this._pitch, limits.pitchMin, limits.pitchMax);
97
98
  this._radius = Clamp(this._radius, limits.radiusMin, limits.radiusMax);
99
+ this._center = ClampCenterFromPolesInPlace(this._center);
98
100
  }
99
101
  _setOrientation(yaw, pitch, radius, center) {
100
102
  this._yaw = yaw;
@@ -160,15 +162,56 @@ export class GeospatialCamera extends Camera {
160
162
  * @param targetCenter
161
163
  * @param flightDurationMs
162
164
  * @param easingFunction
165
+ * @param centerHopScale If supplied, will define the parabolic hop height scale for center animation to create a "bounce" effect
163
166
  * @returns Promise that will return when the animation is complete (or interuppted by pointer input)
164
167
  */
165
- async flyToAsync(targetYaw, targetPitch, targetRadius, targetCenter, flightDurationMs = 1000, easingFunction) {
168
+ async flyToAsync(targetYaw, targetPitch, targetRadius, targetCenter, flightDurationMs = 1000, easingFunction, centerHopScale) {
166
169
  this._flyToTargets.clear();
167
170
  this._flyToTargets.set("yaw", targetYaw);
168
171
  this._flyToTargets.set("pitch", targetPitch);
169
172
  this._flyToTargets.set("radius", targetRadius);
170
173
  this._flyToTargets.set("center", targetCenter);
171
- return await this._flyingBehavior.animatePropertiesAsync(this._flyToTargets, flightDurationMs, easingFunction);
174
+ let overrideAnimationFunction;
175
+ if (targetCenter !== undefined && !targetCenter.equals(this.center)) {
176
+ // Animate center directly with custom interpolation
177
+ const start = this.center.clone();
178
+ const end = targetCenter.clone();
179
+ overrideAnimationFunction = (key, animation) => {
180
+ if (key === "center") {
181
+ // Override the Vector3 interpolation to use SLERP + hop
182
+ animation.vector3InterpolateFunction = (startValue, endValue, gradient) => {
183
+ // gradient is the eased value (0 to 1) after easing function is applied
184
+ // Slerp between start and end
185
+ const newCenter = Vector3.SlerpToRef(start, end, gradient, this._tempCenter);
186
+ // Apply parabolic hop if requested
187
+ if (centerHopScale && centerHopScale > 0) {
188
+ // Parabolic formula: peaks at t=0.5, returns to 0 at gradient=0 and gradient=1
189
+ // if hopPeakT = .5 the denominator would be hopPeakT * hopPeakT - hopPeakT, which = -.25
190
+ const hopPeakOffset = centerHopScale * Vector3Distance(start, end);
191
+ const hopOffset = hopPeakOffset * Clamp((gradient * gradient - gradient) / -0.25);
192
+ // Scale the center outward (away from origin)
193
+ newCenter.scaleInPlace(1 + hopOffset / newCenter.length());
194
+ }
195
+ return newCenter;
196
+ };
197
+ }
198
+ };
199
+ }
200
+ return await this._flyingBehavior.animatePropertiesAsync(this._flyToTargets, flightDurationMs, easingFunction, overrideAnimationFunction);
201
+ }
202
+ /**
203
+ * Helper function to move camera towards a given point by radiusScale% of radius (by default 50%)
204
+ * @param destination point to move towards
205
+ * @param radiusScale value between 0 and 1, % of radius to move
206
+ * @param durationMs duration of flight, default 1s
207
+ * @param easingFn optional easing function for flight interpolation of properties
208
+ * @param overshootRadiusScale optional scale to apply to the current radius to achieve a 'hop' animation
209
+ */
210
+ async flyToPointAsync(destination, radiusScale = 0.5, durationMs = 1000, easingFn, overshootRadiusScale) {
211
+ // Zoom to radiusScale% of radius towards the given destination point
212
+ const zoomDistance = this.radius * radiusScale;
213
+ const newRadius = this._getCenterAndRadiusFromZoomToPoint(destination, zoomDistance, this._tempCenter);
214
+ await this.flyToAsync(undefined, undefined, newRadius, this._tempCenter, durationMs, easingFn, overshootRadiusScale);
172
215
  }
173
216
  get limits() {
174
217
  return this._limits;
@@ -236,47 +279,93 @@ export class GeospatialCamera extends Camera {
236
279
  this._setOrientation(yaw, pitch, this._radius, this._geocentricRotationPt);
237
280
  }
238
281
  }
239
- _applyZoom(zoomVector, distance) {
240
- // TODO this function will be re-worked shortly after checkin, becuase today it breaks down if you zoom to a point past the center
241
- // (ex: tilted view zooming towards cursor near horizon where the center is closer than the cursor point).
242
- // Project zoom vector onto lookAt vector to find the amount the camera-to-center distance should change.
243
- // - zoom vector is normalized
244
- // - distance is how much to move in this call
245
- const directionDotLookAt = Vector3Dot(zoomVector, this._lookAtVector);
246
- const hasRadialComponent = Math.abs(directionDotLookAt) > Epsilon;
247
- const requestedRadius = hasRadialComponent ? this._radius - distance * directionDotLookAt : this._radius;
282
+ _getCenterAndRadiusFromZoomToPoint(targetPoint, distance, newCenter) {
283
+ // Clamp new radius to limits
284
+ const requestedRadius = this._radius - distance;
248
285
  const newRadius = Clamp(requestedRadius, this.limits.radiusMin, this.limits.radiusMax);
249
- const actualRadiusChange = newRadius - this._radius;
250
- const actualDistanceChange = hasRadialComponent ? actualRadiusChange / directionDotLookAt : 0;
251
- // Use this to compute new camera position and new center position.
252
- const newCameraPosition = this._position.add(zoomVector.scale(-actualDistanceChange));
253
- const newCenter = newCameraPosition.add(this._lookAtVector.scaleToRef(newRadius, TmpVectors.Vector3[3]));
254
- // Rescale new center to maintain same altitude as the old center.
286
+ const actualDistance = this._radius - newRadius;
287
+ const actualRatio = actualDistance / this._radius;
288
+ // Direction from current center to target point
289
+ const directionToTarget = TmpVectors.Vector3[0];
290
+ targetPoint.subtractToRef(this._center, directionToTarget);
291
+ // Move center toward target by the ratio amount
292
+ const centerOffset = TmpVectors.Vector3[1];
293
+ directionToTarget.scaleToRef(actualRatio, centerOffset);
294
+ // Calculate new center
295
+ this._center.addToRef(centerOffset, newCenter);
296
+ // Preserve center altitude (distance from planet origin)
255
297
  const currentCenterRadius = this._center.length();
256
298
  const newCenterRadius = newCenter.length();
257
- const newCenterRescale = currentCenterRadius / newCenterRadius;
258
- newCenter.scaleInPlace(newCenterRescale);
259
- // Apply changes
260
- this._setOrientation(this._yaw, this._pitch, newRadius, newCenter);
299
+ if (newCenterRadius > Epsilon) {
300
+ newCenter.scaleInPlace(currentCenterRadius / newCenterRadius);
301
+ }
302
+ return newRadius;
303
+ }
304
+ /**
305
+ * Apply zoom by moving the camera toward/away from a target point.
306
+ */
307
+ _applyZoom() {
308
+ const zoomDelta = this.movement.zoomDeltaCurrentFrame;
309
+ const pickedPoint = this.movement.computedPerFrameZoomPickPoint;
310
+ if (pickedPoint) {
311
+ // Zoom toward the picked point under cursor
312
+ this._zoomToPoint(pickedPoint, zoomDelta);
313
+ }
314
+ else {
315
+ // Zoom along lookAt vector (fallback when no surface under cursor)
316
+ this._zoomAlongLookAt(zoomDelta);
317
+ }
318
+ }
319
+ _zoomToPoint(targetPoint, distance) {
320
+ const newRadius = this._getCenterAndRadiusFromZoomToPoint(targetPoint, distance, this._tempCenter);
321
+ // Apply the new orientation
322
+ this._setOrientation(this._yaw, this._pitch, newRadius, this._tempCenter);
323
+ }
324
+ _zoomAlongLookAt(distance) {
325
+ // Clamp radius to limits
326
+ const requestedRadius = this._radius - distance;
327
+ const newRadius = Clamp(requestedRadius, this.limits.radiusMin, this.limits.radiusMax);
328
+ // Simply change radius without moving center
329
+ this._setOrientation(this._yaw, this._pitch, newRadius, this._center);
261
330
  }
262
331
  _checkInputs() {
263
332
  this.inputs.checkInputs();
264
333
  // Let movement class handle all per-frame logic
265
334
  this.movement.computeCurrentFrameDeltas();
335
+ let recalculateCenter = false;
266
336
  if (this.movement.panDeltaCurrentFrame.lengthSquared() > 0) {
267
337
  this._applyGeocentricTranslation();
268
- this._isViewMatrixDirty = true;
338
+ recalculateCenter = true;
269
339
  }
270
340
  if (this.movement.rotationDeltaCurrentFrame.lengthSquared() > 0) {
271
341
  this._applyGeocentricRotation();
272
- this._isViewMatrixDirty = true;
273
342
  }
274
343
  if (Math.abs(this.movement.zoomDeltaCurrentFrame) > Epsilon) {
275
- this._applyZoom(this.movement.computedPerFrameZoomVector, this.movement.zoomDeltaCurrentFrame);
276
- this._isViewMatrixDirty = true;
344
+ this._applyZoom();
345
+ recalculateCenter = true;
277
346
  }
347
+ // After a movement impacting center or radius, recalculate the center point to ensure it's still on the surface.
348
+ recalculateCenter && this._recalculateCenter();
278
349
  super._checkInputs();
279
350
  }
351
+ _recalculateCenter() {
352
+ // Wait until dragging is complete to avoid wasted raycasting
353
+ if (!this.movement.isDragging) {
354
+ const newCenter = this.movement.pickAlongVector(this._lookAtVector);
355
+ if (newCenter?.pickedPoint) {
356
+ // Direction from new center to origin
357
+ const centerToOrigin = TmpVectors.Vector3[4];
358
+ centerToOrigin.copyFrom(newCenter.pickedPoint).negateInPlace().normalize();
359
+ // Check if this direction aligns with camera's lookAt vector
360
+ const dotProduct = Vector3.Dot(this._lookAtVector, centerToOrigin);
361
+ // Only update if the center is looking toward the origin (dot product > 0) to avoid a center on the opposite side of globe
362
+ if (dotProduct > 0) {
363
+ const newRadius = Vector3.Distance(this.position, newCenter.pickedPoint);
364
+ this._setOrientation(this._yaw, this._pitch, newRadius, newCenter.pickedPoint);
365
+ }
366
+ }
367
+ }
368
+ }
280
369
  attachControl(noPreventDefault) {
281
370
  this.inputs.attachElement(noPreventDefault);
282
371
  }
@@ -1 +1 @@
1
- {"version":3,"file":"geospatialCamera.js","sourceRoot":"","sources":["../../../../dev/core/src/Cameras/geospatialCamera.ts"],"names":[],"mappings":"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","sourcesContent":["import { GeospatialCameraInputsManager } from \"./geospatialCameraInputsManager\";\r\nimport { Vector3, Matrix, TmpVectors } from \"../Maths/math.vector\";\r\nimport { Epsilon } from \"../Maths/math.constants\";\r\nimport { Camera } from \"./camera\";\r\nimport type { Scene } from \"../scene\";\r\nimport type { MeshPredicate } from \"../Culling/ray.core\";\r\nimport type { DeepImmutable } from \"../types\";\r\nimport { GeospatialLimits } from \"./Limits/geospatialLimits\";\r\nimport { ComputeLocalBasisToRefs, GeospatialCameraMovement } from \"./geospatialCameraMovement\";\r\nimport type { IVector3Like } from \"../Maths/math.like\";\r\nimport { Vector3CopyToRef, Vector3Dot } from \"../Maths/math.vector.functions\";\r\nimport { Clamp } from \"../Maths/math.scalar.functions\";\r\nimport type { AllowedAnimValue } from \"../Behaviors/Cameras/interpolatingBehavior\";\r\nimport { InterpolatingBehavior } from \"../Behaviors/Cameras/interpolatingBehavior\";\r\nimport type { EasingFunction } from \"../Animations/easing\";\r\n\r\ntype CameraOptions = {\r\n planetRadius: number; // Radius of the planet\r\n};\r\n\r\n/**\r\n * @experimental\r\n * This camera's movements are limited to a camera orbiting a globe, and as the API evolves it will introduce conversions between cartesian coordinates and true lat/long/alt\r\n *\r\n * Please note this is marked as experimental and the API (including the constructor!) will change until we remove that flag\r\n */\r\nexport class GeospatialCamera extends Camera {\r\n override inputs: GeospatialCameraInputsManager;\r\n\r\n /** If supplied, will be used when picking the globe */\r\n public pickPredicate?: MeshPredicate;\r\n\r\n /** Movement controller that turns input pixelDeltas into currentFrameDeltas used by camera*/\r\n public readonly movement: GeospatialCameraMovement;\r\n\r\n // Temp vars\r\n private _tempPosition: Vector3 = new Vector3();\r\n\r\n private _viewMatrix = new Matrix();\r\n private _isViewMatrixDirty: boolean;\r\n private _lookAtVector: Vector3 = new Vector3();\r\n\r\n /** Behavior used for smooth flying animations */\r\n private _flyingBehavior: InterpolatingBehavior<GeospatialCamera>;\r\n private _flyToTargets: Map<keyof GeospatialCamera, AllowedAnimValue> = new Map();\r\n\r\n constructor(name: string, scene: Scene, options: CameraOptions, pickPredicate?: MeshPredicate) {\r\n super(name, new Vector3(), scene);\r\n\r\n this._limits = new GeospatialLimits(options.planetRadius);\r\n this._resetToDefault(this._limits);\r\n\r\n this._flyingBehavior = new InterpolatingBehavior();\r\n this.addBehavior(this._flyingBehavior);\r\n\r\n this.movement = new GeospatialCameraMovement(scene, this._limits, this.position, this.center, this._lookAtVector, pickPredicate);\r\n\r\n this.pickPredicate = pickPredicate;\r\n this.inputs = new GeospatialCameraInputsManager(this);\r\n this.inputs.addMouse().addMouseWheel().addKeyboard();\r\n }\r\n\r\n private _center: Vector3 = new Vector3();\r\n /** The point on the globe that we are anchoring around. If no alternate rotation point is supplied, this will represent the center of screen*/\r\n public get center(): Vector3 {\r\n return this._center;\r\n }\r\n\r\n /**\r\n * Sets the camera position to orbit around a new center point\r\n * @param center The world position (ECEF) to orbit around\r\n */\r\n public set center(center: IVector3Like) {\r\n this._center.copyFromFloats(center.x, center.y, center.z);\r\n this._setOrientation(this._yaw, this._pitch, this._radius, this._center);\r\n }\r\n\r\n private _yaw: number = 0;\r\n /**\r\n * Gets the camera's yaw (rotation around the geocentric normal) in radians\r\n */\r\n public get yaw(): number {\r\n return this._yaw;\r\n }\r\n\r\n /**\r\n * Sets the camera's yaw (rotation around the geocentric normal)\r\n * @param yaw The desired yaw angle in radians (0 = north, π/2 = east)\r\n */\r\n public set yaw(yaw: number) {\r\n this._setOrientation(yaw, this.pitch, this.radius, this.center);\r\n }\r\n\r\n private _pitch: number = 0;\r\n\r\n /**\r\n * Gets the camera's pitch (angle from looking straight at globe)\r\n * Pitch is measured from looking straight down at planet center:\r\n * - zero pitch = looking straight at planet center (down)\r\n * - positive pitch = tilting up away from planet\r\n * - π/2 pitch = looking at horizon (perpendicular to geocentric normal)\r\n */\r\n public get pitch(): number {\r\n return this._pitch;\r\n }\r\n\r\n /**\r\n * Sets the camera's pitch (angle from looking straight at globe)\r\n * @param pitch The desired pitch angle in radians (0 = looking at planet center, π/2 = looking at horizon)\r\n */\r\n public set pitch(pitch: number) {\r\n this._setOrientation(this.yaw, pitch, this.radius, this.center);\r\n }\r\n\r\n private _radius: number = 0;\r\n public get radius(): number {\r\n return this._radius;\r\n }\r\n\r\n /**\r\n * Sets the camera's distance from the current center point\r\n * @param radius The desired radius\r\n */\r\n public set radius(radius: number) {\r\n this._setOrientation(this.yaw, this.pitch, radius, this.center);\r\n }\r\n\r\n protected _checkLimits() {\r\n const limits = this.limits;\r\n this._yaw = Clamp(this._yaw, limits.yawMin, limits.yawMax);\r\n this._pitch = Clamp(this._pitch, limits.pitchMin, limits.pitchMax);\r\n this._radius = Clamp(this._radius, limits.radiusMin, limits.radiusMax);\r\n }\r\n\r\n private _tempVect = new Vector3();\r\n private _tempEast = new Vector3();\r\n private _tempNorth = new Vector3();\r\n private _tempUp = new Vector3();\r\n\r\n private _setOrientation(yaw: number, pitch: number, radius: number, center: DeepImmutable<IVector3Like>): void {\r\n this._yaw = yaw;\r\n this._pitch = pitch;\r\n this._radius = radius;\r\n\r\n Vector3CopyToRef(center, this._center);\r\n\r\n // Clamp to limits\r\n this._checkLimits();\r\n\r\n // Refresh local basis at center (treat these as read-only for the whole call)\r\n ComputeLocalBasisToRefs(this._center, this._tempEast, this._tempNorth, this._tempUp);\r\n\r\n // Trig\r\n const yawScale = this._scene.useRightHandedSystem ? 1 : -1;\r\n const cosYaw = Math.cos(this._yaw * yawScale);\r\n const sinYaw = Math.sin(this._yaw * yawScale);\r\n const sinPitch = Math.sin(this._pitch); // horizontal weight\r\n const cosPitch = Math.cos(this._pitch); // vertical weight (toward center)\r\n\r\n // Temps\r\n const horiz = TmpVectors.Vector3[0];\r\n const t1 = TmpVectors.Vector3[1];\r\n const t2 = TmpVectors.Vector3[2];\r\n const right = TmpVectors.Vector3[3];\r\n\r\n // horizontalDirection = North*cosYaw + East*sinYaw (avoids mutating _temp basis vectors)\r\n horiz.copyFrom(this._tempNorth).scaleInPlace(cosYaw).addInPlace(t1.copyFrom(this._tempEast).scaleInPlace(sinYaw));\r\n\r\n // look = horiz*sinPitch - Up*cosPitch\r\n this._lookAtVector.copyFrom(horiz).scaleInPlace(sinPitch).addInPlace(t2.copyFrom(this._tempUp).scaleInPlace(-cosPitch)).normalize(); // keep it unit\r\n\r\n // Build an orthonormal up aligned with geocentric Up\r\n // right = normalize(cross(upRef, look))\r\n Vector3.CrossToRef(this._tempUp, this._lookAtVector, right);\r\n\r\n // up = normalize(cross(look, right))\r\n Vector3.CrossToRef(this._lookAtVector, right, this.upVector);\r\n\r\n // Position = center - look * radius (preserve unit look)\r\n this._tempVect.copyFrom(this._lookAtVector).scaleInPlace(-this._radius);\r\n this._tempPosition.copyFrom(this._center).addInPlace(this._tempVect);\r\n\r\n this._position.copyFrom(this._tempPosition);\r\n\r\n this._isViewMatrixDirty = true;\r\n }\r\n\r\n /** The point around which the camera will geocentrically rotate. Uses center (pt we are anchored to) if no alternateRotationPt is defined */\r\n private get _geocentricRotationPt(): Vector3 {\r\n return this.movement.alternateRotationPt ?? this.center;\r\n }\r\n\r\n /**\r\n * If camera is actively in flight, will update the target properties and use up the remaining duration from original flyTo call\r\n *\r\n * To start a new flyTo curve entirely, call into flyToAsync again (it will stop the inflight animation)\r\n * @param targetYaw\r\n * @param targetPitch\r\n * @param targetRadius\r\n * @param targetCenter\r\n */\r\n public updateFlyToDestination(targetYaw?: number, targetPitch?: number, targetRadius?: number, targetCenter?: Vector3): void {\r\n this._flyToTargets.clear();\r\n\r\n this._flyToTargets.set(\"yaw\", targetYaw);\r\n this._flyToTargets.set(\"pitch\", targetPitch);\r\n this._flyToTargets.set(\"radius\", targetRadius);\r\n this._flyToTargets.set(\"center\", targetCenter);\r\n\r\n this._flyingBehavior.updateProperties(this._flyToTargets);\r\n }\r\n\r\n /**\r\n * Animate camera towards passed in property values. If undefined, will use current value\r\n * @param targetYaw\r\n * @param targetPitch\r\n * @param targetRadius\r\n * @param targetCenter\r\n * @param flightDurationMs\r\n * @param easingFunction\r\n * @returns Promise that will return when the animation is complete (or interuppted by pointer input)\r\n */\r\n public async flyToAsync(\r\n targetYaw?: number,\r\n targetPitch?: number,\r\n targetRadius?: number,\r\n targetCenter?: Vector3,\r\n flightDurationMs: number = 1000,\r\n easingFunction?: EasingFunction\r\n ): Promise<void> {\r\n this._flyToTargets.clear();\r\n\r\n this._flyToTargets.set(\"yaw\", targetYaw);\r\n this._flyToTargets.set(\"pitch\", targetPitch);\r\n this._flyToTargets.set(\"radius\", targetRadius);\r\n this._flyToTargets.set(\"center\", targetCenter);\r\n\r\n return await this._flyingBehavior.animatePropertiesAsync(this._flyToTargets, flightDurationMs, easingFunction);\r\n }\r\n\r\n private _limits: GeospatialLimits;\r\n public get limits(): GeospatialLimits {\r\n return this._limits;\r\n }\r\n\r\n private _resetToDefault(limits: GeospatialLimits): void {\r\n // Camera configuration vars\r\n const maxCameraRadius = limits.altitudeMax !== undefined ? limits.planetRadius + limits.altitudeMax : undefined;\r\n const restingAltitude = maxCameraRadius ?? limits.planetRadius * 4;\r\n this.position.copyFromFloats(restingAltitude, 0, 0);\r\n this._center.copyFromFloats(limits.planetRadius, 0, 0);\r\n this._radius = Vector3.Distance(this.position, this.center);\r\n\r\n // Temp vars\r\n this._tempPosition = new Vector3();\r\n\r\n // View matrix calculation vars\r\n this._viewMatrix = Matrix.Identity();\r\n this._center.subtractToRef(this._position, this._lookAtVector).normalize(); // Lookat vector of the camera\r\n this.upVector = Vector3.Up(); // Up vector of the camera (does work for -X look at)\r\n this._isViewMatrixDirty = true;\r\n\r\n this._setOrientation(this._yaw, this._pitch, this._radius, this._center);\r\n }\r\n\r\n /** @internal */\r\n override _getViewMatrix() {\r\n if (!this._isViewMatrixDirty) {\r\n return this._viewMatrix;\r\n }\r\n this._isViewMatrixDirty = false;\r\n\r\n // Ensure vectors are normalized\r\n this.upVector.normalize();\r\n this._lookAtVector.normalize();\r\n\r\n // Calculate view matrix with camera position and center\r\n if (this.getScene().useRightHandedSystem) {\r\n Matrix.LookAtRHToRef(this.position, this._center, this.upVector, this._viewMatrix);\r\n } else {\r\n Matrix.LookAtLHToRef(this.position, this._center, this.upVector, this._viewMatrix);\r\n }\r\n\r\n return this._viewMatrix;\r\n }\r\n\r\n /** @internal */\r\n override _isSynchronizedViewMatrix(): boolean {\r\n if (!super._isSynchronizedViewMatrix() || this._isViewMatrixDirty) {\r\n return false;\r\n }\r\n return true;\r\n }\r\n\r\n private _applyGeocentricTranslation() {\r\n // Store pending position (without any corrections applied)\r\n this.center.addToRef(this.movement.panDeltaCurrentFrame, this._tempPosition);\r\n\r\n if (!this.movement.isInterpolating) {\r\n // Calculate the position correction to keep camera at the same radius when applying translation\r\n this._tempPosition.normalize().scaleInPlace(this.center.length());\r\n }\r\n // Set center which will call _setOrientation\r\n this.center = this._tempPosition;\r\n }\r\n\r\n /**\r\n * This rotation keeps the camera oriented towards the globe as it orbits around it. This is different from cameraCentricRotation which is when the camera rotates around its own axis\r\n */\r\n private _applyGeocentricRotation(): void {\r\n const rotationDeltaCurrentFrame = this.movement.rotationDeltaCurrentFrame;\r\n if (rotationDeltaCurrentFrame.x !== 0 || rotationDeltaCurrentFrame.y !== 0) {\r\n const pitch = rotationDeltaCurrentFrame.x !== 0 ? Clamp(this._pitch + rotationDeltaCurrentFrame.x, 0, 0.5 * Math.PI - Epsilon) : this._pitch;\r\n const yaw = rotationDeltaCurrentFrame.y !== 0 ? this._yaw + rotationDeltaCurrentFrame.y : this._yaw;\r\n\r\n // TODO: If _geocentricRotationPt is not the center, this will need to be adjusted.\r\n this._setOrientation(yaw, pitch, this._radius, this._geocentricRotationPt);\r\n }\r\n }\r\n\r\n private _applyZoom(zoomVector: Vector3, distance: number) {\r\n // TODO this function will be re-worked shortly after checkin, becuase today it breaks down if you zoom to a point past the center\r\n // (ex: tilted view zooming towards cursor near horizon where the center is closer than the cursor point).\r\n\r\n // Project zoom vector onto lookAt vector to find the amount the camera-to-center distance should change.\r\n // - zoom vector is normalized\r\n // - distance is how much to move in this call\r\n const directionDotLookAt = Vector3Dot(zoomVector, this._lookAtVector);\r\n const hasRadialComponent = Math.abs(directionDotLookAt) > Epsilon;\r\n const requestedRadius = hasRadialComponent ? this._radius - distance * directionDotLookAt : this._radius;\r\n const newRadius = Clamp(requestedRadius, this.limits.radiusMin, this.limits.radiusMax);\r\n const actualRadiusChange = newRadius - this._radius;\r\n const actualDistanceChange = hasRadialComponent ? actualRadiusChange / directionDotLookAt : 0;\r\n\r\n // Use this to compute new camera position and new center position.\r\n const newCameraPosition = this._position.add(zoomVector.scale(-actualDistanceChange));\r\n const newCenter = newCameraPosition.add(this._lookAtVector.scaleToRef(newRadius, TmpVectors.Vector3[3]));\r\n\r\n // Rescale new center to maintain same altitude as the old center.\r\n const currentCenterRadius = this._center.length();\r\n const newCenterRadius = newCenter.length();\r\n const newCenterRescale = currentCenterRadius / newCenterRadius;\r\n newCenter.scaleInPlace(newCenterRescale);\r\n\r\n // Apply changes\r\n this._setOrientation(this._yaw, this._pitch, newRadius, newCenter);\r\n }\r\n\r\n override _checkInputs(): void {\r\n this.inputs.checkInputs();\r\n\r\n // Let movement class handle all per-frame logic\r\n this.movement.computeCurrentFrameDeltas();\r\n\r\n if (this.movement.panDeltaCurrentFrame.lengthSquared() > 0) {\r\n this._applyGeocentricTranslation();\r\n this._isViewMatrixDirty = true;\r\n }\r\n if (this.movement.rotationDeltaCurrentFrame.lengthSquared() > 0) {\r\n this._applyGeocentricRotation();\r\n this._isViewMatrixDirty = true;\r\n }\r\n\r\n if (Math.abs(this.movement.zoomDeltaCurrentFrame) > Epsilon) {\r\n this._applyZoom(this.movement.computedPerFrameZoomVector, this.movement.zoomDeltaCurrentFrame);\r\n this._isViewMatrixDirty = true;\r\n }\r\n\r\n super._checkInputs();\r\n }\r\n\r\n override attachControl(noPreventDefault?: boolean): void {\r\n this.inputs.attachElement(noPreventDefault);\r\n }\r\n\r\n override detachControl(): void {\r\n this.inputs.detachElement();\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"geospatialCamera.js","sourceRoot":"","sources":["../../../../dev/core/src/Cameras/geospatialCamera.ts"],"names":[],"mappings":"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","sourcesContent":["import { GeospatialCameraInputsManager } from \"./geospatialCameraInputsManager\";\r\nimport { Vector3, Matrix, TmpVectors } from \"../Maths/math.vector\";\r\nimport { Epsilon } from \"../Maths/math.constants\";\r\nimport { Camera } from \"./camera\";\r\nimport type { Scene } from \"../scene\";\r\nimport type { MeshPredicate } from \"../Culling/ray.core\";\r\nimport type { DeepImmutable } from \"../types\";\r\nimport { GeospatialLimits } from \"./Limits/geospatialLimits\";\r\nimport { ClampCenterFromPolesInPlace, ComputeLocalBasisToRefs, GeospatialCameraMovement } from \"./geospatialCameraMovement\";\r\nimport type { IVector3Like } from \"../Maths/math.like\";\r\nimport { Vector3CopyToRef, Vector3Distance } from \"../Maths/math.vector.functions\";\r\nimport { Clamp } from \"../Maths/math.scalar.functions\";\r\nimport type { AllowedAnimValue } from \"../Behaviors/Cameras/interpolatingBehavior\";\r\nimport { InterpolatingBehavior } from \"../Behaviors/Cameras/interpolatingBehavior\";\r\nimport type { EasingFunction } from \"../Animations/easing\";\r\nimport type { Animation } from \"../Animations/animation\";\r\n\r\ntype CameraOptions = {\r\n planetRadius: number; // Radius of the planet\r\n};\r\n\r\n/**\r\n * @experimental\r\n * This camera's movements are limited to a camera orbiting a globe, and as the API evolves it will introduce conversions between cartesian coordinates and true lat/long/alt\r\n *\r\n * Please note this is marked as experimental and the API (including the constructor!) will change until we remove that flag\r\n */\r\nexport class GeospatialCamera extends Camera {\r\n override inputs: GeospatialCameraInputsManager;\r\n\r\n /** If supplied, will be used when picking the globe */\r\n public pickPredicate?: MeshPredicate;\r\n\r\n /** Movement controller that turns input pixelDeltas into currentFrameDeltas used by camera*/\r\n public readonly movement: GeospatialCameraMovement;\r\n\r\n // Temp vars\r\n private _tempPosition: Vector3 = new Vector3();\r\n private _tempCenter: Vector3 = new Vector3();\r\n\r\n private _viewMatrix = new Matrix();\r\n private _isViewMatrixDirty: boolean;\r\n private _lookAtVector: Vector3 = new Vector3();\r\n\r\n /** Behavior used for smooth flying animations */\r\n private _flyingBehavior: InterpolatingBehavior<GeospatialCamera>;\r\n private _flyToTargets: Map<keyof GeospatialCamera, AllowedAnimValue> = new Map();\r\n\r\n constructor(name: string, scene: Scene, options: CameraOptions, pickPredicate?: MeshPredicate) {\r\n super(name, new Vector3(), scene);\r\n\r\n this._limits = new GeospatialLimits(options.planetRadius);\r\n this._resetToDefault(this._limits);\r\n\r\n this._flyingBehavior = new InterpolatingBehavior();\r\n this.addBehavior(this._flyingBehavior);\r\n\r\n this.movement = new GeospatialCameraMovement(scene, this._limits, this.position, this.center, this._lookAtVector, pickPredicate, this._flyingBehavior);\r\n\r\n this.pickPredicate = pickPredicate;\r\n this.inputs = new GeospatialCameraInputsManager(this);\r\n this.inputs.addMouse().addMouseWheel().addKeyboard();\r\n }\r\n\r\n private _center: Vector3 = new Vector3();\r\n /** The point on the globe that we are anchoring around. If no alternate rotation point is supplied, this will represent the center of screen*/\r\n public get center(): Vector3 {\r\n return this._center;\r\n }\r\n\r\n /**\r\n * Sets the camera position to orbit around a new center point\r\n * @param center The world position (ECEF) to orbit around\r\n */\r\n public set center(center: IVector3Like) {\r\n this._center.copyFromFloats(center.x, center.y, center.z);\r\n this._setOrientation(this._yaw, this._pitch, this._radius, this._center);\r\n }\r\n\r\n private _yaw: number = 0;\r\n /**\r\n * Gets the camera's yaw (rotation around the geocentric normal) in radians\r\n */\r\n public get yaw(): number {\r\n return this._yaw;\r\n }\r\n\r\n /**\r\n * Sets the camera's yaw (rotation around the geocentric normal)\r\n * @param yaw The desired yaw angle in radians (0 = north, π/2 = east)\r\n */\r\n public set yaw(yaw: number) {\r\n this._setOrientation(yaw, this.pitch, this.radius, this.center);\r\n }\r\n\r\n private _pitch: number = 0;\r\n\r\n /**\r\n * Gets the camera's pitch (angle from looking straight at globe)\r\n * Pitch is measured from looking straight down at planet center:\r\n * - zero pitch = looking straight at planet center (down)\r\n * - positive pitch = tilting up away from planet\r\n * - π/2 pitch = looking at horizon (perpendicular to geocentric normal)\r\n */\r\n public get pitch(): number {\r\n return this._pitch;\r\n }\r\n\r\n /**\r\n * Sets the camera's pitch (angle from looking straight at globe)\r\n * @param pitch The desired pitch angle in radians (0 = looking at planet center, π/2 = looking at horizon)\r\n */\r\n public set pitch(pitch: number) {\r\n this._setOrientation(this.yaw, pitch, this.radius, this.center);\r\n }\r\n\r\n private _radius: number = 0;\r\n public get radius(): number {\r\n return this._radius;\r\n }\r\n\r\n /**\r\n * Sets the camera's distance from the current center point\r\n * @param radius The desired radius\r\n */\r\n public set radius(radius: number) {\r\n this._setOrientation(this.yaw, this.pitch, radius, this.center);\r\n }\r\n\r\n protected _checkLimits() {\r\n const limits = this.limits;\r\n this._yaw = Clamp(this._yaw, limits.yawMin, limits.yawMax);\r\n this._pitch = Clamp(this._pitch, limits.pitchMin, limits.pitchMax);\r\n this._radius = Clamp(this._radius, limits.radiusMin, limits.radiusMax);\r\n this._center = ClampCenterFromPolesInPlace(this._center);\r\n }\r\n\r\n private _tempVect = new Vector3();\r\n private _tempEast = new Vector3();\r\n private _tempNorth = new Vector3();\r\n private _tempUp = new Vector3();\r\n\r\n private _setOrientation(yaw: number, pitch: number, radius: number, center: DeepImmutable<IVector3Like>): void {\r\n this._yaw = yaw;\r\n this._pitch = pitch;\r\n this._radius = radius;\r\n\r\n Vector3CopyToRef(center, this._center);\r\n\r\n // Clamp to limits\r\n this._checkLimits();\r\n\r\n // Refresh local basis at center (treat these as read-only for the whole call)\r\n ComputeLocalBasisToRefs(this._center, this._tempEast, this._tempNorth, this._tempUp);\r\n\r\n // Trig\r\n const yawScale = this._scene.useRightHandedSystem ? 1 : -1;\r\n const cosYaw = Math.cos(this._yaw * yawScale);\r\n const sinYaw = Math.sin(this._yaw * yawScale);\r\n const sinPitch = Math.sin(this._pitch); // horizontal weight\r\n const cosPitch = Math.cos(this._pitch); // vertical weight (toward center)\r\n\r\n // Temps\r\n const horiz = TmpVectors.Vector3[0];\r\n const t1 = TmpVectors.Vector3[1];\r\n const t2 = TmpVectors.Vector3[2];\r\n const right = TmpVectors.Vector3[3];\r\n\r\n // horizontalDirection = North*cosYaw + East*sinYaw (avoids mutating _temp basis vectors)\r\n horiz.copyFrom(this._tempNorth).scaleInPlace(cosYaw).addInPlace(t1.copyFrom(this._tempEast).scaleInPlace(sinYaw));\r\n\r\n // look = horiz*sinPitch - Up*cosPitch\r\n this._lookAtVector.copyFrom(horiz).scaleInPlace(sinPitch).addInPlace(t2.copyFrom(this._tempUp).scaleInPlace(-cosPitch)).normalize(); // keep it unit\r\n\r\n // Build an orthonormal up aligned with geocentric Up\r\n // right = normalize(cross(upRef, look))\r\n Vector3.CrossToRef(this._tempUp, this._lookAtVector, right);\r\n\r\n // up = normalize(cross(look, right))\r\n Vector3.CrossToRef(this._lookAtVector, right, this.upVector);\r\n\r\n // Position = center - look * radius (preserve unit look)\r\n this._tempVect.copyFrom(this._lookAtVector).scaleInPlace(-this._radius);\r\n this._tempPosition.copyFrom(this._center).addInPlace(this._tempVect);\r\n\r\n this._position.copyFrom(this._tempPosition);\r\n\r\n this._isViewMatrixDirty = true;\r\n }\r\n\r\n /** The point around which the camera will geocentrically rotate. Uses center (pt we are anchored to) if no alternateRotationPt is defined */\r\n private get _geocentricRotationPt(): Vector3 {\r\n return this.movement.alternateRotationPt ?? this.center;\r\n }\r\n\r\n /**\r\n * If camera is actively in flight, will update the target properties and use up the remaining duration from original flyTo call\r\n *\r\n * To start a new flyTo curve entirely, call into flyToAsync again (it will stop the inflight animation)\r\n * @param targetYaw\r\n * @param targetPitch\r\n * @param targetRadius\r\n * @param targetCenter\r\n */\r\n public updateFlyToDestination(targetYaw?: number, targetPitch?: number, targetRadius?: number, targetCenter?: Vector3): void {\r\n this._flyToTargets.clear();\r\n\r\n this._flyToTargets.set(\"yaw\", targetYaw);\r\n this._flyToTargets.set(\"pitch\", targetPitch);\r\n this._flyToTargets.set(\"radius\", targetRadius);\r\n this._flyToTargets.set(\"center\", targetCenter);\r\n\r\n this._flyingBehavior.updateProperties(this._flyToTargets);\r\n }\r\n\r\n /**\r\n * Animate camera towards passed in property values. If undefined, will use current value\r\n * @param targetYaw\r\n * @param targetPitch\r\n * @param targetRadius\r\n * @param targetCenter\r\n * @param flightDurationMs\r\n * @param easingFunction\r\n * @param centerHopScale If supplied, will define the parabolic hop height scale for center animation to create a \"bounce\" effect\r\n * @returns Promise that will return when the animation is complete (or interuppted by pointer input)\r\n */\r\n public async flyToAsync(\r\n targetYaw?: number,\r\n targetPitch?: number,\r\n targetRadius?: number,\r\n targetCenter?: Vector3,\r\n flightDurationMs: number = 1000,\r\n easingFunction?: EasingFunction,\r\n centerHopScale?: number\r\n ): Promise<void> {\r\n this._flyToTargets.clear();\r\n\r\n this._flyToTargets.set(\"yaw\", targetYaw);\r\n this._flyToTargets.set(\"pitch\", targetPitch);\r\n this._flyToTargets.set(\"radius\", targetRadius);\r\n this._flyToTargets.set(\"center\", targetCenter);\r\n\r\n let overrideAnimationFunction;\r\n if (targetCenter !== undefined && !targetCenter.equals(this.center)) {\r\n // Animate center directly with custom interpolation\r\n const start = this.center.clone();\r\n const end = targetCenter.clone();\r\n\r\n overrideAnimationFunction = (key: string, animation: Animation): void => {\r\n if (key === \"center\") {\r\n // Override the Vector3 interpolation to use SLERP + hop\r\n animation.vector3InterpolateFunction = (startValue, endValue, gradient) => {\r\n // gradient is the eased value (0 to 1) after easing function is applied\r\n\r\n // Slerp between start and end\r\n const newCenter = Vector3.SlerpToRef(start, end, gradient, this._tempCenter);\r\n\r\n // Apply parabolic hop if requested\r\n if (centerHopScale && centerHopScale > 0) {\r\n // Parabolic formula: peaks at t=0.5, returns to 0 at gradient=0 and gradient=1\r\n // if hopPeakT = .5 the denominator would be hopPeakT * hopPeakT - hopPeakT, which = -.25\r\n const hopPeakOffset = centerHopScale * Vector3Distance(start, end);\r\n const hopOffset = hopPeakOffset * Clamp((gradient * gradient - gradient) / -0.25);\r\n // Scale the center outward (away from origin)\r\n newCenter.scaleInPlace(1 + hopOffset / newCenter.length());\r\n }\r\n\r\n return newCenter;\r\n };\r\n }\r\n };\r\n }\r\n\r\n return await this._flyingBehavior.animatePropertiesAsync(this._flyToTargets, flightDurationMs, easingFunction, overrideAnimationFunction);\r\n }\r\n\r\n /**\r\n * Helper function to move camera towards a given point by radiusScale% of radius (by default 50%)\r\n * @param destination point to move towards\r\n * @param radiusScale value between 0 and 1, % of radius to move\r\n * @param durationMs duration of flight, default 1s\r\n * @param easingFn optional easing function for flight interpolation of properties\r\n * @param overshootRadiusScale optional scale to apply to the current radius to achieve a 'hop' animation\r\n */\r\n public async flyToPointAsync(destination: Vector3, radiusScale: number = 0.5, durationMs: number = 1000, easingFn?: EasingFunction, overshootRadiusScale?: number) {\r\n // Zoom to radiusScale% of radius towards the given destination point\r\n const zoomDistance = this.radius * radiusScale;\r\n const newRadius = this._getCenterAndRadiusFromZoomToPoint(destination, zoomDistance, this._tempCenter);\r\n await this.flyToAsync(undefined, undefined, newRadius, this._tempCenter, durationMs, easingFn, overshootRadiusScale);\r\n }\r\n\r\n private _limits: GeospatialLimits;\r\n public get limits(): GeospatialLimits {\r\n return this._limits;\r\n }\r\n\r\n private _resetToDefault(limits: GeospatialLimits): void {\r\n // Camera configuration vars\r\n const maxCameraRadius = limits.altitudeMax !== undefined ? limits.planetRadius + limits.altitudeMax : undefined;\r\n const restingAltitude = maxCameraRadius ?? limits.planetRadius * 4;\r\n this.position.copyFromFloats(restingAltitude, 0, 0);\r\n this._center.copyFromFloats(limits.planetRadius, 0, 0);\r\n this._radius = Vector3.Distance(this.position, this.center);\r\n\r\n // Temp vars\r\n this._tempPosition = new Vector3();\r\n\r\n // View matrix calculation vars\r\n this._viewMatrix = Matrix.Identity();\r\n this._center.subtractToRef(this._position, this._lookAtVector).normalize(); // Lookat vector of the camera\r\n this.upVector = Vector3.Up(); // Up vector of the camera (does work for -X look at)\r\n this._isViewMatrixDirty = true;\r\n\r\n this._setOrientation(this._yaw, this._pitch, this._radius, this._center);\r\n }\r\n\r\n /** @internal */\r\n override _getViewMatrix() {\r\n if (!this._isViewMatrixDirty) {\r\n return this._viewMatrix;\r\n }\r\n this._isViewMatrixDirty = false;\r\n\r\n // Ensure vectors are normalized\r\n this.upVector.normalize();\r\n this._lookAtVector.normalize();\r\n\r\n // Calculate view matrix with camera position and center\r\n if (this.getScene().useRightHandedSystem) {\r\n Matrix.LookAtRHToRef(this.position, this._center, this.upVector, this._viewMatrix);\r\n } else {\r\n Matrix.LookAtLHToRef(this.position, this._center, this.upVector, this._viewMatrix);\r\n }\r\n\r\n return this._viewMatrix;\r\n }\r\n\r\n /** @internal */\r\n override _isSynchronizedViewMatrix(): boolean {\r\n if (!super._isSynchronizedViewMatrix() || this._isViewMatrixDirty) {\r\n return false;\r\n }\r\n return true;\r\n }\r\n\r\n private _applyGeocentricTranslation() {\r\n // Store pending position (without any corrections applied)\r\n this.center.addToRef(this.movement.panDeltaCurrentFrame, this._tempPosition);\r\n\r\n if (!this.movement.isInterpolating) {\r\n // Calculate the position correction to keep camera at the same radius when applying translation\r\n this._tempPosition.normalize().scaleInPlace(this.center.length());\r\n }\r\n // Set center which will call _setOrientation\r\n this.center = this._tempPosition;\r\n }\r\n\r\n /**\r\n * This rotation keeps the camera oriented towards the globe as it orbits around it. This is different from cameraCentricRotation which is when the camera rotates around its own axis\r\n */\r\n private _applyGeocentricRotation(): void {\r\n const rotationDeltaCurrentFrame = this.movement.rotationDeltaCurrentFrame;\r\n if (rotationDeltaCurrentFrame.x !== 0 || rotationDeltaCurrentFrame.y !== 0) {\r\n const pitch = rotationDeltaCurrentFrame.x !== 0 ? Clamp(this._pitch + rotationDeltaCurrentFrame.x, 0, 0.5 * Math.PI - Epsilon) : this._pitch;\r\n const yaw = rotationDeltaCurrentFrame.y !== 0 ? this._yaw + rotationDeltaCurrentFrame.y : this._yaw;\r\n\r\n // TODO: If _geocentricRotationPt is not the center, this will need to be adjusted.\r\n this._setOrientation(yaw, pitch, this._radius, this._geocentricRotationPt);\r\n }\r\n }\r\n\r\n private _getCenterAndRadiusFromZoomToPoint(targetPoint: Vector3, distance: number, newCenter: Vector3): number {\r\n // Clamp new radius to limits\r\n const requestedRadius = this._radius - distance;\r\n const newRadius = Clamp(requestedRadius, this.limits.radiusMin, this.limits.radiusMax);\r\n const actualDistance = this._radius - newRadius;\r\n const actualRatio = actualDistance / this._radius;\r\n\r\n // Direction from current center to target point\r\n const directionToTarget = TmpVectors.Vector3[0];\r\n targetPoint.subtractToRef(this._center, directionToTarget);\r\n\r\n // Move center toward target by the ratio amount\r\n const centerOffset = TmpVectors.Vector3[1];\r\n directionToTarget.scaleToRef(actualRatio, centerOffset);\r\n\r\n // Calculate new center\r\n this._center.addToRef(centerOffset, newCenter);\r\n\r\n // Preserve center altitude (distance from planet origin)\r\n const currentCenterRadius = this._center.length();\r\n const newCenterRadius = newCenter.length();\r\n if (newCenterRadius > Epsilon) {\r\n newCenter.scaleInPlace(currentCenterRadius / newCenterRadius);\r\n }\r\n\r\n return newRadius;\r\n }\r\n\r\n /**\r\n * Apply zoom by moving the camera toward/away from a target point.\r\n */\r\n private _applyZoom() {\r\n const zoomDelta = this.movement.zoomDeltaCurrentFrame;\r\n const pickedPoint = this.movement.computedPerFrameZoomPickPoint;\r\n\r\n if (pickedPoint) {\r\n // Zoom toward the picked point under cursor\r\n this._zoomToPoint(pickedPoint, zoomDelta);\r\n } else {\r\n // Zoom along lookAt vector (fallback when no surface under cursor)\r\n this._zoomAlongLookAt(zoomDelta);\r\n }\r\n }\r\n\r\n private _zoomToPoint(targetPoint: Vector3, distance: number) {\r\n const newRadius = this._getCenterAndRadiusFromZoomToPoint(targetPoint, distance, this._tempCenter);\r\n // Apply the new orientation\r\n this._setOrientation(this._yaw, this._pitch, newRadius, this._tempCenter);\r\n }\r\n\r\n private _zoomAlongLookAt(distance: number) {\r\n // Clamp radius to limits\r\n const requestedRadius = this._radius - distance;\r\n const newRadius = Clamp(requestedRadius, this.limits.radiusMin, this.limits.radiusMax);\r\n\r\n // Simply change radius without moving center\r\n this._setOrientation(this._yaw, this._pitch, newRadius, this._center);\r\n }\r\n\r\n override _checkInputs(): void {\r\n this.inputs.checkInputs();\r\n\r\n // Let movement class handle all per-frame logic\r\n this.movement.computeCurrentFrameDeltas();\r\n\r\n let recalculateCenter = false;\r\n if (this.movement.panDeltaCurrentFrame.lengthSquared() > 0) {\r\n this._applyGeocentricTranslation();\r\n recalculateCenter = true;\r\n }\r\n if (this.movement.rotationDeltaCurrentFrame.lengthSquared() > 0) {\r\n this._applyGeocentricRotation();\r\n }\r\n\r\n if (Math.abs(this.movement.zoomDeltaCurrentFrame) > Epsilon) {\r\n this._applyZoom();\r\n recalculateCenter = true;\r\n }\r\n\r\n // After a movement impacting center or radius, recalculate the center point to ensure it's still on the surface.\r\n recalculateCenter && this._recalculateCenter();\r\n\r\n super._checkInputs();\r\n }\r\n\r\n private _recalculateCenter() {\r\n // Wait until dragging is complete to avoid wasted raycasting\r\n if (!this.movement.isDragging) {\r\n const newCenter = this.movement.pickAlongVector(this._lookAtVector);\r\n if (newCenter?.pickedPoint) {\r\n // Direction from new center to origin\r\n const centerToOrigin = TmpVectors.Vector3[4];\r\n centerToOrigin.copyFrom(newCenter.pickedPoint).negateInPlace().normalize();\r\n\r\n // Check if this direction aligns with camera's lookAt vector\r\n const dotProduct = Vector3.Dot(this._lookAtVector, centerToOrigin);\r\n\r\n // Only update if the center is looking toward the origin (dot product > 0) to avoid a center on the opposite side of globe\r\n if (dotProduct > 0) {\r\n const newRadius = Vector3.Distance(this.position, newCenter.pickedPoint);\r\n this._setOrientation(this._yaw, this._pitch, newRadius, newCenter.pickedPoint);\r\n }\r\n }\r\n }\r\n }\r\n override attachControl(noPreventDefault?: boolean): void {\r\n this.inputs.attachElement(noPreventDefault);\r\n }\r\n\r\n override detachControl(): void {\r\n this.inputs.detachElement();\r\n }\r\n}\r\n"]}
@@ -5,6 +5,8 @@ import type { MeshPredicate } from "../Culling/ray.core.js";
5
5
  import type { Scene } from "../scene.js";
6
6
  import type { PickingInfo } from "../Collisions/pickingInfo.js";
7
7
  import type { Nullable } from "../types.js";
8
+ import type { InterpolatingBehavior } from "../Behaviors/Cameras/interpolatingBehavior.js";
9
+ import type { GeospatialCamera } from "./geospatialCamera.js";
8
10
  /**
9
11
  * @experimental
10
12
  * This class is subject to change as the geospatial camera evolves.
@@ -26,7 +28,8 @@ export declare class GeospatialCameraMovement extends CameraMovement {
26
28
  private _cameraLookAt;
27
29
  /** Predicate function to determine which meshes to pick against (e.g., globe mesh) */
28
30
  pickPredicate?: MeshPredicate;
29
- computedPerFrameZoomVector: Vector3;
31
+ /** World-space picked point under cursor for zoom-to-cursor behavior (may be undefined) */
32
+ computedPerFrameZoomPickPoint?: Vector3;
30
33
  zoomToCursor: boolean;
31
34
  /**
32
35
  * Enables rotation around a specific point, instead of default rotation around center
@@ -41,7 +44,7 @@ export declare class GeospatialCameraMovement extends CameraMovement {
41
44
  private _dragPlaneOriginPointEcef;
42
45
  private _dragPlaneHitPointLocal;
43
46
  private _previousDragPlaneHitPointLocal;
44
- constructor(scene: Scene, limits: GeospatialLimits, cameraPosition: Vector3, _cameraCenter: Vector3, _cameraLookAt: Vector3, pickPredicate?: MeshPredicate);
47
+ constructor(scene: Scene, limits: GeospatialLimits, cameraPosition: Vector3, _cameraCenter: Vector3, _cameraLookAt: Vector3, pickPredicate?: MeshPredicate, behavior?: InterpolatingBehavior<GeospatialCamera>);
45
48
  startDrag(pointerX: number, pointerY: number): void;
46
49
  stopDrag(): void;
47
50
  /**
@@ -55,10 +58,12 @@ export declare class GeospatialCameraMovement extends CameraMovement {
55
58
  handleDrag(pointerX: number, pointerY: number): void;
56
59
  /** @override */
57
60
  computeCurrentFrameDeltas(): void;
61
+ get isDragging(): boolean;
58
62
  private _handleZoom;
59
63
  private _clampZoomDistance;
60
64
  pickAlongVector(vector: Vector3): Nullable<PickingInfo>;
61
65
  }
66
+ export declare function ClampCenterFromPolesInPlace(center: Vector3): Vector3;
62
67
  /**
63
68
  * Helper to build east/north/up basis vectors at a world position.
64
69
  * @internal
@@ -4,6 +4,7 @@ import { Matrix, TmpVectors, Vector3 } from "../Maths/math.vector.js";
4
4
  import { Plane } from "../Maths/math.plane.js";
5
5
  import { Ray } from "../Culling/ray.js";
6
6
  import { Vector3Distance } from "../Maths/math.vector.functions.js";
7
+ import { Clamp } from "../Maths/math.scalar.functions.js";
7
8
  /**
8
9
  * @experimental
9
10
  * This class is subject to change as the geospatial camera evolves.
@@ -20,12 +21,11 @@ import { Vector3Distance } from "../Maths/math.vector.functions.js";
20
21
  * - Zoom direction calculation (towards cursor vs along look vector)
21
22
  */
22
23
  export class GeospatialCameraMovement extends CameraMovement {
23
- constructor(scene, limits, cameraPosition, _cameraCenter, _cameraLookAt, pickPredicate) {
24
- super(scene, cameraPosition);
24
+ constructor(scene, limits, cameraPosition, _cameraCenter, _cameraLookAt, pickPredicate, behavior) {
25
+ super(scene, cameraPosition, behavior);
25
26
  this.limits = limits;
26
27
  this._cameraCenter = _cameraCenter;
27
28
  this._cameraLookAt = _cameraLookAt;
28
- this.computedPerFrameZoomVector = new Vector3();
29
29
  this.zoomToCursor = true;
30
30
  this._hitPointRadius = undefined;
31
31
  this._dragPlane = new Plane(0, 0, 0, 0);
@@ -33,7 +33,6 @@ export class GeospatialCameraMovement extends CameraMovement {
33
33
  this._dragPlaneOriginPointEcef = Vector3.Zero();
34
34
  this._dragPlaneHitPointLocal = Vector3.Zero();
35
35
  this._previousDragPlaneHitPointLocal = Vector3.Zero();
36
- this.computedPerFrameZoomVector.copyFrom(this._cameraLookAt);
37
36
  this.pickPredicate = pickPredicate;
38
37
  this._tempPickingRay = new Ray(this._cameraPosition, this._cameraLookAt);
39
38
  this.panInertia = 0;
@@ -97,9 +96,24 @@ export class GeospatialCameraMovement extends CameraMovement {
97
96
  /** @override */
98
97
  computeCurrentFrameDeltas() {
99
98
  const cameraCenter = this._cameraCenter;
99
+ // Slows down panning near the poles
100
+ if (this.panAccumulatedPixels.lengthSquared() > Epsilon) {
101
+ const centerRadius = cameraCenter.length(); // distance from planet origin to camera center
102
+ const currentRadius = this._cameraPosition.length();
103
+ // Dampen the pan speed based on latitude (slower near poles)
104
+ const sineOfSphericalLat = centerRadius === 0 ? 0 : cameraCenter.z / centerRadius;
105
+ const cosOfSphericalLat = Math.sqrt(1 - Math.min(1, sineOfSphericalLat * sineOfSphericalLat));
106
+ const latitudeDampening = Math.sqrt(Math.abs(cosOfSphericalLat)); // sqrt here reduces effect near equator
107
+ // Reduce the dampening effect near surface (so that at ground level, pan speed is not affected by latitude)
108
+ const height = Math.max(currentRadius - centerRadius, Epsilon);
109
+ const latitudeDampeningScale = Math.max(1, centerRadius / height);
110
+ this._panSpeedMultiplier = Clamp(latitudeDampeningScale * latitudeDampening, 0, 1);
111
+ }
112
+ else {
113
+ this._panSpeedMultiplier = 1;
114
+ }
100
115
  // If a pan drag is occurring, stop zooming.
101
- const isDragging = this._hitPointRadius !== undefined;
102
- if (isDragging) {
116
+ if (this.isDragging) {
103
117
  this._zoomSpeedMultiplier = 0;
104
118
  this._zoomVelocity = 0;
105
119
  }
@@ -112,6 +126,9 @@ export class GeospatialCameraMovement extends CameraMovement {
112
126
  super.computeCurrentFrameDeltas();
113
127
  this._handleZoom(activeZoom);
114
128
  }
129
+ get isDragging() {
130
+ return this._hitPointRadius !== undefined;
131
+ }
115
132
  _handleZoom(activeZoom) {
116
133
  if (Math.abs(this.zoomDeltaCurrentFrame) > Epsilon) {
117
134
  let pickDistance;
@@ -124,17 +141,17 @@ export class GeospatialCameraMovement extends CameraMovement {
124
141
  // Active zoom - pick and store the distance
125
142
  const pickResult = this._scene.pick(this._scene.pointerX, this._scene.pointerY, this.pickPredicate);
126
143
  if (pickResult.hit && pickResult.pickedPoint && pickResult.ray && this.zoomToCursor) {
127
- // Store both the zoom direction and the pick distance for use during inertia
128
- pickResult.ray.direction.normalizeToRef(this.computedPerFrameZoomVector);
144
+ // Store both the zoom picked point and the pick distance for use during inertia
129
145
  pickDistance = pickResult.distance;
130
146
  this._storedZoomPickDistance = pickDistance;
147
+ this.computedPerFrameZoomPickPoint = pickResult.pickedPoint;
131
148
  }
132
149
  else {
133
150
  // If no hit under cursor, zoom along lookVector instead
134
- this._cameraLookAt.normalizeToRef(this.computedPerFrameZoomVector);
135
- const lookPickResult = this.pickAlongVector(this.computedPerFrameZoomVector);
151
+ const lookPickResult = this.pickAlongVector(this._cameraLookAt);
136
152
  pickDistance = lookPickResult?.distance;
137
153
  this._storedZoomPickDistance = pickDistance;
154
+ this.computedPerFrameZoomPickPoint = undefined;
138
155
  }
139
156
  }
140
157
  // Clamp distance based on limits and update center
@@ -167,6 +184,25 @@ export class GeospatialCameraMovement extends CameraMovement {
167
184
  return this._scene.pickWithRay(this._tempPickingRay, this.pickPredicate);
168
185
  }
169
186
  }
187
+ export function ClampCenterFromPolesInPlace(center) {
188
+ const sineOfSphericalLatitudeLimit = 0.998749218; // ~90 degrees
189
+ const centerMagnitude = center.length(); // distance from planet origin
190
+ if (centerMagnitude > Epsilon) {
191
+ const sineSphericalLat = centerMagnitude === 0 ? 0 : center.z / centerMagnitude;
192
+ if (Math.abs(sineSphericalLat) > sineOfSphericalLatitudeLimit) {
193
+ // Clamp the spherical latitude (and derive longitude)
194
+ const sineOfClampedSphericalLat = Clamp(sineSphericalLat, -sineOfSphericalLatitudeLimit, sineOfSphericalLatitudeLimit);
195
+ const cosineOfClampedSphericalLat = Math.sqrt(1 - sineOfClampedSphericalLat * sineOfClampedSphericalLat);
196
+ const longitude = Math.atan2(center.y, center.x);
197
+ // Spherical to Cartesian
198
+ const newX = centerMagnitude * Math.cos(longitude) * cosineOfClampedSphericalLat;
199
+ const newY = centerMagnitude * Math.sin(longitude) * cosineOfClampedSphericalLat;
200
+ const newZ = centerMagnitude * sineOfClampedSphericalLat;
201
+ center.set(newX, newY, newZ);
202
+ }
203
+ }
204
+ return center;
205
+ }
170
206
  function IntersectRayWithPlaneToRef(ray, plane, ref) {
171
207
  // Distance along the ray to the plane; null if no hit
172
208
  const dist = ray.intersectsPlane(plane);