import { Camera } from "../../Cameras/camera.js"; import { Engine } from "../../Engines/engine.js"; import { Scene } from "../../scene.js"; import { InternalTexture, InternalTextureSource } from "../../Materials/Textures/internalTexture.js"; import { Matrix, TmpVectors } from "../../Maths/math.vector.js"; import { UniformBuffer } from "../../Materials/uniformBuffer.js"; import { MultiviewRenderTarget } from "../../Materials/Textures/MultiviewRenderTarget.js"; import { Frustum } from "../../Maths/math.frustum.js"; Engine.prototype.createMultiviewRenderTargetTexture = function (width, height, colorTexture, depthStencilTexture) { const gl = this._gl; if (!this.getCaps().multiview) { // eslint-disable-next-line no-throw-literal throw "Multiview is not supported"; } const rtWrapper = this._createHardwareRenderTargetWrapper(false, false, { width, height }); rtWrapper._framebuffer = gl.createFramebuffer(); const internalTexture = new InternalTexture(this, InternalTextureSource.Unknown, true); internalTexture.width = width; internalTexture.height = height; internalTexture.isMultiview = true; if (!colorTexture) { colorTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D_ARRAY, colorTexture); gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.RGBA8, width, height, 2); } rtWrapper._colorTextureArray = colorTexture; if (!depthStencilTexture) { depthStencilTexture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D_ARRAY, depthStencilTexture); gl.texStorage3D(gl.TEXTURE_2D_ARRAY, 1, gl.DEPTH24_STENCIL8, width, height, 2); } rtWrapper._depthStencilTextureArray = depthStencilTexture; internalTexture.isReady = true; rtWrapper.setTextures(internalTexture); rtWrapper._depthStencilTexture = internalTexture; return rtWrapper; }; Engine.prototype.bindMultiviewFramebuffer = function (_multiviewTexture) { const multiviewTexture = _multiviewTexture; const gl = this._gl; const ext = this.getCaps().oculusMultiview || this.getCaps().multiview; this.bindFramebuffer(multiviewTexture, undefined, undefined, undefined, true); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, multiviewTexture._framebuffer); if (multiviewTexture._colorTextureArray && multiviewTexture._depthStencilTextureArray) { if (this.getCaps().oculusMultiview) { ext.framebufferTextureMultisampleMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, multiviewTexture._colorTextureArray, 0, multiviewTexture.samples, 0, 2); ext.framebufferTextureMultisampleMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, multiviewTexture._depthStencilTextureArray, 0, multiviewTexture.samples, 0, 2); } else { ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, multiviewTexture._colorTextureArray, 0, 0, 2); ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, multiviewTexture._depthStencilTextureArray, 0, 0, 2); } } else { // eslint-disable-next-line no-throw-literal throw "Invalid multiview frame buffer"; } }; Engine.prototype.bindSpaceWarpFramebuffer = function (_spaceWarpTexture) { const spaceWarpTexture = _spaceWarpTexture; const gl = this._gl; const ext = this.getCaps().oculusMultiview || this.getCaps().multiview; this.bindFramebuffer(spaceWarpTexture, undefined, undefined, undefined, true); gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, spaceWarpTexture._framebuffer); if (spaceWarpTexture._colorTextureArray && spaceWarpTexture._depthStencilTextureArray) { ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, spaceWarpTexture._colorTextureArray, 0, 0, 2); ext.framebufferTextureMultiviewOVR(gl.DRAW_FRAMEBUFFER, gl.DEPTH_ATTACHMENT, spaceWarpTexture._depthStencilTextureArray, 0, 0, 2); } else { throw new Error("Invalid Space Warp framebuffer"); } }; Camera.prototype._useMultiviewToSingleView = false; Camera.prototype._multiviewTexture = null; Camera.prototype._resizeOrCreateMultiviewTexture = function (width, height) { if (!this._multiviewTexture) { this._multiviewTexture = new MultiviewRenderTarget(this.getScene(), { width: width, height: height }); } else if (this._multiviewTexture.getRenderWidth() != width || this._multiviewTexture.getRenderHeight() != height) { this._multiviewTexture.dispose(); this._multiviewTexture = new MultiviewRenderTarget(this.getScene(), { width: width, height: height }); } }; function createMultiviewUbo(engine, name) { const ubo = new UniformBuffer(engine, undefined, true, name); ubo.addUniform("viewProjection", 16); ubo.addUniform("viewProjectionR", 16); ubo.addUniform("view", 16); ubo.addUniform("projection", 16); ubo.addUniform("vEyePosition", 4); return ubo; } const currentCreateSceneUniformBuffer = Scene.prototype.createSceneUniformBuffer; Scene.prototype._transformMatrixR = Matrix.Zero(); Scene.prototype._multiviewSceneUbo = null; Scene.prototype._createMultiviewUbo = function () { this._multiviewSceneUbo = createMultiviewUbo(this.getEngine(), "scene_multiview"); }; Scene.prototype.createSceneUniformBuffer = function (name) { if (this._multiviewSceneUbo) { return createMultiviewUbo(this.getEngine(), name); } return currentCreateSceneUniformBuffer.bind(this)(name); }; Scene.prototype._updateMultiviewUbo = function (viewR, projectionR) { if (viewR && projectionR) { viewR.multiplyToRef(projectionR, this._transformMatrixR); } if (viewR && projectionR) { viewR.multiplyToRef(projectionR, TmpVectors.Matrix[0]); Frustum.GetRightPlaneToRef(TmpVectors.Matrix[0], this._frustumPlanes[3]); // Replace right plane by second camera right plane } if (this._multiviewSceneUbo) { this._multiviewSceneUbo.updateMatrix("viewProjection", this.getTransformMatrix()); this._multiviewSceneUbo.updateMatrix("viewProjectionR", this._transformMatrixR); this._multiviewSceneUbo.updateMatrix("view", this._viewMatrix); this._multiviewSceneUbo.updateMatrix("projection", this._projectionMatrix); } }; Scene.prototype._renderMultiviewToSingleView = function (camera) { // Multiview is only able to be displayed directly for API's such as webXR // This displays a multiview image by rendering to the multiview image and then // copying the result into the sub cameras instead of rendering them and proceeding as normal from there // Render to a multiview texture camera._resizeOrCreateMultiviewTexture(camera._rigPostProcess && camera._rigPostProcess && camera._rigPostProcess.width > 0 ? camera._rigPostProcess.width : this.getEngine().getRenderWidth(true), camera._rigPostProcess && camera._rigPostProcess && camera._rigPostProcess.height > 0 ? camera._rigPostProcess.height : this.getEngine().getRenderHeight(true)); if (!this._multiviewSceneUbo) { this._createMultiviewUbo(); } camera.outputRenderTarget = camera._multiviewTexture; this._renderForCamera(camera); camera.outputRenderTarget = null; // Consume the multiview texture through a shader for each eye for (let index = 0; index < camera._rigCameras.length; index++) { const engine = this.getEngine(); this._activeCamera = camera._rigCameras[index]; engine.setViewport(this._activeCamera.viewport); if (this.postProcessManager) { this.postProcessManager._prepareFrame(); this.postProcessManager._finalizeFrame(this._activeCamera.isIntermediate); } } }; //# sourceMappingURL=engine.multiview.js.map