babylon.camera.ts 34 KB

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