0
votes

I am rendering a scene using three.js that needs multiple post-processing passes. Most of those steps need the depth buffer. My plan was to first render all visible objects to obtain the color and depth and then render all post-processing passes using 2 framebuffers which are alternating read and write framebuffers. The passes are just examples:

  1. Render Objects -> FB0
  2. DistortionPass, taking FB0 as input -> FB1
  3. GodrayPass, taking FB1 as input -> FB0
  4. SSAOPass, taking FB0 as input -> screen

The GodrayPass needs to read the depth of the first render pass, therefore I need to bind the depth texture and it should not be the one bound to FB0, otherwise it would lead to a feedback loop, since that shader is writing to FB0.

I think it would make sense to copy the depth into a separate texture after rendering the objects, so I can bind this texture whenever needed in a pass without worrying about a feedback loop.

However,

  • copyTexImage2D seem to not support copying from the depth buffer.
  • using a shader to pack the depth buffer after the first pass into an RGBA8 texture would require every pass to "unpack" the float again
  • render all objects again using a shader that output the depth to the color buffer? Would require packing or precision loss again.

What is the best practice here? Am I on the right path?

I can make use of WebGL 2.0 (OpenGL ES 3.0), but would like to avoid using unpopular extensions.

1
which are you using, Three.js or WebGL? They are not the same, require people with entirely different knowledge to answer, and the answers will be totally different - gman
I am using Three.js utilizing the WebGL renderer, however I am willed to modify three.js if needed - Bastian Born

1 Answers

2
votes

Three.js doesn't call them FB's, it calls them RenderTargets. For webgl they are WebGLRenderTarget

https://threejs.org/docs/#api/en/renderers/WebGLRenderTarget

This example show setting up a depth texture with a render target

target = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight );
target.texture.format = THREE.RGBFormat;
target.texture.minFilter = THREE.NearestFilter;
target.texture.magFilter = THREE.NearestFilter;
target.texture.generateMipmaps = false;
target.stencilBuffer = false;
target.depthBuffer = true;
target.depthTexture = new THREE.DepthTexture();
target.depthTexture.format = THREE.DepthFormat;
target.depthTexture.type = THREE.UnsignedShortType;

And this article shows rendering to render targets. And this article shows rendering to render targets for the purposes of post processing using EffectComposer and Pass three.js objects.

So, just make 3 render targets

RT0 = color + depth
RT1 = color
RT2 = color

Then setup Pass objects such that

Render Objects -> RT0(color+depth)
DistortionPass, taking RT0(color) as input -> RT1(color)
GodrayPass, taking RT1(color) + RT0(depth) as input -> RT2(color)
SSAOPass, taking RT2(color as input -> screen