@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
JavaScript
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