Distortion effect using Three.js & WebGL not working after implementing GSAP scroll animation with scrollTrigger

84 Views Asked by At

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();
0

There are 0 best solutions below