Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feedback loop when using DepthOfFieldEffect with multiple other effect passes #416

Closed
Ameobea opened this issue Oct 24, 2022 · 5 comments
Closed
Labels
bug Something isn't working

Comments

@Ameobea
Copy link

Ameobea commented Oct 24, 2022

Description of the bug

When using multiple passes surrounding an EffectPass that contains a DepthOfFieldEffect, chrome + firefox print errors involving feedback loops in the render graph.

Chrome error: [.WebGL-0x13400e82d80] GL_INVALID_OPERATION: Feedback loop formed between Framebuffer and active Texture.

Firefox error: WebGL warning: drawArraysInstanced: Texture level 0 would be read by TEXTURE_2D unit 1, but written by framebuffer attachment DEPTH_ATTACHMENT, which would be illegal feedback.

Interestingly, these errors only seem to happen on Mac laptop. On my Linux desktop, things work fine.

To Reproduce

Repro: https://postprocessing-dof-repro.ameo.design/

Code:

import * as THREE from "three";

import {
  SMAAEffect,
  RenderPass,
  EffectPass,
  EffectComposer,
  DepthOfFieldEffect,
} from "https://cdn.skypack.dev/pin/[email protected]/mode=imports/optimized/postprocessing.js";

const renderer = new THREE.WebGLRenderer();
document.body.append(renderer.domElement);
const composer = new EffectComposer(renderer);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(
  75,
  window.innerWidth / window.innerHeight,
  0.1,
  100
);

composer.addPass(new RenderPass(scene, camera));

composer.addPass(new EffectPass(camera, new SMAAEffect()));

composer.addPass(new EffectPass(camera, new DepthOfFieldEffect()));

composer.addPass(new EffectPass(camera, new SMAAEffect()));

function render() {
  composer.render();
  requestAnimationFrame(render);
}

render();

Expected behavior

I have a somewhat complex scene that makes use of two render passes. I render some background objects, apply some effects (notably a custom effect that makes use of depth info and then a DepthOfFieldEffect. Then, I render the foreground scene and apply a SMAAEffect at the end.

I'd like to apply the custom depth-based effect, then apply the depth of field, then render the foreground, and finally render some final effects. However, no matter what I do, I either get the feedback loop error or my custom depth-based effect does nothing.

When I include the depth-based effect in the same EffectsPass as the DepthOfFieldEffect, the custom effect is not applied. Here is a demo of that situation: https://postprocessing-dof-repro-2.ameo.design/

I'm not sure if that is expected behavior or not for that effect. I looked at the code and it appears to be a highly complex effect with many internal passes, so I'm not completely surprised it doesn't work.

However, when I include the custom effect in a separateEffectPass before the effect pass containing the DepthOfFieldPass, I get the feedback loop errors.

Note that these errors only occur on mac; this works fine on my Linux desktop.

Library versions used

  • Three: 0.145
  • Post Processing: 6.29

Desktop

  • OS: Works on Linux Debian with Mesa graphics AMD GPU, doesn't work on M1 Mac
  • Browser: Tested both Google Chrome | 108.0.5351.0 (Official Build) canary (arm64) and 106.0.1
  • Graphics hardware: works on Desktop with 5700 XT GPU, doesn't work on M1 mac with built-in GPU

Mobile

Not tested on mobile

@Ameobea
Copy link
Author

Ameobea commented Oct 24, 2022

Thank you for maintaining this awesome library btw; it's a huge step forward for Three.JS and the whole web graphics ecosystem!

@vanruesc
Copy link
Member

This is probably related to #225. I'm currently writing up a battle plan for the v7 redesign which will address this issue.

@vanruesc vanruesc added the bug Something isn't working label Oct 24, 2022
@Ameobea
Copy link
Author

Ameobea commented Oct 24, 2022

Alright cool, ty for the quick response!

Any ideas for workarounds in the meantime? Do you think it would work to copy the depth buffer to a temp render target after the background render pass, and then bind the copied buffer as a custom uniform for my custom effect?

@Ameobea
Copy link
Author

Ameobea commented Oct 24, 2022

Alright I've managed to find a workaround for this:

Use two EffectComposers. One for the background, and another for the foreground.

const bgComposer = new EffectComposer(renderer);
// \/ Uncommenting this brings back the feedback loop for some reason
// bgComposer.autoRenderToScreen = false;
bgComposer.addPass(new RenderPass(...));
const bgEffectPass = new EffectPass(camera, new DepthOfFieldPass(...));
bgEffectPass.needsSwap = false;
bgComposer.addPass(bgEffectPass);

const fgComposer = new EffectComposer(renderer);
fgComposer.inputBuffer = bgComposer.outputBuffer;
fgComposer.addPass(new RenderPass(...));
const fgEffectPass = new EffectPass(...);
fgComposer.addPass(fgEffectPass);

function render(tDiffSeconds) {
  bgComposer.render(tDiffSeconds);
  fgComposer.render(tDiffSeconds);
}

Probably suboptimal in some way be it performance or otherwise, but this allows my use-case to work!

Ameobea added a commit to Ameobea/three-good-godrays that referenced this issue Aug 29, 2023
 * Copy depth texture to intermediate buffer to prevent binding depth texture to both input and output buffers in compositor shader
 * See pmndrs/postprocessing#225, pmndrs/postprocessing#416 for additional context
@vanruesc
Copy link
Member

Closing this as it seems to be resolved.

Depth texture management is fixed in the postprocessing v7 alpha which will eventually replace v6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants