babylon.camera.ts 34 KB

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