Struggling to get multiple passes working on effectcomposer

i can’t get multiple passes working together for some reason, chromaticaberrationpass speaks for itself and transitionpass is just an empty copypass currently, both work fine seperately but once i enable both the screen renders black. been stuck for some time and really don’t know what to do. am i doing something wrong? can’t be a glsl issue since the first pass literally just copies readbuffer’s texture onto the screen
image
image
image

1 Like

The code doesn’t get much more complex than what you have - you just setup a chain of passes and call composer.render() - first pass should be RenderPass, and all subsequent passes must have .renderToScreen set to false in order not to override the frame (they can still render to render targets, if necessary.)

  1. Which version of three are you using?
  2. Are you using built-in postprocessing or an external postprocessing library?
  3. What’s the content of the passes you’re using? Are you importing necessary shaders? (postprocessing often relies on you also importing CopyShader and other necessary external shaders to work.)
  4. Are there any errors in the devtools console? (passes sometimes require you to pass params as an empty {} object, instead of not passing anything at all, which may cause the code to just throw right away.)
1 Like

Implying that OP should probably set

luminosityPass.renderToScreen = true to make the last pass actually output to the screen?

all passes except renderpass are written by me, so there is no .renderToScreen()

  1. 0.159.0
  2. no, everything written by me
  3. chromaticaberrationpass code below, the other one is similar and works when it’s the only pass in the chain so i don’t think its contents are important
  4. no errors unfortunately, an error would make my life so much easier right now :smiley:

`import * as THREE from ‘three’;
import { Pass, FullScreenQuad } from ‘three/addons/postprocessing/Pass.js’;

class ChromaticAberrationPass extends Pass {

constructor( ) {

	super();

	this.material = this.getVerticalBoxBlurMaterial();
	this.fsQuad = new FullScreenQuad( this.material);
}

render( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
	this.material.uniforms['tDiffuse'].value = readBuffer.texture;
    renderer.setRenderTarget( null );
    renderer.clear();
	this.fsQuad.render( renderer );
}

dispose() {

	this.material.dispose();

	this.fsQuad.dispose();

}

getVerticalBoxBlurMaterial()
{
	return new THREE.ShaderMaterial({
        defines: {

            // 0: NONE, 1: RGB, 2: RYGCBV
            BAND_MODE: 2,
    
            CHROMA_SAMPLES: 1,
    
        },
    
        uniforms: {
    
            tDiffuse: { value: null },
            baseIor: { value: 1.1 },
            bandOffset: { value: 0.02 },
            jitterIntensity: { value: 0.0 },
            jitterOffset: { value: 0.0 }
        },
    
        vertexShader: /* glsl */`
    
            varying vec2 vUv;
            varying vec2 viewDir;

            float map(float value, float min1, float max1, float min2, float max2) {
                return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
              }
    
            void main() {
    
                vUv = uv;
                gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
                //viewDir = normalize( ( modelViewMatrix * vec4( position, 1.0 ) ).xyz );
                viewDir = uv;
            }
    
        `,
    
        fragmentShader: /* glsl */`
        uniform sampler2D tDiffuse;
        varying vec2 vUv;
        varying vec2 viewDir;

        float map(float value, float min1, float max1, float min2, float max2) {
            return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
          }

        vec2 map(vec2 value, vec2 min1, vec2 max1, vec2 min2, vec2 max2) {
            return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
          }

        void main()
        {	
            float rior = 10.0;
            float gior = 10.0;
            float bior = 10.0;

            vec3 normal = vec3( ( map(vUv.xy,vec2(0.0),vec2(1.0),vec2(-1.0),vec2(1.0)) ), 1.0 );
		    normal.z = 1.0;
		    normal = normalize( normal );
            vec3 mappedNormal = vec3(map(normal.xy,vec2(0.0),vec2(1.0),vec2(-0.0),vec2(1.0)), 1.0);

            vec3 uvRed = refract(mappedNormal, vec3(0.0, 0.0, 1.0), rior);
            vec2 reMappedNormalRed = map(uvRed.xy / rior,vec2(-1.0),vec2(1.0),vec2(0.0),vec2(1.0));

            vec3 uvGreen = refract(mappedNormal, vec3(0.0, 0.0, 1.0), gior);
            vec2 reMappedNormalGreen = map(uvGreen.xy / gior,vec2(-1.0),vec2(1.0),vec2(0.0),vec2(1.0));

            vec3 uvBlue = refract(mappedNormal, vec3(0.0, 0.0, 1.0), bior);
            vec2 reMappedNormalBlue = map(uvBlue.xy / bior,vec2(-1.0),vec2(1.0),vec2(0.0),vec2(1.0));

            vec2 finalizedUvRed = mix(reMappedNormalRed, vUv, pow(abs(1.0 - abs(map(vUv.y, 0.0, 1.0, -0.88, 0.88))),0.5));
            vec2 finalizedUvGreen = mix(reMappedNormalGreen, vUv, pow(abs(1.0 - abs(map(vUv.y, 0.0, 1.0, -0.9, 0.9))),0.5));
            vec2 finalizedUvBlue = mix(reMappedNormalBlue, vUv, pow(abs(1.0 - abs(map(vUv.y, 0.0, 1.0, -0.92, 0.92))),0.5));
            
            float red = texture2D(tDiffuse,finalizedUvRed).r;
            float green = texture2D(tDiffuse,finalizedUvGreen).g;
            float blue = texture2D(tDiffuse,finalizedUvBlue).b;

            gl_FragColor = vec4(red, green, blue, 1.0);
            //texture2D(tDiffuse,finalizedUv);
        }
    
        `
		});
}

}

export { ChromaticAberrationPass };
`

Can you post a jsfiddle/glitch/codepen that shows the issue?

If I were you, I’d first try with a pass-friendly render method (i.e. a method that renders off-screen when it is not the final pass, and on-screen if it is final pass). Something like this:

render( renderer, writeBuffer, readBuffer /*, deltaTime , maskActive */ ) {
	this.material.uniforms['tDiffuse'].value = readBuffer.texture;
	if ( this.renderToScreen ) {
		renderer.setRenderTarget( null );
		this.fsQuad.render( renderer );
	} else {
		renderer.setRenderTarget( writeBuffer );
		if ( this.clear ) renderer.clear();
		this.fsQuad.render( renderer );
	}
}

Note: renderToScreen is managed by the effect composer, so it is already defined.

1 Like