When I reuse WebGLRenderTarget as material it gets zeroed

Hello, I am new to using shaders,
my problem is that I use FBO to create materials and transfer the materials to the fragment shader as uniforms. Originally everything was normal and I could get randomly distributed color materials.
The program code is as follows

setupFBO(){
        this.size = 128;
        this.fbo = this.getRenderTarget();

        this.fboScene = new THREE.Scene();
        this.fboCamera = new THREE.OrthographicCamera(-1, 1, 1, -1, -1, 1);
        this.fboCamera.position.set(0, 0, 0.5);

        let geometry = new THREE.PlaneGeometry(2, 2);

 
        this.data = new Float32Array(this.size * this.size * 4);


        for(let i = 0; i < this.size; i++){
            for(let j = 0; j < this.size; j++){

                let index = (i + j * this.size) * 4;
                let theta = Math.random() * Math.PI * 2; 
                let r = 0.5 + 0.5 * Math.random(); 


                this.data[index + 0] = r * Math.cos(theta);
                this.data[index + 1] = r * Math.sin(theta);
                this.data[index + 2] = 1.0;
                this.data[index + 3] = 1.0;
            }
        }

        this.fboTexture = new THREE.DataTexture(this.data, this.size, this.size, THREE.RGBAFormat, THREE.FloatType);
        this.fboTexture.magFilter = THREE.NearestFilter;
        this.fboTexture.minFilter = THREE.NearestFilter;
        this.fboTexture.needsUpdate = true;


        this.fboMaterial = new THREE.ShaderMaterial({
            uniforms: {
                uPositions: {value: this.fboTexture},
                time: {value: 0}
            },
            vertexShader: simVertex,
            fragmentShader: simFragment
        })
       
        let FBOmesh = new THREE.Mesh(geometry, this.fboMaterial);
        
       

        this.fboScene.add(FBOmesh);
        this.renderer.setRenderTarget(null);
        this.renderer.setRenderTarget(this.fbo);
        this.renderer.render(this.fboScene, this.fboCamera);
        this.renderer.setRenderTarget(null);
        
      ////here is the problem
      //this.fboMaterial.uniforms.uPositions.value = this.fbo.texture;  //here is the problem
      //this.renderer.setRenderTarget(null);
      //this.renderer.setRenderTarget(this.fbo);
      //this.renderer.render(this.fboScene, this.fboCamera);

      //this.renderer.setRenderTarget(null);
     // this.renderer.render(this.fboScene, this.fboCamera);


    }



    getRenderTarget(){
        const renderTarget = new THREE.WebGLRenderTarget(this.canvas.width, this.canvas.height, {
            minFilter: THREE.NearestFilter,
            magFilter: THREE.NearestFilter,  
            format: THREE.RGBAFormat,
            type: THREE.FloatType,
            stencilBuffer: false
        });
        return renderTarget;
    }

But when I added this line, I found that the material would become completely black.
I think I imported this material back into uniforms after confirming that the rendering was completed and loaded into this.fob. Why did it turn black?
I don’t know what the principle is? Does anyone know?

this.fboMaterial.uniforms.uPositions.value = this.fbo.texture;
this.renderer.setRenderTarget(null);
this.renderer.setRenderTarget(this.fbo);
this.renderer.render(this.fboScene, this.fboCamera);

this.renderer.setRenderTarget(null);
this.renderer.render(this.fboScene, this.fboCamera);

Below is my vertex shader with fragment shading

//simVertex.glsl
uniform float time;
varying vec2 vUv;
varying vec3 vPosition;
float PI = 3.141592653589793238;


void main(){
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
//simFragment.glsl

uniform float time;
uniform float progress;
uniform sampler2D uPositions;  
varying vec2 vUv;
varying vec3 vPosition;


void main(){
    vec4 pos = texture2D(uPositions, vUv);
    gl_FragColor = vec4(pos.xyz, 1);
}

When I’ve read your code correctly then it produces a so called feedback loop which is invalid. You can’t render to a render target and use it as a texture at the same time (meaning in the same render() call). You should actually see WebGL warnings about the feedback loop in the browser console.

3D objects that use the render target as a texture must be invisible (Object3D.visible = false) or no part of the scene when this.renderer.setRenderTarget(this.fbo); has been executed.

1 Like

/cc

1 Like

Thanks, this problem has stuck with me for several hours. It turns out to be a problem called feedback loop, and the solution is a method called ping-pong.

thank you for your help.

1 Like