简体   繁体   中英

Rendering particles in Canvas, improving FireFox FPS

I'm trying to get the FPS above 30 in Firefox. I'm really not sure what else I may do to improve it. Any suggestions?

Chrome and Opera hover around 60 fps, while FF is stuck between 10-20, and because of that it's causing lag issues on the rest of my page.

http://jsfiddle.net/7vv2tur7/

window.requestAnimFrame = (function(){
    return window.requestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    function( callback ) {
        window.setTimeout(callback, 1000 / 60);
    };
})();


(function() {

    particleCanvas();

    con = particle.getContext('2d');
    pxs = [];
    for(var i = 0; i < 25; i++) {
        pxs[i] = new Circle();
        pxs[i].reset();
    }

    requestAnimFrame(paintParticles);

    window.onresize = function(event) {
        particleCanvas();
    };

})();

function Circle() {

    // settings
    this.s = {

        ttl:10000,

        // speeds
        xmax:4,
        ymax:4,

        // max size
        size:1,

        rt:4,

        xdrift:60,
        ydrift:60,

        opacity: 0.3,
    };


    this.reset = function() {

        // randomise positioning for each particle
        this.x = particle.width * Math.random();
        this.y = particle.height * Math.random();

        // size
        this.r = ((this.s.size-1)*Math.random()) + 1;


        this.dx = (Math.random()*this.s.xmax) * (Math.random() < 0.5 ? -1 : 1);
        this.dy = (Math.random()*this.s.ymax) * (Math.random() < 0.5 ? -1 : 1);
        this.hl = this.s.ttl / 4 * (this.r/this.s.size);
        this.rt = Math.random()*this.hl;
        this.s.rt = Math.random() +1;
        this.stop = Math.random();
        this.s.xdrift *= Math.random() * (Math.random() < 0.5 ? -1 : 1);
        this.s.ydrift *= Math.random() * (Math.random() < 0.5 ? -1 : 1);
    };

    this.fade = function() {
        this.rt += 5 + this.s.rt;
    };

    this.draw = function() {

        if(this.rt >= this.hl) this.reset();
        var newo = 1 - (this.rt/this.hl);



        con.globalAlpha = this.s.opacity;


        con.beginPath();
        con.arc(this.x,this.y,this.r,0,Math.PI*2,true);
        con.closePath();
        var cr = this.r*newo;

        g = con.createRadialGradient(this.x, this.y, 0, this.x, this.y, (cr <= 0 ? 1 : 5));
        g.addColorStop(0.0, 'rgba(255,255,255,' + newo + ')');
        g.addColorStop(this.stop, 'rgba(255,255,255,' + 0.5 * newo + ')');
        g.addColorStop(1.0, 'rgba(255,255,255, 0)');


        con.fillStyle = g;
        con.fill();
    };

    this.move = function() {
        this.x += (this.rt/this.hl)*this.dx;
        this.y += (this.rt/this.hl)*this.dy;
        if(this.x > particle.width || this.x < 0) this.dx *= -1;
        if(this.y > particle.height || this.y < 0) this.dy *= -1;
    };

    this.getX = function() { return this.x; };
    this.getY = function() { return this.y; };
}

function particleCanvas() {
    particle.width  = document.querySelector('.start').offsetWidth / 2;
    particle.height = document.querySelector('.start').offsetHeight / 2;
}

function paintParticles() {

    requestAnimFrame(paintParticles);

    con.clearRect ( 0 , 0 , particle.width, particle.height );

    for(var i = 0; i < pxs.length; i++) {
        pxs[i].fade();
        pxs[i].move();
        pxs[i].draw();
    }

    var thisFrameFPS = 1000 / ((now=new Date()) - lastUpdate);
        fps += (thisFrameFPS - fps) / fpsFilter;
        lastUpdate = now;

}

var fps = 0, now,
    lastUpdate = (new Date())*1 - 1, fpsFilter = 50;



setInterval(function(){
    document.querySelector('.fps').innerHTML = fps.toFixed(1) + ' fps';
}, 1000);

Your performance killer is creating a gradient for each particle during each animation frame.

You might swap the expensive gradient for the relatively cheaper globalAlpha .

Here's a refactoring that uses globalAlpha instead of gradient. I left it for you to tweak the globalAlpha to match your effect, but this refactoring is much faster on Firefox (59+ on my machine).

There are other optimizations possible in your code, but using gradients is the performance killer...

 window.requestAnimFrame = (function(){ return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function( callback ) { window.setTimeout(callback, 1000 / 60); }; })(); (function() { particleCanvas(); con = particle.getContext('2d'); pxs = []; for(var i = 0; i < 25; i++) { pxs[i] = new Circle(); pxs[i].reset(); } requestAnimFrame(paintParticles); window.onresize = function(event) { particleCanvas(); }; })(); function Circle() { // settings this.s = { ttl:10000, // speeds xmax:4, ymax:4, // max size size:1, rt:4, xdrift:60, ydrift:60, opacity: 0.7, }; this.reset = function() { // randomise positioning for each particle this.x = particle.width * Math.random(); this.y = particle.height * Math.random(); // size this.r = ((this.s.size-1)*Math.random()) + 1; this.dx = (Math.random()*this.s.xmax) * (Math.random() < 0.5 ? -1 : 1); this.dy = (Math.random()*this.s.ymax) * (Math.random() < 0.5 ? -1 : 1); this.hl = this.s.ttl / 4 * (this.r/this.s.size); this.rt = Math.random()*this.hl; this.s.rt = Math.random() +1; this.stop = Math.random(); this.s.xdrift *= Math.random() * (Math.random() < 0.5 ? -1 : 1); this.s.ydrift *= Math.random() * (Math.random() < 0.5 ? -1 : 1); this.s.opacity=0.70; }; this.fade = function() { this.rt += 5 + this.s.rt; this.s.opacity-=.005; }; this.draw = function() { if(this.rt >= this.hl) this.reset(); var newo = 1 - (this.rt/this.hl); con.globalAlpha = this.s.opacity; con.beginPath(); con.arc(this.x,this.y,this.r,0,Math.PI*2,true); con.closePath(); var cr = this.r*newo; con.fill(); }; this.move = function() { this.x += (this.rt/this.hl)*this.dx; this.y += (this.rt/this.hl)*this.dy; if(this.x > particle.width || this.x < 0) this.dx *= -1; if(this.y > particle.height || this.y < 0) this.dy *= -1; }; this.getX = function() { return this.x; }; this.getY = function() { return this.y; }; } function particleCanvas() { particle.width = document.querySelector('body').offsetWidth / 2; particle.height = document.querySelector('body').offsetHeight / 2; } function paintParticles() { requestAnimFrame(paintParticles); con.clearRect ( 0 , 0 , particle.width, particle.height ); con.fillStyle = 'white'; for(var i = 0; i < pxs.length; i++) { pxs[i].fade(); pxs[i].move(); pxs[i].draw(); } var thisFrameFPS = 1000 / ((now=new Date()) - lastUpdate); fps += (thisFrameFPS - fps) / fpsFilter; lastUpdate = now; } var fps = 0, now, lastUpdate = (new Date())*1 - 1, fpsFilter = 50; setInterval(function(){ document.querySelector('.fps').innerHTML = fps.toFixed(1) + ' fps'; }, 1000); 
 html, body {height:100%;width:100%;display:block;margin:0;padding:0;background:black} * {box-sizing:border-box} span { position:absolute; top:50px; left:50px; font-size:28px; color:white; font-family:mono; } canvas {width:100%;height:100%} </style> 
 <canvas id="particle"></canvas> <span class="fps"></span> 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM