freeCameraDeviceOrientationInput.ts 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. import { Nullable } from "../../types";
  2. import { ICameraInput, CameraInputTypes } from "../../Cameras/cameraInputsManager";
  3. import { FreeCamera } from "../../Cameras/freeCamera";
  4. import { Quaternion } from "../../Maths/math";
  5. import { Tools } from "../../Misc/tools";
  6. import { FreeCameraInputsManager } from "../../Cameras/freeCameraInputsManager";
  7. import { Observable } from '../../Misc/observable';
  8. // Module augmentation to abstract orientation inputs from camera.
  9. declare module "../../Cameras/freeCameraInputsManager" {
  10. export interface FreeCameraInputsManager {
  11. /**
  12. * @hidden
  13. */
  14. _deviceOrientationInput: Nullable<FreeCameraDeviceOrientationInput>;
  15. /**
  16. * Add orientation input support to the input manager.
  17. * @returns the current input manager
  18. */
  19. addDeviceOrientation(): FreeCameraInputsManager;
  20. }
  21. }
  22. /**
  23. * Add orientation input support to the input manager.
  24. * @returns the current input manager
  25. */
  26. FreeCameraInputsManager.prototype.addDeviceOrientation = function(): FreeCameraInputsManager {
  27. if (!this._deviceOrientationInput) {
  28. this._deviceOrientationInput = new FreeCameraDeviceOrientationInput();
  29. this.add(this._deviceOrientationInput);
  30. }
  31. return this;
  32. };
  33. /**
  34. * Takes information about the orientation of the device as reported by the deviceorientation event to orient the camera.
  35. * Screen rotation is taken into account.
  36. * @see http://doc.babylonjs.com/how_to/customizing_camera_inputs
  37. */
  38. export class FreeCameraDeviceOrientationInput implements ICameraInput<FreeCamera> {
  39. private _camera: FreeCamera;
  40. private _screenOrientationAngle: number = 0;
  41. private _constantTranform: Quaternion;
  42. private _screenQuaternion: Quaternion = new Quaternion();
  43. private _alpha: number = 0;
  44. private _beta: number = 0;
  45. private _gamma: number = 0;
  46. /**
  47. * @hidden
  48. */
  49. public _onDeviceOrientationChangedObservable = new Observable<void>();
  50. /**
  51. * Instantiates a new input
  52. * @see http://doc.babylonjs.com/how_to/customizing_camera_inputs
  53. */
  54. constructor() {
  55. this._constantTranform = new Quaternion(- Math.sqrt(0.5), 0, 0, Math.sqrt(0.5));
  56. this._orientationChanged();
  57. }
  58. /**
  59. * Define the camera controlled by the input.
  60. */
  61. public get camera(): FreeCamera {
  62. return this._camera;
  63. }
  64. public set camera(camera: FreeCamera) {
  65. this._camera = camera;
  66. if (this._camera != null && !this._camera.rotationQuaternion) {
  67. this._camera.rotationQuaternion = new Quaternion();
  68. }
  69. if (this._camera) {
  70. this._camera.onDisposeObservable.add(() => {
  71. this._onDeviceOrientationChangedObservable.clear();
  72. });
  73. }
  74. }
  75. /**
  76. * Attach the input controls to a specific dom element to get the input from.
  77. * @param element Defines the element the controls should be listened from
  78. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
  79. */
  80. public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
  81. window.addEventListener("orientationchange", this._orientationChanged);
  82. window.addEventListener("deviceorientation", this._deviceOrientation);
  83. //In certain cases, the attach control is called AFTER orientation was changed,
  84. //So this is needed.
  85. this._orientationChanged();
  86. }
  87. private _orientationChanged = () => {
  88. this._screenOrientationAngle = (<any>window.orientation !== undefined ? +<any>window.orientation : ((<any>window.screen).orientation && ((<any>window.screen).orientation)['angle'] ? ((<any>window.screen).orientation).angle : 0));
  89. this._screenOrientationAngle = -Tools.ToRadians(this._screenOrientationAngle / 2);
  90. this._screenQuaternion.copyFromFloats(0, Math.sin(this._screenOrientationAngle), 0, Math.cos(this._screenOrientationAngle));
  91. }
  92. private _deviceOrientation = (evt: DeviceOrientationEvent) => {
  93. this._alpha = evt.alpha !== null ? evt.alpha : 0;
  94. this._beta = evt.beta !== null ? evt.beta : 0;
  95. this._gamma = evt.gamma !== null ? evt.gamma : 0;
  96. if (evt.alpha !== null) {
  97. this._onDeviceOrientationChangedObservable.notifyObservers();
  98. }
  99. }
  100. /**
  101. * Detach the current controls from the specified dom element.
  102. * @param element Defines the element to stop listening the inputs from
  103. */
  104. public detachControl(element: Nullable<HTMLElement>): void {
  105. window.removeEventListener("orientationchange", this._orientationChanged);
  106. window.removeEventListener("deviceorientation", this._deviceOrientation);
  107. this._alpha = 0;
  108. }
  109. /**
  110. * Update the current camera state depending on the inputs that have been used this frame.
  111. * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop.
  112. */
  113. public checkInputs(): void {
  114. //if no device orientation provided, don't update the rotation.
  115. //Only testing against alpha under the assumption thatnorientation will never be so exact when set.
  116. if (!this._alpha) { return; }
  117. Quaternion.RotationYawPitchRollToRef(Tools.ToRadians(this._alpha), Tools.ToRadians(this._beta), -Tools.ToRadians(this._gamma), this.camera.rotationQuaternion);
  118. this._camera.rotationQuaternion.multiplyInPlace(this._screenQuaternion);
  119. this._camera.rotationQuaternion.multiplyInPlace(this._constantTranform);
  120. //Mirror on XY Plane
  121. this._camera.rotationQuaternion.z *= -1;
  122. this._camera.rotationQuaternion.w *= -1;
  123. }
  124. /**
  125. * Gets the class name of the current intput.
  126. * @returns the class name
  127. */
  128. public getClassName(): string {
  129. return "FreeCameraDeviceOrientationInput";
  130. }
  131. /**
  132. * Get the friendly name associated with the input class.
  133. * @returns the input friendly name
  134. */
  135. public getSimpleName(): string {
  136. return "deviceOrientation";
  137. }
  138. }
  139. (<any>CameraInputTypes)["FreeCameraDeviceOrientationInput"] = FreeCameraDeviceOrientationInput;