Hello friends,
I’m facing an issue trying to render shaders that can receive one another (and themselves) as sampler2D Uniforms (the problem is not feedback loop, I believe I solved that with a ping-pong render target swap), and I’m not sure if I’m doing something silly in my render logic, or if I’m missing something in ThreeJS’s renderer (or WebGLRenderTarget
) configuration.
I’m trying to replicate the rendering of this shader posted on this website, however, when trying to use ThreeJS for what I imagine would be necessary to achieve the same result I’m failing miserably.
To better illustrate what I’m trying to do instead of using my poor description skills, I created this CodeSandbox with the exact same app I’m trying to write. As you can see, the result is far from the expected seen on the website I linked before.
As you can see, at least apparently it seems one shader can receive another shader’s rendered texture as a sampler2D uniform, but shader2 and shader3 receive one another’s texture, and their own texture as sampler2D uniforms, and I believe there’s something wrong there. *edit: I see no errors on the console, nor WebGL warnings.
I tried a few things in regards to the renderer
autoclear, but it was mostly trial and error, and nothing worked. I also suspected I may be using wrong parameters when creating the read
and write
WebGLRenderTarget
s on the TargetManager
class, but I couldn’t spot so far anything that seems utterly wrong.
This is basically what happens in my render loop.
this.shaders.forEach((shader) => {
this.renderTargets.forEach((renderTarget, targetIndex) => {
shader.uniforms[`prgm${targetIndex}Texture`]!.value =
renderTarget.readBuffer.texture;
shader.uniforms.resolution!.value = this.resolution;
shader.uniforms.time!.value = this.time;
shader.uniforms.frame!.value = this.frame;
shader.uniforms.mouse!.value = this.mouse;
});
});
this.renderTargets.forEach((target, targetIndex) => {
const shader = this.shaders.get(targetIndex);
if (!shader) throw new Error(`error: this.shaders.get(${targetIndex})`);
target.render(shader!.scene, this.camera, true, false);
});
this.renderTargets
.get(0)!
.render(this.shaders.get(0)!.scene, this.camera, false, true);
this.time += this.clock.getDelta();
this.frame++;
First for every shader, I pass every RenderTarget
’s readBuffer.texture
as a sampler2D uniform called prgm${targetIndex}Texture
. And right away, other uniforms like resolution, frame, time, and the mouse position.
Then, using every TargetManager
instance, I render the shader with its corresponding index, using the global camera, passing true to the argument I use to tell my render target manager if it should swap the buffers or not, and false to the argument that is responsible for rendering to screen or not (if true, inside the TargetManager
, this.renderer.setRenderTarget(null)
will be called to render to the screen).
Finally, I use the TargetManager
to use the render target correspondent to shader0 (which should produce the texture I want to render on the screen), with the proper arguments to avoid swapping, and rendering to screen.
When debugging and console.logging some things, I could see that the shaders are apparently receiving the proper textures for every sampler2D uniform (rendered on the previous frame by themselves and by the other shaders), and the buffer swapping on the TargetManager
class is occurring in the moments when I guessed they should.
Am I at least close of getting this to work? Thank you very much in advance. Any help will be incredibly appreciated.