engine.multiview.ts 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { Camera } from "../../Cameras/camera";
  2. import { Engine } from "../../Engines/engine";
  3. import { Scene } from "../../scene";
  4. import { InternalTexture, InternalTextureSource } from '../../Materials/Textures/internalTexture';
  5. import { Nullable } from '../../types';
  6. import { RenderTargetTexture } from '../../Materials/Textures/renderTargetTexture';
  7. import { Matrix, TmpVectors } from '../../Maths/math.vector';
  8. import { UniformBuffer } from '../../Materials/uniformBuffer';
  9. import { MultiviewRenderTarget } from '../../Materials/Textures/MultiviewRenderTarget';
  10. import { Frustum } from '../../Maths/math.frustum';
  11. declare module "../../Engines/engine" {
  12. export interface Engine {
  13. /**
  14. * Creates a new multiview render target
  15. * @param width defines the width of the texture
  16. * @param height defines the height of the texture
  17. * @returns the created multiview texture
  18. */
  19. createMultiviewRenderTargetTexture(width: number, height: number): InternalTexture;
  20. /**
  21. * Binds a multiview framebuffer to be drawn to
  22. * @param multiviewTexture texture to bind
  23. */
  24. bindMultiviewFramebuffer(multiviewTexture: InternalTexture): void;
  25. }
  26. }
  27. Engine.prototype.createMultiviewRenderTargetTexture = function(width: number, height: number) {
  28. var gl = this._gl;
  29. if (!this.getCaps().multiview) {
  30. throw "Multiview is not supported";
  31. }
  32. var internalTexture = new InternalTexture(this, InternalTextureSource.Unknown, true);
  33. internalTexture.width = width;
  34. internalTexture.height = height;
  35. internalTexture._framebuffer = gl.createFramebuffer();
  36. internalTexture._colorTextureArray = gl.createTexture();
  37. gl.bindTexture(gl.TEXTURE_2D_ARRAY, internalTexture._colorTextureArray);
  38. (gl as any).texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, 2);
  39. internalTexture._depthStencilTextureArray = gl.createTexture();
  40. gl.bindTexture(gl.TEXTURE_2D_ARRAY, internalTexture._depthStencilTextureArray);
  41. (gl as any).texStorage3D(gl.TEXTURE_2D_ARRAY, 1, (gl as any).DEPTH32F_STENCIL8, width, height, 2);
  42. internalTexture.isReady = true;
  43. return internalTexture;
  44. };
  45. Engine.prototype.bindMultiviewFramebuffer = function(multiviewTexture: InternalTexture) {
  46. var gl: any = this._gl;
  47. var ext = this.getCaps().oculusMultiview || this.getCaps().multiview;
  48. this.bindFramebuffer(multiviewTexture, undefined, undefined, undefined, true);
  49. gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, multiviewTexture._framebuffer);
  50. if (multiviewTexture._colorTextureArray && multiviewTexture._depthStencilTextureArray) {
  51. if (this.getCaps().oculusMultiview) {
  52. ext.framebufferTextureMultisampleMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, multiviewTexture._colorTextureArray, 0, multiviewTexture.samples, 0, 2);
  53. ext.framebufferTextureMultisampleMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, multiviewTexture._depthStencilTextureArray, 0, multiviewTexture.samples, 0, 2);
  54. } else {
  55. ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, multiviewTexture._colorTextureArray, 0, 0, 2);
  56. ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, multiviewTexture._depthStencilTextureArray, 0, 0, 2);
  57. }
  58. } else {
  59. throw "Invalid multiview frame buffer";
  60. }
  61. };
  62. declare module "../../Cameras/camera" {
  63. export interface Camera {
  64. /**
  65. * @hidden
  66. * For cameras that cannot use multiview images to display directly. (e.g. webVR camera will render to multiview texture, then copy to each eye texture and go from there)
  67. */
  68. _useMultiviewToSingleView: boolean;
  69. /**
  70. * @hidden
  71. * For cameras that cannot use multiview images to display directly. (e.g. webVR camera will render to multiview texture, then copy to each eye texture and go from there)
  72. */
  73. _multiviewTexture: Nullable<RenderTargetTexture>;
  74. /**
  75. * @hidden
  76. * ensures the multiview texture of the camera exists and has the specified width/height
  77. * @param width height to set on the multiview texture
  78. * @param height width to set on the multiview texture
  79. */
  80. _resizeOrCreateMultiviewTexture(width: number, height: number): void;
  81. }
  82. }
  83. Camera.prototype._useMultiviewToSingleView = false;
  84. Camera.prototype._multiviewTexture = null;
  85. Camera.prototype._resizeOrCreateMultiviewTexture = function(width: number, height: number) {
  86. if (!this._multiviewTexture) {
  87. this._multiviewTexture = new MultiviewRenderTarget(this.getScene(), { width: width, height: height });
  88. } else if (this._multiviewTexture.getRenderWidth() != width || this._multiviewTexture.getRenderHeight() != height) {
  89. this._multiviewTexture.dispose();
  90. this._multiviewTexture = new MultiviewRenderTarget(this.getScene(), { width: width, height: height });
  91. }
  92. };
  93. declare module "../../scene" {
  94. export interface Scene {
  95. /** @hidden */
  96. _transformMatrixR: Matrix;
  97. /** @hidden */
  98. _multiviewSceneUbo: Nullable<UniformBuffer>;
  99. /** @hidden */
  100. _createMultiviewUbo(): void;
  101. /** @hidden */
  102. _updateMultiviewUbo(viewR?: Matrix, projectionR?: Matrix): void;
  103. /** @hidden */
  104. _renderMultiviewToSingleView(camera: Camera): void;
  105. }
  106. }
  107. Scene.prototype._transformMatrixR = Matrix.Zero();
  108. Scene.prototype._multiviewSceneUbo = null;
  109. Scene.prototype._createMultiviewUbo = function() {
  110. this._multiviewSceneUbo = new UniformBuffer(this.getEngine(), undefined, true);
  111. this._multiviewSceneUbo.addUniform("viewProjection", 16);
  112. this._multiviewSceneUbo.addUniform("viewProjectionR", 16);
  113. this._multiviewSceneUbo.addUniform("view", 16);
  114. };
  115. Scene.prototype._updateMultiviewUbo = function(viewR?: Matrix, projectionR?: Matrix) {
  116. if (viewR && projectionR) {
  117. viewR.multiplyToRef(projectionR, this._transformMatrixR);
  118. }
  119. if (viewR && projectionR) {
  120. viewR.multiplyToRef(projectionR, TmpVectors.Matrix[0]);
  121. Frustum.GetRightPlaneToRef(TmpVectors.Matrix[0], this._frustumPlanes[3]); // Replace right plane by second camera right plane
  122. }
  123. if (this._multiviewSceneUbo) {
  124. this._multiviewSceneUbo.updateMatrix("viewProjection", this.getTransformMatrix());
  125. this._multiviewSceneUbo.updateMatrix("viewProjectionR", this._transformMatrixR);
  126. this._multiviewSceneUbo.updateMatrix("view", this._viewMatrix);
  127. this._multiviewSceneUbo.update();
  128. }
  129. };
  130. Scene.prototype._renderMultiviewToSingleView = function(camera: Camera) {
  131. // Multiview is only able to be displayed directly for API's such as webXR
  132. // This displays a multiview image by rendering to the multiview image and then
  133. // copying the result into the sub cameras instead of rendering them and proceeding as normal from there
  134. // Render to a multiview texture
  135. camera._resizeOrCreateMultiviewTexture(
  136. (camera._rigPostProcess && camera._rigPostProcess && camera._rigPostProcess.width > 0) ? camera._rigPostProcess.width : this.getEngine().getRenderWidth(true),
  137. (camera._rigPostProcess && camera._rigPostProcess && camera._rigPostProcess.height > 0) ? camera._rigPostProcess.height : this.getEngine().getRenderHeight(true)
  138. );
  139. if (!this._multiviewSceneUbo) {
  140. this._createMultiviewUbo();
  141. }
  142. camera.outputRenderTarget = camera._multiviewTexture;
  143. this._renderForCamera(camera);
  144. camera.outputRenderTarget = null;
  145. // Consume the multiview texture through a shader for each eye
  146. for (var index = 0; index < camera._rigCameras.length; index++) {
  147. var engine = this.getEngine();
  148. this._activeCamera = camera._rigCameras[index];
  149. engine.setViewport(this._activeCamera.viewport);
  150. if (this.postProcessManager) {
  151. this.postProcessManager._prepareFrame();
  152. this.postProcessManager._finalizeFrame(this._activeCamera.isIntermediate);
  153. }
  154. }
  155. };