/home/lindsay/xeolabs/xeogl-next/xeogl/src/camera/camera.js
API Docs for:

File: /home/lindsay/xeolabs/xeogl-next/xeogl/src/camera/camera.js

  1. /**
  2. A **Camera** defines viewing and projection transforms for its {{#crossLink "Scene"}}{{/crossLink}}.
  3.  
  4. ## Overview
  5.  
  6. * One Camera per Scene
  7. * Controls viewing and projection transforms
  8. * Has methods to pan, zoom and orbit (or first-person rotation)
  9. * Dynamically configurable World-space "up" direction
  10. * Switchable between perspective, frustum and orthographic projections
  11. * Switchable gimbal lock
  12. * Can be "flown" to look at targets using a {{#crossLink "CameraFlightAnimation"}}{{/crossLink}}
  13. * Can be animated along a path using a {{#crossLink "CameraPathAnimation"}}{{/crossLink}}
  14. * Can follow a target using a {{#crossLink "CameraFollowAnimation"}}{{/crossLink}}
  15.  
  16. ## Examples
  17.  
  18. * [Perspective projection](../../examples/#camera_perspective)
  19. * [Orthographic projection](../../examples/#camera_orthographic)
  20. * [Frustum projection](../../examples/#camera_frustum)
  21. * [Camera with world Z-axis as "up"](../../examples/#camera_zAxisUp)
  22. * [Camera with world Y-axis as "up"](../../examples/#camera_yAxisUp)
  23. * [Automatically following a Mesh with a Camera](../../examples/#camera_follow)
  24. * [Animating a Camera along a path](../../examples/#camera_path_interpolation)
  25. * [Architectural fly-through](../../examples/#importing_gltf_ModernOffice)
  26.  
  27. ## Usage
  28.  
  29. * [Getting the Camera](#getting-the-camera)
  30. * [Moving around](#moving-around)
  31. * [Projection](#projection)
  32. * [Configuring World up direction](#configuring-world-up-direction)
  33. * [Gimbal locking](#gimbal-locking)
  34. * [Stereo rendering](#stereo-rendering)
  35.  
  36. ### Getting the Camera
  37.  
  38. There is exactly one Camera per Scene:
  39.  
  40. ````javascript
  41. var camera = myScene.camera;
  42. ````
  43.  
  44. ### Moving around
  45.  
  46. Get and set the Camera's absolute position at any time via its {{#crossLink "Camera/eye:property"}}{{/crossLink}},
  47. {{#crossLink "Camera/look:property"}}{{/crossLink}} and {{#crossLink "Camera/up:property"}}{{/crossLink}} properties:
  48.  
  49. ````javascript
  50. camera.eye = [-10,0,0];
  51. camera.look = [-10,0,0];
  52. camera.up = [0,1,0];
  53. ````
  54.  
  55. Get the view matrix:
  56.  
  57. ````javascript
  58. var viewMatrix = camera.viewMatrix;
  59. var viewNormalMatrix = camera.normalMatrix;
  60. ````
  61.  
  62. Listen for view matrix updates:
  63.  
  64. ````javascript
  65. camera.on("matrix", function(matrix) { ... });
  66. ````
  67.  
  68. Orbiting the {{#crossLink "Camera/look:property"}}{{/crossLink}} position:
  69.  
  70. ````javascript
  71. camera.orbitYaw(20.0);
  72. camera.orbitPitch(10.0);
  73. ````
  74.  
  75. First-person rotation, rotates {{#crossLink "Camera/look:property"}}{{/crossLink}}
  76. and {{#crossLink "Camera/up:property"}}{{/crossLink}} about {{#crossLink "Camera/eye:property"}}{{/crossLink}}:
  77.  
  78. ````javascript
  79. camera.yaw(5.0);
  80. camera.pitch(-10.0);
  81. ````
  82.  
  83. Panning along the Camera's local axis (ie. left/right, up/down, forward/backward):
  84.  
  85. ````javascript
  86. camera.pan([-20, 0, 10]);
  87. ````
  88.  
  89. Zoom to vary distance between {{#crossLink "Camera/eye:property"}}{{/crossLink}} and {{#crossLink "Camera/look:property"}}{{/crossLink}}:
  90.  
  91. ````javascript
  92. camera.zoom(-5); // Move five units closer
  93. ````
  94.  
  95. Get the current distance between {{#crossLink "Camera/eye:property"}}{{/crossLink}} and {{#crossLink "Camera/look:property"}}{{/crossLink}}:
  96.  
  97. ````javascript
  98. var distance = camera.eyeLookDist;
  99. ````
  100.  
  101. ### Projection
  102.  
  103. For each projection type, the Camera has a Component to manage that projection's configuration. You can hot-switch the Camera
  104. between those projection types, while updating the properties of each projection component at any time.
  105.  
  106. ````javascript
  107. camera.perspective.near = 0.4;
  108. camera.perspective.fov = 45;
  109. //...
  110.  
  111. camera.ortho.near = 0.8;
  112. camera.ortho.far = 1000;
  113. //...
  114.  
  115. camera.frustum.left = -1.0;
  116. camera.frustum.right = 1.0;
  117. camera.frustum.far = 1000.0;
  118. //...
  119.  
  120. camera.customProjection.matrix = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
  121.  
  122. camera.projection = "perspective"; // Switch to perspective
  123. camera.projection = "frustum"; // Switch to frustum
  124. camera.projection = "ortho"; // Switch to ortho
  125. camera.projection = "customProjection"; // Switch to custom
  126. ````
  127.  
  128. Get the projection matrix:
  129.  
  130. ````javascript
  131. var projMatrix = camera.projMatrix;
  132. ````
  133.  
  134. Listen for projection matrix updates:
  135.  
  136. ````javascript
  137. camera.on("projMatrix", function(matrix) { ... });
  138. ````
  139.  
  140. ### Configuring World up direction
  141.  
  142. We can dynamically configure the direction that we consider to be "up" in the World-space coordinate system.
  143.  
  144. Set the +Y axis as World "up" (convention in some modeling software):
  145.  
  146. ````javascript
  147. camera.worldAxis = [
  148. 1, 0, 0, // Right
  149. 0, 1, 0, // Up
  150. 0, 0,-1 // Forward
  151. ];
  152. ````
  153.  
  154. Set the +Z axis as World "up" (convention in most CAD and BIM viewers):
  155.  
  156. ````javascript
  157. camera.worldAxis = [
  158. 1, 0, 0, // Right
  159. 0, 0, 1, // Up
  160. 0,-1, 0 // Forward
  161. ];
  162. ````
  163.  
  164. The Camera has read-only convenience properties that provide each axis individually:
  165.  
  166. ````javascript
  167. var worldRight = camera.worldRight;
  168. var worldForward = camera.worldForward;
  169. var worldUp = camera.worldUp;
  170. ````
  171.  
  172. ### Gimbal locking
  173.  
  174. By default, the Camera locks yaw rotation to pivot about the World-space "up" axis. We can dynamically lock and unlock that
  175. at any time:
  176.  
  177. ````javascript
  178. camera.gimbalLock = false; // Yaw rotation now happens about Camera's local Y-axis
  179. camera.gimbalLock = true; // Yaw rotation now happens about World's "up" axis
  180. ````
  181.  
  182. See: <a href="https://en.wikipedia.org/wiki/Gimbal_lock">https://en.wikipedia.org/wiki/Gimbal_lock</a>
  183.  
  184. ### Stereo rendering
  185.  
  186. TODO: Describe stereo techniques and the deviceMatrix property
  187.  
  188. @class Camera
  189. @module xeogl
  190. @submodule camera
  191. @constructor
  192. @param [owner] {Component} Owner component. When destroyed, the owner will destroy this component as well. Creates this component within the default {{#crossLink "Scene"}}{{/crossLink}} when omitted.
  193. @param [cfg] {*} Configs
  194. @param [cfg.id] {String} Optional ID, unique among all components in the parent {{#crossLink "Scene"}}Scene{{/crossLink}}, generated automatically when omitted.
  195. You only need to supply an ID if you need to be able to find the Camera by ID within its parent {{#crossLink "Scene"}}Scene{{/crossLink}} later.
  196. @param [cfg.meta] {String:Object} Optional map of user-defined metadata to attach to this Camera.
  197. @extends Component
  198. */
  199. import {math} from '../math/math.js';
  200. import {Component} from '../component.js';
  201. import {State} from '../renderer/state.js';
  202. import {Perspective} from './perspective.js';
  203. import {Ortho} from './ortho.js';
  204. import {Frustum} from './frustum.js';
  205. import {CustomProjection} from './customProjection.js';
  206. import {componentClasses} from "./../componentClasses.js";
  207.  
  208. const tempVec3 = math.vec3();
  209. const tempVec3b = math.vec3();
  210. const tempVec3c = math.vec3();
  211. const tempVec3d = math.vec3();
  212. const tempVec3e = math.vec3();
  213. const tempVec3f = math.vec3();
  214. const tempMat = math.mat4();
  215. const tempMatb = math.mat4();
  216. const eyeLookVec = math.vec3();
  217. const eyeLookVecNorm = math.vec3();
  218. const eyeLookOffset = math.vec3();
  219. const offsetEye = math.vec3();
  220.  
  221. const type = "xeogl.Camera";
  222.  
  223. class Camera extends Component {
  224.  
  225. /**
  226. JavaScript class name for this Component.
  227.  
  228. For example: "xeogl.AmbientLight", "xeogl.MetallicMaterial" etc.
  229.  
  230. @property type
  231. @type String
  232. @final
  233. */
  234. get type() {
  235. return type;
  236. }
  237.  
  238. init(cfg) {
  239.  
  240. super.init(cfg);
  241.  
  242. this._state = new State({
  243. deviceMatrix: math.mat4(),
  244. hasDeviceMatrix: false, // True when deviceMatrix set to other than identity
  245. matrix: math.mat4(),
  246. normalMatrix: math.mat4()
  247. });
  248.  
  249. this._perspective = new Perspective(this);
  250. this._ortho = new Ortho(this);
  251. this._frustum = new Frustum(this);
  252. this._customProjection = new CustomProjection(this);
  253. this._project = this._perspective;
  254.  
  255. this._eye = math.vec3([0, 0, 10.0]);
  256. this._look = math.vec3([0, 0, 0]);
  257. this._up = math.vec3([0, 1, 0]);
  258.  
  259. this._worldUp = math.vec3([0, 1, 0]);
  260. this._worldRight = math.vec3([1, 0, 0]);
  261. this._worldForward = math.vec3([0, 0, -1]);
  262.  
  263. this.deviceMatrix = cfg.deviceMatrix;
  264. this.eye = cfg.eye;
  265. this.look = cfg.look;
  266. this.up = cfg.up;
  267. this.worldAxis = cfg.worldAxis;
  268. this.gimbalLock = cfg.gimbalLock;
  269. this.constrainPitch = cfg.constrainPitch;
  270.  
  271. this.projection = cfg.projection;
  272.  
  273. this._perspective.on("matrix", () => {
  274. if (this._projectionType === "perspective") {
  275. this.fire("projMatrix", this._perspective.matrix);
  276. }
  277. });
  278. this._ortho.on("matrix", () => {
  279. if (this._projectionType === "ortho") {
  280. this.fire("projMatrix", this._ortho.matrix);
  281. }
  282. });
  283. this._frustum.on("matrix", () => {
  284. if (this._projectionType === "frustum") {
  285. this.fire("projMatrix", this._frustum.matrix);
  286. }
  287. });
  288. this._customProjection.on("matrix", () => {
  289. if (this._projectionType === "customProjection") {
  290. this.fire("projMatrix", this._customProjection.matrix);
  291. }
  292. });
  293. }
  294.  
  295. _update() {
  296. const state = this._state;
  297. // In ortho mode, build the view matrix with an eye position that's translated
  298. // well back from look, so that the front clip plane doesn't unexpectedly cut
  299. // the front off the view (not a problem with perspective, since objects close enough
  300. // to be clipped by the front plane are usually too big to see anything of their cross-sections).
  301. let eye;
  302. if (this.projection === "ortho") {
  303. math.subVec3(this._eye, this._look, eyeLookVec);
  304. math.normalizeVec3(eyeLookVec, eyeLookVecNorm);
  305. math.mulVec3Scalar(eyeLookVecNorm, 1000.0, eyeLookOffset);
  306. math.addVec3(this._look, eyeLookOffset, offsetEye);
  307. eye = offsetEye;
  308. } else {
  309. eye = this._eye;
  310. }
  311. if (state.hasDeviceMatrix) {
  312. math.lookAtMat4v(eye, this._look, this._up, tempMatb);
  313. math.mulMat4(state.deviceMatrix, tempMatb, state.matrix);
  314. //state.matrix.set(state.deviceMatrix);
  315. } else {
  316. math.lookAtMat4v(eye, this._look, this._up, state.matrix);
  317. }
  318. math.inverseMat4(this._state.matrix, this._state.normalMatrix);
  319. math.transposeMat4(this._state.normalMatrix);
  320. this._renderer.imageDirty();
  321. this.fire("matrix", this._state.matrix);
  322. this.fire("viewMatrix", this._state.matrix);
  323. }
  324.  
  325. /**
  326. Rotates {{#crossLink "Camera/eye:property"}}{{/crossLink}} about {{#crossLink "Camera/look:property"}}{{/crossLink}}, around the {{#crossLink "Camera/up:property"}}{{/crossLink}} vector
  327.  
  328. @method orbitYaw
  329. @param {Number} angle Angle of rotation in degrees
  330. */
  331. orbitYaw(angle) {
  332. let lookEyeVec = math.subVec3(this._eye, this._look, tempVec3);
  333. math.rotationMat4v(angle * 0.0174532925, this._gimbalLock ? this._worldUp : this._up, tempMat);
  334. lookEyeVec = math.transformPoint3(tempMat, lookEyeVec, tempVec3b);
  335. this.eye = math.addVec3(this._look, lookEyeVec, tempVec3c); // Set eye position as 'look' plus 'eye' vector
  336. this.up = math.transformPoint3(tempMat, this._up, tempVec3d); // Rotate 'up' vector
  337. }
  338.  
  339. /**
  340. Rotates {{#crossLink "Camera/eye:property"}}{{/crossLink}} about {{#crossLink "Camera/look:property"}}{{/crossLink}} around the right axis (orthogonal to {{#crossLink "Camera/up:property"}}{{/crossLink}} and "look").
  341.  
  342. @method orbitPitch
  343. @param {Number} angle Angle of rotation in degrees
  344. */
  345. orbitPitch(angle) {
  346. let eye2 = math.subVec3(this._eye, this._look, tempVec3);
  347. const left = math.cross3Vec3(math.normalizeVec3(eye2, tempVec3b), math.normalizeVec3(this._up, tempVec3c));
  348. math.rotationMat4v(angle * 0.0174532925, left, tempMat);
  349. eye2 = math.transformPoint3(tempMat, eye2, tempVec3d);
  350. const up = math.transformPoint3(tempMat, this._up, tempVec3e);
  351. if (this._constrainPitch) {
  352. var angle = math.dotVec3(up, this._worldUp) / math.DEGTORAD;
  353. if (angle < 1) {
  354. return;
  355. }
  356. }
  357. this.up = up;
  358. this.eye = math.addVec3(eye2, this._look, tempVec3f);
  359. }
  360.  
  361. /**
  362. Rotates {{#crossLink "Camera/look:property"}}{{/crossLink}} about {{#crossLink "Camera/eye:property"}}{{/crossLink}}, around the {{#crossLink "Camera/up:property"}}{{/crossLink}} vector.
  363.  
  364. @method yaw
  365. @param {Number} angle Angle of rotation in degrees
  366. */
  367. yaw(angle) {
  368. let look2 = math.subVec3(this._look, this._eye, tempVec3);
  369. math.rotationMat4v(angle * 0.0174532925, this._gimbalLock ? this._worldUp : this._up, tempMat);
  370. look2 = math.transformPoint3(tempMat, look2, tempVec3b);
  371. this.look = math.addVec3(look2, this._eye, tempVec3c);
  372. if (this._gimbalLock) {
  373. this.up = math.transformPoint3(tempMat, this._up, tempVec3d);
  374. }
  375. }
  376.  
  377. /**
  378. Rotates {{#crossLink "Camera/look:property"}}{{/crossLink}} about {{#crossLink "Camera/eye:property"}}{{/crossLink}}, around the right axis (orthogonal to {{#crossLink "Camera/up:property"}}{{/crossLink}} and "look").
  379.  
  380. @method pitch
  381. @param {Number} angle Angle of rotation in degrees
  382. */
  383. pitch(angle) {
  384. let look2 = math.subVec3(this._look, this._eye, tempVec3);
  385. const left = math.cross3Vec3(math.normalizeVec3(look2, tempVec3b), math.normalizeVec3(this._up, tempVec3c));
  386. math.rotationMat4v(angle * 0.0174532925, left, tempMat);
  387. const up = math.transformPoint3(tempMat, this._up, tempVec3f);
  388. if (this._constrainPitch) {
  389. var angle = math.dotVec3(up, this._worldUp) / math.DEGTORAD;
  390. if (angle < 1) {
  391. return;
  392. }
  393. }
  394. this.up = up;
  395. look2 = math.transformPoint3(tempMat, look2, tempVec3d);
  396. this.look = math.addVec3(look2, this._eye, tempVec3e);
  397. }
  398.  
  399. /**
  400. Pans the camera along the camera's local X, Y and Z axis.
  401.  
  402. @method pan
  403. @param pan The pan vector
  404. */
  405. pan(pan) {
  406. const eye2 = math.subVec3(this._eye, this._look, tempVec3);
  407. const vec = [0, 0, 0];
  408. let v;
  409. if (pan[0] !== 0) {
  410. const left = math.cross3Vec3(math.normalizeVec3(eye2, []), math.normalizeVec3(this._up, tempVec3b));
  411. v = math.mulVec3Scalar(left, pan[0]);
  412. vec[0] += v[0];
  413. vec[1] += v[1];
  414. vec[2] += v[2];
  415. }
  416. if (pan[1] !== 0) {
  417. v = math.mulVec3Scalar(math.normalizeVec3(this._up, tempVec3c), pan[1]);
  418. vec[0] += v[0];
  419. vec[1] += v[1];
  420. vec[2] += v[2];
  421. }
  422. if (pan[2] !== 0) {
  423. v = math.mulVec3Scalar(math.normalizeVec3(eye2, tempVec3d), pan[2]);
  424. vec[0] += v[0];
  425. vec[1] += v[1];
  426. vec[2] += v[2];
  427. }
  428. this.eye = math.addVec3(this._eye, vec, tempVec3e);
  429. this.look = math.addVec3(this._look, vec, tempVec3f);
  430. }
  431.  
  432. /**
  433. Increments/decrements zoom factor, ie. distance between {{#crossLink "Camera/eye:property"}}{{/crossLink}}
  434. and {{#crossLink "Camera/look:property"}}{{/crossLink}}.
  435.  
  436. @method zoom
  437. @param delta
  438. */
  439. zoom(delta) {
  440. const vec = math.subVec3(this._eye, this._look, tempVec3);
  441. const lenLook = Math.abs(math.lenVec3(vec, tempVec3b));
  442. const newLenLook = Math.abs(lenLook + delta);
  443. if (newLenLook < 0.5) {
  444. return;
  445. }
  446. const dir = math.normalizeVec3(vec, tempVec3c);
  447. this.eye = math.addVec3(this._look, math.mulVec3Scalar(dir, newLenLook), tempVec3d);
  448. }
  449.  
  450.  
  451. /**
  452. Position of this Camera's eye.
  453.  
  454. Fires an {{#crossLink "Camera/eye:event"}}{{/crossLink}} event on change.
  455.  
  456. @property eye
  457. @default [0,0,10]
  458. @type Float32Array
  459. */
  460. set eye(value) {
  461. this._eye.set(value || [0, 0, 10]);
  462. this._needUpdate(0); // Ensure matrix built on next "tick"
  463. /**
  464. Fired whenever this Camera's {{#crossLink "Camera/eye:property"}}{{/crossLink}} property changes.
  465.  
  466. @event eye
  467. @param value The property's new value
  468. */
  469. this.fire("eye", this._eye);
  470. }
  471.  
  472. get eye() {
  473. return this._eye;
  474. }
  475.  
  476. /**
  477. Position of this Camera's point-of-interest.
  478.  
  479. Fires a {{#crossLink "Camera/look:event"}}{{/crossLink}} event on change.
  480.  
  481. @property look
  482. @default [0,0,0]
  483. @type Float32Array
  484. */
  485. set look(value) {
  486. this._look.set(value || [0, 0, 0]);
  487. this._needUpdate(0); // Ensure matrix built on next "tick"
  488. /**
  489. Fired whenever this Camera's {{#crossLink "Camera/look:property"}}{{/crossLink}} property changes.
  490.  
  491. @event look
  492. @param value The property's new value
  493. */
  494. this.fire("look", this._look);
  495. }
  496.  
  497. get look() {
  498. return this._look;
  499. }
  500.  
  501. /**
  502. Direction of this Camera's {{#crossLink "Camera/up:property"}}{{/crossLink}} vector.
  503.  
  504. Fires an {{#crossLink "Camera/up:event"}}{{/crossLink}} event on change.
  505.  
  506. @property up
  507. @default [0,1,0]
  508. @type Float32Array
  509. */
  510. set up(value) {
  511. this._up.set(value || [0, 1, 0]);
  512. this._needUpdate(0);
  513. /**
  514. Fired whenever this Camera's {{#crossLink "Camera/up:property"}}{{/crossLink}} property changes.
  515.  
  516. @event up
  517. @param value The property's new value
  518. */
  519. this.fire("up", this._up);
  520. }
  521.  
  522. get up() {
  523. return this._up;
  524. }
  525.  
  526. /**
  527. Sets an optional matrix to premultiply into this Camera's {{#crossLink "Camera/matrix:property"}}{{/crossLink}} matrix.
  528.  
  529. This is intended to be used for stereo rendering with WebVR etc.
  530.  
  531. @property deviceMatrix
  532. @type {Float32Array}
  533. */
  534. set deviceMatrix(matrix) {
  535. this._state.deviceMatrix.set(matrix || [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
  536. this._state.hasDeviceMatrix = !!matrix;
  537. this._needUpdate(0);
  538. /**
  539. Fired whenever this CustomProjection's {{#crossLink "CustomProjection/matrix:property"}}{{/crossLink}} property changes.
  540.  
  541. @event deviceMatrix
  542. @param value The property's new value
  543. */
  544. this.fire("deviceMatrix", this._state.deviceMatrix);
  545. }
  546.  
  547. get deviceMatrix() {
  548. return this._state.deviceMatrix;
  549. }
  550.  
  551. /**
  552. Indicates the up, right and forward axis of the World coordinate system.
  553.  
  554. Has format: ````[rightX, rightY, rightZ, upX, upY, upZ, forwardX, forwardY, forwardZ]````
  555.  
  556. @property worldAxis
  557. @default [1, 0, 0, 0, 1, 0, 0, 0, 1]
  558. @type Float32Array
  559. */
  560. set worldAxis(value) {
  561. value = value || [1, 0, 0, 0, 1, 0, 0, 0, 1];
  562. if (!this._worldAxis) {
  563. this._worldAxis = new Float32Array(value);
  564. } else {
  565. this._worldAxis.set(value);
  566. }
  567. this._worldRight[0] = this._worldAxis[0];
  568. this._worldRight[1] = this._worldAxis[1];
  569. this._worldRight[2] = this._worldAxis[2];
  570. this._worldUp[0] = this._worldAxis[3];
  571. this._worldUp[1] = this._worldAxis[4];
  572. this._worldUp[2] = this._worldAxis[5];
  573. this._worldForward[0] = this._worldAxis[6];
  574. this._worldForward[1] = this._worldAxis[7];
  575. this._worldForward[2] = this._worldAxis[8];
  576. /**
  577. * Fired whenever this Camera's {{#crossLink "Camera/worldAxis:property"}}{{/crossLink}} property changes.
  578. *
  579. * @event worldAxis
  580. * @param value The property's new value
  581. */
  582. this.fire("worldAxis", this._worldAxis);
  583. }
  584.  
  585. get worldAxis() {
  586. return this._worldAxis;
  587. }
  588.  
  589. /**
  590. Direction of World-space "up".
  591.  
  592. @property worldUp
  593. @default [0,1,0]
  594. @type Float32Array
  595. @final
  596. */
  597. get worldUp() {
  598. return this._worldUp;
  599. }
  600.  
  601. /**
  602. Direction of World-space "right".
  603.  
  604. @property worldRight
  605. @default [1,0,0]
  606. @type Float32Array
  607. @final
  608. */
  609. get worldRight() {
  610. return this._worldRight;
  611. }
  612.  
  613. /**
  614. Direction of World-space "forwards".
  615.  
  616. @property worldForward
  617. @default [0,0,-1]
  618. @type Float32Array
  619. @final
  620. */
  621. get worldForward() {
  622. return this._worldForward;
  623. }
  624.  
  625. /**
  626. Whether to lock yaw rotation to pivot about the World-space "up" axis.
  627.  
  628. Fires a {{#crossLink "Camera/gimbalLock:event"}}{{/crossLink}} event on change.
  629.  
  630. @property gimbalLock
  631. @default true
  632. @type Boolean
  633. */
  634. set gimbalLock(value) {
  635. this._gimbalLock = value !== false;
  636. /**
  637. Fired whenever this Camera's {{#crossLink "Camera/gimbalLock:property"}}{{/crossLink}} property changes.
  638.  
  639. @event gimbalLock
  640. @param value The property's new value
  641. */
  642. this.fire("gimbalLock", this._gimbalLock);
  643. }
  644.  
  645. get gimbalLock() {
  646. return this._gimbalLock;
  647. }
  648.  
  649. /**
  650. Whether to prevent camera from being pitched upside down.
  651.  
  652. The camera is upside down when the angle
  653. between {{#crossLink "Camera/up:property"}}{{/crossLink}} and {{#crossLink "Camera/worldUp:property"}}{{/crossLink}} is less than one degree.
  654.  
  655. Fires a {{#crossLink "Camera/constrainPitch:event"}}{{/crossLink}} event on change.
  656.  
  657. @property constrainPitch
  658. @default false
  659. @type Boolean
  660. */
  661. set constrainPitch(value) {
  662. this._constrainPitch = !!value;
  663. /**
  664. Fired whenever this Camera's {{#crossLink "Camera/constrainPitch:property"}}{{/crossLink}} property changes.
  665.  
  666. @event constrainPitch
  667. @param value The property's new value
  668. */
  669. this.fire("constrainPitch", this._constrainPitch);
  670. }
  671.  
  672. get constrainPitch() {
  673. return this._constrainPitch;
  674. }
  675.  
  676. /**
  677. Distance from "look" to "eye".
  678. @property eyeLookDist
  679. @type Number
  680. @final
  681. */
  682. get eyeLookDist() {
  683. return math.lenVec3(math.subVec3(this._look, this._eye, tempVec3));
  684. }
  685.  
  686. /**
  687. The Camera's viewing transformation matrix.
  688.  
  689. Fires a {{#crossLink "Camera/matrix:event"}}{{/crossLink}} event on change.
  690.  
  691. @property matrix
  692. @type {Float32Array}
  693. @final
  694. @deprecated
  695. */
  696. get matrix() {
  697. if (this._updateScheduled) {
  698. this._doUpdate();
  699. }
  700. return this._state.matrix;
  701. }
  702.  
  703. /**
  704. The Camera's viewing transformation matrix.
  705.  
  706. Fires a {{#crossLink "Camera/matrix:event"}}{{/crossLink}} event on change.
  707.  
  708. @property viewMatrix
  709. @final
  710. @type {Float32Array}
  711. */
  712. get viewMatrix() {
  713. if (this._updateScheduled) {
  714. this._doUpdate();
  715. }
  716. return this._state.matrix;
  717. }
  718.  
  719.  
  720. /**
  721. The Camera's viewing normal transformation matrix.
  722.  
  723. Fires a {{#crossLink "Camera/matrix:event"}}{{/crossLink}} event on change.
  724.  
  725. @property normalMatrix
  726. @type {Float32Array}
  727. @final
  728. @deprecated
  729. */
  730. get normalMatrix() {
  731. if (this._updateScheduled) {
  732. this._doUpdate();
  733. }
  734. return this._state.normalMatrix;
  735. }
  736.  
  737. /**
  738. The Camera's viewing normal transformation matrix.
  739.  
  740. Fires a {{#crossLink "Camera/matrix:event"}}{{/crossLink}} event on change.
  741.  
  742. @property viewNormalMatrix
  743. @final
  744. @type {Float32Array}
  745. */
  746. get viewNormalMatrix() {
  747. if (this._updateScheduled) {
  748. this._doUpdate();
  749. }
  750. return this._state.normalMatrix;
  751. }
  752.  
  753. /**
  754. Camera's projection transformation projMatrix.
  755.  
  756. Fires a {{#crossLink "Camera/projMatrix:event"}}{{/crossLink}} event on change.
  757.  
  758. @property projMatrix
  759. @final
  760. @type {Float32Array}
  761. */
  762. get projMatrix() {
  763. return this[this.projection].matrix;
  764. }
  765.  
  766.  
  767. /**
  768. The perspective projection transform for this Camera.
  769.  
  770. This is used while {{#crossLink "Camera/projection:property"}}{{/crossLink}} equals "perspective".
  771.  
  772. @property perspective
  773. @type Perspective
  774. @final
  775. */
  776. get perspective() {
  777. return this._perspective;
  778. }
  779.  
  780. /**
  781. The orthographic projection transform for this Camera.
  782.  
  783. This is used while {{#crossLink "Camera/projection:property"}}{{/crossLink}} equals "ortho".
  784.  
  785. @property ortho
  786. @type Ortho
  787. @final
  788. */
  789. get ortho() {
  790. return this._ortho;
  791. }
  792.  
  793.  
  794. /**
  795. The frustum projection transform for this Camera.
  796.  
  797. This is used while {{#crossLink "Camera/projection:property"}}{{/crossLink}} equals "frustum".
  798.  
  799. @property frustum
  800. @type Frustum
  801. @final
  802. */
  803. get frustum() {
  804. return this._frustum;
  805. }
  806.  
  807. /**
  808. A custom projection transform, given as a 4x4 matrix.
  809.  
  810. This is used while {{#crossLink "Camera/projection:property"}}{{/crossLink}} equals "customProjection".
  811.  
  812. @property customProjection
  813. @type CustomProjection
  814. @final
  815. */
  816. get customProjection() {
  817. return this._customProjection;
  818. }
  819.  
  820. /**
  821. The active projection type.
  822.  
  823. Accepted values are "perspective", "ortho", "frustum" and "customProjection".
  824.  
  825. @property projection
  826. @default "perspective"
  827. @type {String}
  828. */
  829. set projection(value) {
  830. value = value || "perspective";
  831. if (this._projectionType === value) {
  832. return;
  833. }
  834. if (value === "perspective") {
  835. this._project = this._perspective;
  836. } else if (value === "ortho") {
  837. this._project = this._ortho;
  838. } else if (value === "frustum") {
  839. this._project = this._frustum;
  840. } else if (value === "customProjection") {
  841. this._project = this._customProjection;
  842. } else {
  843. this.error("Unsupported value for 'projection': " + value + " defaulting to 'perspective'");
  844. this._project = this._perspective;
  845. value = "perspective";
  846. }
  847. this._projectionType = value;
  848. this._renderer.imageDirty();
  849. this._update(); // Need to rebuild lookat matrix with full eye, look & up
  850. this.fire("dirty");
  851. }
  852.  
  853. get projection() {
  854. return this._projectionType;
  855. }
  856.  
  857. /**
  858. The active projection transform for this Camera.
  859.  
  860. @property project
  861. @type Transform
  862. @final
  863. */
  864. get project() {
  865. return this._project;
  866. }
  867.  
  868. get view() {
  869. return this;
  870. }
  871.  
  872. destroy() {
  873. super.destroy();
  874. this._state.destroy();
  875. }
  876. }
  877.  
  878. componentClasses[type] = Camera;
  879.  
  880. export{Camera};