@babylonjs/core 8.44.1 → 8.45.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 (121) hide show
  1. package/Cameras/Inputs/geospatialCameraKeyboardInput.js +6 -10
  2. package/Cameras/Inputs/geospatialCameraKeyboardInput.js.map +1 -1
  3. package/Cameras/Inputs/geospatialCameraMouseWheelInput.js +1 -1
  4. package/Cameras/Inputs/geospatialCameraMouseWheelInput.js.map +1 -1
  5. package/Cameras/Limits/geospatialLimits.d.ts +4 -22
  6. package/Cameras/Limits/geospatialLimits.js +4 -36
  7. package/Cameras/Limits/geospatialLimits.js.map +1 -1
  8. package/Cameras/geospatialCamera.d.ts +15 -4
  9. package/Cameras/geospatialCamera.js +90 -37
  10. package/Cameras/geospatialCamera.js.map +1 -1
  11. package/Cameras/geospatialCameraMovement.d.ts +1 -3
  12. package/Cameras/geospatialCameraMovement.js +15 -51
  13. package/Cameras/geospatialCameraMovement.js.map +1 -1
  14. package/Collisions/collisionCoordinator.d.ts +2 -2
  15. package/Collisions/collisionCoordinator.js +1 -0
  16. package/Collisions/collisionCoordinator.js.map +1 -1
  17. package/Engines/Extensions/engine.debugging.d.ts +3 -5
  18. package/Engines/Extensions/engine.debugging.js +3 -4
  19. package/Engines/Extensions/engine.debugging.js.map +1 -1
  20. package/Engines/WebGPU/Extensions/engine.debugging.js +15 -65
  21. package/Engines/WebGPU/Extensions/engine.debugging.js.map +1 -1
  22. package/Engines/WebGPU/webgpuTextureManager.js +9 -9
  23. package/Engines/WebGPU/webgpuTextureManager.js.map +1 -1
  24. package/Engines/abstractEngine.d.ts +2 -0
  25. package/Engines/abstractEngine.js +4 -2
  26. package/Engines/abstractEngine.js.map +1 -1
  27. package/Engines/thinWebGPUEngine.d.ts +0 -2
  28. package/Engines/thinWebGPUEngine.js +0 -8
  29. package/Engines/thinWebGPUEngine.js.map +1 -1
  30. package/Engines/webgpuEngine.d.ts +1 -3
  31. package/Engines/webgpuEngine.js +4 -10
  32. package/Engines/webgpuEngine.js.map +1 -1
  33. package/FrameGraph/Passes/renderPass.js +4 -9
  34. package/FrameGraph/Passes/renderPass.js.map +1 -1
  35. package/FrameGraph/Tasks/PostProcesses/postProcessTask.js +3 -0
  36. package/FrameGraph/Tasks/PostProcesses/postProcessTask.js.map +1 -1
  37. package/FrameGraph/Tasks/Rendering/geometryRendererTask.d.ts +1 -1
  38. package/FrameGraph/Tasks/Rendering/geometryRendererTask.js +4 -1
  39. package/FrameGraph/Tasks/Rendering/geometryRendererTask.js.map +1 -1
  40. package/FrameGraph/Tasks/Rendering/objectRendererTask.d.ts +2 -1
  41. package/FrameGraph/Tasks/Rendering/objectRendererTask.js +31 -7
  42. package/FrameGraph/Tasks/Rendering/objectRendererTask.js.map +1 -1
  43. package/FrameGraph/frameGraph.js +2 -2
  44. package/FrameGraph/frameGraph.js.map +1 -1
  45. package/FrameGraph/frameGraphContext.d.ts +9 -0
  46. package/FrameGraph/frameGraphContext.js +13 -2
  47. package/FrameGraph/frameGraphContext.js.map +1 -1
  48. package/FrameGraph/frameGraphObjectList.js.map +1 -1
  49. package/FrameGraph/frameGraphRenderContext.d.ts +9 -8
  50. package/FrameGraph/frameGraphRenderContext.js +23 -20
  51. package/FrameGraph/frameGraphRenderContext.js.map +1 -1
  52. package/FrameGraph/frameGraphTask.d.ts +2 -0
  53. package/FrameGraph/frameGraphTask.js +14 -4
  54. package/FrameGraph/frameGraphTask.js.map +1 -1
  55. package/Lights/Shadows/cascadedShadowGenerator.js +4 -1
  56. package/Lights/Shadows/cascadedShadowGenerator.js.map +1 -1
  57. package/Lights/Shadows/shadowGenerator.js +8 -3
  58. package/Lights/Shadows/shadowGenerator.js.map +1 -1
  59. package/Lights/areaLight.d.ts +2 -1
  60. package/Lights/areaLight.js +3 -2
  61. package/Lights/areaLight.js.map +1 -1
  62. package/Lights/directionalLight.d.ts +2 -1
  63. package/Lights/directionalLight.js +3 -2
  64. package/Lights/directionalLight.js.map +1 -1
  65. package/Lights/hemisphericLight.d.ts +2 -1
  66. package/Lights/hemisphericLight.js +3 -2
  67. package/Lights/hemisphericLight.js.map +1 -1
  68. package/Lights/light.d.ts +2 -1
  69. package/Lights/light.js +8 -3
  70. package/Lights/light.js.map +1 -1
  71. package/Lights/lightingVolume.js +11 -6
  72. package/Lights/lightingVolume.js.map +1 -1
  73. package/Lights/pointLight.d.ts +2 -1
  74. package/Lights/pointLight.js +3 -2
  75. package/Lights/pointLight.js.map +1 -1
  76. package/Lights/rectAreaLight.d.ts +2 -1
  77. package/Lights/rectAreaLight.js +3 -2
  78. package/Lights/rectAreaLight.js.map +1 -1
  79. package/Lights/spotLight.d.ts +2 -1
  80. package/Lights/spotLight.js +3 -2
  81. package/Lights/spotLight.js.map +1 -1
  82. package/Materials/Node/Blocks/Input/inputBlock.js +3 -0
  83. package/Materials/Node/Blocks/Input/inputBlock.js.map +1 -1
  84. package/Materials/Node/nodeMaterial.d.ts +1 -0
  85. package/Materials/Node/nodeMaterial.js +4 -0
  86. package/Materials/Node/nodeMaterial.js.map +1 -1
  87. package/Materials/Node/nodeMaterialBuildStateSharedData.d.ts +6 -0
  88. package/Materials/Node/nodeMaterialBuildStateSharedData.js +4 -0
  89. package/Materials/Node/nodeMaterialBuildStateSharedData.js.map +1 -1
  90. package/Materials/Textures/Loaders/iesTextureLoader.js +1 -1
  91. package/Materials/Textures/Loaders/iesTextureLoader.js.map +1 -1
  92. package/Materials/Textures/Procedurals/proceduralTexture.js +7 -2
  93. package/Materials/Textures/Procedurals/proceduralTexture.js.map +1 -1
  94. package/Materials/Textures/internalTexture.d.ts +6 -4
  95. package/Materials/Textures/internalTexture.js +6 -4
  96. package/Materials/Textures/internalTexture.js.map +1 -1
  97. package/Materials/Textures/renderTargetTexture.js +2 -2
  98. package/Materials/Textures/renderTargetTexture.js.map +1 -1
  99. package/Materials/Textures/textureSampler.d.ts +3 -3
  100. package/Materials/Textures/textureSampler.js.map +1 -1
  101. package/Misc/minMaxReducer.js +2 -2
  102. package/Misc/minMaxReducer.js.map +1 -1
  103. package/Misc/screenshotTools.d.ts +3 -1
  104. package/Misc/screenshotTools.js +5 -2
  105. package/Misc/screenshotTools.js.map +1 -1
  106. package/Particles/Node/nodeParticleSystemSet.helper.js +47 -46
  107. package/Particles/Node/nodeParticleSystemSet.helper.js.map +1 -1
  108. package/PostProcesses/RenderPipeline/Pipelines/taaMaterialManager.js +4 -1
  109. package/PostProcesses/RenderPipeline/Pipelines/taaMaterialManager.js.map +1 -1
  110. package/Probes/reflectionProbe.js +9 -2
  111. package/Probes/reflectionProbe.js.map +1 -1
  112. package/Rendering/depthRenderer.js +7 -2
  113. package/Rendering/depthRenderer.js.map +1 -1
  114. package/Shaders/particles.vertex.js +8 -1
  115. package/Shaders/particles.vertex.js.map +1 -1
  116. package/ShadersWGSL/particles.vertex.js +6 -0
  117. package/ShadersWGSL/particles.vertex.js.map +1 -1
  118. package/package.json +1 -1
  119. package/scene.d.ts +10 -0
  120. package/scene.js +30 -5
  121. package/scene.js.map +1 -1
@@ -113,13 +113,9 @@ export class GeospatialCameraKeyboardInput {
113
113
  */
114
114
  detachControl() {
115
115
  if (this._scene) {
116
- if (this._onKeyboardObserver) {
117
- this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);
118
- }
119
- if (this._onCanvasBlurObserver) {
120
- this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);
121
- }
116
+ this._onKeyboardObserver?.remove();
122
117
  this._onKeyboardObserver = null;
118
+ this._onCanvasBlurObserver?.remove();
123
119
  this._onCanvasBlurObserver = null;
124
120
  }
125
121
  this._keys.length = 0;
@@ -151,10 +147,10 @@ export class GeospatialCameraKeyboardInput {
151
147
  else {
152
148
  // Zoom
153
149
  if (this.keysZoomIn.indexOf(keyCode) !== -1) {
154
- camera.movement.zoomAccumulatedPixels += this.zoomSensitivity;
150
+ camera.movement.handleZoom(this.zoomSensitivity, false);
155
151
  }
156
152
  else if (this.keysZoomOut.indexOf(keyCode) !== -1) {
157
- camera.movement.zoomAccumulatedPixels -= this.zoomSensitivity;
153
+ camera.movement.handleZoom(-this.zoomSensitivity, false);
158
154
  }
159
155
  else {
160
156
  // Call into movement class handleDrag so that behavior matches that of pointer input, simulating drag from center of screen
@@ -162,10 +158,10 @@ export class GeospatialCameraKeyboardInput {
162
158
  const centerY = this._engine.getRenderHeight() / 2;
163
159
  camera.movement.startDrag(centerX, centerY);
164
160
  if (this.keysLeft.indexOf(keyCode) !== -1) {
165
- camera.movement.handleDrag(centerX - this.panSensitivity, centerY);
161
+ camera.movement.handleDrag(centerX + this.panSensitivity, centerY);
166
162
  }
167
163
  else if (this.keysRight.indexOf(keyCode) !== -1) {
168
- camera.movement.handleDrag(centerX + this.panSensitivity, centerY);
164
+ camera.movement.handleDrag(centerX - this.panSensitivity, centerY);
169
165
  }
170
166
  else if (this.keysUp.indexOf(keyCode) !== -1) {
171
167
  camera.movement.handleDrag(centerX, centerY + this.panSensitivity);
@@ -1 +1 @@
1
- {"version":3,"file":"geospatialCameraKeyboardInput.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Inputs/geospatialCameraKeyboardInput.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAKlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AACjE,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAGzC;;;GAGG;AACH,MAAM,OAAO,6BAA6B;IAA1C;QAMI;;WAEG;QAEI,WAAM,GAAG,CAAC,EAAE,CAAC,CAAC;QAErB;;WAEG;QAEI,aAAQ,GAAG,CAAC,EAAE,CAAC,CAAC;QAEvB;;WAEG;QAEI,aAAQ,GAAG,CAAC,EAAE,CAAC,CAAC;QAEvB;;WAEG;QAEI,cAAS,GAAG,CAAC,EAAE,CAAC,CAAC;QAExB;;WAEG;QAEI,eAAU,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,8BAA8B;QAE9D;;WAEG;QAEI,gBAAW,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,8BAA8B;QAE/D;;;WAGG;QAEI,wBAAmB,GAAG,GAAG,CAAC;QAEjC;;;WAGG;QAEI,mBAAc,GAAW,GAAG,CAAC;QAEpC;;;WAGG;QAEI,oBAAe,GAAW,GAAG,CAAC;QAE7B,UAAK,GAAG,IAAI,KAAK,EAAU,CAAC;IA+JxC,CAAC;IAxJG;;;OAGG;IACI,aAAa,CAAC,gBAA0B;QAC3C,uCAAuC;QACvC,gBAAgB,GAAG,KAAK,CAAC,gCAAgC,CAAC,SAAS,CAAC,CAAC;QAErE,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAC7B,OAAO;QACX,CAAC;QAED,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QAEvC,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC,GAAG,CAAC,GAAG,EAAE;YACtE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACrE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC;YACvB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;gBACf,IAAI,IAAI,CAAC,IAAI,KAAK,kBAAkB,CAAC,OAAO,EAAE,CAAC;oBAC3C,IAAI,CAAC,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC;oBAEhC,IACI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBACvC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBACzC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBACzC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBAC1C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBAC3C,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAC9C,CAAC;wBACC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;wBAE9C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;4BACf,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;wBACjC,CAAC;wBAED,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;4BACrB,IAAI,CAAC,gBAAgB,EAAE,CAAC;gCACpB,GAAG,CAAC,cAAc,EAAE,CAAC;4BACzB,CAAC;wBACL,CAAC;oBACL,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACJ,IACI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBACvC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBACzC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBACzC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBAC1C,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;wBAC3C,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAC9C,CAAC;wBACC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;wBAE9C,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;4BACb,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;wBAChC,CAAC;wBAED,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;4BACrB,IAAI,CAAC,gBAAgB,EAAE,CAAC;gCACpB,GAAG,CAAC,cAAc,EAAE,CAAC;4BACzB,CAAC;wBACL,CAAC;oBACL,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;OAEG;IACI,aAAa;QAChB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YACd,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;gBAC3B,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACtE,CAAC;YACD,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;gBAC7B,IAAI,CAAC,OAAO,CAAC,sBAAsB,CAAC,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;YAC3E,CAAC;YACD,IAAI,CAAC,mBAAmB,GAAG,IAAI,CAAC;YAChC,IAAI,CAAC,qBAAqB,GAAG,IAAI,CAAC;QACtC,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACI,WAAW;QACd,IAAI,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;YAE3B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;gBACrD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;gBAClC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;oBACpB,WAAW;oBACX,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;wBACxC,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,IAAI,IAAI,CAAC,mBAAmB,CAAC;oBAC5E,CAAC;yBAAM,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;wBAChD,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,IAAI,IAAI,CAAC,mBAAmB,CAAC;oBAC5E,CAAC;yBAAM,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;wBAC7C,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,IAAI,IAAI,CAAC,mBAAmB,CAAC;oBAC5E,CAAC;yBAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;wBAC/C,MAAM,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC,IAAI,IAAI,CAAC,mBAAmB,CAAC;oBAC5E,CAAC;gBACL,CAAC;qBAAM,CAAC;oBACJ,OAAO;oBACP,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;wBAC1C,MAAM,CAAC,QAAQ,CAAC,qBAAqB,IAAI,IAAI,CAAC,eAAe,CAAC;oBAClE,CAAC;yBAAM,IAAI,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;wBAClD,MAAM,CAAC,QAAQ,CAAC,qBAAqB,IAAI,IAAI,CAAC,eAAe,CAAC;oBAClE,CAAC;yBAAM,CAAC;wBACJ,4HAA4H;wBAC5H,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;wBAClD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC;wBACnD,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;wBAC5C,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BACxC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;wBACvE,CAAC;6BAAM,IAAI,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BAChD,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,GAAG,IAAI,CAAC,cAAc,EAAE,OAAO,CAAC,CAAC;wBACvE,CAAC;6BAAM,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BAC7C,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;wBACvE,CAAC;6BAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;4BAC/C,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,CAAC;wBACvE,CAAC;wBACD,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;oBAC/B,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAED;;;OAGG;IACI,YAAY;QACf,OAAO,+BAA+B,CAAC;IAC3C,CAAC;IAED;;;OAGG;IACI,aAAa;QAChB,OAAO,UAAU,CAAC;IACtB,CAAC;CACJ;AApNU;IADN,SAAS,EAAE;6DACS;AAMd;IADN,SAAS,EAAE;+DACW;AAMhB;IADN,SAAS,EAAE;+DACW;AAMhB;IADN,SAAS,EAAE;gEACY;AAMjB;IADN,SAAS,EAAE;iEACmB;AAMxB;IADN,SAAS,EAAE;kEACoB;AAOzB;IADN,SAAS,EAAE;0EACqB;AAO1B;IADN,SAAS,EAAE;qEACwB;AAO7B;IADN,SAAS,EAAE;sEACyB;AAmKnC,gBAAiB,CAAC,+BAA+B,CAAC,GAAG,6BAA6B,CAAC","sourcesContent":["import type { Nullable } from \"../../types\";\r\nimport { serialize } from \"../../Misc/decorators\";\r\nimport type { Observer } from \"../../Misc/observable\";\r\nimport type { Scene } from \"../../scene\";\r\nimport type { GeospatialCamera } from \"../geospatialCamera\";\r\nimport type { ICameraInput } from \"../cameraInputsManager\";\r\nimport { CameraInputTypes } from \"../cameraInputsManager\";\r\nimport type { KeyboardInfo } from \"../../Events/keyboardEvents\";\r\nimport { KeyboardEventTypes } from \"../../Events/keyboardEvents\";\r\nimport { Tools } from \"../../Misc/tools\";\r\nimport type { AbstractEngine } from \"../../Engines/abstractEngine\";\r\n\r\n/**\r\n * Manage the keyboard inputs to control the movement of a geospatial camera.\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs\r\n */\r\nexport class GeospatialCameraKeyboardInput implements ICameraInput<GeospatialCamera> {\r\n /**\r\n * Defines the camera the input is attached to.\r\n */\r\n public camera: GeospatialCamera;\r\n\r\n /**\r\n * Defines the list of key codes associated with the up action (pan up)\r\n */\r\n @serialize()\r\n public keysUp = [38];\r\n\r\n /**\r\n * Defines the list of key codes associated with the down action (pan down)\r\n */\r\n @serialize()\r\n public keysDown = [40];\r\n\r\n /**\r\n * Defines the list of key codes associated with the left action (pan left)\r\n */\r\n @serialize()\r\n public keysLeft = [37];\r\n\r\n /**\r\n * Defines the list of key codes associated with the right action (pan right)\r\n */\r\n @serialize()\r\n public keysRight = [39];\r\n\r\n /**\r\n * Defines the list of key codes associated with zoom in (+ or =)\r\n */\r\n @serialize()\r\n public keysZoomIn = [187, 107]; // 187 = + key, 107 = numpad +\r\n\r\n /**\r\n * Defines the list of key codes associated with zoom out (-)\r\n */\r\n @serialize()\r\n public keysZoomOut = [189, 109]; // 189 = - key, 109 = numpad -\r\n\r\n /**\r\n * Defines the rotation sensitivity of the inputs.\r\n * (How many pixels of pointer input to apply per keypress, before rotation speed factor is applied by movement class)\r\n */\r\n @serialize()\r\n public rotationSensitivity = 1.0;\r\n\r\n /**\r\n * Defines the panning sensitivity of the inputs.\r\n * (How many pixels of pointer input to apply per keypress, before pan speed factor is applied by movement class)\r\n */\r\n @serialize()\r\n public panSensitivity: number = 1.0;\r\n\r\n /**\r\n * Defines the zooming sensitivity of the inputs.\r\n * (How many pixels of pointer input to apply per keypress, before zoom speed factor is applied by movement class)\r\n */\r\n @serialize()\r\n public zoomSensitivity: number = 1.0;\r\n\r\n private _keys = new Array<number>();\r\n private _ctrlPressed: boolean;\r\n private _onCanvasBlurObserver: Nullable<Observer<AbstractEngine>>;\r\n private _onKeyboardObserver: Nullable<Observer<KeyboardInfo>>;\r\n private _engine: AbstractEngine;\r\n private _scene: Scene;\r\n\r\n /**\r\n * Attach the input controls to a specific dom element to get the input from.\r\n * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)\r\n */\r\n public attachControl(noPreventDefault?: boolean): void {\r\n // was there a second variable defined?\r\n noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);\r\n\r\n if (this._onCanvasBlurObserver) {\r\n return;\r\n }\r\n\r\n this._scene = this.camera.getScene();\r\n this._engine = this._scene.getEngine();\r\n\r\n this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(() => {\r\n this._keys.length = 0;\r\n });\r\n\r\n this._onKeyboardObserver = this._scene.onKeyboardObservable.add((info) => {\r\n const evt = info.event;\r\n if (!evt.metaKey) {\r\n if (info.type === KeyboardEventTypes.KEYDOWN) {\r\n this._ctrlPressed = evt.ctrlKey;\r\n\r\n if (\r\n this.keysUp.indexOf(evt.keyCode) !== -1 ||\r\n this.keysDown.indexOf(evt.keyCode) !== -1 ||\r\n this.keysLeft.indexOf(evt.keyCode) !== -1 ||\r\n this.keysRight.indexOf(evt.keyCode) !== -1 ||\r\n this.keysZoomIn.indexOf(evt.keyCode) !== -1 ||\r\n this.keysZoomOut.indexOf(evt.keyCode) !== -1\r\n ) {\r\n const index = this._keys.indexOf(evt.keyCode);\r\n\r\n if (index === -1) {\r\n this._keys.push(evt.keyCode);\r\n }\r\n\r\n if (evt.preventDefault) {\r\n if (!noPreventDefault) {\r\n evt.preventDefault();\r\n }\r\n }\r\n }\r\n } else {\r\n if (\r\n this.keysUp.indexOf(evt.keyCode) !== -1 ||\r\n this.keysDown.indexOf(evt.keyCode) !== -1 ||\r\n this.keysLeft.indexOf(evt.keyCode) !== -1 ||\r\n this.keysRight.indexOf(evt.keyCode) !== -1 ||\r\n this.keysZoomIn.indexOf(evt.keyCode) !== -1 ||\r\n this.keysZoomOut.indexOf(evt.keyCode) !== -1\r\n ) {\r\n const index = this._keys.indexOf(evt.keyCode);\r\n\r\n if (index >= 0) {\r\n this._keys.splice(index, 1);\r\n }\r\n\r\n if (evt.preventDefault) {\r\n if (!noPreventDefault) {\r\n evt.preventDefault();\r\n }\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Detach the current controls from the specified dom element.\r\n */\r\n public detachControl(): void {\r\n if (this._scene) {\r\n if (this._onKeyboardObserver) {\r\n this._scene.onKeyboardObservable.remove(this._onKeyboardObserver);\r\n }\r\n if (this._onCanvasBlurObserver) {\r\n this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver);\r\n }\r\n this._onKeyboardObserver = null;\r\n this._onCanvasBlurObserver = null;\r\n }\r\n\r\n this._keys.length = 0;\r\n }\r\n\r\n /**\r\n * Update the current camera state depending on the inputs that have been used this frame.\r\n * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.\r\n */\r\n public checkInputs(): void {\r\n if (this._onKeyboardObserver) {\r\n const camera = this.camera;\r\n\r\n for (let index = 0; index < this._keys.length; index++) {\r\n const keyCode = this._keys[index];\r\n if (this._ctrlPressed) {\r\n // Rotation\r\n if (this.keysLeft.indexOf(keyCode) !== -1) {\r\n camera.movement.rotationAccumulatedPixels.y -= this.rotationSensitivity;\r\n } else if (this.keysRight.indexOf(keyCode) !== -1) {\r\n camera.movement.rotationAccumulatedPixels.y += this.rotationSensitivity;\r\n } else if (this.keysUp.indexOf(keyCode) !== -1) {\r\n camera.movement.rotationAccumulatedPixels.x -= this.rotationSensitivity;\r\n } else if (this.keysDown.indexOf(keyCode) !== -1) {\r\n camera.movement.rotationAccumulatedPixels.x += this.rotationSensitivity;\r\n }\r\n } else {\r\n // Zoom\r\n if (this.keysZoomIn.indexOf(keyCode) !== -1) {\r\n camera.movement.zoomAccumulatedPixels += this.zoomSensitivity;\r\n } else if (this.keysZoomOut.indexOf(keyCode) !== -1) {\r\n camera.movement.zoomAccumulatedPixels -= this.zoomSensitivity;\r\n } else {\r\n // Call into movement class handleDrag so that behavior matches that of pointer input, simulating drag from center of screen\r\n const centerX = this._engine.getRenderWidth() / 2;\r\n const centerY = this._engine.getRenderHeight() / 2;\r\n camera.movement.startDrag(centerX, centerY);\r\n if (this.keysLeft.indexOf(keyCode) !== -1) {\r\n camera.movement.handleDrag(centerX - this.panSensitivity, centerY);\r\n } else if (this.keysRight.indexOf(keyCode) !== -1) {\r\n camera.movement.handleDrag(centerX + this.panSensitivity, centerY);\r\n } else if (this.keysUp.indexOf(keyCode) !== -1) {\r\n camera.movement.handleDrag(centerX, centerY + this.panSensitivity);\r\n } else if (this.keysDown.indexOf(keyCode) !== -1) {\r\n camera.movement.handleDrag(centerX, centerY - this.panSensitivity);\r\n }\r\n camera.movement.stopDrag();\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Gets the class name of the current input.\r\n * @returns the class name\r\n */\r\n public getClassName(): string {\r\n return \"GeospatialCameraKeyboardInput\";\r\n }\r\n\r\n /**\r\n * Get the friendly name associated with the input class.\r\n * @returns the input friendly name\r\n */\r\n public getSimpleName(): string {\r\n return \"keyboard\";\r\n }\r\n}\r\n\r\n(<any>CameraInputTypes)[\"GeospatialCameraKeyboardInput\"] = GeospatialCameraKeyboardInput;\r\n"]}
1
+ {"version":3,"file":"geospatialCameraKeyboardInput.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Inputs/geospatialCameraKeyboardInput.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Nullable } from \"../../types\";\r\nimport { serialize } from \"../../Misc/decorators\";\r\nimport type { Observer } from \"../../Misc/observable\";\r\nimport type { Scene } from \"../../scene\";\r\nimport type { GeospatialCamera } from \"../geospatialCamera\";\r\nimport type { ICameraInput } from \"../cameraInputsManager\";\r\nimport { CameraInputTypes } from \"../cameraInputsManager\";\r\nimport type { KeyboardInfo } from \"../../Events/keyboardEvents\";\r\nimport { KeyboardEventTypes } from \"../../Events/keyboardEvents\";\r\nimport { Tools } from \"../../Misc/tools\";\r\nimport type { AbstractEngine } from \"../../Engines/abstractEngine\";\r\n\r\n/**\r\n * Manage the keyboard inputs to control the movement of a geospatial camera.\r\n * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs\r\n */\r\nexport class GeospatialCameraKeyboardInput implements ICameraInput<GeospatialCamera> {\r\n /**\r\n * Defines the camera the input is attached to.\r\n */\r\n public camera: GeospatialCamera;\r\n\r\n /**\r\n * Defines the list of key codes associated with the up action (pan up)\r\n */\r\n @serialize()\r\n public keysUp = [38];\r\n\r\n /**\r\n * Defines the list of key codes associated with the down action (pan down)\r\n */\r\n @serialize()\r\n public keysDown = [40];\r\n\r\n /**\r\n * Defines the list of key codes associated with the left action (pan left)\r\n */\r\n @serialize()\r\n public keysLeft = [37];\r\n\r\n /**\r\n * Defines the list of key codes associated with the right action (pan right)\r\n */\r\n @serialize()\r\n public keysRight = [39];\r\n\r\n /**\r\n * Defines the list of key codes associated with zoom in (+ or =)\r\n */\r\n @serialize()\r\n public keysZoomIn = [187, 107]; // 187 = + key, 107 = numpad +\r\n\r\n /**\r\n * Defines the list of key codes associated with zoom out (-)\r\n */\r\n @serialize()\r\n public keysZoomOut = [189, 109]; // 189 = - key, 109 = numpad -\r\n\r\n /**\r\n * Defines the rotation sensitivity of the inputs.\r\n * (How many pixels of pointer input to apply per keypress, before rotation speed factor is applied by movement class)\r\n */\r\n @serialize()\r\n public rotationSensitivity = 1.0;\r\n\r\n /**\r\n * Defines the panning sensitivity of the inputs.\r\n * (How many pixels of pointer input to apply per keypress, before pan speed factor is applied by movement class)\r\n */\r\n @serialize()\r\n public panSensitivity: number = 1.0;\r\n\r\n /**\r\n * Defines the zooming sensitivity of the inputs.\r\n * (How many pixels of pointer input to apply per keypress, before zoom speed factor is applied by movement class)\r\n */\r\n @serialize()\r\n public zoomSensitivity: number = 1.0;\r\n\r\n private _keys = new Array<number>();\r\n private _ctrlPressed: boolean;\r\n private _onCanvasBlurObserver: Nullable<Observer<AbstractEngine>>;\r\n private _onKeyboardObserver: Nullable<Observer<KeyboardInfo>>;\r\n private _engine: AbstractEngine;\r\n private _scene: Scene;\r\n\r\n /**\r\n * Attach the input controls to a specific dom element to get the input from.\r\n * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)\r\n */\r\n public attachControl(noPreventDefault?: boolean): void {\r\n // was there a second variable defined?\r\n noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);\r\n\r\n if (this._onCanvasBlurObserver) {\r\n return;\r\n }\r\n\r\n this._scene = this.camera.getScene();\r\n this._engine = this._scene.getEngine();\r\n\r\n this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(() => {\r\n this._keys.length = 0;\r\n });\r\n\r\n this._onKeyboardObserver = this._scene.onKeyboardObservable.add((info) => {\r\n const evt = info.event;\r\n if (!evt.metaKey) {\r\n if (info.type === KeyboardEventTypes.KEYDOWN) {\r\n this._ctrlPressed = evt.ctrlKey;\r\n\r\n if (\r\n this.keysUp.indexOf(evt.keyCode) !== -1 ||\r\n this.keysDown.indexOf(evt.keyCode) !== -1 ||\r\n this.keysLeft.indexOf(evt.keyCode) !== -1 ||\r\n this.keysRight.indexOf(evt.keyCode) !== -1 ||\r\n this.keysZoomIn.indexOf(evt.keyCode) !== -1 ||\r\n this.keysZoomOut.indexOf(evt.keyCode) !== -1\r\n ) {\r\n const index = this._keys.indexOf(evt.keyCode);\r\n\r\n if (index === -1) {\r\n this._keys.push(evt.keyCode);\r\n }\r\n\r\n if (evt.preventDefault) {\r\n if (!noPreventDefault) {\r\n evt.preventDefault();\r\n }\r\n }\r\n }\r\n } else {\r\n if (\r\n this.keysUp.indexOf(evt.keyCode) !== -1 ||\r\n this.keysDown.indexOf(evt.keyCode) !== -1 ||\r\n this.keysLeft.indexOf(evt.keyCode) !== -1 ||\r\n this.keysRight.indexOf(evt.keyCode) !== -1 ||\r\n this.keysZoomIn.indexOf(evt.keyCode) !== -1 ||\r\n this.keysZoomOut.indexOf(evt.keyCode) !== -1\r\n ) {\r\n const index = this._keys.indexOf(evt.keyCode);\r\n\r\n if (index >= 0) {\r\n this._keys.splice(index, 1);\r\n }\r\n\r\n if (evt.preventDefault) {\r\n if (!noPreventDefault) {\r\n evt.preventDefault();\r\n }\r\n }\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Detach the current controls from the specified dom element.\r\n */\r\n public detachControl(): void {\r\n if (this._scene) {\r\n this._onKeyboardObserver?.remove();\r\n this._onKeyboardObserver = null;\r\n this._onCanvasBlurObserver?.remove();\r\n this._onCanvasBlurObserver = null;\r\n }\r\n\r\n this._keys.length = 0;\r\n }\r\n\r\n /**\r\n * Update the current camera state depending on the inputs that have been used this frame.\r\n * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.\r\n */\r\n public checkInputs(): void {\r\n if (this._onKeyboardObserver) {\r\n const camera = this.camera;\r\n\r\n for (let index = 0; index < this._keys.length; index++) {\r\n const keyCode = this._keys[index];\r\n if (this._ctrlPressed) {\r\n // Rotation\r\n if (this.keysLeft.indexOf(keyCode) !== -1) {\r\n camera.movement.rotationAccumulatedPixels.y -= this.rotationSensitivity;\r\n } else if (this.keysRight.indexOf(keyCode) !== -1) {\r\n camera.movement.rotationAccumulatedPixels.y += this.rotationSensitivity;\r\n } else if (this.keysUp.indexOf(keyCode) !== -1) {\r\n camera.movement.rotationAccumulatedPixels.x -= this.rotationSensitivity;\r\n } else if (this.keysDown.indexOf(keyCode) !== -1) {\r\n camera.movement.rotationAccumulatedPixels.x += this.rotationSensitivity;\r\n }\r\n } else {\r\n // Zoom\r\n if (this.keysZoomIn.indexOf(keyCode) !== -1) {\r\n camera.movement.handleZoom(this.zoomSensitivity, false);\r\n } else if (this.keysZoomOut.indexOf(keyCode) !== -1) {\r\n camera.movement.handleZoom(-this.zoomSensitivity, false);\r\n } else {\r\n // Call into movement class handleDrag so that behavior matches that of pointer input, simulating drag from center of screen\r\n const centerX = this._engine.getRenderWidth() / 2;\r\n const centerY = this._engine.getRenderHeight() / 2;\r\n camera.movement.startDrag(centerX, centerY);\r\n if (this.keysLeft.indexOf(keyCode) !== -1) {\r\n camera.movement.handleDrag(centerX + this.panSensitivity, centerY);\r\n } else if (this.keysRight.indexOf(keyCode) !== -1) {\r\n camera.movement.handleDrag(centerX - this.panSensitivity, centerY);\r\n } else if (this.keysUp.indexOf(keyCode) !== -1) {\r\n camera.movement.handleDrag(centerX, centerY + this.panSensitivity);\r\n } else if (this.keysDown.indexOf(keyCode) !== -1) {\r\n camera.movement.handleDrag(centerX, centerY - this.panSensitivity);\r\n }\r\n camera.movement.stopDrag();\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Gets the class name of the current input.\r\n * @returns the class name\r\n */\r\n public getClassName(): string {\r\n return \"GeospatialCameraKeyboardInput\";\r\n }\r\n\r\n /**\r\n * Get the friendly name associated with the input class.\r\n * @returns the input friendly name\r\n */\r\n public getSimpleName(): string {\r\n return \"keyboard\";\r\n }\r\n}\r\n\r\n(<any>CameraInputTypes)[\"GeospatialCameraKeyboardInput\"] = GeospatialCameraKeyboardInput;\r\n"]}
@@ -13,7 +13,7 @@ export class GeospatialCameraMouseWheelInput extends BaseCameraMouseWheelInput {
13
13
  return "GeospatialCameraMouseWheelInput";
14
14
  }
15
15
  checkInputs() {
16
- this.camera.movement.zoomAccumulatedPixels = this._wheelDeltaY;
16
+ this.camera.movement.handleZoom(this._wheelDeltaY, true);
17
17
  super.checkInputs();
18
18
  }
19
19
  }
@@ -1 +1 @@
1
- {"version":3,"file":"geospatialCameraMouseWheelInput.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Inputs/geospatialCameraMouseWheelInput.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE;;;GAGG;AACH,MAAM,OAAO,+BAAgC,SAAQ,yBAAyB;IAM1E;;;OAGG;IACa,YAAY;QACxB,OAAO,iCAAiC,CAAC;IAC7C,CAAC;IAEe,WAAW;QACvB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,qBAAqB,GAAG,IAAI,CAAC,YAAY,CAAC;QAC/D,KAAK,CAAC,WAAW,EAAE,CAAC;IACxB,CAAC;CACJ;AAEK,gBAAiB,CAAC,iCAAiC,CAAC,GAAG,+BAA+B,CAAC","sourcesContent":["import type { GeospatialCamera } from \"../../Cameras/geospatialCamera\";\r\nimport { CameraInputTypes } from \"../../Cameras/cameraInputsManager\";\r\nimport { BaseCameraMouseWheelInput } from \"./BaseCameraMouseWheelInput\";\r\n\r\n/**\r\n * @experimental\r\n * Manage the mouse wheel inputs to control a geospatial camera. As this feature is experimental the API will evolve\r\n */\r\nexport class GeospatialCameraMouseWheelInput extends BaseCameraMouseWheelInput {\r\n /**\r\n * Defines the camera the input is attached to.\r\n */\r\n public camera: GeospatialCamera;\r\n\r\n /**\r\n * Gets the class name of the current input.\r\n * @returns the class name\r\n */\r\n public override getClassName(): string {\r\n return \"GeospatialCameraMouseWheelInput\";\r\n }\r\n\r\n public override checkInputs(): void {\r\n this.camera.movement.zoomAccumulatedPixels = this._wheelDeltaY;\r\n super.checkInputs();\r\n }\r\n}\r\n\r\n(<any>CameraInputTypes)[\"GeospatialCameraMouseWheelInput\"] = GeospatialCameraMouseWheelInput;\r\n"]}
1
+ {"version":3,"file":"geospatialCameraMouseWheelInput.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Inputs/geospatialCameraMouseWheelInput.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAExE;;;GAGG;AACH,MAAM,OAAO,+BAAgC,SAAQ,yBAAyB;IAM1E;;;OAGG;IACa,YAAY;QACxB,OAAO,iCAAiC,CAAC;IAC7C,CAAC;IAEe,WAAW;QACvB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACzD,KAAK,CAAC,WAAW,EAAE,CAAC;IACxB,CAAC;CACJ;AAEK,gBAAiB,CAAC,iCAAiC,CAAC,GAAG,+BAA+B,CAAC","sourcesContent":["import type { GeospatialCamera } from \"../../Cameras/geospatialCamera\";\r\nimport { CameraInputTypes } from \"../../Cameras/cameraInputsManager\";\r\nimport { BaseCameraMouseWheelInput } from \"./BaseCameraMouseWheelInput\";\r\n\r\n/**\r\n * @experimental\r\n * Manage the mouse wheel inputs to control a geospatial camera. As this feature is experimental the API will evolve\r\n */\r\nexport class GeospatialCameraMouseWheelInput extends BaseCameraMouseWheelInput {\r\n /**\r\n * Defines the camera the input is attached to.\r\n */\r\n public camera: GeospatialCamera;\r\n\r\n /**\r\n * Gets the class name of the current input.\r\n * @returns the class name\r\n */\r\n public override getClassName(): string {\r\n return \"GeospatialCameraMouseWheelInput\";\r\n }\r\n\r\n public override checkInputs(): void {\r\n this.camera.movement.handleZoom(this._wheelDeltaY, true);\r\n super.checkInputs();\r\n }\r\n}\r\n\r\n(<any>CameraInputTypes)[\"GeospatialCameraMouseWheelInput\"] = GeospatialCameraMouseWheelInput;\r\n"]}
@@ -1,9 +1,7 @@
1
1
  /**
2
- * Limits for geospatial cameras with altitude/radius synchronization
2
+ * Limits for geospatial camera
3
3
  */
4
4
  export declare class GeospatialLimits {
5
- private _altitudeMin;
6
- private _altitudeMax;
7
5
  private _planetRadius;
8
6
  private _radiusMin;
9
7
  private _radiusMax;
@@ -22,33 +20,17 @@ export declare class GeospatialLimits {
22
20
  */
23
21
  pinchToPanMax: number;
24
22
  /**
25
- * @param planetRadius The radius of the planet (used for altitude/radius conversions)
23
+ * @param planetRadius The radius of the planet
26
24
  */
27
25
  constructor(planetRadius: number);
28
- /**
29
- * Gets the minimum altitude (height above planet surface)
30
- */
31
- get altitudeMin(): number;
32
- /**
33
- * Sets the minimum altitude and syncs it with radius
34
- */
35
- set altitudeMin(value: number);
36
- /**
37
- * Gets the maximum altitude (height above planet surface)
38
- */
39
- get altitudeMax(): number;
40
- /**
41
- * Sets the maximum altitude and syncs it with radius
42
- */
43
- set altitudeMax(value: number);
44
26
  get radiusMin(): number;
45
27
  /**
46
- * Sets the minimum radius and syncs it with altitude
28
+ * Sets the minimum radius
47
29
  */
48
30
  set radiusMin(value: number);
49
31
  get radiusMax(): number;
50
32
  /**
51
- * Sets the maximum radius and syncs it with altitude
33
+ * Sets the maximum radius
52
34
  */
53
35
  set radiusMax(value: number);
54
36
  /**
@@ -1,13 +1,12 @@
1
1
  import { Epsilon } from "../../Maths/math.constants.js";
2
2
  /**
3
- * Limits for geospatial cameras with altitude/radius synchronization
3
+ * Limits for geospatial camera
4
4
  */
5
5
  export class GeospatialLimits {
6
6
  /**
7
- * @param planetRadius The radius of the planet (used for altitude/radius conversions)
7
+ * @param planetRadius The radius of the planet
8
8
  */
9
9
  constructor(planetRadius) {
10
- this._altitudeMin = Epsilon;
11
10
  this._radiusMin = Epsilon;
12
11
  this._radiusMax = Infinity;
13
12
  /** Gets the minimum pitch angle (angle from horizon) -- 0 means looking straight down at planet */
@@ -26,51 +25,23 @@ export class GeospatialLimits {
26
25
  this.pinchToPanMax = 20;
27
26
  this._planetRadius = planetRadius;
28
27
  }
29
- /**
30
- * Gets the minimum altitude (height above planet surface)
31
- */
32
- get altitudeMin() {
33
- return this._altitudeMin;
34
- }
35
- /**
36
- * Sets the minimum altitude and syncs it with radius
37
- */
38
- set altitudeMin(value) {
39
- this._altitudeMin = value;
40
- this._radiusMin = this._planetRadius + value;
41
- }
42
- /**
43
- * Gets the maximum altitude (height above planet surface)
44
- */
45
- get altitudeMax() {
46
- return this._altitudeMax;
47
- }
48
- /**
49
- * Sets the maximum altitude and syncs it with radius
50
- */
51
- set altitudeMax(value) {
52
- this._altitudeMax = value;
53
- this._radiusMax = this._planetRadius + value;
54
- }
55
28
  get radiusMin() {
56
29
  return this._radiusMin;
57
30
  }
58
31
  /**
59
- * Sets the minimum radius and syncs it with altitude
32
+ * Sets the minimum radius
60
33
  */
61
34
  set radiusMin(value) {
62
35
  this._radiusMin = value;
63
- this._altitudeMin = value - this._planetRadius;
64
36
  }
65
37
  get radiusMax() {
66
38
  return this._radiusMax;
67
39
  }
68
40
  /**
69
- * Sets the maximum radius and syncs it with altitude
41
+ * Sets the maximum radius
70
42
  */
71
43
  set radiusMax(value) {
72
44
  this._radiusMax = value;
73
- this._altitudeMax = value - this._planetRadius;
74
45
  }
75
46
  /**
76
47
  * Gets the planet radius used for altitude/radius conversions
@@ -81,9 +52,6 @@ export class GeospatialLimits {
81
52
  /** Sets the planet radius and updates the radius limits to maintain current altitude */
82
53
  set planetRadius(value) {
83
54
  this._planetRadius = value;
84
- // Update radius limits to maintain current altitude
85
- this._radiusMin = value + this._altitudeMin;
86
- this._radiusMax = value + this._altitudeMax;
87
55
  }
88
56
  }
89
57
  //# sourceMappingURL=geospatialLimits.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"geospatialLimits.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Limits/geospatialLimits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD;;GAEG;AACH,MAAM,OAAO,gBAAgB;IAyBzB;;OAEG;IACH,YAAY,YAAoB;QA3BxB,iBAAY,GAAW,OAAO,CAAC;QAG/B,eAAU,GAAW,OAAO,CAAC;QAC7B,eAAU,GAAW,QAAQ,CAAC;QAEtC,mGAAmG;QAC5F,aAAQ,GAAW,OAAO,CAAC;QAElC,0FAA0F;QACnF,aAAQ,GAAW,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAEtC,2DAA2D;QACpD,WAAM,GAAW,CAAC,QAAQ,CAAC;QAElC,2DAA2D;QACpD,WAAM,GAAW,QAAQ,CAAC;QACjC;;;;WAIG;QACI,kBAAa,GAAW,EAAE,CAAC;QAM9B,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,IAAW,WAAW;QAClB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,IAAW,WAAW,CAAC,KAAa;QAChC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IACjD,CAAC;IAED;;OAEG;IACH,IAAW,WAAW;QAClB,OAAO,IAAI,CAAC,YAAY,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,IAAW,WAAW,CAAC,KAAa;QAChC,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IACjD,CAAC;IAED,IAAW,SAAS;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,IAAW,SAAS,CAAC,KAAa;QAC9B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC;IACnD,CAAC;IAED,IAAW,SAAS;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,IAAW,SAAS,CAAC,KAAa;QAC9B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;QACxB,IAAI,CAAC,YAAY,GAAG,KAAK,GAAG,IAAI,CAAC,aAAa,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,IAAW,YAAY;QACnB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC9B,CAAC;IAED,wFAAwF;IACxF,IAAW,YAAY,CAAC,KAAa;QACjC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC3B,oDAAoD;QACpD,IAAI,CAAC,UAAU,GAAG,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;QAC5C,IAAI,CAAC,UAAU,GAAG,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC;IAChD,CAAC;CACJ","sourcesContent":["import { Epsilon } from \"../../Maths/math.constants\";\r\n/**\r\n * Limits for geospatial cameras with altitude/radius synchronization\r\n */\r\nexport class GeospatialLimits {\r\n private _altitudeMin: number = Epsilon;\r\n private _altitudeMax: number;\r\n private _planetRadius: number;\r\n private _radiusMin: number = Epsilon;\r\n private _radiusMax: number = Infinity;\r\n\r\n /** Gets the minimum pitch angle (angle from horizon) -- 0 means looking straight down at planet */\r\n public pitchMin: number = Epsilon;\r\n\r\n /** Gets the maximum pitch angle (angle from horizon) -- Pi/1 means looking at horizon */\r\n public pitchMax: number = Math.PI / 2;\r\n\r\n /** Gets the minimum yaw angle (rotation around up axis) */\r\n public yawMin: number = -Infinity;\r\n\r\n /** Gets the maximum yaw angle (rotation around up axis) */\r\n public yawMax: number = Infinity;\r\n /**\r\n * Defines the distance used to consider the camera in pan mode vs pinch/zoom.\r\n * Basically if your fingers moves away from more than this distance you will be considered\r\n * in pinch mode.\r\n */\r\n public pinchToPanMax: number = 20;\r\n\r\n /**\r\n * @param planetRadius The radius of the planet (used for altitude/radius conversions)\r\n */\r\n constructor(planetRadius: number) {\r\n this._planetRadius = planetRadius;\r\n }\r\n\r\n /**\r\n * Gets the minimum altitude (height above planet surface)\r\n */\r\n public get altitudeMin(): number {\r\n return this._altitudeMin;\r\n }\r\n\r\n /**\r\n * Sets the minimum altitude and syncs it with radius\r\n */\r\n public set altitudeMin(value: number) {\r\n this._altitudeMin = value;\r\n this._radiusMin = this._planetRadius + value;\r\n }\r\n\r\n /**\r\n * Gets the maximum altitude (height above planet surface)\r\n */\r\n public get altitudeMax(): number {\r\n return this._altitudeMax;\r\n }\r\n\r\n /**\r\n * Sets the maximum altitude and syncs it with radius\r\n */\r\n public set altitudeMax(value: number) {\r\n this._altitudeMax = value;\r\n this._radiusMax = this._planetRadius + value;\r\n }\r\n\r\n public get radiusMin(): number {\r\n return this._radiusMin;\r\n }\r\n\r\n /**\r\n * Sets the minimum radius and syncs it with altitude\r\n */\r\n public set radiusMin(value: number) {\r\n this._radiusMin = value;\r\n this._altitudeMin = value - this._planetRadius;\r\n }\r\n\r\n public get radiusMax(): number {\r\n return this._radiusMax;\r\n }\r\n\r\n /**\r\n * Sets the maximum radius and syncs it with altitude\r\n */\r\n public set radiusMax(value: number) {\r\n this._radiusMax = value;\r\n this._altitudeMax = value - this._planetRadius;\r\n }\r\n\r\n /**\r\n * Gets the planet radius used for altitude/radius conversions\r\n */\r\n public get planetRadius(): number {\r\n return this._planetRadius;\r\n }\r\n\r\n /** Sets the planet radius and updates the radius limits to maintain current altitude */\r\n public set planetRadius(value: number) {\r\n this._planetRadius = value;\r\n // Update radius limits to maintain current altitude\r\n this._radiusMin = value + this._altitudeMin;\r\n this._radiusMax = value + this._altitudeMax;\r\n }\r\n}\r\n"]}
1
+ {"version":3,"file":"geospatialLimits.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Limits/geospatialLimits.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,4BAA4B,CAAC;AACrD;;GAEG;AACH,MAAM,OAAO,gBAAgB;IAuBzB;;OAEG;IACH,YAAY,YAAoB;QAxBxB,eAAU,GAAW,OAAO,CAAC;QAC7B,eAAU,GAAW,QAAQ,CAAC;QAEtC,mGAAmG;QAC5F,aAAQ,GAAW,OAAO,CAAC;QAElC,0FAA0F;QACnF,aAAQ,GAAW,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAEtC,2DAA2D;QACpD,WAAM,GAAW,CAAC,QAAQ,CAAC;QAElC,2DAA2D;QACpD,WAAM,GAAW,QAAQ,CAAC;QACjC;;;;WAIG;QACI,kBAAa,GAAW,EAAE,CAAC;QAM9B,IAAI,CAAC,aAAa,GAAG,YAAY,CAAC;IACtC,CAAC;IAED,IAAW,SAAS;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,IAAW,SAAS,CAAC,KAAa;QAC9B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED,IAAW,SAAS;QAChB,OAAO,IAAI,CAAC,UAAU,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,IAAW,SAAS,CAAC,KAAa;QAC9B,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,IAAW,YAAY;QACnB,OAAO,IAAI,CAAC,aAAa,CAAC;IAC9B,CAAC;IAED,wFAAwF;IACxF,IAAW,YAAY,CAAC,KAAa;QACjC,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;IAC/B,CAAC;CACJ","sourcesContent":["import { Epsilon } from \"../../Maths/math.constants\";\r\n/**\r\n * Limits for geospatial camera\r\n */\r\nexport class GeospatialLimits {\r\n private _planetRadius: number;\r\n private _radiusMin: number = Epsilon;\r\n private _radiusMax: number = Infinity;\r\n\r\n /** Gets the minimum pitch angle (angle from horizon) -- 0 means looking straight down at planet */\r\n public pitchMin: number = Epsilon;\r\n\r\n /** Gets the maximum pitch angle (angle from horizon) -- Pi/1 means looking at horizon */\r\n public pitchMax: number = Math.PI / 2;\r\n\r\n /** Gets the minimum yaw angle (rotation around up axis) */\r\n public yawMin: number = -Infinity;\r\n\r\n /** Gets the maximum yaw angle (rotation around up axis) */\r\n public yawMax: number = Infinity;\r\n /**\r\n * Defines the distance used to consider the camera in pan mode vs pinch/zoom.\r\n * Basically if your fingers moves away from more than this distance you will be considered\r\n * in pinch mode.\r\n */\r\n public pinchToPanMax: number = 20;\r\n\r\n /**\r\n * @param planetRadius The radius of the planet\r\n */\r\n constructor(planetRadius: number) {\r\n this._planetRadius = planetRadius;\r\n }\r\n\r\n public get radiusMin(): number {\r\n return this._radiusMin;\r\n }\r\n\r\n /**\r\n * Sets the minimum radius\r\n */\r\n public set radiusMin(value: number) {\r\n this._radiusMin = value;\r\n }\r\n\r\n public get radiusMax(): number {\r\n return this._radiusMax;\r\n }\r\n\r\n /**\r\n * Sets the maximum radius\r\n */\r\n public set radiusMax(value: number) {\r\n this._radiusMax = value;\r\n }\r\n\r\n /**\r\n * Gets the planet radius used for altitude/radius conversions\r\n */\r\n public get planetRadius(): number {\r\n return this._planetRadius;\r\n }\r\n\r\n /** Sets the planet radius and updates the radius limits to maintain current altitude */\r\n public set planetRadius(value: number) {\r\n this._planetRadius = value;\r\n }\r\n}\r\n"]}
@@ -30,6 +30,10 @@ export declare class GeospatialCamera extends Camera {
30
30
  /** Behavior used for smooth flying animations */
31
31
  private _flyingBehavior;
32
32
  private _flyToTargets;
33
+ private _collider?;
34
+ private _collisionVelocity;
35
+ /** Public option to customize the collision offset applied each frame - vs the one calculated using internal CollisionCoordinator */
36
+ perFrameCollisionOffset: Vector3;
33
37
  constructor(name: string, scene: Scene, options: CameraOptions, pickPredicate?: MeshPredicate);
34
38
  private _center;
35
39
  /** The point on the globe that we are anchoring around. If no alternate rotation point is supplied, this will represent the center of screen*/
@@ -99,14 +103,14 @@ export declare class GeospatialCamera extends Camera {
99
103
  */
100
104
  flyToAsync(targetYaw?: number, targetPitch?: number, targetRadius?: number, targetCenter?: Vector3, flightDurationMs?: number, easingFunction?: EasingFunction, centerHopScale?: number): Promise<void>;
101
105
  /**
102
- * Helper function to move camera towards a given point by radiusScale% of radius (by default 50%)
106
+ * Helper function to move camera towards a given point by `distanceScale` of the current camera-to-destination distance (by default 50%).
103
107
  * @param destination point to move towards
104
- * @param radiusScale value between 0 and 1, % of radius to move
108
+ * @param distanceScale value between 0 and 1, % of distance to move
105
109
  * @param durationMs duration of flight, default 1s
106
110
  * @param easingFn optional easing function for flight interpolation of properties
107
- * @param overshootRadiusScale optional scale to apply to the current radius to achieve a 'hop' animation
111
+ * @param centerHopScale If supplied, will define the parabolic hop height scale for center animation to create a "bounce" effect
108
112
  */
109
- flyToPointAsync(destination: Vector3, radiusScale?: number, durationMs?: number, easingFn?: EasingFunction, overshootRadiusScale?: number): Promise<void>;
113
+ flyToPointAsync(destination: Vector3, distanceScale?: number, durationMs?: number, easingFn?: EasingFunction, centerHopScale?: number): Promise<void>;
110
114
  private _limits;
111
115
  get limits(): GeospatialLimits;
112
116
  private _resetToDefault;
@@ -124,11 +128,18 @@ export declare class GeospatialCamera extends Camera {
124
128
  * Apply zoom by moving the camera toward/away from a target point.
125
129
  */
126
130
  private _applyZoom;
131
+ private _clampZoomDelta;
127
132
  private _zoomToPoint;
128
133
  private _zoomAlongLookAt;
129
134
  _checkInputs(): void;
130
135
  private _wasCenterMovingLastFrame;
131
136
  private _recalculateCenter;
137
+ /**
138
+ * Allows extended classes to override how collision offset is calculated
139
+ * @param newPosition
140
+ * @returns
141
+ */
142
+ protected _getCollisionOffset(newPosition: Vector3): Vector3;
132
143
  attachControl(noPreventDefault?: boolean): void;
133
144
  detachControl(): void;
134
145
  }
@@ -4,7 +4,7 @@ import { Epsilon } from "../Maths/math.constants.js";
4
4
  import { Camera } from "./camera.js";
5
5
  import { GeospatialLimits } from "./Limits/geospatialLimits.js";
6
6
  import { ClampCenterFromPolesInPlace, ComputeLocalBasisToRefs, GeospatialCameraMovement } from "./geospatialCameraMovement.js";
7
- import { Vector3CopyToRef, Vector3Distance, Vector3Dot } from "../Maths/math.vector.functions.js";
7
+ import { Vector3CopyToRef, Vector3Distance, Vector3Dot, Vector3SubtractToRef } from "../Maths/math.vector.functions.js";
8
8
  import { Clamp, NormalizeRadians } from "../Maths/math.scalar.functions.js";
9
9
  import { InterpolatingBehavior } from "../Behaviors/Cameras/interpolatingBehavior.js";
10
10
  /**
@@ -22,6 +22,9 @@ export class GeospatialCamera extends Camera {
22
22
  this._viewMatrix = new Matrix();
23
23
  this._lookAtVector = new Vector3();
24
24
  this._flyToTargets = new Map();
25
+ this._collisionVelocity = new Vector3();
26
+ /** Public option to customize the collision offset applied each frame - vs the one calculated using internal CollisionCoordinator */
27
+ this.perFrameCollisionOffset = new Vector3();
25
28
  this._center = new Vector3();
26
29
  this._yaw = 0;
27
30
  this._pitch = 0;
@@ -132,6 +135,8 @@ export class GeospatialCamera extends Camera {
132
135
  // Position = center - look * radius (preserve unit look)
133
136
  this._tempVect.copyFrom(this._lookAtVector).scaleInPlace(-this._radius);
134
137
  this._tempPosition.copyFrom(this._center).addInPlace(this._tempVect);
138
+ // Recalculate collisionOffset to be applied later when viewMatrix is calculated (allowing camera users to modify the value in afterCheckInputsObservable)
139
+ this.perFrameCollisionOffset = this._getCollisionOffset(this._tempPosition);
135
140
  this._position.copyFrom(this._tempPosition);
136
141
  this._isViewMatrixDirty = true;
137
142
  }
@@ -151,7 +156,7 @@ export class GeospatialCamera extends Camera {
151
156
  this._flyToTargets.set("yaw", deltaYaw === 0 ? undefined : this._yaw + deltaYaw);
152
157
  this._flyToTargets.set("pitch", targetPitch != undefined ? NormalizeRadians(targetPitch) : undefined);
153
158
  this._flyToTargets.set("radius", targetRadius);
154
- this._flyToTargets.set("center", targetCenter);
159
+ this._flyToTargets.set("center", targetCenter?.clone());
155
160
  this._flyingBehavior.updateProperties(this._flyToTargets);
156
161
  }
157
162
  /**
@@ -172,24 +177,22 @@ export class GeospatialCamera extends Camera {
172
177
  this._flyToTargets.set("yaw", deltaYaw === 0 ? undefined : this._yaw + deltaYaw);
173
178
  this._flyToTargets.set("pitch", targetPitch !== undefined ? NormalizeRadians(targetPitch) : undefined);
174
179
  this._flyToTargets.set("radius", targetRadius);
175
- this._flyToTargets.set("center", targetCenter);
180
+ this._flyToTargets.set("center", targetCenter?.clone());
176
181
  let overrideAnimationFunction;
177
182
  if (targetCenter !== undefined && !targetCenter.equals(this.center)) {
178
183
  // Animate center directly with custom interpolation
179
- const start = this.center.clone();
180
- const end = targetCenter.clone();
181
184
  overrideAnimationFunction = (key, animation) => {
182
185
  if (key === "center") {
183
186
  // Override the Vector3 interpolation to use SLERP + hop
184
187
  animation.vector3InterpolateFunction = (startValue, endValue, gradient) => {
185
188
  // gradient is the eased value (0 to 1) after easing function is applied
186
189
  // Slerp between start and end
187
- const newCenter = Vector3.SlerpToRef(start, end, gradient, this._tempCenter);
190
+ const newCenter = Vector3.SlerpToRef(startValue, endValue, gradient, this._tempCenter);
188
191
  // Apply parabolic hop if requested
189
192
  if (centerHopScale && centerHopScale > 0) {
190
193
  // Parabolic formula: peaks at t=0.5, returns to 0 at gradient=0 and gradient=1
191
194
  // if hopPeakT = .5 the denominator would be hopPeakT * hopPeakT - hopPeakT, which = -.25
192
- const hopPeakOffset = centerHopScale * Vector3Distance(start, end);
195
+ const hopPeakOffset = centerHopScale * Vector3Distance(startValue, endValue);
193
196
  const hopOffset = hopPeakOffset * Clamp((gradient * gradient - gradient) / -0.25);
194
197
  // Scale the center outward (away from origin)
195
198
  newCenter.scaleInPlace(1 + hopOffset / newCenter.length());
@@ -202,26 +205,25 @@ export class GeospatialCamera extends Camera {
202
205
  return await this._flyingBehavior.animatePropertiesAsync(this._flyToTargets, flightDurationMs, easingFunction, overrideAnimationFunction);
203
206
  }
204
207
  /**
205
- * Helper function to move camera towards a given point by radiusScale% of radius (by default 50%)
208
+ * Helper function to move camera towards a given point by `distanceScale` of the current camera-to-destination distance (by default 50%).
206
209
  * @param destination point to move towards
207
- * @param radiusScale value between 0 and 1, % of radius to move
210
+ * @param distanceScale value between 0 and 1, % of distance to move
208
211
  * @param durationMs duration of flight, default 1s
209
212
  * @param easingFn optional easing function for flight interpolation of properties
210
- * @param overshootRadiusScale optional scale to apply to the current radius to achieve a 'hop' animation
213
+ * @param centerHopScale If supplied, will define the parabolic hop height scale for center animation to create a "bounce" effect
211
214
  */
212
- async flyToPointAsync(destination, radiusScale = 0.5, durationMs = 1000, easingFn, overshootRadiusScale) {
213
- // Zoom to radiusScale% of radius towards the given destination point
214
- const zoomDistance = this.radius * radiusScale;
215
+ async flyToPointAsync(destination, distanceScale = 0.5, durationMs = 1000, easingFn, centerHopScale) {
216
+ // Move by a fraction of the camera-to-destination distance
217
+ const zoomDistance = Vector3Distance(this.position, destination) * distanceScale;
215
218
  const newRadius = this._getCenterAndRadiusFromZoomToPoint(destination, zoomDistance, this._tempCenter);
216
- await this.flyToAsync(undefined, undefined, newRadius, this._tempCenter, durationMs, easingFn, overshootRadiusScale);
219
+ await this.flyToAsync(undefined, undefined, newRadius, this._tempCenter, durationMs, easingFn, centerHopScale);
217
220
  }
218
221
  get limits() {
219
222
  return this._limits;
220
223
  }
221
224
  _resetToDefault(limits) {
222
225
  // Camera configuration vars
223
- const maxCameraRadius = limits.altitudeMax !== undefined ? limits.planetRadius + limits.altitudeMax : undefined;
224
- const restingAltitude = maxCameraRadius ?? limits.planetRadius * 4;
226
+ const restingAltitude = limits.radiusMax !== Infinity ? limits.radiusMax : limits.planetRadius * 4;
225
227
  this.position.copyFromFloats(restingAltitude, 0, 0);
226
228
  this._center.copyFromFloats(limits.planetRadius, 0, 0);
227
229
  this._radius = Vector3.Distance(this.position, this.center);
@@ -243,6 +245,10 @@ export class GeospatialCamera extends Camera {
243
245
  // Ensure vectors are normalized
244
246
  this.upVector.normalize();
245
247
  this._lookAtVector.normalize();
248
+ // Apply the same offset to both position and center to preserve orbital relationship
249
+ // This keeps yaw/pitch/radius intact - just lifts the whole "rig"
250
+ this._position.addInPlace(this.perFrameCollisionOffset);
251
+ this._center.addInPlace(this.perFrameCollisionOffset);
246
252
  // Calculate view matrix with camera position and center
247
253
  if (this.getScene().useRightHandedSystem) {
248
254
  Matrix.LookAtRHToRef(this.position, this._center, this.upVector, this._viewMatrix);
@@ -280,34 +286,37 @@ export class GeospatialCamera extends Camera {
280
286
  this._setOrientation(yaw, pitch, this._radius, this._center);
281
287
  }
282
288
  }
283
- _getCenterAndRadiusFromZoomToPoint(targetPoint, distance, newCenter) {
284
- // Clamp new radius to limits
285
- const requestedRadius = this._radius - distance;
286
- const newRadius = Clamp(requestedRadius, this.limits.radiusMin, this.limits.radiusMax);
287
- const actualDistance = this._radius - newRadius;
288
- const actualRatio = actualDistance / this._radius;
289
- // Direction from current center to target point
290
- const directionToTarget = TmpVectors.Vector3[0];
291
- targetPoint.subtractToRef(this._center, directionToTarget);
292
- // Move center toward target by the ratio amount
293
- const centerOffset = TmpVectors.Vector3[1];
294
- directionToTarget.scaleToRef(actualRatio, centerOffset);
295
- // Calculate new center
296
- this._center.addToRef(centerOffset, newCenter);
297
- // Preserve center altitude (distance from planet origin)
298
- const currentCenterRadius = this._center.length();
299
- const newCenterRadius = newCenter.length();
300
- if (newCenterRadius > Epsilon) {
301
- newCenter.scaleInPlace(currentCenterRadius / newCenterRadius);
289
+ _getCenterAndRadiusFromZoomToPoint(targetPoint, distance, newCenterResult) {
290
+ const directionToTarget = Vector3SubtractToRef(targetPoint, this._position, TmpVectors.Vector3[0]);
291
+ const distanceToTarget = directionToTarget.length();
292
+ // Don't zoom past the min radius limit.
293
+ if (distanceToTarget < this.limits.radiusMin) {
294
+ newCenterResult.copyFrom(this._center);
295
+ const requestedRadius = this._radius - distance;
296
+ const newRadius = Clamp(requestedRadius, this.limits.radiusMin, this.limits.radiusMax);
297
+ return newRadius;
302
298
  }
303
- return newRadius;
299
+ // Move the camera position towards targetPoint by distanceToTarget
300
+ directionToTarget.scaleInPlace(distance / distanceToTarget);
301
+ const newPosition = this._position.addToRef(directionToTarget, TmpVectors.Vector3[1]);
302
+ // Project the movement onto the look vector to derive the new center/radius.
303
+ const projectedDistance = Vector3Dot(directionToTarget, this._lookAtVector);
304
+ const newRadius = this._radius - projectedDistance;
305
+ const newRadiusClamped = Clamp(newRadius, this.limits.radiusMin, this.limits.radiusMax);
306
+ newCenterResult.copyFrom(newPosition).addInPlace(this._lookAtVector.scale(newRadiusClamped));
307
+ return newRadiusClamped;
304
308
  }
305
309
  /**
306
310
  * Apply zoom by moving the camera toward/away from a target point.
307
311
  */
308
312
  _applyZoom() {
309
- const zoomDelta = this.movement.zoomDeltaCurrentFrame;
313
+ let zoomDelta = this.movement.zoomDeltaCurrentFrame;
310
314
  const pickedPoint = this.movement.computedPerFrameZoomPickPoint;
315
+ // Clamp zoom delta to limits before applying
316
+ zoomDelta = this._clampZoomDelta(zoomDelta, pickedPoint);
317
+ if (Math.abs(zoomDelta) < Epsilon) {
318
+ return;
319
+ }
311
320
  if (pickedPoint) {
312
321
  // Zoom toward the picked point under cursor
313
322
  this._zoomToPoint(pickedPoint, zoomDelta);
@@ -317,6 +326,26 @@ export class GeospatialCamera extends Camera {
317
326
  this._zoomAlongLookAt(zoomDelta);
318
327
  }
319
328
  }
329
+ _clampZoomDelta(zoomDelta, pickedPoint) {
330
+ if (Math.abs(zoomDelta) < Epsilon) {
331
+ return 0;
332
+ }
333
+ if (zoomDelta > 0) {
334
+ // Zooming IN - respect radiusMin as distance to surface
335
+ if (pickedPoint) {
336
+ const pickDistance = Vector3Distance(this._position, pickedPoint);
337
+ // Don't zoom past the picked surface point + radiusMin
338
+ const maxZoomToSurface = pickDistance - this.limits.radiusMin;
339
+ return Math.min(zoomDelta, Math.max(0, maxZoomToSurface));
340
+ }
341
+ return zoomDelta;
342
+ }
343
+ else {
344
+ // Zooming OUT - respect radiusMax
345
+ const maxZoomOut = this.limits.radiusMax - this._radius;
346
+ return Math.max(zoomDelta, -Math.max(0, maxZoomOut));
347
+ }
348
+ }
320
349
  _zoomToPoint(targetPoint, distance) {
321
350
  const newRadius = this._getCenterAndRadiusFromZoomToPoint(targetPoint, distance, this._tempCenter);
322
351
  // Apply the new orientation
@@ -331,6 +360,7 @@ export class GeospatialCamera extends Camera {
331
360
  }
332
361
  _checkInputs() {
333
362
  this.inputs.checkInputs();
363
+ this.perFrameCollisionOffset.setAll(0);
334
364
  // Let movement class handle all per-frame logic
335
365
  this.movement.computeCurrentFrameDeltas();
336
366
  let isCenterMoving = false;
@@ -370,6 +400,29 @@ export class GeospatialCamera extends Camera {
370
400
  }
371
401
  }
372
402
  }
403
+ /**
404
+ * Allows extended classes to override how collision offset is calculated
405
+ * @param newPosition
406
+ * @returns
407
+ */
408
+ _getCollisionOffset(newPosition) {
409
+ const coordinator = this.getScene().collisionCoordinator;
410
+ const collisionOffset = TmpVectors.Vector3[6].setAll(0);
411
+ if (!coordinator || !this._scene.collisionsEnabled) {
412
+ return collisionOffset;
413
+ }
414
+ if (!this._collider) {
415
+ this._collider = coordinator.createCollider();
416
+ }
417
+ this._collider._radius.setAll(this.limits.radiusMin);
418
+ // Calculate velocity from old position to new position
419
+ newPosition.subtractToRef(this._position, this._collisionVelocity);
420
+ // Get the collision-adjusted position
421
+ const adjustedPosition = coordinator.getNewPosition(this._position, this._collisionVelocity, this._collider, 3, null, () => { }, this.uniqueId);
422
+ // Calculate the collision offset (how much the position was pushed)
423
+ adjustedPosition.subtractToRef(newPosition, collisionOffset);
424
+ return collisionOffset;
425
+ }
373
426
  attachControl(noPreventDefault) {
374
427
  this.inputs.attachElement(noPreventDefault);
375
428
  }