Skip to content

Commit

Permalink
Improvement to layer handling by render passes (#7001)
Browse files Browse the repository at this point in the history
* Improvement to layer handling by render passes

* log warning when post-effects are used together with render passes

* variable name

* warning when render target is set up after render passes

* handle the flipY class

---------

Co-authored-by: Martin Valigursky <[email protected]>
  • Loading branch information
mvaligursky and Martin Valigursky authored Oct 1, 2024
1 parent 9a587d2 commit e8aa2d6
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 17 deletions.
17 changes: 13 additions & 4 deletions src/extras/render-passes/render-pass-camera-frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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;
}
}
}

Expand Down
13 changes: 10 additions & 3 deletions src/framework/components/camera/component.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();
}
Expand Down
10 changes: 7 additions & 3 deletions src/scene/composition/layer-composition.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/**
Expand Down
6 changes: 6 additions & 0 deletions src/scene/renderer/forward-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
26 changes: 19 additions & 7 deletions src/scene/renderer/render-pass-forward.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ class RenderPassForward extends RenderPass {
this.renderer = renderer;
}

get rendersAnything() {
return this.renderActions.length > 0;
}

addRenderAction(renderAction) {
this.renderActions.push(renderAction);
}
Expand Down Expand Up @@ -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.
Expand All @@ -114,19 +118,18 @@ 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;
while (index < layerList.length) {

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;
}
Expand Down Expand Up @@ -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);
}
}
Expand Down

0 comments on commit e8aa2d6

Please sign in to comment.