I’ve also implemented a custom godrays effect that works with
three-good-godrays. It creates a custom pass that is added to the postprocessing
EffectComposer which renders volumetric screen-space godrays by reading the depth buffer and shadow map for a light.
For one of my scenes, the postprocessing chain had gotten pretty long with several different effects in use. At some point, I started seeing errors like this in the JS console:
[.WebGL-0x16c00334d00]GL ERROR :GL_INVALID_OPERATION : glDrawArrays: Source and destination textures of the draw are the same.
In addition, my godrays effect stopped working. I used the Spector.JS browser extension to debug the WebGL rendering sequence for one of my frames and I saw that the shaders were getting launched, but nothing seemed to be getting rendered into the destination buffers.
As I mentioned previously, the shaders used internally by
three-good-godrays and some of the other effects in my pipeline needed access to scene depth information. The
Passes added to the
EffectComposer have a
needsDepthTexture attribute that they can set to indicate that they need access to the depth buffer. If set, the
EffectComposer will call their
setDepthTexture() method and provide them a texture containing it.
EffectComposer has two buffers that it swaps back and forth between when rendering the passes. I looked at the code and the logic looks roughly like this:
input_buffer, output_buffer = build_buffers() if any_pass_needs_depth_texture: input_buffer.bind_depth_texture(build_depth_texture()) for i, fx_pass in enumerate(passes): is_last = i == len(passes) - 1 render_to_screen = is_last or pass.render_to_screen # Passing None indicates that the pass should render to the canvas framebuffer # which puts its output directly onto the screen fx_pass.render(input_buffer, None if is_last else output_buffer) # needs_swap defaults to true if pass.needs_swap and not render_to_screen: output_buffer, input_buffer = input_buffer, output_buffer
When the depth texture is first initialized, it gets set on the input buffer. Since these buffers swap back and forth each frame, it’s possible that the depth buffer will be attached to the output buffer while processing the effect. If the pass makes use of the depth texture as input for some shader by passing it as a uniform or similar, it will cause the WebGL error I pasted before and cause the pass to fail to render.
This is a known bug/limitation of
postprocessing. There are multiple issues about this:
They plan to address it in a release of version 7, which is not yet out at the time of writing this.
Luckily, it’s possible to work around this issue. I had to update
three-good-godrays to detect and handle case where the provided depth texture is the same as the one bound to the provided output buffer.
If it is the same, then I allocate an additional framebuffer the same size of the depth texture, run a
CopyPass to copy the contents of the depth texture into it, and then bind that copied buffer as the input for the
sceneDepth uniform of the shader instead. This fixes the “Source and destination texture sof the draw are the same” error and allows the pass to render without issue.
I made that change in this commit. I do hope that pmndrs
postprocessing gets that v7 rework; it was very hard to figure out what was causing this and debugging it took several hours.