arcRotateCameraVRDeviceOrientationInput.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. import { Nullable } from "../../types";
  2. import { ArcRotateCamera } from "../../Cameras/arcRotateCamera";
  3. import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
  4. import { ArcRotateCameraInputsManager } from "../../Cameras/arcRotateCameraInputsManager";
  5. import { Tools } from '../../Misc/tools';
  6. // Module augmentation to abstract orientation inputs from camera.
  7. declare module "../../Cameras/arcRotateCameraInputsManager" {
  8. export interface ArcRotateCameraInputsManager {
  9. /**
  10. * Add orientation input support to the input manager.
  11. * @returns the current input manager
  12. */
  13. addVRDeviceOrientation(): ArcRotateCameraInputsManager;
  14. }
  15. }
  16. /**
  17. * Add orientation input support to the input manager.
  18. * @returns the current input manager
  19. */
  20. ArcRotateCameraInputsManager.prototype.addVRDeviceOrientation = function(): ArcRotateCameraInputsManager {
  21. this.add(new ArcRotateCameraVRDeviceOrientationInput());
  22. return this;
  23. };
  24. /**
  25. * Manage the device orientation inputs (gyroscope) to control an arc rotate camera.
  26. * @see http://doc.babylonjs.com/how_to/customizing_camera_inputs
  27. */
  28. export class ArcRotateCameraVRDeviceOrientationInput implements ICameraInput<ArcRotateCamera> {
  29. /**
  30. * Defines the camera the input is attached to.
  31. */
  32. public camera: ArcRotateCamera;
  33. /**
  34. * Defines a correction factor applied on the alpha value retrieved from the orientation events.
  35. */
  36. public alphaCorrection = 1;
  37. /**
  38. * Defines a correction factor applied on the gamma value retrieved from the orientation events.
  39. */
  40. public gammaCorrection = 1;
  41. private _alpha = 0;
  42. private _gamma = 0;
  43. private _dirty = false;
  44. private _deviceOrientationHandler: () => void;
  45. /**
  46. * Instantiate a new ArcRotateCameraVRDeviceOrientationInput.
  47. */
  48. constructor() {
  49. this._deviceOrientationHandler = this._onOrientationEvent.bind(this);
  50. }
  51. /**
  52. * Attach the input controls to a specific dom element to get the input from.
  53. * @param element Defines the element the controls should be listened from
  54. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
  55. */
  56. public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
  57. this.camera.attachControl(element, noPreventDefault);
  58. let hostWindow = this.camera.getScene().getEngine().getHostWindow();
  59. if (hostWindow) {
  60. // check iOS 13+ support
  61. if (typeof (<any>DeviceOrientationEvent).requestPermission === 'function') {
  62. (<any>DeviceOrientationEvent).requestPermission()
  63. .then((response: string) => {
  64. if (response === 'granted') {
  65. hostWindow!.addEventListener("deviceorientation", this._deviceOrientationHandler);
  66. } else {
  67. Tools.Warn("Permission not granted.");
  68. }
  69. })
  70. .catch((error: any) => {
  71. Tools.Error(error);
  72. });
  73. } else {
  74. hostWindow.addEventListener("deviceorientation", this._deviceOrientationHandler);
  75. }
  76. }
  77. }
  78. /** @hidden */
  79. public _onOrientationEvent(evt: DeviceOrientationEvent): void {
  80. if (evt.alpha !== null) {
  81. this._alpha = (+evt.alpha | 0) * this.alphaCorrection;
  82. }
  83. if (evt.gamma !== null) {
  84. this._gamma = (+evt.gamma | 0) * this.gammaCorrection;
  85. }
  86. this._dirty = true;
  87. }
  88. /**
  89. * Update the current camera state depending on the inputs that have been used this frame.
  90. * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
  91. */
  92. public checkInputs(): void {
  93. if (this._dirty) {
  94. this._dirty = false;
  95. if (this._gamma < 0) {
  96. this._gamma = 180 + this._gamma;
  97. }
  98. this.camera.alpha = (-this._alpha / 180.0 * Math.PI) % Math.PI * 2;
  99. this.camera.beta = (this._gamma / 180.0 * Math.PI);
  100. }
  101. }
  102. /**
  103. * Detach the current controls from the specified dom element.
  104. * @param element Defines the element to stop listening the inputs from
  105. */
  106. public detachControl(element: Nullable<HTMLElement>): void {
  107. window.removeEventListener("deviceorientation", this._deviceOrientationHandler);
  108. }
  109. /**
  110. * Gets the class name of the current intput.
  111. * @returns the class name
  112. */
  113. public getClassName(): string {
  114. return "ArcRotateCameraVRDeviceOrientationInput";
  115. }
  116. /**
  117. * Get the friendly name associated with the input class.
  118. * @returns the input friendly name
  119. */
  120. public getSimpleName(): string {
  121. return "VRDeviceOrientation";
  122. }
  123. }
  124. (<any>CameraInputTypes)["ArcRotateCameraVRDeviceOrientationInput"] = ArcRotateCameraVRDeviceOrientationInput;