Hi there,
I am really close to creating my first custom postprocessing shader for the composer. BUT, I cannot make work the last piece.
Everything works fine, except one thing.To create a mask, I change the color of the selected objects temporarily to pure red.
My intention is to change them back, but here is the thing, changing it back is invalidating make them red. Is like the material never changed in the first place.
Any idea of what can it be?
And also, if you think the code can be improved or optimized, please let me know!
this.selectedObjects.forEach((object) => {
this.materialsCache[object.uuid] = object.mesh.material;
object.mesh.material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
});
this.selectedObjects.forEach((object) => {
object.mesh.material = this.materialsCache[object.uuid];
});
import * as THREE from 'three';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
const grayscaleShader = {
uniforms: {
tDiffuse: { value: null },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tDiffuse, vUv);
float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = vec4(vec3(gray), color.a);
}
`
};
const compositeShader = {
uniforms: {
tDiffuse: { value: null },
tGrayscale: { value: null },
tMask: { value: null },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
uniform sampler2D tGrayscale;
uniform sampler2D tMask;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tMask, vUv);
gl_FragColor = vec4(color.rgb, 1.0);
}
`
};
const maskShader = {
uniforms: {
tDiffuse: { value: null },
},
vertexShader: `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
`,
fragmentShader: `
uniform sampler2D tDiffuse;
varying vec2 vUv;
void main() {
vec4 color = texture2D(tDiffuse, vUv);
//if color.r is pure red
if (color.r > 0.8 && color.g < 0.2 && color.b < 0.2) {
gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
} else {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
}
`
};
export class IsolatedRenderPass extends ShaderPass {
constructor(scene, camera) {
super(); // Using an empty ShaderPass because rendering is manual
this.scene = scene;
this.camera = camera;
// Initialize the internal shader passes
this.grayscalePass = new ShaderPass(grayscaleShader);
this.compositeShaderPass = new ShaderPass(compositeShader);
this.maskPass = new ShaderPass(maskShader);
// Render targets
this.normalTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
this.processedTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
this.maskTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
this.grayscaleTarget = new THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight);
this.selectedObjects = [];
this.materialsCache = {};
}
render(renderer, writeBuffer, readBuffer, deltaTime, maskActive) {
renderer.autoClear = false;
// Render the scene into the normal target
renderer.setRenderTarget(this.normalTarget);
// Apply mask pass
this.grayscalePass.uniforms.tDiffuse.value = this.normalTarget.texture;
renderer.setRenderTarget(this.grayscaleTarget);
renderer.clear();
this.fsQuad.render( renderer );
this.grayscalePass.render(renderer, this.grayscaleTarget, readBuffer, deltaTime, maskActive);
this.selectedObjects.forEach((object) => {
this.materialsCache[object.uuid] = object.mesh.material;
object.mesh.material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
});
// Apply mask pass
this.maskPass.uniforms.tDiffuse.value = this.normalTarget.texture;
renderer.setRenderTarget(this.maskTarget);
renderer.clear();
this.fsQuad.render( renderer );
this.maskPass.render(renderer, this.maskTarget, readBuffer, deltaTime, maskActive);
this.selectedObjects.forEach((object) => {
object.mesh.material = this.materialsCache[object.uuid];
});
// Apply composite pass
this.compositeShaderPass.uniforms.tDiffuse.value = this.normalTarget.texture;
this.compositeShaderPass.uniforms.tGrayscale.value = this.grayscaleTarget.texture;
this.compositeShaderPass.uniforms.tMask.value = this.maskTarget.texture;
renderer.setRenderTarget(null);
renderer.clear();
this.fsQuad.render( renderer );
this.compositeShaderPass.render(renderer, null, readBuffer, deltaTime, maskActive);
// Reset the render target to the default (screen)
renderer.setRenderTarget( readBuffer );
this.fsQuad.render( renderer );
}
dispose() {
this.grayscalePass.dispose();
this.compositeShaderPass.dispose();
this.maskPass.dispose();
this.normalTarget.dispose();
this.processedTarget.dispose();
this.maskTarget.dispose();
this.grayscaleTarget.dispose();
}
}