Search code examples
three.jsfragment-shader

reuse WebGLRenderTarget as material it gets zeroed and black


I am a newbie in shader. I am currently using three.js with shadermaterial. I would like to ask the following questions. 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. But when I use this.fbo.texture as my own uniforms parameter value, the material will become completely black. 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;
    }
//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);
}

If I change the position to after rendering, it works fine, but I mean shouldn't it be the same result? After all, the result is stored in this.fbo first and then I setRenderTarget again. Why is the result all black?

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);

But when I use the new fbo1 as the carrier, it will not be affected, so I think it is because render changed its value


Solution

  • Thanks to Mugen in another community for his assistance. The cause of this problem is a problem called feedback loop. The solution is to use ping-pong.