babylon.arcRotateCamera.ts 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849
  1. module BABYLON {
  2. export class ArcRotateCamera extends TargetCamera {
  3. @serialize()
  4. public alpha: number;
  5. @serialize()
  6. public beta: number;
  7. @serialize()
  8. public radius: number;
  9. @serializeAsVector3("target")
  10. protected _target: Vector3;
  11. protected _targetHost: Nullable<AbstractMesh>;
  12. public get target(): Vector3 {
  13. return this._target;
  14. }
  15. public set target(value: Vector3) {
  16. this.setTarget(value);
  17. }
  18. @serialize()
  19. public inertialAlphaOffset = 0;
  20. @serialize()
  21. public inertialBetaOffset = 0;
  22. @serialize()
  23. public inertialRadiusOffset = 0;
  24. @serialize()
  25. public lowerAlphaLimit: Nullable<number> = null;
  26. @serialize()
  27. public upperAlphaLimit: Nullable<number> = null;
  28. @serialize()
  29. public lowerBetaLimit = 0.01;
  30. @serialize()
  31. public upperBetaLimit = Math.PI;
  32. @serialize()
  33. public lowerRadiusLimit: Nullable<number> = null;
  34. @serialize()
  35. public upperRadiusLimit: Nullable<number> = null;
  36. @serialize()
  37. public inertialPanningX: number = 0;
  38. @serialize()
  39. public inertialPanningY: number = 0;
  40. @serialize()
  41. public pinchToPanMaxDistance: number = 20;
  42. @serialize()
  43. public panningDistanceLimit: Nullable<number> = null;
  44. @serializeAsVector3()
  45. public panningOriginTarget: Vector3 = Vector3.Zero();
  46. @serialize()
  47. public panningInertia = 0.9;
  48. //-- begin properties for backward compatibility for inputs
  49. public get angularSensibilityX(): number {
  50. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  51. if (pointers)
  52. return pointers.angularSensibilityX;
  53. return 0;
  54. }
  55. public set angularSensibilityX(value: number) {
  56. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  57. if (pointers) {
  58. pointers.angularSensibilityX = value;
  59. }
  60. }
  61. public get angularSensibilityY(): number {
  62. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  63. if (pointers)
  64. return pointers.angularSensibilityY;
  65. return 0;
  66. }
  67. public set angularSensibilityY(value: number) {
  68. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  69. if (pointers) {
  70. pointers.angularSensibilityY = value;
  71. }
  72. }
  73. public get angularTouchSensibilityX(): number {
  74. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  75. if (pointers)
  76. return pointers.angularTouchSensibilityX;
  77. return 0;
  78. }
  79. public set angularTouchSensibilityX(value: number) {
  80. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  81. if (pointers) {
  82. pointers.angularTouchSensibilityX = value;
  83. }
  84. }
  85. public get angularTouchSensibilityY(): number {
  86. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  87. if (pointers)
  88. return pointers.angularTouchSensibilityY;
  89. return 0;
  90. }
  91. public set angularTouchSensibilityY(value: number) {
  92. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  93. if (pointers) {
  94. pointers.angularTouchSensibilityY = value;
  95. }
  96. }
  97. public get pinchPrecision(): number {
  98. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  99. if (pointers)
  100. return pointers.pinchPrecision;
  101. return 0;
  102. }
  103. public set pinchPrecision(value: number) {
  104. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  105. if (pointers) {
  106. pointers.pinchPrecision = value;
  107. }
  108. }
  109. public get pinchDeltaPercentage(): number {
  110. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  111. if (pointers)
  112. return pointers.pinchDeltaPercentage;
  113. return 0;
  114. }
  115. public set pinchDeltaPercentage(value: number) {
  116. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  117. if (pointers) {
  118. pointers.pinchDeltaPercentage = value;
  119. }
  120. }
  121. public get panningSensibility(): number {
  122. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  123. if (pointers)
  124. return pointers.panningSensibility;
  125. return 0;
  126. }
  127. public set panningSensibility(value: number) {
  128. var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
  129. if (pointers) {
  130. pointers.panningSensibility = value;
  131. }
  132. }
  133. public get keysUp(): number[] {
  134. var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  135. if (keyboard)
  136. return keyboard.keysUp;
  137. return [];
  138. }
  139. public set keysUp(value: number[]) {
  140. var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  141. if (keyboard)
  142. keyboard.keysUp = value;
  143. }
  144. public get keysDown(): number[] {
  145. var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  146. if (keyboard)
  147. return keyboard.keysDown;
  148. return [];
  149. }
  150. public set keysDown(value: number[]) {
  151. var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  152. if (keyboard)
  153. keyboard.keysDown = value;
  154. }
  155. public get keysLeft(): number[] {
  156. var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  157. if (keyboard)
  158. return keyboard.keysLeft;
  159. return [];
  160. }
  161. public set keysLeft(value: number[]) {
  162. var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  163. if (keyboard)
  164. keyboard.keysLeft = value;
  165. }
  166. public get keysRight(): number[] {
  167. var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  168. if (keyboard)
  169. return keyboard.keysRight;
  170. return [];
  171. }
  172. public set keysRight(value: number[]) {
  173. var keyboard = <ArcRotateCameraKeyboardMoveInput>this.inputs.attached["keyboard"];
  174. if (keyboard)
  175. keyboard.keysRight = value;
  176. }
  177. public get wheelPrecision(): number {
  178. var mousewheel = <ArcRotateCameraMouseWheelInput>this.inputs.attached["mousewheel"];
  179. if (mousewheel)
  180. return mousewheel.wheelPrecision;
  181. return 0;
  182. }
  183. public set wheelPrecision(value: number) {
  184. var mousewheel = <ArcRotateCameraMouseWheelInput>this.inputs.attached["mousewheel"];
  185. if (mousewheel)
  186. mousewheel.wheelPrecision = value;
  187. }
  188. public get wheelDeltaPercentage(): number {
  189. var mousewheel = <ArcRotateCameraMouseWheelInput>this.inputs.attached["mousewheel"];
  190. if (mousewheel)
  191. return mousewheel.wheelDeltaPercentage;
  192. return 0;
  193. }
  194. public set wheelDeltaPercentage(value: number) {
  195. var mousewheel = <ArcRotateCameraMouseWheelInput>this.inputs.attached["mousewheel"];
  196. if (mousewheel)
  197. mousewheel.wheelDeltaPercentage = value;
  198. }
  199. //-- end properties for backward compatibility for inputs
  200. @serialize()
  201. public zoomOnFactor = 1;
  202. public targetScreenOffset = Vector2.Zero();
  203. @serialize()
  204. public allowUpsideDown = true;
  205. public _viewMatrix = new Matrix();
  206. public _useCtrlForPanning: boolean;
  207. public _panningMouseButton: number;
  208. public inputs: ArcRotateCameraInputsManager;
  209. public _reset: () => void;
  210. // Panning
  211. public panningAxis: Vector3 = new Vector3(1, 1, 0);
  212. protected _localDirection: Vector3;
  213. protected _transformedDirection: Vector3;
  214. // Behaviors
  215. private _bouncingBehavior: Nullable<BouncingBehavior>;
  216. public get bouncingBehavior(): Nullable<BouncingBehavior> {
  217. return this._bouncingBehavior;
  218. }
  219. public get useBouncingBehavior(): boolean {
  220. return this._bouncingBehavior != null;
  221. }
  222. public set useBouncingBehavior(value: boolean) {
  223. if (value === this.useBouncingBehavior) {
  224. return;
  225. }
  226. if (value) {
  227. this._bouncingBehavior = new BouncingBehavior();
  228. this.addBehavior(this._bouncingBehavior);
  229. } else if (this._bouncingBehavior) {
  230. this.removeBehavior(this._bouncingBehavior);
  231. this._bouncingBehavior = null;
  232. }
  233. }
  234. private _framingBehavior: Nullable<FramingBehavior>;
  235. public get framingBehavior(): Nullable<FramingBehavior> {
  236. return this._framingBehavior;
  237. }
  238. public get useFramingBehavior(): boolean {
  239. return this._framingBehavior != null;
  240. }
  241. public set useFramingBehavior(value: boolean) {
  242. if (value === this.useFramingBehavior) {
  243. return;
  244. }
  245. if (value) {
  246. this._framingBehavior = new FramingBehavior();
  247. this.addBehavior(this._framingBehavior);
  248. } else if (this._framingBehavior) {
  249. this.removeBehavior(this._framingBehavior);
  250. this._framingBehavior = null;
  251. }
  252. }
  253. private _autoRotationBehavior: Nullable<AutoRotationBehavior>;
  254. public get autoRotationBehavior(): Nullable<AutoRotationBehavior> {
  255. return this._autoRotationBehavior;
  256. }
  257. public get useAutoRotationBehavior(): boolean {
  258. return this._autoRotationBehavior != null;
  259. }
  260. public set useAutoRotationBehavior(value: boolean) {
  261. if (value === this.useAutoRotationBehavior) {
  262. return;
  263. }
  264. if (value) {
  265. this._autoRotationBehavior = new AutoRotationBehavior();
  266. this.addBehavior(this._autoRotationBehavior);
  267. } else if (this._autoRotationBehavior) {
  268. this.removeBehavior(this._autoRotationBehavior);
  269. this._autoRotationBehavior = null;
  270. }
  271. }
  272. public onMeshTargetChangedObservable = new Observable<AbstractMesh>();
  273. // Collisions
  274. public onCollide: (collidedMesh: AbstractMesh) => void;
  275. public checkCollisions = false;
  276. public collisionRadius = new Vector3(0.5, 0.5, 0.5);
  277. protected _collider: Collider;
  278. protected _previousPosition = Vector3.Zero();
  279. protected _collisionVelocity = Vector3.Zero();
  280. protected _newPosition = Vector3.Zero();
  281. protected _previousAlpha: number;
  282. protected _previousBeta: number;
  283. protected _previousRadius: number;
  284. //due to async collision inspection
  285. protected _collisionTriggered: boolean;
  286. protected _targetBoundingCenter: Nullable<Vector3>;
  287. constructor(name: string, alpha: number, beta: number, radius: number, target: Vector3, scene: Scene) {
  288. super(name, Vector3.Zero(), scene);
  289. this._target = Vector3.Zero();
  290. if (target) {
  291. this.setTarget(target);
  292. }
  293. this.alpha = alpha;
  294. this.beta = beta;
  295. this.radius = radius;
  296. this.getViewMatrix();
  297. this.inputs = new ArcRotateCameraInputsManager(this);
  298. this.inputs.addKeyboard().addMouseWheel().addPointers();
  299. }
  300. // Cache
  301. public _initCache(): void {
  302. super._initCache();
  303. this._cache._target = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  304. this._cache.alpha = undefined;
  305. this._cache.beta = undefined;
  306. this._cache.radius = undefined;
  307. this._cache.targetScreenOffset = Vector2.Zero();
  308. }
  309. public _updateCache(ignoreParentClass?: boolean): void {
  310. if (!ignoreParentClass) {
  311. super._updateCache();
  312. }
  313. this._cache._target.copyFrom(this._getTargetPosition());
  314. this._cache.alpha = this.alpha;
  315. this._cache.beta = this.beta;
  316. this._cache.radius = this.radius;
  317. this._cache.targetScreenOffset.copyFrom(this.targetScreenOffset);
  318. }
  319. protected _getTargetPosition(): Vector3 {
  320. if (this._targetHost && this._targetHost.getAbsolutePosition) {
  321. var pos: Vector3 = this._targetHost.getAbsolutePosition();
  322. if (this._targetBoundingCenter) {
  323. pos.addToRef(this._targetBoundingCenter, this._target);
  324. } else {
  325. this._target.copyFrom(pos);
  326. }
  327. }
  328. var lockedTargetPosition = this._getLockedTargetPosition();
  329. if (lockedTargetPosition) {
  330. return lockedTargetPosition;
  331. }
  332. return this._target;
  333. }
  334. // State
  335. /**
  336. * Store current camera state (fov, position, etc..)
  337. */
  338. private _storedAlpha: number;
  339. private _storedBeta: number;
  340. private _storedRadius: number;
  341. private _storedTarget: Vector3;
  342. public storeState(): Camera {
  343. this._storedAlpha = this.alpha;
  344. this._storedBeta = this.beta;
  345. this._storedRadius = this.radius;
  346. this._storedTarget = this._getTargetPosition().clone();
  347. return super.storeState();
  348. }
  349. /**
  350. * Restored camera state. You must call storeState() first
  351. */
  352. public _restoreStateValues(): boolean {
  353. if (!super._restoreStateValues()) {
  354. return false;
  355. }
  356. this.alpha = this._storedAlpha;
  357. this.beta = this._storedBeta;
  358. this.radius = this._storedRadius;
  359. this.setTarget(this._storedTarget.clone());
  360. this.inertialAlphaOffset = 0;
  361. this.inertialBetaOffset = 0;
  362. this.inertialRadiusOffset = 0;
  363. this.inertialPanningX = 0;
  364. this.inertialPanningY = 0;
  365. return true;
  366. }
  367. // Synchronized
  368. public _isSynchronizedViewMatrix(): boolean {
  369. if (!super._isSynchronizedViewMatrix())
  370. return false;
  371. return this._cache._target.equals(this._getTargetPosition())
  372. && this._cache.alpha === this.alpha
  373. && this._cache.beta === this.beta
  374. && this._cache.radius === this.radius
  375. && this._cache.targetScreenOffset.equals(this.targetScreenOffset);
  376. }
  377. // Methods
  378. public attachControl(element: HTMLElement, noPreventDefault?: boolean, useCtrlForPanning: boolean = true, panningMouseButton: number = 2): void {
  379. this._useCtrlForPanning = useCtrlForPanning;
  380. this._panningMouseButton = panningMouseButton;
  381. this.inputs.attachElement(element, noPreventDefault);
  382. this._reset = () => {
  383. this.inertialAlphaOffset = 0;
  384. this.inertialBetaOffset = 0;
  385. this.inertialRadiusOffset = 0;
  386. this.inertialPanningX = 0;
  387. this.inertialPanningY = 0;
  388. };
  389. }
  390. public detachControl(element: HTMLElement): void {
  391. this.inputs.detachElement(element);
  392. if (this._reset) {
  393. this._reset();
  394. }
  395. }
  396. public _checkInputs(): void {
  397. //if (async) collision inspection was triggered, don't update the camera's position - until the collision callback was called.
  398. if (this._collisionTriggered) {
  399. return;
  400. }
  401. this.inputs.checkInputs();
  402. // Inertia
  403. if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset !== 0) {
  404. if (this.getScene().useRightHandedSystem) {
  405. this.alpha -= this.beta <= 0 ? -this.inertialAlphaOffset : this.inertialAlphaOffset;
  406. } else {
  407. this.alpha += this.beta <= 0 ? -this.inertialAlphaOffset : this.inertialAlphaOffset;
  408. }
  409. this.beta += this.inertialBetaOffset;
  410. this.radius -= this.inertialRadiusOffset;
  411. this.inertialAlphaOffset *= this.inertia;
  412. this.inertialBetaOffset *= this.inertia;
  413. this.inertialRadiusOffset *= this.inertia;
  414. if (Math.abs(this.inertialAlphaOffset) < Epsilon)
  415. this.inertialAlphaOffset = 0;
  416. if (Math.abs(this.inertialBetaOffset) < Epsilon)
  417. this.inertialBetaOffset = 0;
  418. if (Math.abs(this.inertialRadiusOffset) < this.speed * Epsilon)
  419. this.inertialRadiusOffset = 0;
  420. }
  421. // Panning inertia
  422. if (this.inertialPanningX !== 0 || this.inertialPanningY !== 0) {
  423. if (!this._localDirection) {
  424. this._localDirection = Vector3.Zero();
  425. this._transformedDirection = Vector3.Zero();
  426. }
  427. this._localDirection.copyFromFloats(this.inertialPanningX, this.inertialPanningY, this.inertialPanningY);
  428. this._localDirection.multiplyInPlace(this.panningAxis);
  429. this._viewMatrix.invertToRef(this._cameraTransformMatrix);
  430. Vector3.TransformNormalToRef(this._localDirection, this._cameraTransformMatrix, this._transformedDirection);
  431. //Eliminate y if map panning is enabled (panningAxis == 1,0,1)
  432. if (!this.panningAxis.y) {
  433. this._transformedDirection.y = 0;
  434. }
  435. if (!this._targetHost) {
  436. if (this.panningDistanceLimit) {
  437. this._transformedDirection.addInPlace(this._target);
  438. var distanceSquared = Vector3.DistanceSquared(this._transformedDirection, this.panningOriginTarget);
  439. if (distanceSquared <= (this.panningDistanceLimit * this.panningDistanceLimit)) {
  440. this._target.copyFrom(this._transformedDirection);
  441. }
  442. }
  443. else {
  444. this._target.addInPlace(this._transformedDirection);
  445. }
  446. }
  447. this.inertialPanningX *= this.panningInertia;
  448. this.inertialPanningY *= this.panningInertia;
  449. if (Math.abs(this.inertialPanningX) < this.speed * Epsilon)
  450. this.inertialPanningX = 0;
  451. if (Math.abs(this.inertialPanningY) < this.speed * Epsilon)
  452. this.inertialPanningY = 0;
  453. }
  454. // Limits
  455. this._checkLimits();
  456. super._checkInputs();
  457. }
  458. protected _checkLimits() {
  459. if (this.lowerBetaLimit === null || this.lowerBetaLimit === undefined) {
  460. if (this.allowUpsideDown && this.beta > Math.PI) {
  461. this.beta = this.beta - (2 * Math.PI);
  462. }
  463. } else {
  464. if (this.beta < this.lowerBetaLimit) {
  465. this.beta = this.lowerBetaLimit;
  466. }
  467. }
  468. if (this.upperBetaLimit === null || this.upperBetaLimit === undefined) {
  469. if (this.allowUpsideDown && this.beta < -Math.PI) {
  470. this.beta = this.beta + (2 * Math.PI);
  471. }
  472. } else {
  473. if (this.beta > this.upperBetaLimit) {
  474. this.beta = this.upperBetaLimit;
  475. }
  476. }
  477. if (this.lowerAlphaLimit && this.alpha < this.lowerAlphaLimit) {
  478. this.alpha = this.lowerAlphaLimit;
  479. }
  480. if (this.upperAlphaLimit && this.alpha > this.upperAlphaLimit) {
  481. this.alpha = this.upperAlphaLimit;
  482. }
  483. if (this.lowerRadiusLimit && this.radius < this.lowerRadiusLimit) {
  484. this.radius = this.lowerRadiusLimit;
  485. }
  486. if (this.upperRadiusLimit && this.radius > this.upperRadiusLimit) {
  487. this.radius = this.upperRadiusLimit;
  488. }
  489. }
  490. public rebuildAnglesAndRadius() {
  491. var radiusv3 = this.position.subtract(this._getTargetPosition());
  492. this.radius = radiusv3.length();
  493. if (this.radius === 0) {
  494. this.radius = 0.0001; // Just to avoid division by zero
  495. }
  496. // Alpha
  497. this.alpha = Math.acos(radiusv3.x / Math.sqrt(Math.pow(radiusv3.x, 2) + Math.pow(radiusv3.z, 2)));
  498. if (radiusv3.z < 0) {
  499. this.alpha = 2 * Math.PI - this.alpha;
  500. }
  501. // Beta
  502. this.beta = Math.acos(radiusv3.y / this.radius);
  503. this._checkLimits();
  504. }
  505. public setPosition(position: Vector3): void {
  506. if (this.position.equals(position)) {
  507. return;
  508. }
  509. this.position.copyFrom(position);
  510. this.rebuildAnglesAndRadius();
  511. }
  512. public setTarget(target: AbstractMesh | Vector3, toBoundingCenter = false, allowSamePosition = false): void {
  513. if ((<any>target).getBoundingInfo) {
  514. if (toBoundingCenter) {
  515. this._targetBoundingCenter = (<any>target).getBoundingInfo().boundingBox.centerWorld.clone();
  516. } else {
  517. this._targetBoundingCenter = null;
  518. }
  519. this._targetHost = <AbstractMesh>target;
  520. this._target = this._getTargetPosition();
  521. this.onMeshTargetChangedObservable.notifyObservers(this._targetHost);
  522. } else {
  523. var newTarget = <Vector3>target;
  524. var currentTarget = this._getTargetPosition();
  525. if (currentTarget && !allowSamePosition && currentTarget.equals(newTarget)) {
  526. return;
  527. }
  528. this._targetHost = null;
  529. this._target = newTarget;
  530. this._targetBoundingCenter = null;
  531. this.onMeshTargetChangedObservable.notifyObservers(null);
  532. }
  533. this.rebuildAnglesAndRadius();
  534. }
  535. public _getViewMatrix(): Matrix {
  536. // Compute
  537. var cosa = Math.cos(this.alpha);
  538. var sina = Math.sin(this.alpha);
  539. var cosb = Math.cos(this.beta);
  540. var sinb = Math.sin(this.beta);
  541. if (sinb === 0) {
  542. sinb = 0.0001;
  543. }
  544. var target = this._getTargetPosition();
  545. target.addToRef(new Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this._newPosition);
  546. if (this.getScene().collisionsEnabled && this.checkCollisions) {
  547. if (!this._collider) {
  548. this._collider = new Collider();
  549. }
  550. this._collider.radius = this.collisionRadius;
  551. this._newPosition.subtractToRef(this.position, this._collisionVelocity);
  552. this._collisionTriggered = true;
  553. this.getScene().collisionCoordinator.getNewPosition(this.position, this._collisionVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
  554. } else {
  555. this.position.copyFrom(this._newPosition);
  556. var up = this.upVector;
  557. if (this.allowUpsideDown && sinb < 0) {
  558. up = up.clone();
  559. up = up.negate();
  560. }
  561. if (this.getScene().useRightHandedSystem) {
  562. Matrix.LookAtRHToRef(this.position, target, up, this._viewMatrix);
  563. } else {
  564. Matrix.LookAtLHToRef(this.position, target, up, this._viewMatrix);
  565. }
  566. this._viewMatrix.m[12] += this.targetScreenOffset.x;
  567. this._viewMatrix.m[13] += this.targetScreenOffset.y;
  568. }
  569. this._currentTarget = target;
  570. return this._viewMatrix;
  571. }
  572. protected _onCollisionPositionChange = (collisionId: number, newPosition: Vector3, collidedMesh: Nullable<AbstractMesh> = null) => {
  573. if (this.getScene().workerCollisions && this.checkCollisions) {
  574. newPosition.multiplyInPlace(this._collider.radius);
  575. }
  576. if (!collidedMesh) {
  577. this._previousPosition.copyFrom(this.position);
  578. } else {
  579. this.setPosition(newPosition);
  580. if (this.onCollide) {
  581. this.onCollide(collidedMesh);
  582. }
  583. }
  584. // Recompute because of constraints
  585. var cosa = Math.cos(this.alpha);
  586. var sina = Math.sin(this.alpha);
  587. var cosb = Math.cos(this.beta);
  588. var sinb = Math.sin(this.beta);
  589. if (sinb === 0) {
  590. sinb = 0.0001;
  591. }
  592. var target = this._getTargetPosition();
  593. target.addToRef(new Vector3(this.radius * cosa * sinb, this.radius * cosb, this.radius * sina * sinb), this._newPosition);
  594. this.position.copyFrom(this._newPosition);
  595. var up = this.upVector;
  596. if (this.allowUpsideDown && this.beta < 0) {
  597. up = up.clone();
  598. up = up.negate();
  599. }
  600. Matrix.LookAtLHToRef(this.position, target, up, this._viewMatrix);
  601. this._viewMatrix.m[12] += this.targetScreenOffset.x;
  602. this._viewMatrix.m[13] += this.targetScreenOffset.y;
  603. this._collisionTriggered = false;
  604. }
  605. public zoomOn(meshes?: AbstractMesh[], doNotUpdateMaxZ = false): void {
  606. meshes = meshes || this.getScene().meshes;
  607. var minMaxVector = Mesh.MinMax(meshes);
  608. var distance = Vector3.Distance(minMaxVector.min, minMaxVector.max);
  609. this.radius = distance * this.zoomOnFactor;
  610. this.focusOn({ min: minMaxVector.min, max: minMaxVector.max, distance: distance }, doNotUpdateMaxZ);
  611. }
  612. public focusOn(meshesOrMinMaxVectorAndDistance: AbstractMesh[] | { min: Vector3, max: Vector3, distance: number }, doNotUpdateMaxZ = false): void {
  613. var meshesOrMinMaxVector: { min: Vector3, max: Vector3 };
  614. var distance: number;
  615. if ((<any>meshesOrMinMaxVectorAndDistance).min === undefined) { // meshes
  616. var meshes = (<AbstractMesh[]>meshesOrMinMaxVectorAndDistance) || this.getScene().meshes;
  617. meshesOrMinMaxVector = Mesh.MinMax(meshes);
  618. distance = Vector3.Distance(meshesOrMinMaxVector.min, meshesOrMinMaxVector.max);
  619. }
  620. else { //minMaxVector and distance
  621. var minMaxVectorAndDistance = <any>meshesOrMinMaxVectorAndDistance;
  622. meshesOrMinMaxVector = minMaxVectorAndDistance;
  623. distance = minMaxVectorAndDistance.distance;
  624. }
  625. this._target = Mesh.Center(meshesOrMinMaxVector);
  626. if (!doNotUpdateMaxZ) {
  627. this.maxZ = distance * 2;
  628. }
  629. }
  630. /**
  631. * @override
  632. * Override Camera.createRigCamera
  633. */
  634. public createRigCamera(name: string, cameraIndex: number): Camera {
  635. var alphaShift: number = 0;
  636. switch (this.cameraRigMode) {
  637. case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
  638. case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
  639. case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
  640. case Camera.RIG_MODE_VR:
  641. alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? 1 : -1);
  642. break;
  643. case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
  644. alphaShift = this._cameraRigParams.stereoHalfAngle * (cameraIndex === 0 ? -1 : 1);
  645. break;
  646. }
  647. var rigCam = new ArcRotateCamera(name, this.alpha + alphaShift, this.beta, this.radius, this._target, this.getScene());
  648. rigCam._cameraRigParams = {};
  649. return rigCam;
  650. }
  651. /**
  652. * @override
  653. * Override Camera._updateRigCameras
  654. */
  655. public _updateRigCameras() {
  656. var camLeft = <ArcRotateCamera>this._rigCameras[0];
  657. var camRight = <ArcRotateCamera>this._rigCameras[1];
  658. camLeft.beta = camRight.beta = this.beta;
  659. camLeft.radius = camRight.radius = this.radius;
  660. switch (this.cameraRigMode) {
  661. case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
  662. case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
  663. case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
  664. case Camera.RIG_MODE_VR:
  665. camLeft.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
  666. camRight.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
  667. break;
  668. case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
  669. camLeft.alpha = this.alpha + this._cameraRigParams.stereoHalfAngle;
  670. camRight.alpha = this.alpha - this._cameraRigParams.stereoHalfAngle;
  671. break;
  672. }
  673. super._updateRigCameras();
  674. }
  675. public dispose(): void {
  676. this.inputs.clear();
  677. super.dispose();
  678. }
  679. public getClassName(): string {
  680. return "ArcRotateCamera";
  681. }
  682. }
  683. }