使用Canvas和WebGL实现粒子效果的基本方法

蔷薇花开 2020-01-15 ⋅ 18 阅读

粒子效果是一种常见的web动画效果,通过使用Canvas和WebGL技术,我们可以实现各种各样的粒子效果,如星空、烟花、雨滴等等。本篇博客将介绍使用Canvas和WebGL实现粒子效果的基本方法,并且提供一些相关的代码示例。

1. 使用Canvas实现粒子效果

Canvas是HTML5提供的一个2D绘图API,可以在网页上绘制各种图形,包括粒子效果。下面是一个简单的使用Canvas实现粒子效果的示例:

<canvas id="particle-canvas"></canvas>

<script>
    const canvas = document.getElementById('particle-canvas');
    const ctx = canvas.getContext('2d');
    const particles = [];

    // 初始化粒子
    function initParticles() {
        for (let i = 0; i < 100; i++) {
            const x = Math.random() * canvas.width;
            const y = Math.random() * canvas.height;
            const radius = Math.random() * 5;
            const color = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, 1)`;
            const particle = { x, y, radius, color };
            particles.push(particle);
        }
    }

    // 更新粒子位置
    function updateParticles() {
        particles.forEach(particle => {
            particle.x += Math.random() * 2 - 1;
            particle.y += Math.random() * 2 - 1;
        });
    }

    // 绘制粒子
    function drawParticles() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        particles.forEach(particle => {
            ctx.beginPath();
            ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);
            ctx.fillStyle = particle.color;
            ctx.fill();
            ctx.closePath();
        });
    }

    // 动画循环
    function animate() {
        updateParticles();
        drawParticles();
        requestAnimationFrame(animate);
    }

    // 入口函数
    function init() {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        initParticles();
        animate();
    }

    init();
</script>

上面的代码实现了一个简单的粒子效果,每个粒子在画布中随机移动,并且具有随机的颜色和半径。

2. 使用WebGL实现粒子效果

WebGL是一种基于OpenGL的图形渲染技术,可以在网页上绘制复杂的3D图形。下面是一个使用WebGL实现粒子效果的示例:

<canvas id="particle-canvas"></canvas>

<script>
    const canvas = document.getElementById('particle-canvas');
    const gl = canvas.getContext('webgl');
    const vertexShaderSource = `
        attribute vec2 a_position;

        void main() {
            gl_Position = vec4(a_position, 0, 1);
            gl_PointSize = 5.0;
        }
    `;
    const fragmentShaderSource = `
        precision mediump float;
        uniform vec4 u_color;

        void main() {
            gl_FragColor = u_color;
        }
    `;
    const program = initShaderProgram(gl, vertexShaderSource, fragmentShaderSource);
    const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
    const colorUniformLocation = gl.getUniformLocation(program, 'u_color');
    const buffer = gl.createBuffer();
    const particles = [];

    // 初始化粒子
    function initParticles() {
        for (let i = 0; i < 100; i++) {
            const x = Math.random() * 2 - 1;
            const y = Math.random() * 2 - 1;
            const color = [Math.random(), Math.random(), Math.random(), 1];
            particles.push({ x, y, color });
        }
    }

    // 更新粒子位置
    function updateParticles() {
        particles.forEach(particle => {
            particle.x += Math.random() * 0.02 - 0.01;
            particle.y += Math.random() * 0.02 - 0.01;
        });
    }

    // 绘制粒子
    function drawParticles() {
        const positions = particles.flatMap(particle => [particle.x, particle.y]);
        const colors = particles.flatMap(particle => particle.color);
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
        gl.enableVertexAttribArray(positionAttributeLocation);
        gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
        gl.uniform4fv(colorUniformLocation, colors);
        gl.drawArrays(gl.POINTS, 0, particles.length);
    }

    // 编译着色器程序
    function initShaderProgram(gl, vertexShaderSource, fragmentShaderSource) {
        const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
        const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        return program;
    }

    // 加载着色器
    function loadShader(gl, type, source) {
        const shader = gl.createShader(type);
        gl.shaderSource(shader, source);
        gl.compileShader(shader);
        return shader;
    }

    // 动画循环
    function animate() {
        updateParticles();
        drawParticles();
        requestAnimationFrame(animate);
    }

    // 入口函数
    function init() {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
        gl.clearColor(0, 0, 0, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);
        initParticles();
        animate();
    }

    init();
</script>

上面的代码使用WebGL绘制了100个带有随机颜色的粒子,并在每一帧中随机移动粒子的位置。使用WebGL实现粒子效果相对复杂一些,需要编写着色器程序,并且需要了解WebGL的一些基本概念和API。

总结

本篇博客介绍了使用Canvas和WebGL实现粒子效果的基本方法,并提供了相应的代码示例。通过Canvas和WebGL,我们可以实现各种各样的粒子效果,为网页增添动感和视觉效果。如果你对粒子效果感兴趣或者想要学习更多关于Canvas和WebGL的知识,可以继续深入学习相关的文档和教程。


全部评论: 0

    我有话说: