babylon.camera.ts 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. module BABYLON {
  2. export class Camera extends Node {
  3. public inputs: CameraInputsManager<Camera>;
  4. // Statics
  5. private static _PERSPECTIVE_CAMERA = 0;
  6. private static _ORTHOGRAPHIC_CAMERA = 1;
  7. private static _FOVMODE_VERTICAL_FIXED = 0;
  8. private static _FOVMODE_HORIZONTAL_FIXED = 1;
  9. private static _RIG_MODE_NONE = 0;
  10. private static _RIG_MODE_STEREOSCOPIC_ANAGLYPH = 10;
  11. private static _RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL = 11;
  12. private static _RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED = 12;
  13. private static _RIG_MODE_STEREOSCOPIC_OVERUNDER = 13;
  14. private static _RIG_MODE_VR = 20;
  15. private static _RIG_MODE_WEBVR = 21;
  16. public static get PERSPECTIVE_CAMERA(): number {
  17. return Camera._PERSPECTIVE_CAMERA;
  18. }
  19. public static get ORTHOGRAPHIC_CAMERA(): number {
  20. return Camera._ORTHOGRAPHIC_CAMERA;
  21. }
  22. public static get FOVMODE_VERTICAL_FIXED(): number {
  23. return Camera._FOVMODE_VERTICAL_FIXED;
  24. }
  25. public static get FOVMODE_HORIZONTAL_FIXED(): number {
  26. return Camera._FOVMODE_HORIZONTAL_FIXED;
  27. }
  28. public static get RIG_MODE_NONE(): number {
  29. return Camera._RIG_MODE_NONE;
  30. }
  31. public static get RIG_MODE_STEREOSCOPIC_ANAGLYPH(): number {
  32. return Camera._RIG_MODE_STEREOSCOPIC_ANAGLYPH;
  33. }
  34. public static get RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL(): number {
  35. return Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL;
  36. }
  37. public static get RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED(): number {
  38. return Camera._RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED;
  39. }
  40. public static get RIG_MODE_STEREOSCOPIC_OVERUNDER(): number {
  41. return Camera._RIG_MODE_STEREOSCOPIC_OVERUNDER;
  42. }
  43. public static get RIG_MODE_VR(): number {
  44. return Camera._RIG_MODE_VR;
  45. }
  46. public static get RIG_MODE_WEBVR(): number {
  47. return Camera._RIG_MODE_WEBVR;
  48. }
  49. public static ForceAttachControlToAlwaysPreventDefault = false;
  50. // Members
  51. @serializeAsVector3()
  52. public position: Vector3;
  53. @serializeAsVector3()
  54. public upVector = Vector3.Up();
  55. @serialize()
  56. public orthoLeft = null;
  57. @serialize()
  58. public orthoRight = null;
  59. @serialize()
  60. public orthoBottom = null;
  61. @serialize()
  62. public orthoTop = null;
  63. @serialize()
  64. public fov = 0.8;
  65. @serialize()
  66. public minZ = 1;
  67. @serialize()
  68. public maxZ = 10000.0;
  69. @serialize()
  70. public inertia = 0.9;
  71. @serialize()
  72. public mode = Camera.PERSPECTIVE_CAMERA;
  73. public isIntermediate = false;
  74. public viewport = new Viewport(0, 0, 1.0, 1.0);
  75. @serialize()
  76. public layerMask: number = 0x0FFFFFFF;
  77. @serialize()
  78. public fovMode: number = Camera.FOVMODE_VERTICAL_FIXED;
  79. // Camera rig members
  80. @serialize()
  81. public cameraRigMode = Camera.RIG_MODE_NONE;
  82. @serialize()
  83. public interaxialDistance: number
  84. @serialize()
  85. public isStereoscopicSideBySide: boolean
  86. public _cameraRigParams: any;
  87. public _rigCameras = new Array<Camera>();
  88. public _rigPostProcess: PostProcess;
  89. protected _webvrViewMatrix = Matrix.Identity();
  90. public customRenderTargets = new Array<RenderTargetTexture>();
  91. // Observables
  92. public onViewMatrixChangedObservable = new Observable<Camera>();
  93. public onProjectionMatrixChangedObservable = new Observable<Camera>();
  94. public onAfterCheckInputsObservable = new Observable<Camera>();
  95. // Cache
  96. private _computedViewMatrix = Matrix.Identity();
  97. public _projectionMatrix = new Matrix();
  98. private _doNotComputeProjectionMatrix = false;
  99. private _worldMatrix: Matrix;
  100. public _postProcesses = new Array<PostProcess>();
  101. private _transformMatrix = Matrix.Zero();
  102. public _activeMeshes = new SmartArray<Mesh>(256);
  103. private _globalPosition = Vector3.Zero();
  104. private _frustumPlanes: Plane[];
  105. private _refreshFrustumPlanes = true;
  106. constructor(name: string, position: Vector3, scene: Scene) {
  107. super(name, scene);
  108. this.getScene().addCamera(this);
  109. if (!this.getScene().activeCamera) {
  110. this.getScene().activeCamera = this;
  111. }
  112. this.position = position;
  113. }
  114. private _storedFov: number;
  115. private _stateStored: boolean;
  116. /**
  117. * Store current camera state (fov, position, etc..)
  118. */
  119. public storeState(): Camera {
  120. this._stateStored = true;
  121. this._storedFov = this.fov;
  122. return this;
  123. }
  124. /**
  125. * Restored camera state. You must call storeState() first
  126. */
  127. public restoreState(): boolean {
  128. if (!this._stateStored) {
  129. return false;
  130. }
  131. this.fov = this._storedFov;
  132. return true;
  133. }
  134. public getClassName(): string {
  135. return "Camera";
  136. }
  137. /**
  138. * @param {boolean} fullDetails - support for multiple levels of logging within scene loading
  139. */
  140. public toString(fullDetails?: boolean): string {
  141. var ret = "Name: " + this.name;
  142. ret += ", type: " + this.getClassName();
  143. if (this.animations) {
  144. for (var i = 0; i < this.animations.length; i++) {
  145. ret += ", animation[0]: " + this.animations[i].toString(fullDetails);
  146. }
  147. }
  148. if (fullDetails) {
  149. }
  150. return ret;
  151. }
  152. public get globalPosition(): Vector3 {
  153. return this._globalPosition;
  154. }
  155. public getActiveMeshes(): SmartArray<Mesh> {
  156. return this._activeMeshes;
  157. }
  158. public isActiveMesh(mesh: Mesh): boolean {
  159. return (this._activeMeshes.indexOf(mesh) !== -1);
  160. }
  161. //Cache
  162. public _initCache() {
  163. super._initCache();
  164. this._cache.position = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  165. this._cache.upVector = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
  166. this._cache.mode = undefined;
  167. this._cache.minZ = undefined;
  168. this._cache.maxZ = undefined;
  169. this._cache.fov = undefined;
  170. this._cache.fovMode = undefined;
  171. this._cache.aspectRatio = undefined;
  172. this._cache.orthoLeft = undefined;
  173. this._cache.orthoRight = undefined;
  174. this._cache.orthoBottom = undefined;
  175. this._cache.orthoTop = undefined;
  176. this._cache.renderWidth = undefined;
  177. this._cache.renderHeight = undefined;
  178. }
  179. public _updateCache(ignoreParentClass?: boolean): void {
  180. if (!ignoreParentClass) {
  181. super._updateCache();
  182. }
  183. var engine = this.getEngine();
  184. this._cache.position.copyFrom(this.position);
  185. this._cache.upVector.copyFrom(this.upVector);
  186. this._cache.mode = this.mode;
  187. this._cache.minZ = this.minZ;
  188. this._cache.maxZ = this.maxZ;
  189. this._cache.fov = this.fov;
  190. this._cache.fovMode = this.fovMode;
  191. this._cache.aspectRatio = engine.getAspectRatio(this);
  192. this._cache.orthoLeft = this.orthoLeft;
  193. this._cache.orthoRight = this.orthoRight;
  194. this._cache.orthoBottom = this.orthoBottom;
  195. this._cache.orthoTop = this.orthoTop;
  196. this._cache.renderWidth = engine.getRenderWidth();
  197. this._cache.renderHeight = engine.getRenderHeight();
  198. }
  199. public _updateFromScene(): void {
  200. this.updateCache();
  201. this.update();
  202. }
  203. // Synchronized
  204. public _isSynchronized(): boolean {
  205. return this._isSynchronizedViewMatrix() && this._isSynchronizedProjectionMatrix();
  206. }
  207. public _isSynchronizedViewMatrix(): boolean {
  208. if (!super._isSynchronized())
  209. return false;
  210. return this._cache.position.equals(this.position)
  211. && this._cache.upVector.equals(this.upVector)
  212. && this.isSynchronizedWithParent();
  213. }
  214. public _isSynchronizedProjectionMatrix(): boolean {
  215. var check = this._cache.mode === this.mode
  216. && this._cache.minZ === this.minZ
  217. && this._cache.maxZ === this.maxZ;
  218. if (!check) {
  219. return false;
  220. }
  221. var engine = this.getEngine();
  222. if (this.mode === Camera.PERSPECTIVE_CAMERA) {
  223. check = this._cache.fov === this.fov
  224. && this._cache.fovMode === this.fovMode
  225. && this._cache.aspectRatio === engine.getAspectRatio(this);
  226. }
  227. else {
  228. check = this._cache.orthoLeft === this.orthoLeft
  229. && this._cache.orthoRight === this.orthoRight
  230. && this._cache.orthoBottom === this.orthoBottom
  231. && this._cache.orthoTop === this.orthoTop
  232. && this._cache.renderWidth === engine.getRenderWidth()
  233. && this._cache.renderHeight === engine.getRenderHeight();
  234. }
  235. return check;
  236. }
  237. // Controls
  238. public attachControl(element: HTMLElement, noPreventDefault?: boolean): void {
  239. }
  240. public detachControl(element: HTMLElement): void {
  241. }
  242. public update(): void {
  243. if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
  244. this._updateRigCameras();
  245. }
  246. this._checkInputs();
  247. }
  248. public _checkInputs(): void {
  249. this.onAfterCheckInputsObservable.notifyObservers(this);
  250. }
  251. public get rigCameras(): Camera[] {
  252. return this._rigCameras;
  253. }
  254. public get rigPostProcess(): PostProcess {
  255. return this._rigPostProcess;
  256. }
  257. private _cascadePostProcessesToRigCams(): void {
  258. // invalidate framebuffer
  259. if (this._postProcesses.length > 0) {
  260. this._postProcesses[0].markTextureDirty();
  261. }
  262. // glue the rigPostProcess to the end of the user postprocesses & assign to each sub-camera
  263. for (var i = 0, len = this._rigCameras.length; i < len; i++) {
  264. var cam = this._rigCameras[i];
  265. var rigPostProcess = cam._rigPostProcess;
  266. // for VR rig, there does not have to be a post process
  267. if (rigPostProcess) {
  268. var isPass = rigPostProcess instanceof PassPostProcess;
  269. if (isPass) {
  270. // any rig which has a PassPostProcess for rig[0], cannot be isIntermediate when there are also user postProcesses
  271. cam.isIntermediate = this._postProcesses.length === 0;
  272. }
  273. cam._postProcesses = this._postProcesses.slice(0).concat(rigPostProcess);
  274. rigPostProcess.markTextureDirty();
  275. } else {
  276. cam._postProcesses = this._postProcesses.slice(0);
  277. }
  278. }
  279. }
  280. public attachPostProcess(postProcess: PostProcess, insertAt: number = null): number {
  281. if (!postProcess.isReusable() && this._postProcesses.indexOf(postProcess) > -1) {
  282. Tools.Error("You're trying to reuse a post process not defined as reusable.");
  283. return 0;
  284. }
  285. if (insertAt == null || insertAt < 0) {
  286. this._postProcesses.push(postProcess);
  287. } else {
  288. this._postProcesses.splice(insertAt, 0, postProcess);
  289. }
  290. this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
  291. return this._postProcesses.indexOf(postProcess);
  292. }
  293. public detachPostProcess(postProcess: PostProcess, atIndices: any = null): number[] {
  294. var result = [];
  295. var i: number;
  296. var index: number;
  297. if (!atIndices) {
  298. var idx = this._postProcesses.indexOf(postProcess);
  299. if (idx !== -1) {
  300. this._postProcesses.splice(idx, 1);
  301. }
  302. } else {
  303. atIndices = (atIndices instanceof Array) ? atIndices : [atIndices];
  304. // iterate descending, so can just splice as we go
  305. for (i = atIndices.length - 1; i >= 0; i--) {
  306. if (this._postProcesses[atIndices[i]] !== postProcess) {
  307. result.push(i);
  308. continue;
  309. }
  310. index = atIndices[i];
  311. this._postProcesses.splice(index, 1);
  312. }
  313. }
  314. this._cascadePostProcessesToRigCams(); // also ensures framebuffer invalidated
  315. return result;
  316. }
  317. public getWorldMatrix(): Matrix {
  318. if (!this._worldMatrix) {
  319. this._worldMatrix = Matrix.Identity();
  320. }
  321. var viewMatrix = this.getViewMatrix();
  322. viewMatrix.invertToRef(this._worldMatrix);
  323. return this._worldMatrix;
  324. }
  325. public _getViewMatrix(): Matrix {
  326. return Matrix.Identity();
  327. }
  328. public getViewMatrix(force?: boolean): Matrix {
  329. if (!force && this._isSynchronizedViewMatrix()) {
  330. return this._computedViewMatrix;
  331. }
  332. this._computedViewMatrix = this._getViewMatrix();
  333. this._currentRenderId = this.getScene().getRenderId();
  334. this._refreshFrustumPlanes = true;
  335. if (!this.parent || !this.parent.getWorldMatrix) {
  336. this._globalPosition.copyFrom(this.position);
  337. } else {
  338. if (!this._worldMatrix) {
  339. this._worldMatrix = Matrix.Identity();
  340. }
  341. this._computedViewMatrix.invertToRef(this._worldMatrix);
  342. this._worldMatrix.multiplyToRef(this.parent.getWorldMatrix(), this._computedViewMatrix);
  343. this._globalPosition.copyFromFloats(this._computedViewMatrix.m[12], this._computedViewMatrix.m[13], this._computedViewMatrix.m[14]);
  344. this._computedViewMatrix.invert();
  345. this._markSyncedWithParent();
  346. }
  347. if (this._cameraRigParams && this._cameraRigParams.vrPreViewMatrix) {
  348. this._computedViewMatrix.multiplyToRef(this._cameraRigParams.vrPreViewMatrix, this._computedViewMatrix);
  349. }
  350. this.onViewMatrixChangedObservable.notifyObservers(this);
  351. return this._computedViewMatrix;
  352. }
  353. public freezeProjectionMatrix(projection?: Matrix): void {
  354. this._doNotComputeProjectionMatrix = true;
  355. if (projection !== undefined) {
  356. this._projectionMatrix = projection;
  357. }
  358. };
  359. public unfreezeProjectionMatrix(): void {
  360. this._doNotComputeProjectionMatrix = false;
  361. };
  362. public getProjectionMatrix(force?: boolean): Matrix {
  363. if (this._doNotComputeProjectionMatrix || (!force && this._isSynchronizedProjectionMatrix())) {
  364. return this._projectionMatrix;
  365. }
  366. this._refreshFrustumPlanes = true;
  367. var engine = this.getEngine();
  368. var scene = this.getScene();
  369. if (this.mode === Camera.PERSPECTIVE_CAMERA) {
  370. if (this.minZ <= 0) {
  371. this.minZ = 0.1;
  372. }
  373. if (scene.useRightHandedSystem) {
  374. Matrix.PerspectiveFovRHToRef(this.fov,
  375. engine.getAspectRatio(this),
  376. this.minZ,
  377. this.maxZ,
  378. this._projectionMatrix,
  379. this.fovMode === Camera.FOVMODE_VERTICAL_FIXED);
  380. } else {
  381. Matrix.PerspectiveFovLHToRef(this.fov,
  382. engine.getAspectRatio(this),
  383. this.minZ,
  384. this.maxZ,
  385. this._projectionMatrix,
  386. this.fovMode === Camera.FOVMODE_VERTICAL_FIXED);
  387. }
  388. } else {
  389. var halfWidth = engine.getRenderWidth() / 2.0;
  390. var halfHeight = engine.getRenderHeight() / 2.0;
  391. if (scene.useRightHandedSystem) {
  392. Matrix.OrthoOffCenterRHToRef(this.orthoLeft || -halfWidth,
  393. this.orthoRight || halfWidth,
  394. this.orthoBottom || -halfHeight,
  395. this.orthoTop || halfHeight,
  396. this.minZ,
  397. this.maxZ,
  398. this._projectionMatrix);
  399. } else {
  400. Matrix.OrthoOffCenterLHToRef(this.orthoLeft || -halfWidth,
  401. this.orthoRight || halfWidth,
  402. this.orthoBottom || -halfHeight,
  403. this.orthoTop || halfHeight,
  404. this.minZ,
  405. this.maxZ,
  406. this._projectionMatrix);
  407. }
  408. }
  409. this.onProjectionMatrixChangedObservable.notifyObservers(this);
  410. return this._projectionMatrix;
  411. }
  412. public getTranformationMatrix(): Matrix {
  413. this._computedViewMatrix.multiplyToRef(this._projectionMatrix, this._transformMatrix);
  414. return this._transformMatrix;
  415. }
  416. private updateFrustumPlanes(): void {
  417. if (!this._refreshFrustumPlanes) {
  418. return;
  419. }
  420. this.getTranformationMatrix();
  421. if (!this._frustumPlanes) {
  422. this._frustumPlanes = Frustum.GetPlanes(this._transformMatrix);
  423. } else {
  424. Frustum.GetPlanesToRef(this._transformMatrix, this._frustumPlanes);
  425. }
  426. this._refreshFrustumPlanes = false;
  427. }
  428. public isInFrustum(target: ICullable): boolean {
  429. this.updateFrustumPlanes();
  430. return target.isInFrustum(this._frustumPlanes);
  431. }
  432. public isCompletelyInFrustum(target: ICullable): boolean {
  433. this.updateFrustumPlanes();
  434. return target.isCompletelyInFrustum(this._frustumPlanes);
  435. }
  436. public getForwardRay(length = 100, transform?: Matrix, origin?: Vector3): Ray {
  437. if (!transform) {
  438. transform = this.getWorldMatrix();
  439. }
  440. if (!origin) {
  441. origin = this.position;
  442. }
  443. var forward = new BABYLON.Vector3(0, 0, 1);
  444. var forwardWorld = BABYLON.Vector3.TransformNormal(forward, transform);
  445. var direction = BABYLON.Vector3.Normalize(forwardWorld);
  446. return new Ray(origin, direction, length);
  447. }
  448. public dispose(): void {
  449. // Observables
  450. this.onViewMatrixChangedObservable.clear();
  451. this.onProjectionMatrixChangedObservable.clear();
  452. this.onAfterCheckInputsObservable.clear();
  453. // Inputs
  454. if (this.inputs) {
  455. this.inputs.clear();
  456. }
  457. // Animations
  458. this.getScene().stopAnimation(this);
  459. // Remove from scene
  460. this.getScene().removeCamera(this);
  461. while (this._rigCameras.length > 0) {
  462. this._rigCameras.pop().dispose();
  463. }
  464. // Postprocesses
  465. var i = this._postProcesses.length;
  466. while (--i >= 0) {
  467. this._postProcesses[i].dispose(this);
  468. }
  469. // Render targets
  470. var i = this.customRenderTargets.length;
  471. while (--i >= 0) {
  472. this.customRenderTargets[i].dispose();
  473. }
  474. this.customRenderTargets = [];
  475. // Active Meshes
  476. this._activeMeshes.dispose();
  477. super.dispose();
  478. }
  479. // ---- Camera rigs section ----
  480. public get leftCamera(): FreeCamera {
  481. if (this._rigCameras.length < 1) {
  482. return undefined;
  483. }
  484. return (<FreeCamera>this._rigCameras[0]);
  485. }
  486. public get rightCamera(): FreeCamera {
  487. if (this._rigCameras.length < 2) {
  488. return undefined;
  489. }
  490. return (<FreeCamera>this._rigCameras[1]);
  491. }
  492. public getLeftTarget(): Vector3 {
  493. if (this._rigCameras.length < 1) {
  494. return undefined;
  495. }
  496. return (<TargetCamera>this._rigCameras[0]).getTarget();
  497. }
  498. public getRightTarget(): Vector3 {
  499. if (this._rigCameras.length < 2) {
  500. return undefined;
  501. }
  502. return (<TargetCamera>this._rigCameras[1]).getTarget();
  503. }
  504. public setCameraRigMode(mode: number, rigParams: any): void {
  505. while (this._rigCameras.length > 0) {
  506. this._rigCameras.pop().dispose();
  507. }
  508. this.cameraRigMode = mode;
  509. this._cameraRigParams = {};
  510. //we have to implement stereo camera calcultating left and right viewpoints from interaxialDistance and target,
  511. //not from a given angle as it is now, but until that complete code rewriting provisional stereoHalfAngle value is introduced
  512. this._cameraRigParams.interaxialDistance = rigParams.interaxialDistance || 0.0637;
  513. this._cameraRigParams.stereoHalfAngle = BABYLON.Tools.ToRadians(this._cameraRigParams.interaxialDistance / 0.0637);
  514. // create the rig cameras, unless none
  515. if (this.cameraRigMode !== Camera.RIG_MODE_NONE) {
  516. this._rigCameras.push(this.createRigCamera(this.name + "_L", 0));
  517. this._rigCameras.push(this.createRigCamera(this.name + "_R", 1));
  518. }
  519. switch (this.cameraRigMode) {
  520. case Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH:
  521. this._rigCameras[0]._rigPostProcess = new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]);
  522. this._rigCameras[1]._rigPostProcess = new AnaglyphPostProcess(this.name + "_anaglyph", 1.0, this._rigCameras);
  523. break;
  524. case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL:
  525. case Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED:
  526. case Camera.RIG_MODE_STEREOSCOPIC_OVERUNDER:
  527. var isStereoscopicHoriz = this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_PARALLEL || this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_SIDEBYSIDE_CROSSEYED;
  528. this._rigCameras[0]._rigPostProcess = new PassPostProcess(this.name + "_passthru", 1.0, this._rigCameras[0]);
  529. this._rigCameras[1]._rigPostProcess = new StereoscopicInterlacePostProcess(this.name + "_stereoInterlace", this._rigCameras, isStereoscopicHoriz);
  530. break;
  531. case Camera.RIG_MODE_VR:
  532. var metrics = rigParams.vrCameraMetrics || VRCameraMetrics.GetDefault();
  533. this._rigCameras[0]._cameraRigParams.vrMetrics = metrics;
  534. this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
  535. this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
  536. this._rigCameras[0]._cameraRigParams.vrHMatrix = metrics.leftHMatrix;
  537. this._rigCameras[0]._cameraRigParams.vrPreViewMatrix = metrics.leftPreViewMatrix;
  538. this._rigCameras[0].getProjectionMatrix = this._rigCameras[0]._getVRProjectionMatrix;
  539. this._rigCameras[1]._cameraRigParams.vrMetrics = metrics;
  540. this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
  541. this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
  542. this._rigCameras[1]._cameraRigParams.vrHMatrix = metrics.rightHMatrix;
  543. this._rigCameras[1]._cameraRigParams.vrPreViewMatrix = metrics.rightPreViewMatrix;
  544. this._rigCameras[1].getProjectionMatrix = this._rigCameras[1]._getVRProjectionMatrix;
  545. if (metrics.compensateDistortion) {
  546. this._rigCameras[0]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Left", this._rigCameras[0], false, metrics);
  547. this._rigCameras[1]._rigPostProcess = new VRDistortionCorrectionPostProcess("VR_Distort_Compensation_Right", this._rigCameras[1], true, metrics);
  548. }
  549. break;
  550. case Camera.RIG_MODE_WEBVR:
  551. if (rigParams.vrDisplay) {
  552. var leftEye = rigParams.vrDisplay.getEyeParameters('left');
  553. var rightEye = rigParams.vrDisplay.getEyeParameters('right');
  554. //Left eye
  555. this._rigCameras[0].viewport = new Viewport(0, 0, 0.5, 1.0);
  556. this._rigCameras[0].setCameraRigParameter("left", true);
  557. this._rigCameras[0].setCameraRigParameter("specs", rigParams.specs);
  558. this._rigCameras[0].setCameraRigParameter("eyeParameters", leftEye);
  559. this._rigCameras[0].setCameraRigParameter("frameData", rigParams.frameData);
  560. this._rigCameras[0].setCameraRigParameter("parentCamera", rigParams.parentCamera);
  561. this._rigCameras[0]._cameraRigParams.vrWorkMatrix = new Matrix();
  562. this._rigCameras[0].getProjectionMatrix = this._getWebVRProjectionMatrix;
  563. this._rigCameras[0].parent = this;
  564. this._rigCameras[0]._getViewMatrix = this._getWebVRViewMatrix;
  565. //Right eye
  566. this._rigCameras[1].viewport = new Viewport(0.5, 0, 0.5, 1.0);
  567. this._rigCameras[1].setCameraRigParameter('eyeParameters', rightEye);
  568. this._rigCameras[1].setCameraRigParameter("specs", rigParams.specs);
  569. this._rigCameras[1].setCameraRigParameter("frameData", rigParams.frameData);
  570. this._rigCameras[1].setCameraRigParameter("parentCamera", rigParams.parentCamera);
  571. this._rigCameras[1]._cameraRigParams.vrWorkMatrix = new Matrix();
  572. this._rigCameras[1].getProjectionMatrix = this._getWebVRProjectionMatrix;
  573. this._rigCameras[1].parent = this;
  574. this._rigCameras[1]._getViewMatrix = this._getWebVRViewMatrix;
  575. }
  576. break;
  577. }
  578. this._cascadePostProcessesToRigCams();
  579. this.
  580. update();
  581. }
  582. private _getVRProjectionMatrix(): Matrix {
  583. Matrix.PerspectiveFovLHToRef(this._cameraRigParams.vrMetrics.aspectRatioFov, this._cameraRigParams.vrMetrics.aspectRatio, this.minZ, this.maxZ, this._cameraRigParams.vrWorkMatrix);
  584. this._cameraRigParams.vrWorkMatrix.multiplyToRef(this._cameraRigParams.vrHMatrix, this._projectionMatrix);
  585. return this._projectionMatrix;
  586. }
  587. protected _updateCameraRotationMatrix() {
  588. //Here for WebVR
  589. }
  590. protected _updateWebVRCameraRotationMatrix() {
  591. //Here for WebVR
  592. }
  593. /**
  594. * This function MUST be overwritten by the different WebVR cameras available.
  595. * The context in which it is running is the RIG camera. So 'this' is the TargetCamera, left or right.
  596. */
  597. protected _getWebVRProjectionMatrix(): Matrix {
  598. return Matrix.Identity();
  599. }
  600. /**
  601. * This function MUST be overwritten by the different WebVR cameras available.
  602. * The context in which it is running is the RIG camera. So 'this' is the TargetCamera, left or right.
  603. */
  604. protected _getWebVRViewMatrix(): Matrix {
  605. return Matrix.Identity();
  606. }
  607. public setCameraRigParameter(name: string, value: any) {
  608. if (!this._cameraRigParams) {
  609. this._cameraRigParams = {};
  610. }
  611. this._cameraRigParams[name] = value;
  612. //provisionnally:
  613. if (name === "interaxialDistance") {
  614. this._cameraRigParams.stereoHalfAngle = Tools.ToRadians(value / 0.0637);
  615. }
  616. }
  617. /**
  618. * needs to be overridden by children so sub has required properties to be copied
  619. */
  620. public createRigCamera(name: string, cameraIndex: number): Camera {
  621. return null;
  622. }
  623. /**
  624. * May need to be overridden by children
  625. */
  626. public _updateRigCameras() {
  627. for (var i = 0; i < this._rigCameras.length; i++) {
  628. this._rigCameras[i].minZ = this.minZ;
  629. this._rigCameras[i].maxZ = this.maxZ;
  630. this._rigCameras[i].fov = this.fov;
  631. }
  632. // only update viewport when ANAGLYPH
  633. if (this.cameraRigMode === Camera.RIG_MODE_STEREOSCOPIC_ANAGLYPH) {
  634. this._rigCameras[0].viewport = this._rigCameras[1].viewport = this.viewport;
  635. }
  636. }
  637. public _setupInputs() {
  638. }
  639. public serialize(): any {
  640. var serializationObject = SerializationHelper.Serialize(this);
  641. // Type
  642. serializationObject.type = this.getClassName();
  643. // Parent
  644. if (this.parent) {
  645. serializationObject.parentId = this.parent.id;
  646. }
  647. if (this.inputs) {
  648. this.inputs.serialize(serializationObject);
  649. }
  650. // Animations
  651. Animation.AppendSerializedAnimations(this, serializationObject);
  652. serializationObject.ranges = this.serializeAnimationRanges();
  653. return serializationObject;
  654. }
  655. public clone(name: string): Camera {
  656. return SerializationHelper.Clone(Camera.GetConstructorFromName(this.getClassName(), name, this.getScene(), this.interaxialDistance, this.isStereoscopicSideBySide), this);
  657. }
  658. public getDirection(localAxis: Vector3): Vector3 {
  659. var result = Vector3.Zero();
  660. this.getDirectionToRef(localAxis, result);
  661. return result;
  662. }
  663. public getDirectionToRef(localAxis: Vector3, result: Vector3): void {
  664. Vector3.TransformNormalToRef(localAxis, this.getWorldMatrix(), result);
  665. }
  666. static GetConstructorFromName(type: string, name: string, scene: Scene, interaxial_distance: number = 0, isStereoscopicSideBySide: boolean = true): () => Camera {
  667. switch (type) {
  668. case "ArcRotateCamera":
  669. return () => new ArcRotateCamera(name, 0, 0, 1.0, Vector3.Zero(), scene);
  670. case "DeviceOrientationCamera":
  671. return () => new DeviceOrientationCamera(name, Vector3.Zero(), scene);
  672. case "FollowCamera":
  673. return () => new FollowCamera(name, Vector3.Zero(), scene);
  674. case "ArcFollowCamera":
  675. return () => new ArcFollowCamera(name, 0, 0, 1.0, null, scene);
  676. case "GamepadCamera":
  677. return () => new GamepadCamera(name, Vector3.Zero(), scene);
  678. case "TouchCamera":
  679. return () => new TouchCamera(name, Vector3.Zero(), scene);
  680. case "VirtualJoysticksCamera":
  681. return () => new VirtualJoysticksCamera(name, Vector3.Zero(), scene);
  682. case "WebVRFreeCamera":
  683. return () => new WebVRFreeCamera(name, Vector3.Zero(), scene);
  684. case "WebVRGamepadCamera":
  685. return () => new WebVRFreeCamera(name, Vector3.Zero(), scene);
  686. case "VRDeviceOrientationFreeCamera":
  687. return () => new VRDeviceOrientationFreeCamera(name, Vector3.Zero(), scene);
  688. case "VRDeviceOrientationGamepadCamera":
  689. return () => new VRDeviceOrientationGamepadCamera(name, Vector3.Zero(), scene);
  690. case "AnaglyphArcRotateCamera":
  691. return () => new AnaglyphArcRotateCamera(name, 0, 0, 1.0, Vector3.Zero(), interaxial_distance, scene);
  692. case "AnaglyphFreeCamera":
  693. return () => new AnaglyphFreeCamera(name, Vector3.Zero(), interaxial_distance, scene);
  694. case "AnaglyphGamepadCamera":
  695. return () => new AnaglyphGamepadCamera(name, Vector3.Zero(), interaxial_distance, scene);
  696. case "AnaglyphUniversalCamera":
  697. return () => new AnaglyphUniversalCamera(name, Vector3.Zero(), interaxial_distance, scene);
  698. case "StereoscopicArcRotateCamera":
  699. return () => new StereoscopicArcRotateCamera(name, 0, 0, 1.0, Vector3.Zero(), interaxial_distance, isStereoscopicSideBySide, scene);
  700. case "StereoscopicFreeCamera":
  701. return () => new StereoscopicFreeCamera(name, Vector3.Zero(), interaxial_distance, isStereoscopicSideBySide, scene);
  702. case "StereoscopicGamepadCamera":
  703. return () => new StereoscopicGamepadCamera(name, Vector3.Zero(), interaxial_distance, isStereoscopicSideBySide, scene);
  704. case "StereoscopicUniversalCamera":
  705. return () => new StereoscopicUniversalCamera(name, Vector3.Zero(), interaxial_distance, isStereoscopicSideBySide, scene);
  706. case "FreeCamera": // Forcing Universal here
  707. return () => new UniversalCamera(name, Vector3.Zero(), scene);
  708. default: // Universal Camera is the default value
  709. return () => new UniversalCamera(name, Vector3.Zero(), scene);
  710. }
  711. }
  712. public static Parse(parsedCamera: any, scene: Scene): Camera {
  713. var type = parsedCamera.type;
  714. var construct = Camera.GetConstructorFromName(type, parsedCamera.name, scene, parsedCamera.interaxial_distance, parsedCamera.isStereoscopicSideBySide);
  715. var camera = SerializationHelper.Parse(construct, parsedCamera, scene);
  716. // Parent
  717. if (parsedCamera.parentId) {
  718. camera._waitingParentId = parsedCamera.parentId;
  719. }
  720. //If camera has an input manager, let it parse inputs settings
  721. if (camera.inputs) {
  722. camera.inputs.parse(parsedCamera);
  723. camera._setupInputs();
  724. }
  725. if ((<any>camera).setPosition) { // need to force position
  726. camera.position.copyFromFloats(0, 0, 0);
  727. (<any>camera).setPosition(Vector3.FromArray(parsedCamera.position));
  728. }
  729. // Target
  730. if (parsedCamera.target) {
  731. if ((<any>camera).setTarget) {
  732. (<any>camera).setTarget(Vector3.FromArray(parsedCamera.target));
  733. }
  734. }
  735. // Apply 3d rig, when found
  736. if (parsedCamera.cameraRigMode) {
  737. var rigParams = (parsedCamera.interaxial_distance) ? { interaxialDistance: parsedCamera.interaxial_distance } : {};
  738. camera.setCameraRigMode(parsedCamera.cameraRigMode, rigParams);
  739. }
  740. // Animations
  741. if (parsedCamera.animations) {
  742. for (var animationIndex = 0; animationIndex < parsedCamera.animations.length; animationIndex++) {
  743. var parsedAnimation = parsedCamera.animations[animationIndex];
  744. camera.animations.push(Animation.Parse(parsedAnimation));
  745. }
  746. Node.ParseAnimationRanges(camera, parsedCamera, scene);
  747. }
  748. if (parsedCamera.autoAnimate) {
  749. scene.beginAnimation(camera, parsedCamera.autoAnimateFrom, parsedCamera.autoAnimateTo, parsedCamera.autoAnimateLoop, parsedCamera.autoAnimateSpeed || 1.0);
  750. }
  751. return camera;
  752. }
  753. }
  754. }