在Canvas中渲染粒子,提高FireFox的FPS
Rendering particles in Canvas, improving FireFox FPS
我试图在Firefox中获得30以上的FPS。我真的不知道我还能做些什么来改善它。有什么建议吗?
Chrome和Opera徘徊在60 fps左右,而FF停留在10-20之间,正因为如此,它导致我的页面其余部分出现延迟问题。
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);
你的性能杀手是在每个动画帧中为每个粒子创建渐变。
你可以把昂贵的gradient
换成相对便宜的globalAlpha
。
这是一个使用globalAlpha而不是渐变的重构。我让你调整globalAlpha来匹配你的效果,但是这个重构在Firefox上要快得多(在我的机器上是59+)。
在你的代码中还有其他可能的优化,但是使用梯度是性能杀手…
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>
我也在努力解决这个延迟,缓慢,仅在Firefox上的fps问题。Chrome, safari或ie浏览器都可以。
我有办法了!
问题是你通过N个粒子循环,每次绘制,这N个绘制是我们在Firefox中遇到的问题。我们每帧只画一次就是解决方案。
在每一帧(myRequestAnimationFrame, Polyfills等)
const particles = []; // WE SHOW THIS AS EXAMPLE ONLY - 1000 PARTICLES
const onRender = () => {
myRequestAnimationFrame(onRender);
ctx.clearRect(0, 0, canvas.width, canvas.height); // CLEAR CANVAS EACH FRAME
ctx.beginPath(); // WE START
for (var i = 0; i < particles.length; i++) {
// SET EACH PARTICLE VALUES, INCLUDING THE X, Y
ctx.moveTo(particles[i].x, particles[i].y); // THE KEY TO THE SOLUTION
ctx.arc(particles[i].x, particles[i].y, particles[i].r, Math.PI * 2, false); // WE FILL EACH PARTICLE WITH COLOUR
}
ctx.fill(); // LASTLY WE DRAWN ONCE ONLY PER FRAME
};
myRequestAnimationFrame(onRender);
Bob's your uncle !
丹尼尔相关文章:
- 提高JQuery的性能
- 为什么这在IE中的工作方式与在Firefox中不同
- JS可以在Chrome中工作,但不能在Firefox中工作
- createElement("a") - FireFox JavaScript
- 为什么javascript:void(0)在Firefox中不起作用
- 在Three.js中导出网格会提高性能吗
- Facebook登录按钮没有'不能在Firefox上工作
- jpm的默认Firefox路径没有'不起作用
- 重载JS'firefox中的对象原型
- JavaScript数组优化以提高性能
- Ajax调用在Firefox中不会自动响应
- JS在firefox中无法正常工作
- firefox插件和dev/panel之间的通信
- IE/Chrome中未定义的函数,但Firefox中没有
- ascii输入键通过firefox中的javascript返回0
- 在firefox和chrome中的左侧显示iframe滚动条
- html5 drawImage适用于firefox,而不是chrome
- angularjs$valid-on-dates在firefox中报告错误
- 您可以使用JavaScript和Firefox扩展来更改现有页面吗
- 在Canvas中渲染粒子,提高FireFox的FPS