@onerjs/core 8.26.9 → 8.27.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 (37) hide show
  1. package/Buffers/buffer.d.ts +4 -3
  2. package/Buffers/buffer.js +4 -3
  3. package/Buffers/buffer.js.map +1 -1
  4. package/Cameras/Inputs/BaseCameraPointersInput.js +2 -0
  5. package/Cameras/Inputs/BaseCameraPointersInput.js.map +1 -1
  6. package/Cameras/Inputs/geospatialCameraMouseWheelInput.d.ts +18 -0
  7. package/Cameras/Inputs/geospatialCameraMouseWheelInput.js +21 -0
  8. package/Cameras/Inputs/geospatialCameraMouseWheelInput.js.map +1 -0
  9. package/Cameras/Inputs/geospatialCameraPointersInput.d.ts +45 -0
  10. package/Cameras/Inputs/geospatialCameraPointersInput.js +119 -0
  11. package/Cameras/Inputs/geospatialCameraPointersInput.js.map +1 -0
  12. package/Cameras/Inputs/index.d.ts +2 -0
  13. package/Cameras/Inputs/index.js +2 -0
  14. package/Cameras/Inputs/index.js.map +1 -1
  15. package/Cameras/geospatialCamera.d.ts +89 -0
  16. package/Cameras/geospatialCamera.js +268 -0
  17. package/Cameras/geospatialCamera.js.map +1 -0
  18. package/Cameras/geospatialCameraInputsManager.d.ts +23 -0
  19. package/Cameras/geospatialCameraInputsManager.js +33 -0
  20. package/Cameras/geospatialCameraInputsManager.js.map +1 -0
  21. package/Cameras/index.d.ts +1 -0
  22. package/Cameras/index.js +1 -0
  23. package/Cameras/index.js.map +1 -1
  24. package/Engines/constants.d.ts +2 -0
  25. package/Engines/constants.js +2 -0
  26. package/Engines/constants.js.map +1 -1
  27. package/Events/pointerEvents.d.ts +4 -0
  28. package/Events/pointerEvents.js.map +1 -1
  29. package/Materials/PBR/openPbrMaterial.d.ts +3 -0
  30. package/Materials/PBR/openPbrMaterial.js +11 -2
  31. package/Materials/PBR/openPbrMaterial.js.map +1 -1
  32. package/Materials/PBR/pbrBaseMaterial.d.ts +3 -0
  33. package/Materials/PBR/pbrBaseMaterial.js +11 -2
  34. package/Materials/PBR/pbrBaseMaterial.js.map +1 -1
  35. package/Meshes/geometry.js +26 -25
  36. package/Meshes/geometry.js.map +1 -1
  37. package/package.json +1 -1
@@ -0,0 +1,119 @@
1
+ import { Plane } from "../../Maths/math.plane.js";
2
+ import { TmpVectors, Vector3 } from "../../Maths/math.vector.js";
3
+ import { BaseCameraPointersInput } from "./BaseCameraPointersInput.js";
4
+ /**
5
+ * @experimental
6
+ * Geospatial camera inputs can simulate dragging the globe around or tilting the camera around some point on the globe
7
+ * The input will update the camera's localTranslation or localRotation values, and the camera is responsible for using these updates to calculate viewMatrix appropriately
8
+ *
9
+ * As of right now, the camera correction logic (to keep the camera geospatially oriented around the globe) is happening within the camera class when calculating viewmatrix
10
+ * As this is experimental, it is possible we move that correction step to live within the input class (to enable non-corrected translations in the future), say if we want to allow the camera to move outside of the globe's orbit
11
+ *
12
+ * Left mouse button: drag globe
13
+ * Middle mouse button: tilt globe around cursor location
14
+ * Right mouse button: tilt globe around center of screen
15
+ *
16
+ */
17
+ export class GeospatialCameraPointersInput extends BaseCameraPointersInput {
18
+ constructor() {
19
+ super(...arguments);
20
+ /**
21
+ * Mouse sensitivity for rotation (lower = more sensitive)
22
+ */
23
+ this.angularSensibility = 200.0;
24
+ this._dragPlane = new Plane(0, 0, 0, 0);
25
+ this._dragPlaneNormal = Vector3.Zero();
26
+ this._dragPlaneOriginPoint = Vector3.Zero();
27
+ this._dragPlaneHitPoint = Vector3.Zero();
28
+ this._dragPlaneOffsetVector = Vector3.Zero();
29
+ }
30
+ getClassName() {
31
+ return "GeospatialCameraPointersInput";
32
+ }
33
+ onButtonDown(evt) {
34
+ const scene = this.camera.getScene();
35
+ let pickResult;
36
+ switch (evt.button) {
37
+ case 0: // Left button - drag/pan globe under cursor
38
+ pickResult = scene.pick(scene.pointerX, scene.pointerY, this.camera.pickPredicate);
39
+ if (pickResult.pickedPoint && pickResult.ray) {
40
+ // Store radius from earth center to pickedPoint, used when calculating drag plane
41
+ this._hitPointRadius = pickResult.pickedPoint.length();
42
+ // The dragPlaneOffsetVector will later be recalculated when drag occurs, and the delta between the offset vectors will be applied to localTranslation
43
+ this._recalculateDragPlaneOffsetVectorToRef(this._hitPointRadius, pickResult.ray, this._dragPlaneOffsetVector);
44
+ }
45
+ else {
46
+ this._hitPointRadius = undefined; // can't drag without a hit on the globe
47
+ }
48
+ break;
49
+ case 1: // Middle button - tilt camera around cursor
50
+ pickResult = scene.pick(scene.pointerX, scene.pointerY, this.camera.pickPredicate);
51
+ pickResult.pickedPoint && (this.camera._alternateRotationPt = pickResult.pickedPoint);
52
+ break;
53
+ case 2: // Right button - tilt camera around center of screen, already the default
54
+ this.camera._alternateRotationPt = this.camera.center;
55
+ break;
56
+ default:
57
+ return;
58
+ }
59
+ }
60
+ onTouch(point, offsetX, offsetY) {
61
+ switch (point?.button) {
62
+ case 0: // Left button - drag/pan globe under cursor
63
+ this._hitPointRadius !== undefined && this._handleDrag(this._hitPointRadius);
64
+ break;
65
+ case 1: // Middle button - tilt camera around cursor
66
+ case 2: // Right button - tilt camera
67
+ this._handleTilt(offsetX, offsetY);
68
+ break;
69
+ }
70
+ }
71
+ onButtonUp(_evt) {
72
+ this._hitPointRadius = undefined;
73
+ this.camera._alternateRotationPt = null;
74
+ }
75
+ /**
76
+ * The DragPlaneOffsetVector represents the vector between the dragPlane hit point and the dragPlane origin point.
77
+ * As the drag movement occurs, we will continuously recalculate this vector. The delta between the offsetVectors is the delta we will apply to the camera's localtranslation
78
+ * @param hitPointRadius The distance between the world origin (center of globe) and the initial drag hit point
79
+ * @param ray The ray from the camera to the new cursor location
80
+ * @param ref The offset vector between the drag plane's hitPoint and originPoint
81
+ */
82
+ _recalculateDragPlaneOffsetVectorToRef(hitPointRadius, ray, ref) {
83
+ // Use the camera's geocentric normal to find the dragPlaneOriginPoint which lives at hitPointRadius along the camera's geocentric normal
84
+ this.camera.position.normalizeToRef(this._dragPlaneNormal);
85
+ this._dragPlaneNormal.scaleToRef(hitPointRadius, this._dragPlaneOriginPoint);
86
+ // Now create a plane at that point, perpendicular to the camera's geocentric normal
87
+ Plane.FromPositionAndNormalToRef(this._dragPlaneOriginPoint, this._dragPlaneNormal, this._dragPlane);
88
+ // Lastly, find the _dragPlaneHitPoint where the ray intersects the _dragPlane
89
+ IntersectRayWithPlaneToRef(ray, this._dragPlane, this._dragPlaneHitPoint);
90
+ // Store the new offset between the drag plane's hitPoint and originPoint
91
+ this._dragPlaneHitPoint.subtractToRef(this._dragPlaneOriginPoint, ref);
92
+ }
93
+ _handleDrag(hitPointRadius) {
94
+ const scene = this.camera.getScene();
95
+ const pickResult = scene.pick(scene.pointerX, scene.pointerY);
96
+ if (pickResult.ray) {
97
+ const newDragPlaneOffsetVector = TmpVectors.Vector3[5];
98
+ this._recalculateDragPlaneOffsetVectorToRef(hitPointRadius, pickResult.ray, newDragPlaneOffsetVector);
99
+ const delta = TmpVectors.Vector3[6];
100
+ newDragPlaneOffsetVector.subtractToRef(this._dragPlaneOffsetVector, delta);
101
+ this._dragPlaneOffsetVector.copyFrom(newDragPlaneOffsetVector);
102
+ this.camera._perFrameGeocentricTranslation.subtractInPlace(delta); // ???
103
+ }
104
+ }
105
+ _handleTilt(deltaX, deltaY) {
106
+ this.camera._perFrameGeocentricRotation.y += -deltaX / this.angularSensibility; // yaw - looking side to side
107
+ this.camera._perFrameGeocentricRotation.x += -deltaY / this.angularSensibility; // pitch - look up towards sky / down towards ground
108
+ }
109
+ }
110
+ function IntersectRayWithPlaneToRef(ray, plane, ref) {
111
+ // Distance along the ray to the plane; null if no hit
112
+ const dist = ray.intersectsPlane(plane);
113
+ if (dist !== null && dist >= 0) {
114
+ ray.origin.addToRef(ray.direction.scaleToRef(dist, TmpVectors.Vector3[0]), ref);
115
+ return true;
116
+ }
117
+ return false;
118
+ }
119
+ //# sourceMappingURL=geospatialCameraPointersInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"geospatialCameraPointersInput.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Inputs/geospatialCameraPointersInput.ts"],"names":[],"mappings":"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","sourcesContent":["import type { GeospatialCamera } from \"../../Cameras/geospatialCamera\";\r\nimport type { PickingInfo } from \"../../Collisions/pickingInfo\";\r\nimport type { Ray } from \"../../Culling/ray\";\r\nimport type { IPointerEvent } from \"../../Events/deviceInputEvents\";\r\nimport type { PointerTouch } from \"../../Events/pointerEvents\";\r\nimport { Plane } from \"../../Maths/math.plane\";\r\nimport { TmpVectors, Vector3 } from \"../../Maths/math.vector\";\r\nimport type { Nullable } from \"../../types\";\r\nimport { BaseCameraPointersInput } from \"./BaseCameraPointersInput\";\r\n\r\n/**\r\n * @experimental\r\n * Geospatial camera inputs can simulate dragging the globe around or tilting the camera around some point on the globe\r\n * The input will update the camera's localTranslation or localRotation values, and the camera is responsible for using these updates to calculate viewMatrix appropriately\r\n *\r\n * As of right now, the camera correction logic (to keep the camera geospatially oriented around the globe) is happening within the camera class when calculating viewmatrix\r\n * As this is experimental, it is possible we move that correction step to live within the input class (to enable non-corrected translations in the future), say if we want to allow the camera to move outside of the globe's orbit\r\n *\r\n * Left mouse button: drag globe\r\n * Middle mouse button: tilt globe around cursor location\r\n * Right mouse button: tilt globe around center of screen\r\n *\r\n */\r\nexport class GeospatialCameraPointersInput extends BaseCameraPointersInput {\r\n public camera: GeospatialCamera;\r\n\r\n /**\r\n * Mouse sensitivity for rotation (lower = more sensitive)\r\n */\r\n public angularSensibility = 200.0;\r\n\r\n private _dragPlane: Plane = new Plane(0, 0, 0, 0);\r\n private _dragPlaneNormal: Vector3 = Vector3.Zero();\r\n private _dragPlaneOriginPoint: Vector3 = Vector3.Zero();\r\n private _dragPlaneHitPoint: Vector3 = Vector3.Zero();\r\n private _dragPlaneOffsetVector: Vector3 = Vector3.Zero();\r\n\r\n private _hitPointRadius?: number; // Distance between world origin (center of globe) and the hitPoint (where initial drag started)\r\n\r\n public override getClassName(): string {\r\n return \"GeospatialCameraPointersInput\";\r\n }\r\n\r\n public override onButtonDown(evt: IPointerEvent): void {\r\n const scene = this.camera.getScene();\r\n let pickResult: Nullable<PickingInfo>;\r\n switch (evt.button) {\r\n case 0: // Left button - drag/pan globe under cursor\r\n pickResult = scene.pick(scene.pointerX, scene.pointerY, this.camera.pickPredicate);\r\n if (pickResult.pickedPoint && pickResult.ray) {\r\n // Store radius from earth center to pickedPoint, used when calculating drag plane\r\n this._hitPointRadius = pickResult.pickedPoint.length();\r\n\r\n // The dragPlaneOffsetVector will later be recalculated when drag occurs, and the delta between the offset vectors will be applied to localTranslation\r\n this._recalculateDragPlaneOffsetVectorToRef(this._hitPointRadius, pickResult.ray, this._dragPlaneOffsetVector);\r\n } else {\r\n this._hitPointRadius = undefined; // can't drag without a hit on the globe\r\n }\r\n break;\r\n case 1: // Middle button - tilt camera around cursor\r\n pickResult = scene.pick(scene.pointerX, scene.pointerY, this.camera.pickPredicate);\r\n pickResult.pickedPoint && (this.camera._alternateRotationPt = pickResult.pickedPoint);\r\n break;\r\n case 2: // Right button - tilt camera around center of screen, already the default\r\n this.camera._alternateRotationPt = this.camera.center;\r\n break;\r\n default:\r\n return;\r\n }\r\n }\r\n\r\n public override onTouch(point: Nullable<PointerTouch>, offsetX: number, offsetY: number): void {\r\n switch (point?.button) {\r\n case 0: // Left button - drag/pan globe under cursor\r\n this._hitPointRadius !== undefined && this._handleDrag(this._hitPointRadius);\r\n break;\r\n case 1: // Middle button - tilt camera around cursor\r\n case 2: // Right button - tilt camera\r\n this._handleTilt(offsetX, offsetY);\r\n break;\r\n }\r\n }\r\n\r\n public override onButtonUp(_evt: IPointerEvent): void {\r\n this._hitPointRadius = undefined;\r\n this.camera._alternateRotationPt = null;\r\n }\r\n\r\n /**\r\n * The DragPlaneOffsetVector represents the vector between the dragPlane hit point and the dragPlane origin point.\r\n * As the drag movement occurs, we will continuously recalculate this vector. The delta between the offsetVectors is the delta we will apply to the camera's localtranslation\r\n * @param hitPointRadius The distance between the world origin (center of globe) and the initial drag hit point\r\n * @param ray The ray from the camera to the new cursor location\r\n * @param ref The offset vector between the drag plane's hitPoint and originPoint\r\n */\r\n private _recalculateDragPlaneOffsetVectorToRef(hitPointRadius: number, ray: Ray, ref: Vector3) {\r\n // Use the camera's geocentric normal to find the dragPlaneOriginPoint which lives at hitPointRadius along the camera's geocentric normal\r\n this.camera.position.normalizeToRef(this._dragPlaneNormal);\r\n this._dragPlaneNormal.scaleToRef(hitPointRadius, this._dragPlaneOriginPoint);\r\n\r\n // Now create a plane at that point, perpendicular to the camera's geocentric normal\r\n Plane.FromPositionAndNormalToRef(this._dragPlaneOriginPoint, this._dragPlaneNormal, this._dragPlane);\r\n\r\n // Lastly, find the _dragPlaneHitPoint where the ray intersects the _dragPlane\r\n IntersectRayWithPlaneToRef(ray, this._dragPlane, this._dragPlaneHitPoint);\r\n\r\n // Store the new offset between the drag plane's hitPoint and originPoint\r\n this._dragPlaneHitPoint.subtractToRef(this._dragPlaneOriginPoint, ref);\r\n }\r\n\r\n private _handleDrag(hitPointRadius: number): void {\r\n const scene = this.camera.getScene();\r\n const pickResult = scene.pick(scene.pointerX, scene.pointerY);\r\n if (pickResult.ray) {\r\n const newDragPlaneOffsetVector = TmpVectors.Vector3[5];\r\n this._recalculateDragPlaneOffsetVectorToRef(hitPointRadius, pickResult.ray, newDragPlaneOffsetVector);\r\n const delta = TmpVectors.Vector3[6];\r\n newDragPlaneOffsetVector.subtractToRef(this._dragPlaneOffsetVector, delta);\r\n\r\n this._dragPlaneOffsetVector.copyFrom(newDragPlaneOffsetVector);\r\n\r\n this.camera._perFrameGeocentricTranslation.subtractInPlace(delta); // ???\r\n }\r\n }\r\n\r\n private _handleTilt(deltaX: number, deltaY: number): void {\r\n this.camera._perFrameGeocentricRotation.y += -deltaX / this.angularSensibility; // yaw - looking side to side\r\n this.camera._perFrameGeocentricRotation.x += -deltaY / this.angularSensibility; // pitch - look up towards sky / down towards ground\r\n }\r\n}\r\n\r\nfunction IntersectRayWithPlaneToRef(ray: Ray, plane: Plane, ref: Vector3): boolean {\r\n // Distance along the ray to the plane; null if no hit\r\n const dist = ray.intersectsPlane(plane);\r\n\r\n if (dist !== null && dist >= 0) {\r\n ray.origin.addToRef(ray.direction.scaleToRef(dist, TmpVectors.Vector3[0]), ref);\r\n return true;\r\n }\r\n\r\n return false;\r\n}\r\n"]}
@@ -17,3 +17,5 @@ export * from "./freeCameraMouseInput.js";
17
17
  export * from "./freeCameraMouseWheelInput.js";
18
18
  export * from "./freeCameraTouchInput.js";
19
19
  export * from "./freeCameraVirtualJoystickInput.js";
20
+ export * from "./geospatialCameraPointersInput.js";
21
+ export * from "./geospatialCameraMouseWheelInput.js";
@@ -17,4 +17,6 @@ export * from "./freeCameraMouseInput.js";
17
17
  export * from "./freeCameraMouseWheelInput.js";
18
18
  export * from "./freeCameraTouchInput.js";
19
19
  export * from "./freeCameraVirtualJoystickInput.js";
20
+ export * from "./geospatialCameraPointersInput.js";
21
+ export * from "./geospatialCameraMouseWheelInput.js";
20
22
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Inputs/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2CAA2C,CAAC;AAC1D,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oCAAoC,CAAC;AACnD,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC","sourcesContent":["export * from \"./BaseCameraMouseWheelInput\";\r\nexport * from \"./BaseCameraPointersInput\";\r\nexport * from \"./arcRotateCameraGamepadInput\";\r\nexport * from \"./arcRotateCameraKeyboardMoveInput\";\r\nexport * from \"./arcRotateCameraMouseWheelInput\";\r\nexport * from \"./arcRotateCameraPointersInput\";\r\nexport * from \"./arcRotateCameraVRDeviceOrientationInput\";\r\nexport * from \"./flyCameraKeyboardInput\";\r\nexport * from \"./flyCameraMouseInput\";\r\nexport * from \"./followCameraKeyboardMoveInput\";\r\nexport * from \"./followCameraMouseWheelInput\";\r\nexport * from \"./followCameraPointersInput\";\r\nexport * from \"./freeCameraDeviceOrientationInput\";\r\nexport * from \"./freeCameraGamepadInput\";\r\nexport * from \"./freeCameraKeyboardMoveInput\";\r\nexport * from \"./freeCameraMouseInput\";\r\nexport * from \"./freeCameraMouseWheelInput\";\r\nexport * from \"./freeCameraTouchInput\";\r\nexport * from \"./freeCameraVirtualJoystickInput\";\r\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../dev/core/src/Cameras/Inputs/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,2BAA2B,CAAC;AAC1C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,2CAA2C,CAAC;AAC1D,cAAc,0BAA0B,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,oCAAoC,CAAC;AACnD,cAAc,0BAA0B,CAAC;AACzC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wBAAwB,CAAC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wBAAwB,CAAC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,mCAAmC,CAAC","sourcesContent":["export * from \"./BaseCameraMouseWheelInput\";\r\nexport * from \"./BaseCameraPointersInput\";\r\nexport * from \"./arcRotateCameraGamepadInput\";\r\nexport * from \"./arcRotateCameraKeyboardMoveInput\";\r\nexport * from \"./arcRotateCameraMouseWheelInput\";\r\nexport * from \"./arcRotateCameraPointersInput\";\r\nexport * from \"./arcRotateCameraVRDeviceOrientationInput\";\r\nexport * from \"./flyCameraKeyboardInput\";\r\nexport * from \"./flyCameraMouseInput\";\r\nexport * from \"./followCameraKeyboardMoveInput\";\r\nexport * from \"./followCameraMouseWheelInput\";\r\nexport * from \"./followCameraPointersInput\";\r\nexport * from \"./freeCameraDeviceOrientationInput\";\r\nexport * from \"./freeCameraGamepadInput\";\r\nexport * from \"./freeCameraKeyboardMoveInput\";\r\nexport * from \"./freeCameraMouseInput\";\r\nexport * from \"./freeCameraMouseWheelInput\";\r\nexport * from \"./freeCameraTouchInput\";\r\nexport * from \"./freeCameraVirtualJoystickInput\";\r\nexport * from \"./geospatialCameraPointersInput\";\r\nexport * from \"./geospatialCameraMouseWheelInput\";\r\n"]}
@@ -0,0 +1,89 @@
1
+ import { GeospatialCameraInputsManager } from "./geospatialCameraInputsManager.js";
2
+ import { Vector3, Matrix } from "../Maths/math.vector.js";
3
+ import { Camera } from "./camera.js";
4
+ import type { Scene } from "../scene.js";
5
+ import type { MeshPredicate } from "../Culling/ray.core.js";
6
+ import type { Nullable } from "../types.js";
7
+ type CameraOptions = {
8
+ planetRadius: number;
9
+ minAltitude?: number;
10
+ maxAltitude?: number;
11
+ restingAltitude?: number;
12
+ };
13
+ /**
14
+ * @experimental
15
+ * 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
16
+ *
17
+ * Please note this is marked as experimental and the API (including the constructor!) will change until we remove that flag
18
+ *
19
+ * Still TODO:
20
+ * - Pitch/yaw limits, input speeds
21
+ * - ZoomToPoint
22
+ * - Conversion between lat/long/alt and cartesian coordinates
23
+ */
24
+ export declare class GeospatialCamera extends Camera {
25
+ inputs: GeospatialCameraInputsManager;
26
+ /** @internal */
27
+ _perFrameGeocentricTranslation: Vector3;
28
+ /** @internal */
29
+ _perFrameGeocentricRotation: Vector3;
30
+ /** @internal */
31
+ _perFrameZoom: number;
32
+ /** If supplied, will be used when picking the globe */
33
+ pickPredicate?: MeshPredicate;
34
+ /**
35
+ * Enables rotation around a specific point, instead of default rotation around center
36
+ * @internal
37
+ */
38
+ _alternateRotationPt: Nullable<Vector3>;
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*/
40
+ get center(): Vector3;
41
+ private _tempGeocentricNormal;
42
+ private _tempRotationAxis;
43
+ private _tempRotationMatrix;
44
+ private _tempPickingRay;
45
+ private _tempPosition;
46
+ private _viewMatrix;
47
+ private _isViewMatrixDirty;
48
+ private _lookAtVector;
49
+ private _planetRadius;
50
+ private _minAltitude;
51
+ private _maxAltitude?;
52
+ private _maxCameraRadius?;
53
+ private _restingAltitude;
54
+ /** Target of camera when looking along lookAtVector from current position. This does not necessarily represent a point on the globe */
55
+ private get _target();
56
+ /** The point around which the camera will geocentrically rotate. Uses center (pt we are anchored to) if no alternateRotationPt is defined */
57
+ private get _geocentricRotationPt();
58
+ constructor(name: string, scene: Scene, options: CameraOptions, pickPredicate?: MeshPredicate);
59
+ private _resetToDefault;
60
+ /** @internal */
61
+ _getViewMatrix(): Matrix;
62
+ /** @internal */
63
+ _isSynchronizedViewMatrix(): boolean;
64
+ /**
65
+ * Applies rotation correction to the camera by calculating a changeOfBasis matrix from the camera's current position to the new position
66
+ * and transforming the lookAt and up vectors by that matrix before updating the camera position and marking the view matrix as dirty
67
+ * @param newPos The camera's desired position, before correction is applied
68
+ */
69
+ private _applyRotationCorrectionAndSetPos;
70
+ /**
71
+ * When the geocentric normal has any translation change (due to dragging), we must ensure the camera remains orbiting around the world origin
72
+ * We thus need to perform 2 correction steps
73
+ * 1. Translation correction that keeps the camera at the same radius as before the drag
74
+ * 2. Rotation correction that keeps the camera facing the globe (so that as we pan, the globe stays centered on screen)
75
+ */
76
+ private _applyGeocentricTranslation;
77
+ /**
78
+ * 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
79
+ */
80
+ private _applyGeocentricRotation;
81
+ private _clampZoomDistance;
82
+ private _applyZoom;
83
+ private _moveCameraAlongVectorByDistance;
84
+ private get _pickAlongLook();
85
+ _checkInputs(): void;
86
+ attachControl(noPreventDefault?: boolean): void;
87
+ detachControl(): void;
88
+ }
89
+ export {};
@@ -0,0 +1,268 @@
1
+ import { GeospatialCameraInputsManager } from "./geospatialCameraInputsManager.js";
2
+ import { Vector3, Matrix, TmpVectors } from "../Maths/math.vector.js";
3
+ import { Epsilon } from "../Maths/math.constants.js";
4
+ import { Scalar } from "../Maths/math.scalar.js";
5
+ import { Camera } from "./camera.js";
6
+ import { Ray } from "../Culling/ray.js";
7
+ /**
8
+ * @experimental
9
+ * 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
10
+ *
11
+ * Please note this is marked as experimental and the API (including the constructor!) will change until we remove that flag
12
+ *
13
+ * Still TODO:
14
+ * - Pitch/yaw limits, input speeds
15
+ * - ZoomToPoint
16
+ * - Conversion between lat/long/alt and cartesian coordinates
17
+ */
18
+ export class GeospatialCamera extends Camera {
19
+ /** The point on the globe that we are anchoring around. If no alternate rotation point is supplied, this will represent the center of screen*/
20
+ get center() {
21
+ // NOTE that for now we are falling back to target if no pick on globe (because that shouldn't happen with current implemented inputs)
22
+ // but eventually we want to return a point on the globe even if the camera is looking off into space
23
+ return this._pickAlongLook?.pickedPoint ?? this._target;
24
+ }
25
+ /** Target of camera when looking along lookAtVector from current position. This does not necessarily represent a point on the globe */
26
+ get _target() {
27
+ return this.position.addToRef(this._lookAtVector, this._tempPosition);
28
+ }
29
+ /** The point around which the camera will geocentrically rotate. Uses center (pt we are anchored to) if no alternateRotationPt is defined */
30
+ get _geocentricRotationPt() {
31
+ return this._alternateRotationPt ?? this.center;
32
+ }
33
+ constructor(name, scene, options, pickPredicate) {
34
+ super(name, Vector3.Zero(), scene);
35
+ this._resetToDefault(options);
36
+ this.pickPredicate = pickPredicate;
37
+ this.inputs = new GeospatialCameraInputsManager(this);
38
+ this.inputs.addMouse().addMouseWheel();
39
+ }
40
+ _resetToDefault(options) {
41
+ // Camera configuration vars
42
+ this._minAltitude = options.minAltitude ?? 5;
43
+ this._maxAltitude = options.maxAltitude;
44
+ this._planetRadius = options.planetRadius;
45
+ this._maxCameraRadius = this._maxAltitude ? this._planetRadius + this._maxAltitude : undefined;
46
+ this._restingAltitude = options.restingAltitude ?? this._maxCameraRadius ?? this._planetRadius * 4;
47
+ this.position.copyFromFloats(0, 0, -this._restingAltitude);
48
+ // Input vars
49
+ this._perFrameGeocentricRotation = Vector3.Zero();
50
+ this._perFrameGeocentricTranslation = Vector3.Zero();
51
+ this._perFrameZoom = 0;
52
+ // Temp vars
53
+ this._tempPosition = Vector3.Zero();
54
+ this._tempRotationAxis = Vector3.Right(); // starting axis used to calculate pitch rotation matrix
55
+ this._tempRotationMatrix = Matrix.Identity();
56
+ this._tempGeocentricNormal = Vector3.Zero();
57
+ this._tempPickingRay = new Ray(this.position, this._lookAtVector);
58
+ this._tempPickingRay.direction = Vector3.Zero();
59
+ // View matrix calculation vars
60
+ this.upVector = Vector3.Up(); // Up vector of the camera
61
+ this._lookAtVector = this.position.negate().normalize(); // Lookat vector of the camera
62
+ this._viewMatrix = Matrix.Identity();
63
+ this._isViewMatrixDirty = true;
64
+ }
65
+ /** @internal */
66
+ _getViewMatrix() {
67
+ if (!this._isViewMatrixDirty) {
68
+ return this._viewMatrix;
69
+ }
70
+ this._isViewMatrixDirty = false;
71
+ // Ensure vectors are normalized
72
+ this.upVector.normalize();
73
+ this._lookAtVector.normalize();
74
+ // Calculate view matrix with camera position and target
75
+ if (this.getScene().useRightHandedSystem) {
76
+ Matrix.LookAtRHToRef(this.position, this._target, this.upVector, this._viewMatrix);
77
+ }
78
+ else {
79
+ Matrix.LookAtLHToRef(this.position, this._target, this.upVector, this._viewMatrix);
80
+ }
81
+ return this._viewMatrix;
82
+ }
83
+ /** @internal */
84
+ _isSynchronizedViewMatrix() {
85
+ if (!super._isSynchronizedViewMatrix() || this._isViewMatrixDirty) {
86
+ return false;
87
+ }
88
+ return true;
89
+ }
90
+ /**
91
+ * Applies rotation correction to the camera by calculating a changeOfBasis matrix from the camera's current position to the new position
92
+ * and transforming the lookAt and up vectors by that matrix before updating the camera position and marking the view matrix as dirty
93
+ * @param newPos The camera's desired position, before correction is applied
94
+ */
95
+ _applyRotationCorrectionAndSetPos(newPos) {
96
+ // Compute changeOfBasis between current camera position and new position
97
+ ComputeChangeOfBasisToRef(this.position, newPos, this._tempRotationMatrix);
98
+ // Apply rotation correction to lookat/up vectors
99
+ Vector3.TransformNormalToRef(this._lookAtVector, this._tempRotationMatrix, this._lookAtVector);
100
+ Vector3.TransformNormalToRef(this.upVector, this._tempRotationMatrix, this.upVector);
101
+ // Apply position change and mark viewMatrix as dirty
102
+ this.position.copyFrom(newPos);
103
+ this._isViewMatrixDirty = true;
104
+ }
105
+ /**
106
+ * When the geocentric normal has any translation change (due to dragging), we must ensure the camera remains orbiting around the world origin
107
+ * We thus need to perform 2 correction steps
108
+ * 1. Translation correction that keeps the camera at the same radius as before the drag
109
+ * 2. Rotation correction that keeps the camera facing the globe (so that as we pan, the globe stays centered on screen)
110
+ */
111
+ _applyGeocentricTranslation() {
112
+ // Store pending position (without any corrections applied)
113
+ this.position.addToRef(this._perFrameGeocentricTranslation, this._tempPosition);
114
+ // 1. Calculate the altitude correction to keep camera at the same radius when applying translation
115
+ const tempPositionScaled = TmpVectors.Vector3[2];
116
+ const offset = TmpVectors.Vector3[3];
117
+ this._tempPosition.normalizeToRef(tempPositionScaled).scaleInPlace(this.position.length()); // what would tempPosition be if it were scaled to same radius as before
118
+ this._tempPosition.subtractToRef(tempPositionScaled, offset); // find offset between tempPosition and the tempScaledPosition
119
+ this._tempPosition.subtractInPlace(offset); // reduce tempPosition by that offset
120
+ // 2. Calculate the rotation correction to keep camera facing globe
121
+ this._applyRotationCorrectionAndSetPos(this._tempPosition);
122
+ }
123
+ /**
124
+ * 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
125
+ */
126
+ _applyGeocentricRotation() {
127
+ // Normalize key vectors
128
+ this._geocentricRotationPt.normalizeToRef(this._tempGeocentricNormal);
129
+ this.upVector.normalize();
130
+ this._lookAtVector.normalize();
131
+ const pitchRotationMatrix = Matrix.Identity();
132
+ const yawRotationMatrix = Matrix.Identity();
133
+ // First apply pitch
134
+ if (this._perFrameGeocentricRotation.x !== 0) {
135
+ // Compute a rotation axis that is perpendicular to both the upVector and the geocentricNormalOfPitchPoint
136
+ Vector3.CrossToRef(this.upVector, this._tempGeocentricNormal, this._tempRotationAxis);
137
+ // If upVector and geocentricNormalOfPitchPoint are parallel, fall back to cross(lookAtDirection, geocentricNormalOfPitchPoint)
138
+ if (this._tempRotationAxis.lengthSquared() <= Epsilon) {
139
+ Vector3.CrossToRef(this._lookAtVector, this._tempGeocentricNormal, this._tempRotationAxis);
140
+ }
141
+ const pitchSign = Math.sign(Vector3.Dot(this._tempGeocentricNormal, this.upVector)); // If negative, camera is upside down
142
+ // Since these are pointed in opposite directions, we must negate the dot product to get the proper angle
143
+ const currentPitch = pitchSign * Math.acos(Scalar.Clamp(-Vector3.Dot(this._lookAtVector, this._tempGeocentricNormal), -1, 1));
144
+ const newPitch = Scalar.Clamp(currentPitch + this._perFrameGeocentricRotation.x, 0, 0.5 * Math.PI - Epsilon);
145
+ // Build rotation matrix around normalized axis
146
+ Matrix.RotationAxisToRef(this._tempRotationAxis.normalize(), newPitch - currentPitch, pitchRotationMatrix);
147
+ }
148
+ // Then apply yaw
149
+ if (this._perFrameGeocentricRotation.y !== 0) {
150
+ Matrix.RotationAxisToRef(this._tempGeocentricNormal, this._perFrameGeocentricRotation.y, yawRotationMatrix); // this axis changes if we aren't using center of screen for tilt
151
+ }
152
+ pitchRotationMatrix.multiplyToRef(yawRotationMatrix, this._tempRotationMatrix);
153
+ // Offset camera to be (position-pitchPoint) distance from geocentricOrigin, apply rotation to position/up/lookat vectors, then add back the pitchPoint offset
154
+ this.position.subtractInPlace(this._geocentricRotationPt);
155
+ Vector3.TransformCoordinatesToRef(this.position, this._tempRotationMatrix, this.position);
156
+ Vector3.TransformNormalToRef(this.upVector, this._tempRotationMatrix, this.upVector);
157
+ Vector3.TransformNormalToRef(this._lookAtVector, this._tempRotationMatrix, this._lookAtVector);
158
+ this.position.addInPlace(this._geocentricRotationPt);
159
+ }
160
+ _clampZoomDistance(requestedDistance, pickResultDistance) {
161
+ // If pickResult is defined
162
+ if (requestedDistance > 0) {
163
+ if (pickResultDistance !== undefined) {
164
+ // If there is a pick, allow movement up to pick - minAltitude
165
+ if (pickResultDistance - this._minAltitude < 0) {
166
+ return 0;
167
+ }
168
+ return Math.min(requestedDistance, pickResultDistance - this._minAltitude);
169
+ }
170
+ else {
171
+ return requestedDistance;
172
+ }
173
+ }
174
+ if (requestedDistance < 0) {
175
+ const maxZoomOut = this._maxCameraRadius ? this._maxCameraRadius - this.position.length() : Number.POSITIVE_INFINITY;
176
+ return Math.max(requestedDistance, -maxZoomOut);
177
+ }
178
+ return 0;
179
+ }
180
+ _applyZoom(distance) {
181
+ const pickResult = this._scene.pick(this._scene.pointerX, this._scene.pointerY, this.pickPredicate);
182
+ if (pickResult.hit && pickResult.ray) {
183
+ // Zoom to cursor
184
+ this._moveCameraAlongVectorByDistance(pickResult.ray.direction, this._clampZoomDistance(distance, pickResult.distance));
185
+ }
186
+ else {
187
+ // If no hit under cursor, zoom along lookVector instead
188
+ this._moveCameraAlongVectorByDistance(this._lookAtVector, this._clampZoomDistance(distance, this._pickAlongLook?.distance));
189
+ }
190
+ }
191
+ _moveCameraAlongVectorByDistance(vector, distance) {
192
+ if (distance) {
193
+ vector.scaleAndAddToRef(distance, this._tempPosition);
194
+ this._applyRotationCorrectionAndSetPos(this._tempPosition);
195
+ }
196
+ }
197
+ get _pickAlongLook() {
198
+ this._tempPickingRay.origin.copyFrom(this.position);
199
+ this._tempPickingRay.direction.copyFrom(this._lookAtVector);
200
+ return this._scene.pickWithRay(this._tempPickingRay, this.pickPredicate);
201
+ }
202
+ _checkInputs() {
203
+ this.inputs.checkInputs();
204
+ if (this._perFrameGeocentricTranslation.lengthSquared() > 0) {
205
+ this._applyGeocentricTranslation();
206
+ this._perFrameGeocentricTranslation.setAll(0);
207
+ this._isViewMatrixDirty = true;
208
+ }
209
+ if (this._perFrameGeocentricRotation.lengthSquared() > 0) {
210
+ this._applyGeocentricRotation();
211
+ this._perFrameGeocentricRotation.setAll(0);
212
+ this._isViewMatrixDirty = true;
213
+ }
214
+ if (this._perFrameZoom !== 0) {
215
+ this._applyZoom(this._perFrameZoom);
216
+ this._perFrameZoom = 0;
217
+ this._isViewMatrixDirty = true;
218
+ }
219
+ super._checkInputs();
220
+ }
221
+ attachControl(noPreventDefault) {
222
+ this.inputs.attachElement(noPreventDefault);
223
+ }
224
+ detachControl() {
225
+ this.inputs.detachElement();
226
+ }
227
+ }
228
+ // Helper to build east/north/up basis vectors at a world position
229
+ function ComputeLocalBasisToRefs(worldPos, refEast, refNorth, refUp) {
230
+ // up = normalized position (geocentric normal)
231
+ refUp.copyFrom(worldPos).normalize();
232
+ // east = normalize(up × worldUp)
233
+ // (cross product of up with world Y gives east except at poles)
234
+ const worldUp = Vector3.Up(); // (0,1,0)
235
+ Vector3.CrossToRef(refUp, worldUp, refEast);
236
+ // at poles, cross with worldForward instead
237
+ if (refEast.lengthSquared() < Epsilon) {
238
+ Vector3.CrossToRef(refUp, Vector3.Forward(), refEast);
239
+ }
240
+ refEast.normalize();
241
+ // north = up × east (completes right-handed basis)
242
+ Vector3.CrossToRef(refUp, refEast, refNorth);
243
+ refNorth.normalize();
244
+ }
245
+ /**
246
+ * Calculates changeOfBasis matrix from currentPos to newPos and stores it in ref
247
+ * @param currentPos
248
+ * @param newPos
249
+ * @param ref
250
+ * @returns The changeOfBasis matrix from currentPos to newPos
251
+ */
252
+ function ComputeChangeOfBasisToRef(currentPos, newPos, ref) {
253
+ const currentBasis = TmpVectors.Matrix[5];
254
+ const newBasis = TmpVectors.Matrix[6];
255
+ const inverse = TmpVectors.Matrix[7];
256
+ const east = TmpVectors.Vector3[3];
257
+ const north = TmpVectors.Vector3[4];
258
+ const up = TmpVectors.Vector3[5];
259
+ ComputeLocalBasisToRefs(currentPos, east, north, up);
260
+ Matrix.FromXYZAxesToRef(east, north, up, currentBasis);
261
+ ComputeLocalBasisToRefs(newPos, east, north, up);
262
+ Matrix.FromXYZAxesToRef(east, north, up, newBasis);
263
+ // Change of basis matrix = basis2 * basis1.inverse()
264
+ // (since orthonormal, inverse = transpose)
265
+ currentBasis.transposeToRef(inverse).multiplyToRef(newBasis, ref);
266
+ return ref;
267
+ }
268
+ //# sourceMappingURL=geospatialCamera.js.map
@@ -0,0 +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 { Scalar } from \"../Maths/math.scalar\";\r\nimport { Camera } from \"./camera\";\r\nimport { Ray } from \"../Culling/ray\";\r\nimport type { Scene } from \"../scene\";\r\nimport type { MeshPredicate } from \"../Culling/ray.core\";\r\nimport type { Nullable } from \"../types\";\r\n\r\ntype CameraOptions = {\r\n planetRadius: number; // Radius of the planet\r\n minAltitude?: number; // Minimum altitude of the camera above the planet surface\r\n maxAltitude?: number; // Maximum altitude of the camera above the planet surface\r\n restingAltitude?: number; // The altitude the camera will return to when not being actively zoomed in or out\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\n * Still TODO:\r\n * - Pitch/yaw limits, input speeds\r\n * - ZoomToPoint\r\n * - Conversion between lat/long/alt and cartesian coordinates\r\n */\r\nexport class GeospatialCamera extends Camera {\r\n override inputs: GeospatialCameraInputsManager;\r\n\r\n // Changed by the inputs, reset on every frame\r\n /** @internal */\r\n public _perFrameGeocentricTranslation: Vector3; // Translation that keeps camera at the same radius from the center of the globe\r\n /** @internal */\r\n public _perFrameGeocentricRotation: Vector3; // Rotation around center (distinct from rotation around camera that can cause looking off into space)\r\n /** @internal */\r\n public _perFrameZoom: number;\r\n\r\n /** If supplied, will be used when picking the globe */\r\n public pickPredicate?: MeshPredicate;\r\n\r\n /**\r\n * Enables rotation around a specific point, instead of default rotation around center\r\n * @internal\r\n */\r\n public _alternateRotationPt: Nullable<Vector3>;\r\n\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 // NOTE that for now we are falling back to target if no pick on globe (because that shouldn't happen with current implemented inputs)\r\n // but eventually we want to return a point on the globe even if the camera is looking off into space\r\n return this._pickAlongLook?.pickedPoint ?? this._target;\r\n }\r\n\r\n // Temp vars\r\n private _tempGeocentricNormal: Vector3;\r\n private _tempRotationAxis: Vector3;\r\n private _tempRotationMatrix: Matrix;\r\n private _tempPickingRay: Ray;\r\n private _tempPosition: Vector3;\r\n\r\n private _viewMatrix: Matrix;\r\n private _isViewMatrixDirty: boolean;\r\n private _lookAtVector: Vector3;\r\n\r\n // Camera configuration vars\r\n private _planetRadius: number;\r\n private _minAltitude: number;\r\n private _maxAltitude?: number;\r\n private _maxCameraRadius?: number;\r\n private _restingAltitude: number;\r\n\r\n /** Target of camera when looking along lookAtVector from current position. This does not necessarily represent a point on the globe */\r\n private get _target(): Vector3 {\r\n return this.position.addToRef(this._lookAtVector, this._tempPosition);\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._alternateRotationPt ?? this.center;\r\n }\r\n\r\n constructor(name: string, scene: Scene, options: CameraOptions, pickPredicate?: MeshPredicate) {\r\n super(name, Vector3.Zero(), scene);\r\n this._resetToDefault(options);\r\n this.pickPredicate = pickPredicate;\r\n this.inputs = new GeospatialCameraInputsManager(this);\r\n this.inputs.addMouse().addMouseWheel();\r\n }\r\n\r\n private _resetToDefault(options: CameraOptions): void {\r\n // Camera configuration vars\r\n this._minAltitude = options.minAltitude ?? 5;\r\n this._maxAltitude = options.maxAltitude;\r\n this._planetRadius = options.planetRadius;\r\n this._maxCameraRadius = this._maxAltitude ? this._planetRadius + this._maxAltitude : undefined;\r\n this._restingAltitude = options.restingAltitude ?? this._maxCameraRadius ?? this._planetRadius * 4;\r\n this.position.copyFromFloats(0, 0, -this._restingAltitude);\r\n\r\n // Input vars\r\n this._perFrameGeocentricRotation = Vector3.Zero();\r\n this._perFrameGeocentricTranslation = Vector3.Zero();\r\n this._perFrameZoom = 0;\r\n\r\n // Temp vars\r\n this._tempPosition = Vector3.Zero();\r\n this._tempRotationAxis = Vector3.Right(); // starting axis used to calculate pitch rotation matrix\r\n this._tempRotationMatrix = Matrix.Identity();\r\n this._tempGeocentricNormal = Vector3.Zero();\r\n this._tempPickingRay = new Ray(this.position, this._lookAtVector);\r\n this._tempPickingRay.direction = Vector3.Zero();\r\n\r\n // View matrix calculation vars\r\n this.upVector = Vector3.Up(); // Up vector of the camera\r\n this._lookAtVector = this.position.negate().normalize(); // Lookat vector of the camera\r\n this._viewMatrix = Matrix.Identity();\r\n this._isViewMatrixDirty = true;\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 target\r\n if (this.getScene().useRightHandedSystem) {\r\n Matrix.LookAtRHToRef(this.position, this._target, this.upVector, this._viewMatrix);\r\n } else {\r\n Matrix.LookAtLHToRef(this.position, this._target, 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 /**\r\n * Applies rotation correction to the camera by calculating a changeOfBasis matrix from the camera's current position to the new position\r\n * and transforming the lookAt and up vectors by that matrix before updating the camera position and marking the view matrix as dirty\r\n * @param newPos The camera's desired position, before correction is applied\r\n */\r\n private _applyRotationCorrectionAndSetPos(newPos: Vector3): void {\r\n // Compute changeOfBasis between current camera position and new position\r\n ComputeChangeOfBasisToRef(this.position, newPos, this._tempRotationMatrix);\r\n\r\n // Apply rotation correction to lookat/up vectors\r\n Vector3.TransformNormalToRef(this._lookAtVector, this._tempRotationMatrix, this._lookAtVector);\r\n Vector3.TransformNormalToRef(this.upVector, this._tempRotationMatrix, this.upVector);\r\n\r\n // Apply position change and mark viewMatrix as dirty\r\n this.position.copyFrom(newPos);\r\n this._isViewMatrixDirty = true;\r\n }\r\n\r\n /**\r\n * When the geocentric normal has any translation change (due to dragging), we must ensure the camera remains orbiting around the world origin\r\n * We thus need to perform 2 correction steps\r\n * 1. Translation correction that keeps the camera at the same radius as before the drag\r\n * 2. Rotation correction that keeps the camera facing the globe (so that as we pan, the globe stays centered on screen)\r\n */\r\n private _applyGeocentricTranslation() {\r\n // Store pending position (without any corrections applied)\r\n this.position.addToRef(this._perFrameGeocentricTranslation, this._tempPosition);\r\n\r\n // 1. Calculate the altitude correction to keep camera at the same radius when applying translation\r\n const tempPositionScaled = TmpVectors.Vector3[2];\r\n const offset = TmpVectors.Vector3[3];\r\n this._tempPosition.normalizeToRef(tempPositionScaled).scaleInPlace(this.position.length()); // what would tempPosition be if it were scaled to same radius as before\r\n this._tempPosition.subtractToRef(tempPositionScaled, offset); // find offset between tempPosition and the tempScaledPosition\r\n this._tempPosition.subtractInPlace(offset); // reduce tempPosition by that offset\r\n\r\n // 2. Calculate the rotation correction to keep camera facing globe\r\n this._applyRotationCorrectionAndSetPos(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 // Normalize key vectors\r\n this._geocentricRotationPt.normalizeToRef(this._tempGeocentricNormal);\r\n this.upVector.normalize();\r\n this._lookAtVector.normalize();\r\n\r\n const pitchRotationMatrix = Matrix.Identity();\r\n const yawRotationMatrix = Matrix.Identity();\r\n // First apply pitch\r\n if (this._perFrameGeocentricRotation.x !== 0) {\r\n // Compute a rotation axis that is perpendicular to both the upVector and the geocentricNormalOfPitchPoint\r\n Vector3.CrossToRef(this.upVector, this._tempGeocentricNormal, this._tempRotationAxis);\r\n\r\n // If upVector and geocentricNormalOfPitchPoint are parallel, fall back to cross(lookAtDirection, geocentricNormalOfPitchPoint)\r\n if (this._tempRotationAxis.lengthSquared() <= Epsilon) {\r\n Vector3.CrossToRef(this._lookAtVector, this._tempGeocentricNormal, this._tempRotationAxis);\r\n }\r\n\r\n const pitchSign = Math.sign(Vector3.Dot(this._tempGeocentricNormal, this.upVector)); // If negative, camera is upside down\r\n // Since these are pointed in opposite directions, we must negate the dot product to get the proper angle\r\n const currentPitch = pitchSign * Math.acos(Scalar.Clamp(-Vector3.Dot(this._lookAtVector, this._tempGeocentricNormal), -1, 1));\r\n const newPitch = Scalar.Clamp(currentPitch + this._perFrameGeocentricRotation.x, 0, 0.5 * Math.PI - Epsilon);\r\n // Build rotation matrix around normalized axis\r\n Matrix.RotationAxisToRef(this._tempRotationAxis.normalize(), newPitch - currentPitch, pitchRotationMatrix);\r\n }\r\n\r\n // Then apply yaw\r\n if (this._perFrameGeocentricRotation.y !== 0) {\r\n Matrix.RotationAxisToRef(this._tempGeocentricNormal, this._perFrameGeocentricRotation.y, yawRotationMatrix); // this axis changes if we aren't using center of screen for tilt\r\n }\r\n pitchRotationMatrix.multiplyToRef(yawRotationMatrix, this._tempRotationMatrix);\r\n\r\n // Offset camera to be (position-pitchPoint) distance from geocentricOrigin, apply rotation to position/up/lookat vectors, then add back the pitchPoint offset\r\n this.position.subtractInPlace(this._geocentricRotationPt);\r\n\r\n Vector3.TransformCoordinatesToRef(this.position, this._tempRotationMatrix, this.position);\r\n Vector3.TransformNormalToRef(this.upVector, this._tempRotationMatrix, this.upVector);\r\n Vector3.TransformNormalToRef(this._lookAtVector, this._tempRotationMatrix, this._lookAtVector);\r\n\r\n this.position.addInPlace(this._geocentricRotationPt);\r\n }\r\n\r\n private _clampZoomDistance(requestedDistance: number, pickResultDistance: number | undefined): number {\r\n // If pickResult is defined\r\n if (requestedDistance > 0) {\r\n if (pickResultDistance !== undefined) {\r\n // If there is a pick, allow movement up to pick - minAltitude\r\n if (pickResultDistance - this._minAltitude < 0) {\r\n return 0;\r\n }\r\n return Math.min(requestedDistance, pickResultDistance - this._minAltitude);\r\n } else {\r\n return requestedDistance;\r\n }\r\n }\r\n\r\n if (requestedDistance < 0) {\r\n const maxZoomOut = this._maxCameraRadius ? this._maxCameraRadius - this.position.length() : Number.POSITIVE_INFINITY;\r\n return Math.max(requestedDistance, -maxZoomOut);\r\n }\r\n return 0;\r\n }\r\n\r\n private _applyZoom(distance: number) {\r\n const pickResult = this._scene.pick(this._scene.pointerX, this._scene.pointerY, this.pickPredicate);\r\n if (pickResult.hit && pickResult.ray) {\r\n // Zoom to cursor\r\n this._moveCameraAlongVectorByDistance(pickResult.ray.direction, this._clampZoomDistance(distance, pickResult.distance));\r\n } else {\r\n // If no hit under cursor, zoom along lookVector instead\r\n this._moveCameraAlongVectorByDistance(this._lookAtVector, this._clampZoomDistance(distance, this._pickAlongLook?.distance));\r\n }\r\n }\r\n\r\n private _moveCameraAlongVectorByDistance(vector: Vector3, distance: number) {\r\n if (distance) {\r\n vector.scaleAndAddToRef(distance, this._tempPosition);\r\n this._applyRotationCorrectionAndSetPos(this._tempPosition);\r\n }\r\n }\r\n\r\n private get _pickAlongLook() {\r\n this._tempPickingRay.origin.copyFrom(this.position);\r\n this._tempPickingRay.direction.copyFrom(this._lookAtVector);\r\n return this._scene.pickWithRay(this._tempPickingRay, this.pickPredicate);\r\n }\r\n\r\n override _checkInputs(): void {\r\n this.inputs.checkInputs();\r\n if (this._perFrameGeocentricTranslation.lengthSquared() > 0) {\r\n this._applyGeocentricTranslation();\r\n this._perFrameGeocentricTranslation.setAll(0);\r\n this._isViewMatrixDirty = true;\r\n }\r\n if (this._perFrameGeocentricRotation.lengthSquared() > 0) {\r\n this._applyGeocentricRotation();\r\n this._perFrameGeocentricRotation.setAll(0);\r\n this._isViewMatrixDirty = true;\r\n }\r\n if (this._perFrameZoom !== 0) {\r\n this._applyZoom(this._perFrameZoom);\r\n this._perFrameZoom = 0;\r\n this._isViewMatrixDirty = true;\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\r\n// Helper to build east/north/up basis vectors at a world position\r\nfunction ComputeLocalBasisToRefs(worldPos: Vector3, refEast: Vector3, refNorth: Vector3, refUp: Vector3) {\r\n // up = normalized position (geocentric normal)\r\n refUp.copyFrom(worldPos).normalize();\r\n\r\n // east = normalize(up × worldUp)\r\n // (cross product of up with world Y gives east except at poles)\r\n const worldUp = Vector3.Up(); // (0,1,0)\r\n Vector3.CrossToRef(refUp, worldUp, refEast);\r\n\r\n // at poles, cross with worldForward instead\r\n if (refEast.lengthSquared() < Epsilon) {\r\n Vector3.CrossToRef(refUp, Vector3.Forward(), refEast);\r\n }\r\n refEast.normalize();\r\n\r\n // north = up × east (completes right-handed basis)\r\n Vector3.CrossToRef(refUp, refEast, refNorth);\r\n refNorth.normalize();\r\n}\r\n\r\n/**\r\n * Calculates changeOfBasis matrix from currentPos to newPos and stores it in ref\r\n * @param currentPos\r\n * @param newPos\r\n * @param ref\r\n * @returns The changeOfBasis matrix from currentPos to newPos\r\n */\r\nfunction ComputeChangeOfBasisToRef(currentPos: Vector3, newPos: Vector3, ref: Matrix): Matrix {\r\n const currentBasis = TmpVectors.Matrix[5];\r\n const newBasis = TmpVectors.Matrix[6];\r\n const inverse = TmpVectors.Matrix[7];\r\n const east = TmpVectors.Vector3[3];\r\n const north = TmpVectors.Vector3[4];\r\n const up = TmpVectors.Vector3[5];\r\n\r\n ComputeLocalBasisToRefs(currentPos, east, north, up);\r\n Matrix.FromXYZAxesToRef(east, north, up, currentBasis);\r\n\r\n ComputeLocalBasisToRefs(newPos, east, north, up);\r\n Matrix.FromXYZAxesToRef(east, north, up, newBasis);\r\n\r\n // Change of basis matrix = basis2 * basis1.inverse()\r\n // (since orthonormal, inverse = transpose)\r\n currentBasis.transposeToRef(inverse).multiplyToRef(newBasis, ref);\r\n\r\n return ref;\r\n}\r\n"]}
@@ -0,0 +1,23 @@
1
+ import { CameraInputsManager } from "./cameraInputsManager.js";
2
+ import type { GeospatialCamera } from "./geospatialCamera.js";
3
+ /**
4
+ * Default Inputs manager for the GeospatialCamera.
5
+ * It groups all the default supported inputs for ease of use.
6
+ */
7
+ export declare class GeospatialCameraInputsManager extends CameraInputsManager<GeospatialCamera> {
8
+ /**
9
+ * Instantiates a new GeospatialCameraInputsManager.
10
+ * @param camera Defines the camera the inputs belong to
11
+ */
12
+ constructor(camera: GeospatialCamera);
13
+ /**
14
+ * Add mouse input support to the input manager
15
+ * @returns the current input manager
16
+ */
17
+ addMouse(): GeospatialCameraInputsManager;
18
+ /**
19
+ * Add mouse wheel input support to the input manager
20
+ * @returns the current input manager
21
+ */
22
+ addMouseWheel(): GeospatialCameraInputsManager;
23
+ }