I have pinpointed the problem inside the comments of the render function:
import * as THREE from “three”;
import { OrbitControls } from “three/examples/jsm/controls/OrbitControls.js”;
import fragment from “./shaders/fragment.glsl”;
import vertex from “./shaders/vertex.glsl”;
const brush = new URL(“../images/brush.png”, import.meta.url).href;
const bg = new URL(“../images/baseTexture.jpg”, import.meta.url).href;
import fragmentDistortion from “./shaders/fragmentDistortion.glsl”;
import vertexDistortion from “./shaders/vertexDistortion.glsl”;
import * as dat from “dat.gui”;
import { EffectComposer } from “three/examples/jsm/postprocessing/EffectComposer.js”;
import { RenderPass } from “three/examples/jsm/postprocessing/RenderPass.js”;
import { ShaderPass } from “three/examples/jsm/postprocessing/ShaderPass.js”;
const t1 = new URL(“../images/1.jpg”, import.meta.url).href;
const t2 = new URL(“../images/2.jpg”, import.meta.url).href;
const t3 = new URL(“../images/3.jpg”, import.meta.url).href;
const CustomPass = {
uniforms: {
tDiffuse: { value: null },
time: { value: 0 },
progress: { value: 0 },
tSize: { value: new THREE.Vector2(256, 256) },
center: { value: new THREE.Vector2(0.5, 0.5) },
angle: { value: 1.57 },
scale: { value: 1.0 },
},
vertexShader: /* glsl */ `
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
}`,
fragmentShader: /* glsl */ `
uniform vec2 center;
uniform float angle;
uniform float time;
uniform float progress;
uniform float scale;
uniform vec2 tSize;
uniform sampler2D tDiffuse;
varying vec2 vUv;
float pattern() {
float s = sin( angle ), c = cos( angle );
vec2 tex = vUv * tSize - center;
vec2 point = vec2( c * tex.x - s * tex.y, s * tex.x + c * tex.y ) * scale;
return ( sin( point.x ) * sin( point.y ) ) * 4.0;
}
void main() {
vec2 newUV = vUv;
vec2 p = 2.*vUv - vec2(1.0);
p += 0.1*cos(scale*3.*p.yx + time + vec2(1.2,3.4));
p += 0.1*cos(scale*3.7*p.yx + 1.4*time + vec2(2.2,3.4));
p += 0.1*cos(scale*5.*p.yx + 2.6*time + vec2(4.2,1.4));
p += 0.3*cos(scale*7.*p.yx + 3.6*time + vec2(10.2,3.4));
newUV.x = mix(vUv.x, length(p), progress);
newUV.y = mix(vUv.y, 0.5, progress);
vec4 color = texture2D( tDiffuse, newUV );
gl_FragColor = color;
}`,
};
export default class Sketch {
constructor(options) {
this.distortionScene = new THREE.Scene();
this.distortionUrls = [t3, t1, t2];
this.distortionTextures = this.distortionUrls.map((url) =>
new THREE.TextureLoader().load(url)
);
this.distortionCamera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.001,
1000
);
this.distortionCamera.position.set(0, 0, 2);
this.scene = new THREE.Scene();
this.scene1 = new THREE.Scene();
this.container = options.dom;
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.renderer = new THREE.WebGLRenderer();
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
this.renderer.setSize(this.width, this.height);
this.renderer.setClearColor(0x000000, 1);
this.renderer.physicallyCorrectLights = true;
this.renderer.outputEncoding = THREE.sRGBEncoding;
this.container.appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.001,
1000
);
this.baseTexture = new THREE.WebGLRenderTarget(this.width, this.height, {
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
});
let frustumSize = this.height;
let aspect = this.width / this.height;
this.camera = new THREE.OrthographicCamera(
(frustumSize * aspect) / -2,
(frustumSize * aspect) / 2,
frustumSize / 2,
frustumSize / -2,
-1000,
1000
);
this.camera.position.set(0, 0, 2);
this.controls = new OrbitControls(this.camera, this.renderer.domElement);
this.time = 0;
this.mouse = new THREE.Vector2();
this.prevMouse = new THREE.Vector2();
this.currentWave = 0;
this.isPlaying = true;
this.createRenderTarget();
this.initPost();
this.mouseEvents();
this.addObjects();
this.resize();
this.render();
this.setupResize();
this.settings();
}
createRenderTarget() {
// Create a WebGLRenderTarget with the same dimensions as the canvas
this.distortionRenderTarget = new THREE.WebGLRenderTarget(
this.width,
this.height,
{
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat,
encoding: THREE.sRGBEncoding,
}
);
}
initPost() {
// PostProcessing
this.composer = new EffectComposer(this.renderer);
this.composer.addPass(
new RenderPass(this.distortionScene, this.distortionCamera)
);
this.effect1 = new ShaderPass(CustomPass);
this.composer.addPass(this.effect1);
}
settings() {
this.settings = {
progress: 0,
scale: 1,
};
this.gui = new dat.GUI();
this.gui.add(this.settings, “progress”, 0, 1, 0.01);
this.gui.add(this.settings, “scale”, 0, 10, 0.01);
}
setupResize() {
window.addEventListener(“resize”, this.resize.bind(this));
}
resize() {
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.renderer.setSize(this.width, this.height);
this.camera.aspect = this.width / this.height;
this.camera.updateProjectionMatrix();
this.distortionCamera.aspect = this.width / this.height;
this.distortionCamera.updateProjectionMatrix();
// Update render target size when window resizes
this.distortionRenderTarget.setSize(this.width, this.height);
}
mouseEvents() {
window.addEventListener(“mousemove”, (e) => {
this.mouse.x = e.clientX - this.width / 2;
this.mouse.y = this.height / 2 - e.clientY;
});
}
addObjects() {
this.distortionMaterial = new THREE.ShaderMaterial({
extensions: {
derivatives: “#extension GL_OES_standard_derivatives: enable”,
},
side: THREE.DoubleSide,
uniforms: {
time: { value: 0 },
uTexture: { value: this.distortionTextures[0] },
resolution: { value: new THREE.Vector4() },
},
vertexShader: vertexDistortion,
fragmentShader: fragmentDistortion,
});
this.distortionGeometry = new THREE.PlaneGeometry(1.9 / 2, 1 / 2, 1, 1);
this.distortionMeshes = [];
this.distortionTextures.forEach((texture, index) => {
let distortionMaterial = this.distortionMaterial.clone();
distortionMaterial.uniforms.uTexture.value = texture;
let distortionMesh = new THREE.Mesh(
this.distortionGeometry,
distortionMaterial
);
this.distortionScene.add(distortionMesh);
this.distortionMeshes.push(distortionMesh);
distortionMesh.position.x = index - 1;
});
this.material = new THREE.ShaderMaterial({
extensions: {
derivatives: "#extension GL_OES_standard_derivatives: enable",
},
side: THREE.DoubleSide,
uniforms: {
time: { value: 0 },
uDisplacement: { value: null },
uTexture: { value: this.distortionRenderTarget.texture },
resolution: { value: new THREE.Vector4() },
},
// transparent: true,
vertexShader: vertex,
fragmentShader: fragment,
});
this.max = 100;
this.geometry = new THREE.PlaneGeometry(64, 64, 1, 1);
this.geometryFullScreen = new THREE.PlaneGeometry(
this.width,
this.height,
1,
1
);
this.meshes = [];
for (let i = 0; i < this.max; i++) {
let m = new THREE.MeshBasicMaterial({
map: new THREE.TextureLoader().load(brush),
transparent: true,
blending: THREE.AdditiveBlending,
depthTest: false,
depthWrite: false,
});
let mesh = new THREE.Mesh(this.geometry, m);
mesh.visible = false;
mesh.rotation.z = 2 * Math.PI * Math.random();
this.scene.add(mesh);
this.meshes.push(mesh);
}
this.quad = new THREE.Mesh(this.geometryFullScreen, this.material);
this.scene1.add(this.quad);
}
setNewWave(x, y, index) {
let mesh = this.meshes[index];
mesh.visible = true;
mesh.position.x = x;
mesh.position.y = y;
mesh.scale.x = mesh.scale.y = 0.2;
mesh.material.opacity = 0.5;
}
trackMouse() {
if (
Math.abs(this.mouse.x - this.prevMouse.x) < 4 &&
Math.abs(this.mouse.y - this.prevMouse.y) < 4
) {
// do nothing
} else {
this.setNewWave(this.mouse.x, this.mouse.y, this.currentWave);
this.currentWave = (this.currentWave + 1) % this.max;
}
this.prevMouse.x = this.mouse.x;
this.prevMouse.y = this.mouse.y;
}
render() {
this.trackMouse();
if (!this.isPlaying) return;
this.time += 0.01;
this.material.uniforms.time.value = this.time;
this.renderer.setRenderTarget(this.baseTexture);
this.renderer.render(this.scene, this.camera);
this.material.uniforms.uDisplacement.value = this.baseTexture.texture;
this.renderer.setRenderTarget(null);
this.renderer.clear();
this.renderer.render(this.scene1, this.camera);
this.meshes.forEach((mesh) => {
if (mesh.visible) {
mesh.rotation.z += 0.02;
mesh.material.opacity *= 0.96;
mesh.scale.x = 0.982 * mesh.scale.x + 0.108;
mesh.scale.y = mesh.scale.x;
if (mesh.material.opacity < 0.002) {
mesh.visible = false;
}
}
});
this.renderer.setRenderTarget(this.distortionRenderTarget);
// This line makes my Ripple animation work, if I comment it then it does not work at all.
this.renderer.render(this.distortionScene, this.distortionCamera);
// This line makes my CustomPass/effect1 to work but If I uncomment it then my ripple animation stops working
// this.composer.render();
this.renderer.setRenderTarget(null);
this.distortionMeshes.forEach((m, i) => {
m.rotation.z = this.settings.progress * (Math.PI / 2);
});
this.distortionMaterial.uniforms.time.value = this.time;
this.effect1.uniforms["time"].value = this.time;
this.effect1.uniforms["progress"].value = this.settings.progress;
this.effect1.uniforms["scale"].value = this.settings.scale;
requestAnimationFrame(this.render.bind(this));
}
}
new Sketch({
dom: document.getElementById(“container”),
});
// My Shader Codes
// fragment.glsl:
// uniform float time;
// uniform float progress;
// uniform sampler2D uTexture;
// uniform sampler2D uDisplacement;
// uniform vec4 resolution;
// varying vec2 vUv;
// varying vec3 vPosition;
// float PI = 3.141592653589793238;
// void main() {
// vec4 displacement = texture2D(uDisplacement,vUv);
// float theta = displacement.r2. PI;
// vec2 dir = vec2(sin(theta),cos(theta));
// vec2 uv = vUv + dirdisplacement.r0.1;
// vec4 color = texture2D(uTexture,uv);
// gl_FragColor = color;
// }
// fragmentDistortion.glsl:
// uniform float time;
// uniform float progress;
// uniform sampler2D uTexture;
// uniform vec4 resolution;
// varying vec2 vUv;
// uniform vec3 vPosition;
// float PI = 3.141592653589793238;
// void main() {
// vec4 color = texture2D(uTexture, vUv);
// gl_FragColor = vec4(vUv, 0.0, 1.0);
// gl_FragColor = color;
// }