So I am trying to create ripple effects on mouse over exactly like in homunculus.jp website, I have absolutely no idea on how to go about it, I was able to get some result using the following code
import * as THREE from "three";
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';
// import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { RGBShiftShader } from 'three/examples/jsm/shaders/RGBShiftShader.js';
import { DotScreenShader } from 'three/examples/jsm/shaders/DotScreenShader';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { Custom } from "./shader/Custom";
import fragment from "./shader/fragment.glsl";
import vertex from "./shader/vertex.glsl";
import * as dat from "dat.gui";
import gsap from "gsap";
import brush from '../brush.png'
import { RGBAFormat } from "three";
import ocean from '../1.jpg'
import ocean2 from '../2.jpg'
export default class Sketch {
constructor(options) {
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);
// Get Images
this.images = [...document.querySelectorAll('.project__media__image')];
this.container.appendChild(this.renderer.domElement);
this.camera = new THREE.PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
0.001,
1000
);
var frustumSize = this.height;
var 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.isPlaying = true;
this.mouse = new THREE.Vector2(0, 0);
this.prevMouse = new THREE.Vector2(0, 0);
this.currentWave = 0;
this.base = new THREE.WebGLRenderTarget(this.width, this.height,{
stencilBuffer: true,
minFilter: THREE.LinearFilter,
magFilter: THREE.LinearFilter,
format: THREE.RGBAFormat
})
this.mouseEvents();
// this.addBackPlane();
this.addObjects();
this.setPosition();
this.resize();
this.initPost();
this.render();
this.setupResize();
this.settings();
}
initPost(){
this.composer = new EffectComposer( this.renderer );
this.renderOne = new RenderPass(this.scene1, this.camera);
this.effect1 = new ShaderPass( Custom )
this.effect1.renderToScreen = true;
this.composer.addPass( this.renderOne );
// this.composer.addPass(this.effect);
this.composer.addPass(this.effect1)
}
mouseEvents(){
window.addEventListener('mousemove',(e)=>{
this.mouse.x = e.clientX - this.width/2;
this.mouse.y = this.height/2 - e.clientY;
})
}
settings() {
let that = this;
this.settings = {
progress: 1,
scale: 0.9
};
this.gui = new dat.GUI();
this.gui.add(this.settings, "progress", 0, 1, 0.01);
this.gui.add(this.settings, "scale", 0, 1, 10);
}
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();
}
addObjects() {
let that = this;
this.meshImages = [];
this.imageStore = this.images.map(img => {
let bounds = img.getBoundingClientRect();
let geometry = new THREE.PlaneBufferGeometry(bounds.width, bounds.height, 1, 1);
this.materials = new THREE.ShaderMaterial({
extensions: {
derivatives: "#extension GL_OES_standard_derivatives : enable"
},
side: THREE.DoubleSide,
uniforms: {
time: { value: 0 },
progress: {value: 1 },
uDisplacement: {value: null},
uTexture: { value: new THREE.TextureLoader().load(img.src)},
shiftx: { value: -0.5 },
shifty: { value: -0.5},
damp: {value: 2.0}
},
vertexShader: vertex,
fragmentShader: fragment
})
this.mainMesh = new THREE.Mesh(geometry, this.materials);
this.scene1.add(this.mainMesh);
this.meshImages.push(this.mainMesh);
return{
img: img,
mesh: this.mainMesh,
top: bounds.top,
left: bounds.left,
width: bounds.width,
height: bounds.height,
}
})
// the brushes
this.meshes = [];
this.max = 100;
this.geometry = new THREE.PlaneGeometry(10, 10, 1, 1);
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)
}
console.log(this.base)
}
setPosition(){
this.imageStore.forEach(o=>{
o.mesh.position.y = - o.top + this.height/2 - o.height/2;
o.mesh.position.x = o.left - this.width/2 + o.width/2;
})
}
stop() {
this.isPlaying = false;
}
play() {
if(!this.isPlaying){
this.render()
this.isPlaying = true;
}
}
newWave(x, y, Index){
let m = this.meshes[Index];
m.visible = true;
m.position.x = x;
m.position.y = y;
m.scale.x = m.scale.y = 1;
m.material.opacity = 1
}
trackMouse(){
if((Math.abs(this.mouse.x - this.prevMouse.x) < 4) && (Math.abs(this.mouse.y - this.prevMouse.y)<4)){
}
else{
this.currentWave = (this.currentWave + 1)%this.max;
this.newWave(this.mouse.x, this.mouse.y, this.currentWave);
}
this.prevMouse.x = this.mouse.x;
this.prevMouse.y = this.mouse.y;
}
render() {
this.trackMouse();
if (!this.isPlaying) return;
this.time += 0.003;
// this.material.uniforms.time.value = this.time;
this.effect1.uniforms[ 'time' ].value = this.time;
this.effect1.uniforms[ 'scale' ].value = this.settings.scale;
this.effect1.uniforms[ 'progress' ].value = this.settings.progress;
requestAnimationFrame(this.render.bind(this));
this.renderer.setRenderTarget(this.base);
this.renderer.render(this.scene, this.camera);
for (let index = 0; index < this.meshImages.length; index++) {
this.materials.uniforms.uDisplacement.value = this.base.texture
}
this.renderer.setRenderTarget(null);
this.renderer.clear();
this.composer.render();
this.meshes.forEach(m=>{
if(m.visible){
m.rotation.z += 0.02;
m.material.opacity *= 0.98;
m.scale.x = 0.9*m.scale.x + 1.0;
m.scale.y = m.scale.x
if(m.material.opacity < 0.002){
m.visible = false
}
}
})
}
}
new Sketch({
dom: document.getElementById("container")
});