What’s on our mind?

Collection of articles, design, site, and resources made by designers and publisher @Menu View

** index47
class Stage {
    constructor() {
        this.renderParam = {
            clearColor: 0xffffff,
            width: window.innerWidth,
            height: window.innerHeight
        };
        this.cameraParam = {
            fov: 45,
            near: 0.1,
            far: 100,
            lookAt: new THREE.Vector3(0, 0, 0),
            x: 0,
            y: 0,
            z: 10
        };

        this.scene = null;
        this.camera = null;
        this.renderer = null;
        this.geometry = null;
        this.material = null;
        this.mesh = null;
        this.isInitialized = false;
    }

    init() {
        this._setScene();
        this._setRender();
        this._setCamera();
        this.isInitialized = true;
    }

    _setScene() {
        this.scene = new THREE.Scene();
    }

    _setRender() {
        this.renderer = new THREE.WebGLRenderer({alpha: true});
        this.renderer.setPixelRatio(window.devicePixelRatio);
        this.renderer.setClearColor(new THREE.Color(this.renderParam.clearColor));
        this.renderer.setSize(this.renderParam.width, this.renderParam.height);
        const wrapper = document.querySelector("#webgl");
        wrapper.appendChild(this.renderer.domElement);
    }

    _setCamera() {
        if (!this.isInitialized) {
            this.camera = new THREE.PerspectiveCamera(
                0,
                0,
                this.cameraParam.near,
                this.cameraParam.far
            );

            this.camera.position.set(
                this.cameraParam.x,
                this.cameraParam.y,
                this.cameraParam.z
            );
            this.camera.lookAt(this.cameraParam.lookAt);
        }

        const width = window.innerWidth;
        const height = window.innerHeight;
        this.camera.aspect = width / height;

        this.camera.fov =
            THREE.MathUtils.radToDeg(
                Math.atan(width / this.camera.aspect / (2 * this.camera.position.z))
            ) * 2;
        this.camera.updateProjectionMatrix();
        this.renderer.setSize(width, height);
    }

    _render() {
        this.renderer.render(this.scene, this.camera);
    }

    onResize() {
        this._setCamera();
    }

    onRaf() {
        this._render();
    }
}

class Mesh {
    constructor(stage) {
        this.geometryRatio = 0.8;

        this.geometryParm = {
            width: 1.0,
            height: 1.0,
            widthSegments: 32.0,
            heightSegments: 32.0
        };

        this.materialParam = {
            useWireframe: false
        };

        this.width = window.innerWidth;
        this.height = window.innerHeight;

        this.naturalSize = {
            x: 1728,
            y: 1064
        };

        this.images = [
            "https://images.unsplash.com/photo-1524758631624-e2822e304c36?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
            "https://images.unsplash.com/photo-1638913971789-667874197280?ixlib=rb-1.2.1&ixid=MnwxMjA3fDF8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170&q=80",
            "https://images.unsplash.com/photo-1652783070844-64b446b791dd?crop=entropy&cs=tinysrgb&fm=jpg&ixlib=rb-1.2.1&q=80&raw_url=true&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1170",
            "https://images.unsplash.com/photo-1652631093599-9a971911bd43?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1334&q=80"
        ];

        this.noiseImage =
            "https://hisamikurita.github.io/sample-images/dist/assets/images/noise.webp";

        this.uniforms = {
            u_noise_texture: {
                type: "t",
                value: new THREE.TextureLoader().load(this.noiseImage)
            },
            u_texture_01: {
                type: "t",
                value: new THREE.TextureLoader().load(this.images[0])
            },
            u_texture_02: {
                type: "t",
                value: new THREE.TextureLoader().load(this.images[1])
            },
            u_texture_03: {
                type: "t",
                value: new THREE.TextureLoader().load(this.images[2])
            },
            u_texture_04: {
                type: "t",
                value: new THREE.TextureLoader().load(this.images[3])
            },
            u_noise_switch_01: {
                type: "f",
                value: 0.0
            },
            u_noise_switch_02: {
                type: "f",
                value: 0.0
            },
            u_noise_switch_03: {
                type: "f",
                value: 0.0
            },
            u_noise_switch_04: {
                type: "f",
                value: 0.0
            },
            u_texture_switch_01: {
                type: "f",
                value: 1.0
            },
            u_texture_switch_02: {
                type: "f",
                value: 0.0
            },
            u_texture_switch_03: {
                type: "f",
                value: 0.0
            },
            u_texture_switch_04: {
                type: "f",
                value: 0.0
            },
            u_wave: {
                type: "f",
                value: 0.0
            },
            u_time: {
                type: "f",
                value: 0.0
            },
            u_meshsize: {
                type: "v2",
                value: {
                    x: this.width,
                    y: this.height
                }
            },
            u_texturesize: {
                type: "v2",
                value: {
                    x: this.naturalSize.x,
                    y: this.naturalSize.y
                }
            }
        };

        this.stage = stage;
        this.mesh = null;
        this.duration = 0.9;
        this.ease = "power1.out";
    }

    init() {
        this._setMesh();
        this._setMeshScale();
    }

    _setMesh() {
        const geometry = new THREE.PlaneBufferGeometry(
            this.geometryParm.width,
            this.geometryParm.height,
            this.geometryParm.widthSegments,
            this.geometryParm.heightSegments
        );

        const material = new THREE.RawShaderMaterial({
            vertexShader: document.querySelector("#js-vertex-shader").textContent,
            fragmentShader: document.querySelector("#js-fragment-shader").textContent,
            wireframe: this.materialParam.useWireframe,
            transparent: true,
            uniforms: this.uniforms
        });

        this.mesh = new THREE.Mesh(geometry, material);
        this.stage.scene.add(this.mesh);
    }

    _setMeshScale() {
        this.width =
            document.querySelector("#webgl").getBoundingClientRect().width *
            this.geometryRatio;
        this.height =
            document.querySelector("#webgl").getBoundingClientRect().height *
            this.geometryRatio;

        this.mesh.scale.x = this.width;
        this.mesh.scale.y = this.height;

        this.uniforms.u_meshsize.value.x = this.mesh.scale.x;
        this.uniforms.u_meshsize.value.y = this.mesh.scale.y;
    }

    onResize() {
        this._setMeshScale();
    }

    _setWave() {
        gsap.fromTo(
            this.mesh.material.uniforms.u_wave, {
                value: 0.0
            }, {
                duration: this.duration / 2,
                ease: this.ease,
                value: 1.0,
                onComplete: () => {
                    gsap.to(this.mesh.material.uniforms.u_wave, {
                        duration: this.duration,
                        ease: this.ease,
                        value: 0.0
                    });
                }
            }
        );
    }

    _setNoise(number) {
        switch (number) {
            case 0:
                gsap.fromTo(
                    this.mesh.material.uniforms.u_noise_switch_01, {
                        value: 0.0
                    }, {
                        duration: this.duration,
                        ease: this.ease,
                        value: 1.0
                    }
                );
                gsap.fromTo(
                    this.mesh.material.uniforms.u_noise_switch_02, {
                        value: -1.0
                    }, {
                        duration: this.duration * 1.3,
                        ease: this.ease,
                        value: 0.0
                    }
                );
                break;
            case 1:
                gsap.fromTo(
                    this.mesh.material.uniforms.u_noise_switch_02, {
                        value: 0.0
                    }, {
                        duration: this.duration,
                        ease: this.ease,
                        value: 1.0
                    }
                );
                gsap.fromTo(
                    this.mesh.material.uniforms.u_noise_switch_03, {
                        value: -1.0
                    }, {
                        duration: this.duration * 1.3,
                        ease: this.ease,
                        value: 0.0
                    }
                );
                break;
            case 2:
                gsap.fromTo(
                    this.mesh.material.uniforms.u_noise_switch_03, {
                        value: 0.0
                    }, {
                        duration: this.duration,
                        ease: this.ease,
                        value: 1.0
                    }
                );
                gsap.fromTo(
                    this.mesh.material.uniforms.u_noise_switch_04, {
                        value: -1.0
                    }, {
                        duration: this.duration * 1.3,
                        ease: this.ease,
                        value: 0.0
                    }
                );
                break;
            case 3:
                gsap.fromTo(
                    this.mesh.material.uniforms.u_noise_switch_04, {
                        value: 0.0
                    }, {
                        duration: this.duration,
                        ease: this.ease,
                        value: 1.0
                    }
                );
                gsap.fromTo(
                    this.mesh.material.uniforms.u_noise_switch_01, {
                        value: -1.0
                    }, {
                        duration: this.duration * 1.3,
                        ease: this.ease,
                        value: 0.0
                    }
                );
                break;
        }
    }

    _changeSlide(number) {
        this._setWave();
        this._setNoise(number);

        switch (number) {
            case 0:
                gsap.to(this.mesh.material.uniforms.u_texture_switch_01, {
                    duration: this.duration,
                    ease: this.ease,
                    value: 0.0
                });
                gsap.to(this.mesh.material.uniforms.u_texture_switch_02, {
                    duration: this.duration,
                    ease: this.ease,
                    value: 1.0
                });
                break;
            case 1:
                gsap.to(this.mesh.material.uniforms.u_texture_switch_02, {
                    duration: this.duration,
                    ease: this.ease,
                    value: 0.0
                });
                gsap.to(this.mesh.material.uniforms.u_texture_switch_03, {
                    duration: this.duration,
                    ease: this.ease,
                    value: 1.0
                });
                break;
            case 2:
                gsap.to(this.mesh.material.uniforms.u_texture_switch_03, {
                    duration: this.duration,
                    ease: this.ease,
                    value: 0.0
                });
                gsap.to(this.mesh.material.uniforms.u_texture_switch_04, {
                    duration: this.duration,
                    ease: this.ease,
                    value: 1.0
                });
                break;
            case 3:
                gsap.to(this.mesh.material.uniforms.u_texture_switch_04, {
                    duration: this.duration,
                    ease: this.ease,
                    value: 0.0
                });
                gsap.to(this.mesh.material.uniforms.u_texture_switch_01, {
                    duration: this.duration,
                    ease: this.ease,
                    value: 1.0
                });
                break;
        }
    }

    _render() {
        this.uniforms.u_time.value += 0.05;
    }

    onRaf() {
        this._render();
    }
}

class Slider {
    constructor() {
        const stage = new Stage();
        stage.init();

        const mesh = new Mesh(stage);
        mesh.init();

        window.addEventListener("resize", () => {
            stage.onResize();
            mesh.onResize();
        });

        const _raf = () => {
            window.requestAnimationFrame(() => {
                _raf();

                stage.onRaf();
                mesh.onRaf();
            });
        };

        _raf();

        this.currentNum = 0;

        const _moveChangeSlide = () => {
            if (this.currentNum > 2) {
                this.currentNum = 0;
            } else {
                this.currentNum++;
            }
        };

        const _autoChangeSlide = () => {
            gsap
                .to({}, {
                    ease: "none",
                    duration: 3.0,
                    repeat: -1.0
                })
                .eventCallback("onRepeat", () => {
                    mesh._changeSlide(this.currentNum);
                    _moveChangeSlide();
                });
        };

        window.addEventListener("load", () => {
            _autoChangeSlide();
        });
    }
}

new Slider();