diff --git a/src/extras/render-passes/render-pass-camera-frame.js b/src/extras/render-passes/render-pass-camera-frame.js index 73717b30024..03f2f2e6e02 100644 --- a/src/extras/render-passes/render-pass-camera-frame.js +++ b/src/extras/render-passes/render-pass-camera-frame.js @@ -235,7 +235,8 @@ class RenderPassCameraFrame extends RenderPass { this.rt = new RenderTarget({ colorBuffer: this.sceneTexture, depthBuffer: this.sceneDepth, - samples: options.samples + samples: options.samples, + flipY: !!targetRenderTarget?.flipY // flipY is inherited from the target renderTarget }); this.sceneOptions = { @@ -335,9 +336,17 @@ class RenderPassCameraFrame extends RenderPass { this.scenePassTransparent.init(this.rt); ret.lastAddedIndex = this.scenePassTransparent.addLayers(composition, cameraComponent, ret.lastAddedIndex, ret.clearRenderTarget, options.lastSceneLayerId, options.lastSceneLayerIsTransparent); - // if prepass is enabled, we need to store the depth, as by default it gets discarded - if (options.prepassEnabled) { - this.scenePassTransparent.depthStencilOps.storeDepth = true; + // if no layers are rendered by this pass, remove it + if (!this.scenePassTransparent.rendersAnything) { + this.scenePassTransparent.destroy(); + this.scenePassTransparent = null; + } + + if (this.scenePassTransparent) { + // if prepass is enabled, we need to store the depth, as by default it gets discarded + if (options.prepassEnabled) { + this.scenePassTransparent.depthStencilOps.storeDepth = true; + } } } diff --git a/src/framework/components/camera/component.js b/src/framework/components/camera/component.js index 3020ff19aa5..25ad2bcfd8e 100644 --- a/src/framework/components/camera/component.js +++ b/src/framework/components/camera/component.js @@ -231,13 +231,13 @@ class CameraComponent extends Component { /** * Sets the render passes the camera uses for rendering, instead of its default rendering. - * Set this to an empty array to return to the default behavior. + * Set this to null to return to the default behavior. * - * @type {RenderPass[]} + * @type {RenderPass[]|null} * @ignore */ set renderPasses(passes) { - this._camera.renderPasses = passes; + this._camera.renderPasses = passes || []; this.dirtyLayerCompositionCameras(); this.system.app.scene.updateShaders = true; } @@ -840,6 +840,13 @@ class CameraComponent extends Component { * @type {RenderTarget} */ set renderTarget(value) { + + Debug.call(() => { + if (this._camera.renderPasses.length > 0) { + Debug.warn(`Setting a render target on the camera ${this.entity.name} after the render passes is not supported, set it up first.`); + } + }); + this._camera.renderTarget = value; this.dirtyLayerCompositionCameras(); } diff --git a/src/scene/composition/layer-composition.js b/src/scene/composition/layer-composition.js index 00faddd7c19..b3a19b93a1f 100644 --- a/src/scene/composition/layer-composition.js +++ b/src/scene/composition/layer-composition.js @@ -626,9 +626,13 @@ class LayerComposition extends EventHandler { } isEnabled(layer, transparent) { - const index = transparent ? this.getTransparentIndex(layer) : this.getOpaqueIndex(layer); - Debug.assert(index >= 0, `${transparent ? 'Transparent' : 'Opaque'} layer ${layer.name} is not part of the composition.`); - return this.subLayerEnabled[index]; + if (layer.enabled) { + const index = transparent ? this.getTransparentIndex(layer) : this.getOpaqueIndex(layer); + if (index >= 0) { + return this.subLayerEnabled[index]; + } + } + return false; } /** diff --git a/src/scene/renderer/forward-renderer.js b/src/scene/renderer/forward-renderer.js index 8a4486eef18..0ebce7173d0 100644 --- a/src/scene/renderer/forward-renderer.js +++ b/src/scene/renderer/forward-renderer.js @@ -868,6 +868,12 @@ class ForwardRenderer extends Renderer { if (renderAction.useCameraPasses) { + Debug.call(() => { + if (camera.postEffects.effects.length > 0) { + Debug.warnOnce(`Camera '${camera.entity.name}' uses render passes, which are not compatible with post-effects scripts. Rendering of the post-effects is ignored, but they should not be attached to the camera.`); + } + }); + // schedule render passes from the camera camera.camera.renderPasses.forEach((renderPass) => { frameGraph.addRenderPass(renderPass); diff --git a/src/scene/renderer/render-pass-forward.js b/src/scene/renderer/render-pass-forward.js index 8037a683496..50d41d06b2a 100644 --- a/src/scene/renderer/render-pass-forward.js +++ b/src/scene/renderer/render-pass-forward.js @@ -58,6 +58,10 @@ class RenderPassForward extends RenderPass { this.renderer = renderer; } + get rendersAnything() { + return this.renderActions.length > 0; + } + addRenderAction(renderAction) { this.renderActions.push(renderAction); } @@ -96,8 +100,8 @@ class RenderPassForward extends RenderPass { /** * Adds layers to be rendered by this render pass, starting from the given index of the layer * in the layer composition, till the end of the layer list, or till the last layer with the - * given id and transparency is reached (inclusive). Note that only layers that are enabled - * and are rendered by the specified camera are added. + * given id and transparency is reached (inclusive). Note that only layers that are rendered by + * the specified camera are added. * * @param {LayerComposition} composition - The layer composition containing the layers to be * added, typically the scene layer composition. @@ -114,7 +118,7 @@ class RenderPassForward extends RenderPass { */ addLayers(composition, cameraComponent, startIndex, firstLayerClears, lastLayerId, lastLayerIsTransparent = true) { - const { layerList, subLayerEnabled, subLayerList } = composition; + const { layerList, subLayerList } = composition; let clearRenderTarget = firstLayerClears; let index = startIndex; @@ -122,11 +126,10 @@ class RenderPassForward extends RenderPass { const layer = layerList[index]; const isTransparent = subLayerList[index]; - const enabled = layer.enabled && subLayerEnabled[index]; - const renderedbyCamera = cameraComponent.camera.layersSet.has(layer.id); + const renderedByCamera = cameraComponent.camera.layersSet.has(layer.id); // add it for rendering - if (enabled && renderedbyCamera) { + if (renderedByCamera) { this.addLayer(cameraComponent, layer, isTransparent, clearRenderTarget); clearRenderTarget = false; } @@ -211,7 +214,16 @@ class RenderPassForward extends RenderPass { const { layerComposition, renderActions } = this; for (let i = 0; i < renderActions.length; i++) { const ra = renderActions[i]; - if (layerComposition.isEnabled(ra.layer, ra.transparent)) { + const layer = ra.layer; + + Debug.call(() => { + const compLayer = layerComposition.getLayerByName(layer.name); + if (!compLayer) { + Debug.warnOnce(`Layer ${layer.name} is not found in the scene and will not be rendered. Your render pass setup might need to be updated.`); + } + }); + + if (layerComposition.isEnabled(layer, ra.transparent)) { this.renderRenderAction(ra, i === 0); } }