Skip to content

webgl

Posted on:September 7, 2023 at 03:37 AM
预计阅读时长:3 min read 字数:536

regl

pnpm --filter @notes/docs i regl -r

regl quick start

regl demo
import { useEffect } from "react";
import wrapREGL from "regl";

export default () => {
    useEffect(() => {
        const regl = wrapREGL("#demo");
        const drawTriangle = regl({
            frag: `
  void main() {
    gl_FragColor = vec4(1, 0, 0, 1);
  }`,
            vert: `
  attribute vec2 position;
  void main() {
    gl_Position = vec4(position, 0, 1);
  }`,
            attributes: {
                position: [[0, -1], [-1, 0], [1, 1]]
            },

            count: 3
        })
        regl.frame(() => {
            regl.clear({
                color: [0, 0, 0, 1],
            })
            drawTriangle()
        })
    })
    return <canvas id="demo"></canvas>
}

图片粒子化

import Demo from '@components/react/webgl/Demo.astro'

<Demo/>
particle详情
import { useEffect } from "react";

export const useParticle = (
    canvasId: string = "canvas1",
    imgId: string = "image1",
    buttonId: string = "wrapButton",
    startId: string = "start"
) => {
    useEffect(() => {

        let aId = 0;
        const init = () => {
            const canvas = document.getElementById(canvasId) as HTMLCanvasElement;
            const wrapButton = document.getElementById(buttonId) as HTMLButtonElement;
            const ctx = canvas.getContext("2d") as CanvasRenderingContext2D;

            const width = canvas.clientWidth as number;
            const height = canvas.clientHeight as number;
            class Particle {
                x: number;
                y: number;
                size: number;
                effect: Effect;
                vx: number;
                vy: number;
                originY: number;
                originX: number;
                color: string;
                ease: number = 0.1;
                constructor(effect: Effect, color: string, j: number, i: number) {
                    this.effect = effect;
                    this.x = Math.random() * this.effect.width;
                    this.y = Math.random() * this.effect.height;
                    this.originX = Math.floor(j);
                    this.originY = i;
                    // this.x =this.originX;
                    // this.y = this.originY;
                    this.color = color;
                    this.size = this.effect.gap;
                    this.ease = 0.1;
                    // this.vx = Math.random()  - 0.5;
                    // this.vy = Math.random()  - 0.5;

                    this.vx = 0;
                    this.vy = 0;
                }

                draw(contex: CanvasRenderingContext2D) {
                    contex.fillStyle = this.color;
                    contex.fillRect(this.x, this.y, this.size, this.size);
                }
                update() {
                    //妙
                    this.x += (this.originX - this.x) * this.ease;
                    this.y += (this.originY - this.y) * this.ease;
                    // this.y += this.vy;
                }

                wrap() {
                    this.x = Math.random() * this.effect.width;
                    this.y = Math.random() * this.effect.height;
                    this.ease = 0.05;
                }
            }


            class Effect {
                width: number;
                height: number;
                particles: Array<Particle>;
                imgae: HTMLImageElement;
                centerX: number;
                centerY: number;
                x: number;
                y: number;
                gap: number;
                constructor(width: number, height: number) {
                    this.width = width;
                    this.height = height;
                    this.particles = [];
                    this.imgae = document.getElementById(imgId) as HTMLImageElement;
                    this.centerX = this.width * 0.5;
                    this.centerY = this.height * 0.5;
                    this.x = this.centerX - this.imgae.width * 0.5;
                    this.y = this.centerY - this.imgae.height * 0.5;
                    this.gap = 4;
                }

                init(context: CanvasRenderingContext2D) {
                    context.drawImage(this.imgae, this.x, this.y);
                    const pixels = context.getImageData(0, 0, this.width, this.height).data;
                    for (let i = 0; i < this.height; i += this.gap) {
                        for (let j = 0; j < this.width; j += this.gap) {
                            const index = (i * this.width + j) * 4;
                            const red = pixels[index];
                            const green = pixels[index + 1];
                            const blue = pixels[index + 2];
                            const alpha = pixels[index + 3];

                            let color = `rgb(${red},${green},${blue})`;
                            if (alpha > 0) {
                                this.particles.push(new Particle(this, color, j, i))
                            }
                        }

                    }
                }
                draw(context: CanvasRenderingContext2D) {
                    this.particles.forEach(item => item.draw(context))
                }
                update() {
                    this.particles.forEach(item => item.update())
                }

                wrap() {
                    this.particles.forEach(item => item.wrap())
                }
            }

            const effect = new Effect(width, height);
            effect.init(ctx);
            const animate = () => {
                ctx.clearRect(0, 0, width, height);
                effect.draw(ctx);
                effect.update();
                aId = requestAnimationFrame(animate);
            }
            animate();
            wrapButton.addEventListener('click', () => {
                effect.wrap();
            })
        }

        init();
    })
}

链接