0

我试图弄清楚如何提高使用 requestAnimationFrame 重新绘制画布的粒子文本效果的性能 (fps)。它在较新的设备上运行良好,但是当我在较慢的 CPU 上测试它时,帧数下降到无法忍受的水平。我尝试减少屏幕上的粒子数量,但没有任何效果。即使我从回调函数中删除更新和绘制方法,并为 requestAnimationFrame 设置超时,我也只能获得 2-3 fps 的改进。我附上了一个链接,指向下面来自 Frank's Laboratory 的示例,以展示我正在使用的内容。非常感谢任何帮助。

https://codepen.io/franksLaboratory/pen/VwKEeqR

const canvas = document.getElementById("canvas1");
const ctx = canvas.getContext("2d");
canvas.width = 1200;
canvas.height = 600;
let particleArray = [];
let adjustX = -10;
let adjustY = 3;

// get mouse mouse position //
let mouse = {
    x: null,
    y: null,
  radius: 150
}

let canvasPosition = canvas.getBoundingClientRect();
window.addEventListener('mousemove', 
    function(e){
    mouse.x = e.x - canvasPosition.left;
    mouse.y = e.y - canvasPosition.top;
});

ctx.font = 'bold 16px Verdana';
ctx.fillText('LIQUID', 5, 30);
const data = ctx.getImageData(0, 0, canvas.width, 100);

class Particle {
    constructor(x, y){
        this.x = x + 200,
        this.y = y - 100,
        this.size = 8,
        this.baseX = this.x,
        this.baseY = this.y,
        this.density = ((Math.random() * 30) + 1);
    }
    draw() {
        ctx.fillStyle = 'white';
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
        ctx.closePath();
        ctx.fill();
    }
    update() {
        // check mouse position/particle position - collision detection
        let dx = mouse.x - this.x;
        let dy = mouse.y - this.y;
        let distance = Math.sqrt(dx*dx + dy*dy);
        let forceDirectionX = dx / distance;
        let forceDirectionY = dy / distance;
        // distance past which the force is zero
        var maxDistance = mouse.radius;
        // convert (0...maxDistance) range into a (1...0).
        // Close is near 1, far is near 0
        // for example:
        //   250 => 0.75
        //   100 => 0.9
        //   10  => 0.99
        var force = (maxDistance - distance) / maxDistance;

        // if we went below zero, set it to zero.
        if (force < 0) force = 0;

        let directionX = (forceDirectionX * force * this.density)
        let directionY = (forceDirectionY * force * this.density);

        if (distance < mouse.radius + this.size){
            this.x -= directionX;
            this.y -= directionY;
        } else {
            if (this.x !== this.baseX ) {
                let dx = this.x - this.baseX;
                this.x -= dx/10;
            } if (this.y !== this.baseY) {
                let dy = this.y - this.baseY;
                this.y -= dy/10;
            }
        }
    }
}
function init(){
    particleArray = [];

    for (var y = 0, y2 = data.height; y < y2; y++) {
        for (var x = 0, x2 = data.width; x < x2; x++) {
            if (data.data[(y * 4 * data.width) + (x * 4) + 3] > 128) {
                let positionX = x + adjustX;
                let positionY = y + adjustY;
                //let positionX = x;
                //let positionY = y;
                particleArray.push(new Particle(positionX * 15, positionY * 15));
            }
        }
    }
    
}
function animate(){
    //ctx.fillStyle = 'rgba(0,0,0,0.5)';
    //ctx.fillRect(0,0,innerWidth,innerHeight);
    ctx.clearRect(0,0,innerWidth,innerHeight);
    
    for (let i = 0; i < particleArray.length; i++){
        particleArray[i].update();
        particleArray[i].draw();
    }
    connect();
    requestAnimationFrame(animate);
}
init();
animate();
/*
// RESIZE SETTING - empty and refill particle array every time window changes size + change canvas size
window.addEventListener('resize',
function() {
    canvas.width = innerWidth;
    canvas.height = innerHeight;
    init();
});*/


function connect(){
    let opacityValue = 1;
    for (let a = 0; a < particleArray.length; a++) {
        for (let b = a; b < particleArray.length; b++) {
            let distance = (( particleArray[a].x - particleArray[b].x) * (particleArray[a].x - particleArray[b].x))
            + ((particleArray[a].y - particleArray[b].y) * (particleArray[a].y - particleArray[b].y));
            
            if (distance < 3600) {
                
                opacityValue = 1 - (distance/3600);
                let dx = mouse.x - particleArray[a].x;
                let dy = mouse.y - particleArray[a].y;
                let mouseDistance = Math.sqrt(dx*dx+dy*dy);
                if (mouseDistance < mouse.radius / 2) {
                    particleArray[a].size = 25;
                  ctx.strokeStyle='rgba(255,255,150,' + opacityValue + ')';
                } else if (mouseDistance < mouse.radius - 50) {
                    particleArray[a].size = 20;
                  ctx.strokeStyle='rgba(255,255,180,' + opacityValue + ')';
                } else if (mouseDistance < mouse.radius + 20) {
                    particleArray[a].size = 15;
                  ctx.strokeStyle='rgba(255,255,210,' + opacityValue + ')';
                } else  {
                    particleArray[a].size = 8;
                ctx.strokeStyle='rgba(255,255,255,' + opacityValue + ')';
                }
                ctx.lineWidth = 20;
                ctx.beginPath();
                ctx.moveTo(particleArray[a].x, particleArray[a].y);
                ctx.lineTo(particleArray[b].x, particleArray[b].y);
                ctx.stroke();
            }
        }
    
    }
}

window.addEventListener('resize', function(){
  canvasPosition = canvas.getBoundingClientRect();
});
4

0 回答 0