followCamera.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. import { __decorate } from "../tslib.es6.js";
  2. import { serialize, serializeAsMeshReference } from "../Misc/decorators.js";
  3. import { Tools } from "../Misc/tools.js";
  4. import { TargetCamera } from "./targetCamera.js";
  5. import { TmpVectors, Vector3 } from "../Maths/math.vector.js";
  6. import { Node } from "../node.js";
  7. import { FollowCameraInputsManager } from "./followCameraInputsManager.js";
  8. Node.AddNodeConstructor("FollowCamera", (name, scene) => {
  9. return () => new FollowCamera(name, Vector3.Zero(), scene);
  10. });
  11. Node.AddNodeConstructor("ArcFollowCamera", (name, scene) => {
  12. return () => new ArcFollowCamera(name, 0, 0, 1.0, null, scene);
  13. });
  14. /**
  15. * A follow camera takes a mesh as a target and follows it as it moves. Both a free camera version followCamera and
  16. * an arc rotate version arcFollowCamera are available.
  17. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction#followcamera
  18. */
  19. export class FollowCamera extends TargetCamera {
  20. /**
  21. * Instantiates the follow camera.
  22. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction#followcamera
  23. * @param name Define the name of the camera in the scene
  24. * @param position Define the position of the camera
  25. * @param scene Define the scene the camera belong to
  26. * @param lockedTarget Define the target of the camera
  27. */
  28. constructor(name, position, scene, lockedTarget = null) {
  29. super(name, position, scene);
  30. /**
  31. * Distance the follow camera should follow an object at
  32. */
  33. this.radius = 12;
  34. /**
  35. * Minimum allowed distance of the camera to the axis of rotation
  36. * (The camera can not get closer).
  37. * This can help limiting how the Camera is able to move in the scene.
  38. */
  39. this.lowerRadiusLimit = null;
  40. /**
  41. * Maximum allowed distance of the camera to the axis of rotation
  42. * (The camera can not get further).
  43. * This can help limiting how the Camera is able to move in the scene.
  44. */
  45. this.upperRadiusLimit = null;
  46. /**
  47. * Define a rotation offset between the camera and the object it follows
  48. */
  49. this.rotationOffset = 0;
  50. /**
  51. * Minimum allowed angle to camera position relative to target object.
  52. * This can help limiting how the Camera is able to move in the scene.
  53. */
  54. this.lowerRotationOffsetLimit = null;
  55. /**
  56. * Maximum allowed angle to camera position relative to target object.
  57. * This can help limiting how the Camera is able to move in the scene.
  58. */
  59. this.upperRotationOffsetLimit = null;
  60. /**
  61. * Define a height offset between the camera and the object it follows.
  62. * It can help following an object from the top (like a car chasing a plane)
  63. */
  64. this.heightOffset = 4;
  65. /**
  66. * Minimum allowed height of camera position relative to target object.
  67. * This can help limiting how the Camera is able to move in the scene.
  68. */
  69. this.lowerHeightOffsetLimit = null;
  70. /**
  71. * Maximum allowed height of camera position relative to target object.
  72. * This can help limiting how the Camera is able to move in the scene.
  73. */
  74. this.upperHeightOffsetLimit = null;
  75. /**
  76. * Define how fast the camera can accelerate to follow it s target.
  77. */
  78. this.cameraAcceleration = 0.05;
  79. /**
  80. * Define the speed limit of the camera following an object.
  81. */
  82. this.maxCameraSpeed = 20;
  83. this.lockedTarget = lockedTarget;
  84. this.inputs = new FollowCameraInputsManager(this);
  85. this.inputs.addKeyboard().addMouseWheel().addPointers();
  86. // Uncomment the following line when the relevant handlers have been implemented.
  87. // this.inputs.addKeyboard().addMouseWheel().addPointers().addVRDeviceOrientation();
  88. }
  89. _follow(cameraTarget) {
  90. if (!cameraTarget) {
  91. return;
  92. }
  93. const rotMatrix = TmpVectors.Matrix[0];
  94. cameraTarget.absoluteRotationQuaternion.toRotationMatrix(rotMatrix);
  95. const yRotation = Math.atan2(rotMatrix.m[8], rotMatrix.m[10]);
  96. const radians = Tools.ToRadians(this.rotationOffset) + yRotation;
  97. const targetPosition = cameraTarget.getAbsolutePosition();
  98. const targetX = targetPosition.x + Math.sin(radians) * this.radius;
  99. const targetZ = targetPosition.z + Math.cos(radians) * this.radius;
  100. const dx = targetX - this.position.x;
  101. const dy = targetPosition.y + this.heightOffset - this.position.y;
  102. const dz = targetZ - this.position.z;
  103. let vx = dx * this.cameraAcceleration * 2; //this is set to .05
  104. let vy = dy * this.cameraAcceleration;
  105. let vz = dz * this.cameraAcceleration * 2;
  106. if (vx > this.maxCameraSpeed || vx < -this.maxCameraSpeed) {
  107. vx = vx < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
  108. }
  109. if (vy > this.maxCameraSpeed || vy < -this.maxCameraSpeed) {
  110. vy = vy < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
  111. }
  112. if (vz > this.maxCameraSpeed || vz < -this.maxCameraSpeed) {
  113. vz = vz < 1 ? -this.maxCameraSpeed : this.maxCameraSpeed;
  114. }
  115. this.position = new Vector3(this.position.x + vx, this.position.y + vy, this.position.z + vz);
  116. this.setTarget(targetPosition);
  117. }
  118. /**
  119. * Attached controls to the current camera.
  120. * @param ignored defines an ignored parameter kept for backward compatibility.
  121. * @param noPreventDefault Defines whether event caught by the controls should call preventdefault() (https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault)
  122. */
  123. attachControl(ignored, noPreventDefault) {
  124. // eslint-disable-next-line prefer-rest-params
  125. noPreventDefault = Tools.BackCompatCameraNoPreventDefault(arguments);
  126. this.inputs.attachElement(noPreventDefault);
  127. this._reset = () => { };
  128. }
  129. /**
  130. * Detach the current controls from the specified dom element.
  131. */
  132. detachControl() {
  133. this.inputs.detachElement();
  134. if (this._reset) {
  135. this._reset();
  136. }
  137. }
  138. /** @internal */
  139. _checkInputs() {
  140. this.inputs.checkInputs();
  141. this._checkLimits();
  142. super._checkInputs();
  143. if (this.lockedTarget) {
  144. this._follow(this.lockedTarget);
  145. }
  146. }
  147. _checkLimits() {
  148. if (this.lowerRadiusLimit !== null && this.radius < this.lowerRadiusLimit) {
  149. this.radius = this.lowerRadiusLimit;
  150. }
  151. if (this.upperRadiusLimit !== null && this.radius > this.upperRadiusLimit) {
  152. this.radius = this.upperRadiusLimit;
  153. }
  154. if (this.lowerHeightOffsetLimit !== null && this.heightOffset < this.lowerHeightOffsetLimit) {
  155. this.heightOffset = this.lowerHeightOffsetLimit;
  156. }
  157. if (this.upperHeightOffsetLimit !== null && this.heightOffset > this.upperHeightOffsetLimit) {
  158. this.heightOffset = this.upperHeightOffsetLimit;
  159. }
  160. if (this.lowerRotationOffsetLimit !== null && this.rotationOffset < this.lowerRotationOffsetLimit) {
  161. this.rotationOffset = this.lowerRotationOffsetLimit;
  162. }
  163. if (this.upperRotationOffsetLimit !== null && this.rotationOffset > this.upperRotationOffsetLimit) {
  164. this.rotationOffset = this.upperRotationOffsetLimit;
  165. }
  166. }
  167. /**
  168. * Gets the camera class name.
  169. * @returns the class name
  170. */
  171. getClassName() {
  172. return "FollowCamera";
  173. }
  174. }
  175. __decorate([
  176. serialize()
  177. ], FollowCamera.prototype, "radius", void 0);
  178. __decorate([
  179. serialize()
  180. ], FollowCamera.prototype, "lowerRadiusLimit", void 0);
  181. __decorate([
  182. serialize()
  183. ], FollowCamera.prototype, "upperRadiusLimit", void 0);
  184. __decorate([
  185. serialize()
  186. ], FollowCamera.prototype, "rotationOffset", void 0);
  187. __decorate([
  188. serialize()
  189. ], FollowCamera.prototype, "lowerRotationOffsetLimit", void 0);
  190. __decorate([
  191. serialize()
  192. ], FollowCamera.prototype, "upperRotationOffsetLimit", void 0);
  193. __decorate([
  194. serialize()
  195. ], FollowCamera.prototype, "heightOffset", void 0);
  196. __decorate([
  197. serialize()
  198. ], FollowCamera.prototype, "lowerHeightOffsetLimit", void 0);
  199. __decorate([
  200. serialize()
  201. ], FollowCamera.prototype, "upperHeightOffsetLimit", void 0);
  202. __decorate([
  203. serialize()
  204. ], FollowCamera.prototype, "cameraAcceleration", void 0);
  205. __decorate([
  206. serialize()
  207. ], FollowCamera.prototype, "maxCameraSpeed", void 0);
  208. __decorate([
  209. serializeAsMeshReference("lockedTargetId")
  210. ], FollowCamera.prototype, "lockedTarget", void 0);
  211. /**
  212. * Arc Rotate version of the follow camera.
  213. * It still follows a Defined mesh but in an Arc Rotate Camera fashion.
  214. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction#followcamera
  215. */
  216. export class ArcFollowCamera extends TargetCamera {
  217. /**
  218. * Instantiates a new ArcFollowCamera
  219. * @see https://doc.babylonjs.com/features/featuresDeepDive/cameras/camera_introduction#followcamera
  220. * @param name Define the name of the camera
  221. * @param alpha Define the rotation angle of the camera around the longitudinal axis
  222. * @param beta Define the rotation angle of the camera around the elevation axis
  223. * @param radius Define the radius of the camera from its target point
  224. * @param target Define the target of the camera
  225. * @param scene Define the scene the camera belongs to
  226. */
  227. constructor(name,
  228. /** The longitudinal angle of the camera */
  229. alpha,
  230. /** The latitudinal angle of the camera */
  231. beta,
  232. /** The radius of the camera from its target */
  233. radius,
  234. /** Define the camera target (the mesh it should follow) */
  235. target, scene) {
  236. super(name, Vector3.Zero(), scene);
  237. this.alpha = alpha;
  238. this.beta = beta;
  239. this.radius = radius;
  240. this._cartesianCoordinates = Vector3.Zero();
  241. this.setMeshTarget(target);
  242. }
  243. /**
  244. * Sets the mesh to follow with this camera.
  245. * @param target the target to follow
  246. */
  247. setMeshTarget(target) {
  248. this._meshTarget = target;
  249. this._follow();
  250. }
  251. _follow() {
  252. if (!this._meshTarget) {
  253. return;
  254. }
  255. this._cartesianCoordinates.x = this.radius * Math.cos(this.alpha) * Math.cos(this.beta);
  256. this._cartesianCoordinates.y = this.radius * Math.sin(this.beta);
  257. this._cartesianCoordinates.z = this.radius * Math.sin(this.alpha) * Math.cos(this.beta);
  258. const targetPosition = this._meshTarget.getAbsolutePosition();
  259. this.position = targetPosition.add(this._cartesianCoordinates);
  260. this.setTarget(targetPosition);
  261. }
  262. /** @internal */
  263. _checkInputs() {
  264. super._checkInputs();
  265. this._follow();
  266. }
  267. /**
  268. * Returns the class name of the object.
  269. * It is mostly used internally for serialization purposes.
  270. * @returns the class name
  271. */
  272. getClassName() {
  273. return "ArcFollowCamera";
  274. }
  275. }
  276. //# sourceMappingURL=followCamera.js.map