123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- import { Nullable } from "../types";
- import { serialize, serializeAsMeshReference } from "../Misc/decorators";
- import { Tools } from "../Misc/tools";
- import { TargetCamera } from "./targetCamera";
- import { Scene } from "../scene";
- import { Matrix, Vector3 } from "../Maths/math";
- import { Node } from "../node";
- import { AbstractMesh } from "../Meshes/abstractMesh";
- import { FollowCameraInputsManager } from './followCameraInputsManager';
- Node.AddNodeConstructor("FollowCamera", (name, scene) => {
- return () => new FollowCamera(name, Vector3.Zero(), scene);
- });
- Node.AddNodeConstructor("ArcFollowCamera", (name, scene) => {
- return () => new ArcFollowCamera(name, 0, 0, 1.0, null, scene);
- });
- /**
- * A follow camera takes a mesh as a target and follows it as it moves. Both a free camera version followCamera and
- * an arc rotate version arcFollowCamera are available.
- * @see http://doc.babylonjs.com/features/cameras#follow-camera
- */
- export class FollowCamera extends TargetCamera {
- /**
- * Distance the follow camera should follow an object at
- */
- @serialize()
- public radius: number = 12;
- /**
- * Minimum allowed distance of the camera to the axis of rotation
- * (The camera can not get closer).
- * This can help limiting how the Camera is able to move in the scene.
- */
- @serialize()
- public lowerRadiusLimit: Nullable<number> = null;
- /**
- * Maximum allowed distance of the camera to the axis of rotation
- * (The camera can not get further).
- * This can help limiting how the Camera is able to move in the scene.
- */
- @serialize()
- public upperRadiusLimit: Nullable<number> = null;
- /**
- * Define a rotation offset between the camera and the object it follows
- */
- @serialize()
- public rotationOffset: number = 0;
- /**
- * Minimum allowed angle to camera position relative to target object.
- * This can help limiting how the Camera is able to move in the scene.
- */
- @serialize()
- public lowerRotationOffsetLimit: Nullable<number> = null;
- /**
- * Maximum allowed angle to camera position relative to target object.
- * This can help limiting how the Camera is able to move in the scene.
- */
- @serialize()
- public upperRotationOffsetLimit: Nullable<number> = null;
- /**
- * Define a height offset between the camera and the object it follows.
- * It can help following an object from the top (like a car chaing a plane)
- */
- @serialize()
- public heightOffset: number = 4;
- /**
- * Minimum allowed height of camera position relative to target object.
- * This can help limiting how the Camera is able to move in the scene.
- */
- @serialize()
- public lowerHeightOffsetLimit: Nullable<number> = null;
- /**
- * Maximum allowed height of camera position relative to target object.
- * This can help limiting how the Camera is able to move in the scene.
- */
- @serialize()
- public upperHeightOffsetLimit: Nullable<number> = null;
- /**
- * Define how fast the camera can accelerate to follow it s target.
- */
- @serialize()
- public cameraAcceleration: number = 0.05;
- /**
- * Define the speed limit of the camera following an object.
- */
- @serialize()
- public maxCameraSpeed: number = 20;
- /**
- * Define the target of the camera.
- */
- @serializeAsMeshReference("lockedTargetId")
- public lockedTarget: Nullable<AbstractMesh>;
- /**
- * Defines the input associated with the camera.
- */
- public inputs: FollowCameraInputsManager;
- /**
- * Instantiates the follow camera.
- * @see http://doc.babylonjs.com/features/cameras#follow-camera
- * @param name Define the name of the camera in the scene
- * @param position Define the position of the camera
- * @param scene Define the scene the camera belong to
- * @param lockedTarget Define the target of the camera
- */
- constructor(name: string, position: Vector3, scene: Scene, lockedTarget: Nullable<AbstractMesh> = null) {
- super(name, position, scene);
- this.lockedTarget = lockedTarget;
- this.inputs = new FollowCameraInputsManager(this);
- this.inputs.addKeyboard().addMouseWheel().addPointers();
- // Uncomment the following line when the relevant handlers have been implemented.
- // this.inputs.addKeyboard().addMouseWheel().addPointers().addVRDeviceOrientation();
- }
- private _follow(cameraTarget: AbstractMesh) {
- if (!cameraTarget) {
- return;
- }
- var yRotation;
- if (cameraTarget.rotationQuaternion) {
- var rotMatrix = new Matrix();
- cameraTarget.rotationQuaternion.toRotationMatrix(rotMatrix);
- yRotation = Math.atan2(rotMatrix.m[8], rotMatrix.m[10]);
- } else {
- yRotation = cameraTarget.rotation.y;
- }
- var radians = Tools.ToRadians(this.rotationOffset) + yRotation;
- var targetPosition = cameraTarget.getAbsolutePosition();
- var targetX: number = targetPosition.x + Math.sin(radians) * this.radius;
- var targetZ: number = targetPosition.z + Math.cos(radians) * this.radius;
- var dx: number = targetX - this.position.x;
- var dy: number = (targetPosition.y + this.heightOffset) - this.position.y;
- var dz: number = (targetZ) - this.position.z;
- var vx: number = dx * this.cameraAcceleration * 2; //this is set to .05
- var vy: number = dy * this.cameraAcceleration;
- var vz: number = dz * this.cameraAcceleration * 2;
- if (vx > this.maxCameraSpeed || vx < -this.maxCameraSpeed) {
- vx = vx < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
- }
- if (vy > this.maxCameraSpeed || vy < -this.maxCameraSpeed) {
- vy = vy < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
- }
- if (vz > this.maxCameraSpeed || vz < -this.maxCameraSpeed) {
- vz = vz < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
- }
- this.position = new Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
- this.setTarget(targetPosition);
- }
- /**
- * Attached controls to the current camera.
- * @param element Defines the element the controls should be listened from
- * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
- */
- public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
- this.inputs.attachElement(element, noPreventDefault);
- this._reset = () => {
- };
- }
- /**
- * Detach the current controls from the camera.
- * The camera will stop reacting to inputs.
- * @param element Defines the element to stop listening the inputs from
- */
- public detachControl(element: HTMLElement): void {
- this.inputs.detachElement(element);
- if (this._reset) {
- this._reset();
- }
- }
- /** @hidden */
- public _checkInputs(): void {
- this.inputs.checkInputs();
- this._checkLimits();
- super._checkInputs();
- if (this.lockedTarget) {
- this._follow(this.lockedTarget);
- }
- }
- private _checkLimits() {
- if (this.lowerRadiusLimit !== null && this.radius < this.lowerRadiusLimit) {
- this.radius = this.lowerRadiusLimit;
- }
- if (this.upperRadiusLimit !== null && this.radius > this.upperRadiusLimit) {
- this.radius = this.upperRadiusLimit;
- }
- if (this.lowerHeightOffsetLimit !== null &&
- this.heightOffset < this.lowerHeightOffsetLimit) {
- this.heightOffset = this.lowerHeightOffsetLimit;
- }
- if (this.upperHeightOffsetLimit !== null &&
- this.heightOffset > this.upperHeightOffsetLimit) {
- this.heightOffset = this.upperHeightOffsetLimit;
- }
- if (this.lowerRotationOffsetLimit !== null &&
- this.rotationOffset < this.lowerRotationOffsetLimit) {
- this.rotationOffset = this.lowerRotationOffsetLimit;
- }
- if (this.upperRotationOffsetLimit !== null &&
- this.rotationOffset > this.upperRotationOffsetLimit) {
- this.rotationOffset = this.upperRotationOffsetLimit;
- }
- }
- /**
- * Gets the camera class name.
- * @returns the class name
- */
- public getClassName(): string {
- return "FollowCamera";
- }
- }
- /**
- * Arc Rotate version of the follow camera.
- * It still follows a Defined mesh but in an Arc Rotate Camera fashion.
- * @see http://doc.babylonjs.com/features/cameras#follow-camera
- */
- export class ArcFollowCamera extends TargetCamera {
- private _cartesianCoordinates: Vector3 = Vector3.Zero();
- /**
- * Instantiates a new ArcFollowCamera
- * @see http://doc.babylonjs.com/features/cameras#follow-camera
- * @param name Define the name of the camera
- * @param alpha Define the rotation angle of the camera around the logitudinal axis
- * @param beta Define the rotation angle of the camera around the elevation axis
- * @param radius Define the radius of the camera from its target point
- * @param target Define the target of the camera
- * @param scene Define the scene the camera belongs to
- */
- constructor(name: string,
- /** The longitudinal angle of the camera */
- public alpha: number,
- /** The latitudinal angle of the camera */
- public beta: number,
- /** The radius of the camera from its target */
- public radius: number,
- /** Define the camera target (the messh it should follow) */
- public target: Nullable<AbstractMesh>,
- scene: Scene) {
- super(name, Vector3.Zero(), scene);
- this._follow();
- }
- private _follow(): void {
- if (!this.target) {
- return;
- }
- this._cartesianCoordinates.x = this.radius * Math.cos(this.alpha) * Math.cos(this.beta);
- this._cartesianCoordinates.y = this.radius * Math.sin(this.beta);
- this._cartesianCoordinates.z = this.radius * Math.sin(this.alpha) * Math.cos(this.beta);
- var targetPosition = this.target.getAbsolutePosition();
- this.position = targetPosition.add(this._cartesianCoordinates);
- this.setTarget(targetPosition);
- }
- /** @hidden */
- public _checkInputs(): void {
- super._checkInputs();
- this._follow();
- }
- /**
- * Returns the class name of the object.
- * It is mostly used internally for serialization purposes.
- */
- public getClassName(): string {
- return "ArcFollowCamera";
- }
- }
|