I have 5 sections on my HTML page, among this 5 sections, there are 3 sliders(sections) on horizontal scroll. I use GSAP and scrollTrigger plugin to control the vertical scroll(page) and the horizontal scroll(sliders). And I also created a distortion effect on images of the 1st slider using Three.js & WebGL. The problem is when I connect the GSAP scroll to the Three.js class, the distortion effect stop working: the curve shows up at the beginning et doesn't move while scrolling.
Here is my code below. I don't which function or parameter to modify. Could you help me to solve this problem? Or is there a problem related to GSAP? Thank you very much!!
CSS:
#sliderOne {
width: 100vw;
height: 100vh;
}
.gallery {
height: 100%;
width: fit-content;
display: flex;
flex-wrap: nowrap;
align-items: center;
}
.gallery .item {
display: flex;
margin-top: 1%;
width: 50vw;
max-width: 47em;*/
height: 80vh;
}
.gallery h2 {
color: #f5f7fa;
font-family: 'mijuregular', 'Potta One', cursive;
text-transform: uppercase;
position: relative;
left: 75%;
padding-top: 6%;
width: 100px;
}
.gallery img {
width: 50vw;
min-width: 25em;
max-width: 47em;
height: 80vh;
object-fit: cover;
opacity: 0;
}
And the JS file:
gsap.registerPlugin(ScrollTrigger);
// 1st Slider Scroll
//Get the gallery from the DOM
const gallery = document.querySelector(".gallery");
//Get the gallery total width
let galleryWidth = gallery.offsetWidth;
console.log(galleryWidth);
//Get the amount to scroll horizontally by subtracting the window width from the full width of the gallery
let amountToScroll = (galleryWidth - window.innerWidth) + 100;
console.log(amountToScroll);
let target = 0;
target = window.scrollY;
//const images = [...document.querySelectorAll('#slider1 img')];
const images = [...document.querySelectorAll('slider-inner1 img')];
const slider = document.querySelector('.slider');
class EffectCanvas {
constructor() {
this.container = document.querySelector('#sliderOne');
console.log(this.container);
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.images = [...document.querySelectorAll('#slider-inner1 img')];
console.log(this.images);
this.meshItems = []; // Used to store all meshes we will be creating.
this.setupCamera();
this.createMeshItems();
this.horizontalScroll();
this.render();
}
//Scroll Animation
horizontalScroll() {
gsap.to(gallery, {
x: -amountToScroll,
ease: "none",
scrollTrigger: {
trigger: ".gallery-wrapper",
start: "top top",
end: "+=" + amountToScroll,
pin: true,
scrub: true
}
});
}
// Getter function used to get screen dimensions used for the camera and mesh materials
get viewport() {
let width = window.innerWidth;
let height = window.innerHeight;
let aspectRatio = width / height;
return {
width,
height,
aspectRatio
};
}
setupCamera() {
window.addEventListener('resize', this.resize.bind(this));
// Create new scene
this.scene = new THREE.Scene();
// Initialize perspective camera
let perspective = 1000;
const fov = (180 * (2 * Math.atan(window.innerHeight / 2 / perspective))) / Math.PI; //2 * Math.atan((this.height / 2) / perspective) * (180 / Math.PI);
this.camera = new THREE.PerspectiveCamera(fov, this.viewport.aspectRatio, 1, 1000);
this.camera.position.set(0, 0, perspective) // set the camera position on the z axis, equal to this.camera.position.z = 1000;
//renderer
this.renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true
});
this.renderer.setSize(this.viewport.width, this.viewport.height); // uses the getter viewport function above to set size of canvas / renderer
this.renderer.setPixelRatio(window.devicePixelRatio); // Import to ensure image textures do not appear blurred.
this.container.appendChild(this.renderer.domElement); // append the canvas to the 1st section element
}
resize() {
//init();
this.camera.aspect = this.viewport.aspectRatio; // readjust the aspect ratio.
this.camera.updateProjectionMatrix(); // Used to recalulate projectin dimensions.
this.renderer.setSize(this.viewport.width, this.viewport.height);
}
createMeshItems() {
this.images.forEach(image => {
let meshItem = new MeshItem(image, this.scene);
this.meshItems.push(meshItem);
});
}
render() {
//animate();
for (let i = 0; i < this.meshItems.length; i++) {
this.meshItems[i].render();
}
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(this.render.bind(this));
}
}
class MeshItem {
constructor(element, scene) {
this.element = element;
this.scene = scene;
this.offset = new THREE.Vector2(0, 0);
this.sizes = new THREE.Vector2(0, 0);
this.createMesh();
console.log(this.element.getBoundingClientRect());
}
getDimensions() {
const { width, height, top, left } = this.element.getBoundingClientRect();
//console.log({ width, height, top, left });
this.sizes.set(width, height);
this.container = document.querySelector('#sliderOne');
this.width = this.container.offsetWidth;
this.height = this.container.offsetHeight;
this.offset.set(left - this.width / 2 + width / 2., -top + this.height / 2 - height / 1.99);
}
createMesh() {
this.geometry = new THREE.PlaneGeometry(1, 1, 100, 100);
//let material = new THREE.MeshBasicMaterial({ color: 0xffff00, side: THREE.DoubleSide });
this.imageTexture = new THREE.TextureLoader().load(this.element.src);
console.log(this.imageTexture);
this.uniforms = {
uTexture: { value: this.imageTexture },
uOffset: { value: new THREE.Vector2(0.0, 0.0) },
uAlpha: { value: 1.0 }
}
this.material = new THREE.ShaderMaterial({
uniforms: this.uniforms,
vertexShader: vertexShader,
fragmentShader: fragmentShader
});
this.mesh = new THREE.Mesh(this.geometry, this.material);
this.getDimensions();
this.mesh.position.set(this.offset.x, this.offset.y, 0);
console.log(this.offset.x)
this.mesh.scale.set(this.sizes.x, this.sizes.y, 1);
this.scene.add(this.mesh);
}
render() {
// repeatedly called
this.getDimensions();
this.mesh.position.set(this.offset.x, this.offset.y, 0);
this.mesh.scale.set(this.sizes.x, this.sizes.y, 0);
this.uniforms.uOffset.value.set(-(target - amountToScroll) * 0.00002, 0.0);
}
}
//init();
new EffectCanvas();