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
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.)
- Which version of three are you using?
- Are you using built-in postprocessing or an external postprocessing library?
- 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.) - 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.)
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()
- 0.159.0
- no, everything written by me
- 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
- no errors unfortunately, an error would make my life so much easier right now
`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.