UNPKG

@babylonjs/viewer

Version:

The Babylon Viewer aims to simplify a specific but common Babylon.js use case: loading, viewing, and interacting with a 3D model.

1,257 lines (1,250 loc) 262 kB
import { b as Tools, bw as KeyboardEventTypes, V as Vector3, u as __decorate, v as serialize, bx as CameraInputTypes, O as Observable, by as PointerEventTypes, bz as EventConstants, M as Matrix, bA as CameraInputsManager, bB as TargetCamera, aa as AbstractEngine, a7 as Vector2, bk as serializeAsVector3, R as RegisterClass, H as EngineStore, Y as SerializationHelper, bj as GetClass, m as VertexBuffer, T as Texture, C as Constants, b2 as SmartArray, L as Logger, bC as Decode, bD as GLTFFileLoaderMetadata, bE as GLTFMagicBase64Encoded, bF as DecodeBase64UrlToBinary, bG as RuntimeError, bH as ErrorCodes, aG as RegisterSceneLoaderPlugin, bI as registerGLTFExtension, bJ as unregisterGLTFExtension, t as Material, bK as registeredGLTFExtensions, g as Mesh, ap as AbstractMesh, br as TransformNode, bL as deepMerge, aI as Geometry, Q as Quaternion, a2 as Camera, al as Buffer, bM as PBRMaterial, aH as Color3, bN as Deferred, bO as GetMimeType, bP as IsBase64DataUrl, bQ as LoadFileError, bR as GetTypedArrayConstructor, aS as TmpVectors, a4 as BoundingInfo } from './index-FzOfPXLV.esm.js'; import { B as Bone } from './bone--mL3H5cQ.esm.js'; import { S as Skeleton } from './skeleton-B7-ffRm_.esm.js'; import { A as AssetContainer } from './assetContainer-8JZnoDWQ.esm.js'; import { G as GetMappingForKey } from './objectModelMapping-CJnQ6at_.esm.js'; import './rawTexture-B2DimmQ5.esm.js'; /** * Manage the keyboard inputs to control the movement of a free camera. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs */ class FreeCameraKeyboardMoveInput { constructor() { /** * Gets or Set the list of keyboard keys used to control the forward move of the camera. */ this.keysUp = [38]; /** * Gets or Set the list of keyboard keys used to control the upward move of the camera. */ this.keysUpward = [33]; /** * Gets or Set the list of keyboard keys used to control the backward move of the camera. */ this.keysDown = [40]; /** * Gets or Set the list of keyboard keys used to control the downward move of the camera. */ this.keysDownward = [34]; /** * Gets or Set the list of keyboard keys used to control the left strafe move of the camera. */ this.keysLeft = [37]; /** * Gets or Set the list of keyboard keys used to control the right strafe move of the camera. */ this.keysRight = [39]; /** * Defines the pointer angular sensibility along the X and Y axis or how fast is the camera rotating. */ this.rotationSpeed = 0.5; /** * Gets or Set the list of keyboard keys used to control the left rotation move of the camera. */ this.keysRotateLeft = []; /** * Gets or Set the list of keyboard keys used to control the right rotation move of the camera. */ this.keysRotateRight = []; /** * Gets or Set the list of keyboard keys used to control the up rotation move of the camera. */ this.keysRotateUp = []; /** * Gets or Set the list of keyboard keys used to control the down rotation move of the camera. */ this.keysRotateDown = []; this._keys = new Array(); } /** * Attach the input controls to a specific dom element to get the input from. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) */ attachControl(noPreventDefault) { noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments); if (this._onCanvasBlurObserver) { return; } this._scene = this.camera.getScene(); this._engine = this._scene.getEngine(); this._onCanvasBlurObserver = this._engine.onCanvasBlurObservable.add(() => { this._keys.length = 0; }); this._onKeyboardObserver = this._scene.onKeyboardObservable.add((info) => { const evt = info.event; if (!evt.metaKey) { if (info.type === KeyboardEventTypes.KEYDOWN) { if (this.keysUp.indexOf(evt.keyCode) !== -1 || this.keysDown.indexOf(evt.keyCode) !== -1 || this.keysLeft.indexOf(evt.keyCode) !== -1 || this.keysRight.indexOf(evt.keyCode) !== -1 || this.keysUpward.indexOf(evt.keyCode) !== -1 || this.keysDownward.indexOf(evt.keyCode) !== -1 || this.keysRotateLeft.indexOf(evt.keyCode) !== -1 || this.keysRotateRight.indexOf(evt.keyCode) !== -1 || this.keysRotateUp.indexOf(evt.keyCode) !== -1 || this.keysRotateDown.indexOf(evt.keyCode) !== -1) { const index = this._keys.indexOf(evt.keyCode); if (index === -1) { this._keys.push(evt.keyCode); } if (!noPreventDefault) { evt.preventDefault(); } } } else { if (this.keysUp.indexOf(evt.keyCode) !== -1 || this.keysDown.indexOf(evt.keyCode) !== -1 || this.keysLeft.indexOf(evt.keyCode) !== -1 || this.keysRight.indexOf(evt.keyCode) !== -1 || this.keysUpward.indexOf(evt.keyCode) !== -1 || this.keysDownward.indexOf(evt.keyCode) !== -1 || this.keysRotateLeft.indexOf(evt.keyCode) !== -1 || this.keysRotateRight.indexOf(evt.keyCode) !== -1 || this.keysRotateUp.indexOf(evt.keyCode) !== -1 || this.keysRotateDown.indexOf(evt.keyCode) !== -1) { const index = this._keys.indexOf(evt.keyCode); if (index >= 0) { this._keys.splice(index, 1); } if (!noPreventDefault) { evt.preventDefault(); } } } } }); } /** * Detach the current controls from the specified dom element. */ detachControl() { if (this._scene) { if (this._onKeyboardObserver) { this._scene.onKeyboardObservable.remove(this._onKeyboardObserver); } if (this._onCanvasBlurObserver) { this._engine.onCanvasBlurObservable.remove(this._onCanvasBlurObserver); } this._onKeyboardObserver = null; this._onCanvasBlurObserver = null; } this._keys.length = 0; } /** * Update the current camera state depending on the inputs that have been used this frame. * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop. */ checkInputs() { if (this._onKeyboardObserver) { const camera = this.camera; // Keyboard for (let index = 0; index < this._keys.length; index++) { const keyCode = this._keys[index]; const speed = camera._computeLocalCameraSpeed(); if (this.keysLeft.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(-speed, 0, 0); } else if (this.keysUp.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(0, 0, speed); } else if (this.keysRight.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(speed, 0, 0); } else if (this.keysDown.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(0, 0, -speed); } else if (this.keysUpward.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(0, speed, 0); } else if (this.keysDownward.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(0, -speed, 0); } else if (this.keysRotateLeft.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(0, 0, 0); camera.cameraRotation.y -= this._getLocalRotation(); } else if (this.keysRotateRight.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(0, 0, 0); camera.cameraRotation.y += this._getLocalRotation(); } else if (this.keysRotateUp.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(0, 0, 0); camera.cameraRotation.x -= this._getLocalRotation(); } else if (this.keysRotateDown.indexOf(keyCode) !== -1) { camera._localDirection.copyFromFloats(0, 0, 0); camera.cameraRotation.x += this._getLocalRotation(); } if (camera.getScene().useRightHandedSystem) { camera._localDirection.z *= -1; } camera.getViewMatrix().invertToRef(camera._cameraTransformMatrix); Vector3.TransformNormalToRef(camera._localDirection, camera._cameraTransformMatrix, camera._transformedDirection); camera.cameraDirection.addInPlace(camera._transformedDirection); } } } /** * Gets the class name of the current input. * @returns the class name */ getClassName() { return "FreeCameraKeyboardMoveInput"; } /** @internal */ _onLostFocus() { this._keys.length = 0; } /** * Get the friendly name associated with the input class. * @returns the input friendly name */ getSimpleName() { return "keyboard"; } _getLocalRotation() { const handednessMultiplier = this.camera._calculateHandednessMultiplier(); const rotation = ((this.rotationSpeed * this._engine.getDeltaTime()) / 1000) * handednessMultiplier; return rotation; } } __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysUp", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysUpward", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysDown", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysDownward", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysLeft", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysRight", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "rotationSpeed", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysRotateLeft", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysRotateRight", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysRotateUp", void 0); __decorate([ serialize() ], FreeCameraKeyboardMoveInput.prototype, "keysRotateDown", void 0); CameraInputTypes["FreeCameraKeyboardMoveInput"] = FreeCameraKeyboardMoveInput; /** * Manage the mouse inputs to control the movement of a free camera. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs */ class FreeCameraMouseInput { /** * Manage the mouse inputs to control the movement of a free camera. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs * @param touchEnabled Defines if touch is enabled or not */ constructor( /** * [true] Define if touch is enabled in the mouse input */ touchEnabled = true) { this.touchEnabled = touchEnabled; /** * Defines the buttons associated with the input to handle camera move. */ this.buttons = [0, 1, 2]; /** * Defines the pointer angular sensibility along the X and Y axis or how fast is the camera rotating. */ this.angularSensibility = 2000.0; this._previousPosition = null; /** * Observable for when a pointer move event occurs containing the move offset */ this.onPointerMovedObservable = new Observable(); /** * @internal * If the camera should be rotated automatically based on pointer movement */ this._allowCameraRotation = true; this._currentActiveButton = -1; this._activePointerId = -1; } /** * Attach the input controls to a specific dom element to get the input from. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) */ attachControl(noPreventDefault) { noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments); const engine = this.camera.getEngine(); const element = engine.getInputElement(); if (!this._pointerInput) { this._pointerInput = (p) => { const evt = p.event; const isTouch = evt.pointerType === "touch"; if (!this.touchEnabled && isTouch) { return; } if (p.type !== PointerEventTypes.POINTERMOVE && this.buttons.indexOf(evt.button) === -1) { return; } const srcElement = evt.target; if (p.type === PointerEventTypes.POINTERDOWN) { // If the input is touch with more than one touch OR if the input is mouse and there is already an active button, return if ((isTouch && this._activePointerId !== -1) || (!isTouch && this._currentActiveButton !== -1)) { return; } this._activePointerId = evt.pointerId; try { srcElement?.setPointerCapture(evt.pointerId); } catch (e) { //Nothing to do with the error. Execution will continue. } if (this._currentActiveButton === -1) { this._currentActiveButton = evt.button; } this._previousPosition = { x: evt.clientX, y: evt.clientY, }; if (!noPreventDefault) { evt.preventDefault(); if (element) { element.focus(); } } // This is required to move while pointer button is down if (engine.isPointerLock && this._onMouseMove) { this._onMouseMove(p.event); } } else if (p.type === PointerEventTypes.POINTERUP) { // If input is touch with a different touch id OR if input is mouse with a different button, return if ((isTouch && this._activePointerId !== evt.pointerId) || (!isTouch && this._currentActiveButton !== evt.button)) { return; } try { srcElement?.releasePointerCapture(evt.pointerId); } catch (e) { //Nothing to do with the error. } this._currentActiveButton = -1; this._previousPosition = null; if (!noPreventDefault) { evt.preventDefault(); } this._activePointerId = -1; } else if (p.type === PointerEventTypes.POINTERMOVE && (this._activePointerId === evt.pointerId || !isTouch)) { if (engine.isPointerLock && this._onMouseMove) { this._onMouseMove(p.event); } else if (this._previousPosition) { const handednessMultiplier = this.camera._calculateHandednessMultiplier(); const offsetX = (evt.clientX - this._previousPosition.x) * handednessMultiplier; const offsetY = evt.clientY - this._previousPosition.y; if (this._allowCameraRotation) { this.camera.cameraRotation.y += offsetX / this.angularSensibility; this.camera.cameraRotation.x += offsetY / this.angularSensibility; } this.onPointerMovedObservable.notifyObservers({ offsetX: offsetX, offsetY: offsetY }); this._previousPosition = { x: evt.clientX, y: evt.clientY, }; if (!noPreventDefault) { evt.preventDefault(); } } } }; } this._onMouseMove = (evt) => { if (!engine.isPointerLock) { return; } const handednessMultiplier = this.camera._calculateHandednessMultiplier(); const offsetX = evt.movementX * handednessMultiplier; this.camera.cameraRotation.y += offsetX / this.angularSensibility; const offsetY = evt.movementY; this.camera.cameraRotation.x += offsetY / this.angularSensibility; this._previousPosition = null; if (!noPreventDefault) { evt.preventDefault(); } }; this._observer = this.camera .getScene() ._inputManager._addCameraPointerObserver(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE); if (element) { this._contextMenuBind = (evt) => this.onContextMenu(evt); element.addEventListener("contextmenu", this._contextMenuBind, false); // TODO: We need to figure out how to handle this for Native } } /** * Called on JS contextmenu event. * Override this method to provide functionality. * @param evt the context menu event */ onContextMenu(evt) { evt.preventDefault(); } /** * Detach the current controls from the specified dom element. */ detachControl() { if (this._observer) { this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer); if (this._contextMenuBind) { const engine = this.camera.getEngine(); const element = engine.getInputElement(); if (element) { element.removeEventListener("contextmenu", this._contextMenuBind); } } if (this.onPointerMovedObservable) { this.onPointerMovedObservable.clear(); } this._observer = null; this._onMouseMove = null; this._previousPosition = null; } this._activePointerId = -1; this._currentActiveButton = -1; } /** * Gets the class name of the current input. * @returns the class name */ getClassName() { return "FreeCameraMouseInput"; } /** * Get the friendly name associated with the input class. * @returns the input friendly name */ getSimpleName() { return "mouse"; } } __decorate([ serialize() ], FreeCameraMouseInput.prototype, "buttons", void 0); __decorate([ serialize() ], FreeCameraMouseInput.prototype, "angularSensibility", void 0); CameraInputTypes["FreeCameraMouseInput"] = FreeCameraMouseInput; /** * Base class for mouse wheel input.. * See FollowCameraMouseWheelInput in src/Cameras/Inputs/freeCameraMouseWheelInput.ts * for example usage. */ class BaseCameraMouseWheelInput { constructor() { /** * How fast is the camera moves in relation to X axis mouseWheel events. * Use negative value to reverse direction. */ this.wheelPrecisionX = 3.0; /** * How fast is the camera moves in relation to Y axis mouseWheel events. * Use negative value to reverse direction. */ this.wheelPrecisionY = 3.0; /** * How fast is the camera moves in relation to Z axis mouseWheel events. * Use negative value to reverse direction. */ this.wheelPrecisionZ = 3.0; /** * Observable for when a mouse wheel move event occurs. */ this.onChangedObservable = new Observable(); /** * Incremental value of multiple mouse wheel movements of the X axis. * Should be zero-ed when read. */ this._wheelDeltaX = 0; /** * Incremental value of multiple mouse wheel movements of the Y axis. * Should be zero-ed when read. */ this._wheelDeltaY = 0; /** * Incremental value of multiple mouse wheel movements of the Z axis. * Should be zero-ed when read. */ this._wheelDeltaZ = 0; /** * Firefox uses a different scheme to report scroll distances to other * browsers. Rather than use complicated methods to calculate the exact * multiple we need to apply, let's just cheat and use a constant. * https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent/deltaMode * https://stackoverflow.com/questions/20110224/what-is-the-height-of-a-line-in-a-wheel-event-deltamode-dom-delta-line */ this._ffMultiplier = 12; /** * Different event attributes for wheel data fall into a few set ranges. * Some relevant but dated date here: * https://stackoverflow.com/questions/5527601/normalizing-mousewheel-speed-across-browsers */ this._normalize = 120; } /** * Attach the input controls to a specific dom element to get the input from. * @param noPreventDefault Defines whether event caught by the controls * should call preventdefault(). * (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) */ attachControl(noPreventDefault) { noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments); this._wheel = (pointer) => { // sanity check - this should be a PointerWheel event. if (pointer.type !== PointerEventTypes.POINTERWHEEL) { return; } const event = pointer.event; const platformScale = event.deltaMode === EventConstants.DOM_DELTA_LINE ? this._ffMultiplier : 1; // If this happens to be set to DOM_DELTA_LINE, adjust accordingly this._wheelDeltaX += (this.wheelPrecisionX * platformScale * event.deltaX) / this._normalize; this._wheelDeltaY -= (this.wheelPrecisionY * platformScale * event.deltaY) / this._normalize; this._wheelDeltaZ += (this.wheelPrecisionZ * platformScale * event.deltaZ) / this._normalize; if (event.preventDefault) { if (!noPreventDefault) { event.preventDefault(); } } }; this._observer = this.camera.getScene()._inputManager._addCameraPointerObserver(this._wheel, PointerEventTypes.POINTERWHEEL); } /** * Detach the current controls from the specified dom element. */ detachControl() { if (this._observer) { this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer); this._observer = null; this._wheel = null; } if (this.onChangedObservable) { this.onChangedObservable.clear(); } } /** * Called for each rendered frame. */ checkInputs() { this.onChangedObservable.notifyObservers({ wheelDeltaX: this._wheelDeltaX, wheelDeltaY: this._wheelDeltaY, wheelDeltaZ: this._wheelDeltaZ, }); // Clear deltas. this._wheelDeltaX = 0; this._wheelDeltaY = 0; this._wheelDeltaZ = 0; } /** * Gets the class name of the current input. * @returns the class name */ getClassName() { return "BaseCameraMouseWheelInput"; } /** * Get the friendly name associated with the input class. * @returns the input friendly name */ getSimpleName() { return "mousewheel"; } } __decorate([ serialize() ], BaseCameraMouseWheelInput.prototype, "wheelPrecisionX", void 0); __decorate([ serialize() ], BaseCameraMouseWheelInput.prototype, "wheelPrecisionY", void 0); __decorate([ serialize() ], BaseCameraMouseWheelInput.prototype, "wheelPrecisionZ", void 0); // eslint-disable-next-line @typescript-eslint/naming-convention var _CameraProperty; (function (_CameraProperty) { _CameraProperty[_CameraProperty["MoveRelative"] = 0] = "MoveRelative"; _CameraProperty[_CameraProperty["RotateRelative"] = 1] = "RotateRelative"; _CameraProperty[_CameraProperty["MoveScene"] = 2] = "MoveScene"; })(_CameraProperty || (_CameraProperty = {})); /** * Manage the mouse wheel inputs to control a free camera. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs */ class FreeCameraMouseWheelInput extends BaseCameraMouseWheelInput { constructor() { super(...arguments); this._moveRelative = Vector3.Zero(); this._rotateRelative = Vector3.Zero(); this._moveScene = Vector3.Zero(); /** * These are set to the desired default behaviour. */ this._wheelXAction = _CameraProperty.MoveRelative; this._wheelXActionCoordinate = 0 /* Coordinate.X */; this._wheelYAction = _CameraProperty.MoveRelative; this._wheelYActionCoordinate = 2 /* Coordinate.Z */; this._wheelZAction = null; this._wheelZActionCoordinate = null; } /** * Gets the class name of the current input. * @returns the class name */ getClassName() { return "FreeCameraMouseWheelInput"; } /** * Set which movement axis (relative to camera's orientation) the mouse * wheel's X axis controls. * @param axis The axis to be moved. Set null to clear. */ set wheelXMoveRelative(axis) { if (axis === null && this._wheelXAction !== _CameraProperty.MoveRelative) { // Attempting to clear different _wheelXAction. return; } this._wheelXAction = _CameraProperty.MoveRelative; this._wheelXActionCoordinate = axis; } /** * Get the configured movement axis (relative to camera's orientation) the * mouse wheel's X axis controls. * @returns The configured axis or null if none. */ get wheelXMoveRelative() { if (this._wheelXAction !== _CameraProperty.MoveRelative) { return null; } return this._wheelXActionCoordinate; } /** * Set which movement axis (relative to camera's orientation) the mouse * wheel's Y axis controls. * @param axis The axis to be moved. Set null to clear. */ set wheelYMoveRelative(axis) { if (axis === null && this._wheelYAction !== _CameraProperty.MoveRelative) { // Attempting to clear different _wheelYAction. return; } this._wheelYAction = _CameraProperty.MoveRelative; this._wheelYActionCoordinate = axis; } /** * Get the configured movement axis (relative to camera's orientation) the * mouse wheel's Y axis controls. * @returns The configured axis or null if none. */ get wheelYMoveRelative() { if (this._wheelYAction !== _CameraProperty.MoveRelative) { return null; } return this._wheelYActionCoordinate; } /** * Set which movement axis (relative to camera's orientation) the mouse * wheel's Z axis controls. * @param axis The axis to be moved. Set null to clear. */ set wheelZMoveRelative(axis) { if (axis === null && this._wheelZAction !== _CameraProperty.MoveRelative) { // Attempting to clear different _wheelZAction. return; } this._wheelZAction = _CameraProperty.MoveRelative; this._wheelZActionCoordinate = axis; } /** * Get the configured movement axis (relative to camera's orientation) the * mouse wheel's Z axis controls. * @returns The configured axis or null if none. */ get wheelZMoveRelative() { if (this._wheelZAction !== _CameraProperty.MoveRelative) { return null; } return this._wheelZActionCoordinate; } /** * Set which rotation axis (relative to camera's orientation) the mouse * wheel's X axis controls. * @param axis The axis to be moved. Set null to clear. */ set wheelXRotateRelative(axis) { if (axis === null && this._wheelXAction !== _CameraProperty.RotateRelative) { // Attempting to clear different _wheelXAction. return; } this._wheelXAction = _CameraProperty.RotateRelative; this._wheelXActionCoordinate = axis; } /** * Get the configured rotation axis (relative to camera's orientation) the * mouse wheel's X axis controls. * @returns The configured axis or null if none. */ get wheelXRotateRelative() { if (this._wheelXAction !== _CameraProperty.RotateRelative) { return null; } return this._wheelXActionCoordinate; } /** * Set which rotation axis (relative to camera's orientation) the mouse * wheel's Y axis controls. * @param axis The axis to be moved. Set null to clear. */ set wheelYRotateRelative(axis) { if (axis === null && this._wheelYAction !== _CameraProperty.RotateRelative) { // Attempting to clear different _wheelYAction. return; } this._wheelYAction = _CameraProperty.RotateRelative; this._wheelYActionCoordinate = axis; } /** * Get the configured rotation axis (relative to camera's orientation) the * mouse wheel's Y axis controls. * @returns The configured axis or null if none. */ get wheelYRotateRelative() { if (this._wheelYAction !== _CameraProperty.RotateRelative) { return null; } return this._wheelYActionCoordinate; } /** * Set which rotation axis (relative to camera's orientation) the mouse * wheel's Z axis controls. * @param axis The axis to be moved. Set null to clear. */ set wheelZRotateRelative(axis) { if (axis === null && this._wheelZAction !== _CameraProperty.RotateRelative) { // Attempting to clear different _wheelZAction. return; } this._wheelZAction = _CameraProperty.RotateRelative; this._wheelZActionCoordinate = axis; } /** * Get the configured rotation axis (relative to camera's orientation) the * mouse wheel's Z axis controls. * @returns The configured axis or null if none. */ get wheelZRotateRelative() { if (this._wheelZAction !== _CameraProperty.RotateRelative) { return null; } return this._wheelZActionCoordinate; } /** * Set which movement axis (relative to the scene) the mouse wheel's X axis * controls. * @param axis The axis to be moved. Set null to clear. */ set wheelXMoveScene(axis) { if (axis === null && this._wheelXAction !== _CameraProperty.MoveScene) { // Attempting to clear different _wheelXAction. return; } this._wheelXAction = _CameraProperty.MoveScene; this._wheelXActionCoordinate = axis; } /** * Get the configured movement axis (relative to the scene) the mouse wheel's * X axis controls. * @returns The configured axis or null if none. */ get wheelXMoveScene() { if (this._wheelXAction !== _CameraProperty.MoveScene) { return null; } return this._wheelXActionCoordinate; } /** * Set which movement axis (relative to the scene) the mouse wheel's Y axis * controls. * @param axis The axis to be moved. Set null to clear. */ set wheelYMoveScene(axis) { if (axis === null && this._wheelYAction !== _CameraProperty.MoveScene) { // Attempting to clear different _wheelYAction. return; } this._wheelYAction = _CameraProperty.MoveScene; this._wheelYActionCoordinate = axis; } /** * Get the configured movement axis (relative to the scene) the mouse wheel's * Y axis controls. * @returns The configured axis or null if none. */ get wheelYMoveScene() { if (this._wheelYAction !== _CameraProperty.MoveScene) { return null; } return this._wheelYActionCoordinate; } /** * Set which movement axis (relative to the scene) the mouse wheel's Z axis * controls. * @param axis The axis to be moved. Set null to clear. */ set wheelZMoveScene(axis) { if (axis === null && this._wheelZAction !== _CameraProperty.MoveScene) { // Attempting to clear different _wheelZAction. return; } this._wheelZAction = _CameraProperty.MoveScene; this._wheelZActionCoordinate = axis; } /** * Get the configured movement axis (relative to the scene) the mouse wheel's * Z axis controls. * @returns The configured axis or null if none. */ get wheelZMoveScene() { if (this._wheelZAction !== _CameraProperty.MoveScene) { return null; } return this._wheelZActionCoordinate; } /** * Called for each rendered frame. */ checkInputs() { if (this._wheelDeltaX === 0 && this._wheelDeltaY === 0 && this._wheelDeltaZ == 0) { return; } // Clear the camera properties that we might be updating. this._moveRelative.setAll(0); this._rotateRelative.setAll(0); this._moveScene.setAll(0); // Set the camera properties that are to be updated. this._updateCamera(); if (this.camera.getScene().useRightHandedSystem) { // TODO: Does this need done for worldUpdate too? this._moveRelative.z *= -1; } // Convert updates relative to camera to world position update. const cameraTransformMatrix = Matrix.Zero(); this.camera.getViewMatrix().invertToRef(cameraTransformMatrix); const transformedDirection = Vector3.Zero(); Vector3.TransformNormalToRef(this._moveRelative, cameraTransformMatrix, transformedDirection); // Apply updates to camera position. this.camera.cameraRotation.x += this._rotateRelative.x / 200; this.camera.cameraRotation.y += this._rotateRelative.y / 200; this.camera.cameraDirection.addInPlace(transformedDirection); this.camera.cameraDirection.addInPlace(this._moveScene); // Call the base class implementation to handle observers and do cleanup. super.checkInputs(); } /** * Update the camera according to any configured properties for the 3 * mouse-wheel axis. */ _updateCamera() { // Do the camera updates for each of the 3 touch-wheel axis. this._updateCameraProperty(this._wheelDeltaX, this._wheelXAction, this._wheelXActionCoordinate); this._updateCameraProperty(this._wheelDeltaY, this._wheelYAction, this._wheelYActionCoordinate); this._updateCameraProperty(this._wheelDeltaZ, this._wheelZAction, this._wheelZActionCoordinate); } /** * Update one property of the camera. * @param value * @param cameraProperty * @param coordinate */ _updateCameraProperty( /* Mouse-wheel delta. */ value, /* Camera property to be changed. */ cameraProperty, /* Axis of Camera property to be changed. */ coordinate) { if (value === 0) { // Mouse wheel has not moved. return; } if (cameraProperty === null || coordinate === null) { // Mouse wheel axis not configured. return; } let action = null; switch (cameraProperty) { case _CameraProperty.MoveRelative: action = this._moveRelative; break; case _CameraProperty.RotateRelative: action = this._rotateRelative; break; case _CameraProperty.MoveScene: action = this._moveScene; break; } switch (coordinate) { case 0 /* Coordinate.X */: action.set(value, 0, 0); break; case 1 /* Coordinate.Y */: action.set(0, value, 0); break; case 2 /* Coordinate.Z */: action.set(0, 0, value); break; } } } __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelXMoveRelative", null); __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelYMoveRelative", null); __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelZMoveRelative", null); __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelXRotateRelative", null); __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelYRotateRelative", null); __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelZRotateRelative", null); __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelXMoveScene", null); __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelYMoveScene", null); __decorate([ serialize() ], FreeCameraMouseWheelInput.prototype, "wheelZMoveScene", null); CameraInputTypes["FreeCameraMouseWheelInput"] = FreeCameraMouseWheelInput; /** * Manage the touch inputs to control the movement of a free camera. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs */ class FreeCameraTouchInput { /** * Manage the touch inputs to control the movement of a free camera. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs * @param allowMouse Defines if mouse events can be treated as touch events */ constructor( /** * [false] Define if mouse events can be treated as touch events */ allowMouse = false) { this.allowMouse = allowMouse; /** * Defines the touch sensibility for rotation. * The lower the faster. */ this.touchAngularSensibility = 200000.0; /** * Defines the touch sensibility for move. * The lower the faster. */ this.touchMoveSensibility = 250.0; /** * Swap touch actions so that one touch is used for rotation and multiple for movement */ this.singleFingerRotate = false; this._offsetX = null; this._offsetY = null; this._pointerPressed = new Array(); this._isSafari = Tools.IsSafari(); } /** * Attach the input controls to a specific dom element to get the input from. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault) */ attachControl(noPreventDefault) { noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments); let previousPosition = null; if (this._pointerInput === undefined) { this._onLostFocus = () => { this._offsetX = null; this._offsetY = null; }; this._pointerInput = (p) => { const evt = p.event; const isMouseEvent = evt.pointerType === "mouse" || (this._isSafari && typeof evt.pointerType === "undefined"); if (!this.allowMouse && isMouseEvent) { return; } if (p.type === PointerEventTypes.POINTERDOWN) { if (!noPreventDefault) { evt.preventDefault(); } this._pointerPressed.push(evt.pointerId); if (this._pointerPressed.length !== 1) { return; } previousPosition = { x: evt.clientX, y: evt.clientY, }; } else if (p.type === PointerEventTypes.POINTERUP) { if (!noPreventDefault) { evt.preventDefault(); } const index = this._pointerPressed.indexOf(evt.pointerId); if (index === -1) { return; } this._pointerPressed.splice(index, 1); if (index != 0) { return; } previousPosition = null; this._offsetX = null; this._offsetY = null; } else if (p.type === PointerEventTypes.POINTERMOVE) { if (!noPreventDefault) { evt.preventDefault(); } if (!previousPosition) { return; } const index = this._pointerPressed.indexOf(evt.pointerId); if (index != 0) { return; } this._offsetX = evt.clientX - previousPosition.x; this._offsetY = -(evt.clientY - previousPosition.y); } }; } this._observer = this.camera .getScene() ._inputManager._addCameraPointerObserver(this._pointerInput, PointerEventTypes.POINTERDOWN | PointerEventTypes.POINTERUP | PointerEventTypes.POINTERMOVE); if (this._onLostFocus) { const engine = this.camera.getEngine(); const element = engine.getInputElement(); if (element) { element.addEventListener("blur", this._onLostFocus); } } } /** * Detach the current controls from the specified dom element. */ detachControl() { if (this._pointerInput) { if (this._observer) { this.camera.getScene()._inputManager._removeCameraPointerObserver(this._observer); this._observer = null; } if (this._onLostFocus) { const engine = this.camera.getEngine(); const element = engine.getInputElement(); if (element) { element.removeEventListener("blur", this._onLostFocus); } this._onLostFocus = null; } this._pointerPressed.length = 0; this._offsetX = null; this._offsetY = null; } } /** * Update the current camera state depending on the inputs that have been used this frame. * This is a dynamically created lambda to avoid the performance penalty of looping for inputs in the render loop. */ checkInputs() { if (this._offsetX === null || this._offsetY === null) { return; } if (this._offsetX === 0 && this._offsetY === 0) { return; } const camera = this.camera; const handednessMultiplier = camera._calculateHandednessMultiplier(); camera.cameraRotation.y = (handednessMultiplier * this._offsetX) / this.touchAngularSensibility; const rotateCamera = (this.singleFingerRotate && this._pointerPressed.length === 1) || (!this.singleFingerRotate && this._pointerPressed.length > 1); if (rotateCamera) { camera.cameraRotation.x = -this._offsetY / this.touchAngularSensibility; } else { const speed = camera._computeLocalCameraSpeed(); const direction = new Vector3(0, 0, this.touchMoveSensibility !== 0 ? (speed * this._offsetY) / this.touchMoveSensibility : 0); Matrix.RotationYawPitchRollToRef(camera.rotation.y, camera.rotation.x, 0, camera._cameraRotationMatrix); camera.cameraDirection.addInPlace(Vector3.TransformCoordinates(direction, camera._cameraRotationMatrix)); } } /** * Gets the class name of the current input. * @returns the class name */ getClassName() { return "FreeCameraTouchInput"; } /** * Get the friendly name associated with the input class. * @returns the input friendly name */ getSimpleName() { return "touch"; } } __decorate([ serialize() ], FreeCameraTouchInput.prototype, "touchAngularSensibility", void 0); __decorate([ serialize() ], FreeCameraTouchInput.prototype, "touchMoveSensibility", void 0); CameraInputTypes["FreeCameraTouchInput"] = FreeCameraTouchInput; /** * Default Inputs manager for the FreeCamera. * It groups all the default supported inputs for ease of use. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/customizingCameraInputs */ class FreeCameraInputsManager extends CameraInputsManager { /** * Instantiates a new FreeCameraInputsManager. * @param camera Defines the camera the inputs belong to */ constructor(camera) { super(camera); /** * @internal */ this._mouseInput = null; /** * @internal */ this._mouseWheelInput = null; } /** * Add keyboard input support to the input manager. * @returns the current input manager */ addKeyboard() { this.add(new FreeCameraKeyboardMoveInput()); return this; } /** * Add mouse input support to the input manager. * @param touchEnabled if the FreeCameraMouseInput should support touch (default: true) * @returns the current input manager */ addMouse(touchEnabled = true) { if (!this._mouseInput) { this._mouseInput = new FreeCameraMouseInput(touchEnabled); this.add(this._mouseInput); } return this; } /** * Removes the mouse input support from the manager * @returns the current input manager */ removeMouse() { if (this._mouseInput) { this.remove(this._mouseInput); } return this; } /** * Add mouse wheel input support to the input manager. * @returns the current input manager */ addMouseWheel() { if (!this._mouseWheelInput) { this._mouseWheelInput = new FreeCameraMouseWheelInput(); this.add(this._mouseWheelInput); } return this; } /** * Removes the mouse wheel input support from the manager * @returns the current input manager */ removeMouseWheel() { if (this._mouseWheelInput) { this.remove(this._mouseWheelInput); } return this; } /** * Add touch input support to the input manager. * @returns the current input manager */ addTouch() { this.add(new FreeCameraTouchInput()); return this; } /** * Remove all attached input methods from a camera */ clear() { super.clear(); this._mouseInput = null; } } /** * This represents a free type of camera. It can be useful in First Person Shooter game for instance. * Please consider using the new UniversalCamera instead as it adds more functionality like the gamepad. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction#universal-camera */ class FreeCamera extends TargetCamera { /** * Gets the input sensibility for a mouse input. (default is 2000.0) * Higher values reduce sensitivity. */ get angularSensibility() { const mouse = this.inputs.attached["mouse"]; if (mouse) { return mouse.angularSensibility; } return 0; } /** * Sets the input sensibility for a mouse input. (default is 2000.0) * Higher values reduce sensitivity. */ set angularSensibility(value) { const mouse = this.inputs.attached["mouse"]; if (mouse) { mouse.angularSensibility = value; } } /** * Gets or Set the list of keyboard keys used to control the forward move of the camera. */ get keysUp() { const keyboard = this.inputs.attached["keyboard"]; if (keyboard) { return keyboard.keysUp; } return []; } set k