提高 HTML5 Canvas 中 10,000 个粒子的性能
Increase performance for 10,000 particles in HTML5 Canvas
我有两个JS小提琴,都有10,000片雪花在移动,但有两种不同的方法。
第一把小提琴:http://jsfiddle.net/6eypdhjp/
使用带有 4 x 4 白色正方形的fillRect
,每秒提供大约 60 帧 @ 10,000 片雪花。
所以我想知道我是否可以改进这一点,并在HTML5Rocks的网站上找到了一些关于画布性能的信息。其中一个建议是将雪花预先渲染到画布上,然后使用drawImage
绘制画布。
建议在这里 http://www.html5rocks.com/en/tutorials/canvas/performance/,即在标题下预渲染到屏幕外画布。使用 Ctrl + f 查找该部分。
所以我用这个小提琴尝试了他们的建议:http://jsfiddle.net/r973sr7c/
无论如何,我每秒得到大约 3 帧 @ 10,000 片雪花。这很奇怪,因为 jsPerf 甚至在这里使用相同的方法显示性能提升 http://jsperf.com/render-vs-prerender
我用于预渲染的代码在这里:
//snowflake particles
var mp = 10000; //max particles
var particles = [];
for(var i = 0; i < mp; i++) {
var m_canvas = document.createElement('canvas');
m_canvas.width = 4;
m_canvas.height = 4;
var tmp = m_canvas.getContext("2d");
tmp.fillStyle = "rgba(255,255,255,0.8)";
tmp.fillRect(0,0,4,4);
particles.push({
x : Math.random()*canvas.width, //x-coordinate
y : Math.random()*canvas.height, //y-coordinate
r : Math.random()*4+1, //radius
d : Math.random()*mp, //density
img: m_canvas //tiny canvas
})
}
//Lets draw the flakes
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for(var i = 0; i < particles.length; i++) {
var flake = particles[i];
ctx.drawImage(flake.img, flake.x,flake.y);
}
}
所以我想知道为什么我会得到如此可怕的帧速率?有没有更好的方法可以让更高的粒子数量在屏幕上移动,同时保持每秒 60 帧?
最佳帧速率是通过绘制预渲染的图像(或预渲染的画布)来实现的。
您可以将代码重构为:
- 创建大约 2-3 个屏幕外(内存中)画布,每个画布上绘制了 1/3 的粒子
- 为每个画布分配一个衰减率和一个漂移率。
- 在每个动画帧中,将每个屏幕外画布(根据其自身的衰减率和漂移率进行偏移)绘制到屏幕画布上。
结果应该是每秒大约 60 帧。
此技术牺牲了增加的内存使用量以实现最大帧速率。
下面是示例代码和演示:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
var mp=10000;
var particles=[];
var panels=[];
var panelCount=2;
var pp=panelCount-.01;
var maxFallrate=2;
var minOffsetX=-parseInt(cw*.25);
var maxOffsetX=0;
// create all particles
for(var i=0;i<mp;i++){
particles.push({
x: Math.random()*cw*1.5, //x-coordinate
y: Math.random()*ch, //y-coordinate
r: 1, //radius
panel: parseInt(Math.random()*pp) // panel==0 thru panelCount
})
}
// create a canvas for each panel
var drift=.25;
for(var p=0;p<panelCount;p++){
var c=document.createElement('canvas');
c.width=cw*1.5;
c.height=ch*2;
var offX=(drift<0)?minOffsetX:maxOffsetX;
panels.push({
canvas:c,
ctx:c.getContext('2d'),
offsetX:offX,
offsetY:-ch,
fallrate:2+Math.random()*(maxFallrate-1),
driftrate:drift
});
// change to opposite drift direction for next panel
drift=-drift;
}
// pre-render all particles
// on the specified panel canvases
for(var i=0;i<particles.length;i++){
var p=particles[i];
var cctx=panels[p.panel].ctx;
cctx.fillStyle='white';
cctx.fillRect(p.x,p.y,1,1);
}
// duplicate the top half of each canvas
// onto the bottom half of the same canvas
for(var p=0;p<panelCount;p++){
panels[p].ctx.drawImage(panels[p].canvas,0,ch);
}
// begin animating
drawStartTime=performance.now();
requestAnimationFrame(animate);
function draw(time){
ctx.clearRect(0,0,cw,ch);
for(var i=0;i<panels.length;i++){
var panel=panels[i];
ctx.drawImage(panel.canvas,panel.offsetX,panel.offsetY);
}
}
function animate(time){
for(var i=0;i<panels.length;i++){
var p=panels[i];
p.offsetX+=p.driftrate;
if(p.offsetX<minOffsetX || p.offsetX>maxOffsetX){
p.driftrate*=-1;
p.offsetX+=p.driftrate;
}
p.offsetY+=p.fallrate;
if(p.offsetY>=0){p.offsetY=-ch;}
draw(time);
}
requestAnimationFrame(animate);
}
body{ background-color:#6b92b9; padding:10px; }
#canvas{border:1px solid red;}
<canvas id="canvas" width=300 height=300></canvas>
我认为您不想每次都创建一个新的canvas
元素。这样做会导致巨大的性能消耗。
当我将此代码移出 for 循环时,性能立即提高。我认为这样做将允许您优化代码以实现预期行为:
var m_canvas = document.createElement('canvas');
m_canvas.width = 4;
m_canvas.height = 4;
var tmp = m_canvas.getContext("2d");
tmp.fillStyle = "rgba(255,255,255,0.8)";
tmp.fillRect(0, 0, 4, 4);
看看这个修订的JSFiddle。
希望这有帮助!
您将预先渲染多次绘制的元素。
例如,假设您有一个风景,您可以在游戏滚动期间在不同位置绘制灌木丛(相同形式)。使用内存画布是可以的。
对于您的代码,您应该尝试将薄片分为例如 10 种尺寸。因此,创建 10 个内存画布。然后把它们画成随机的位置。
换句话说,您将 10 张画布复制 1.000 次。不是 10.000 幅画布 10.000 次。
- 函数参数中的数据与指定变量之间的任何性能差异
- 提高JQuery的性能
- 使用正则表达式评估电子邮件地址时出现性能问题
- React:按键的性能提升
- 在Three.js中导出网格会提高性能吗
- 基于粒子的粘弹性流体表面张力问题
- 在javascript中搜索项目列表的性能
- 为什么在许多浏览器中drawImage()的性能略好于createPattern()
- JavaScript数组优化以提高性能
- React+Redux性能优化与组件ShouldUpdate
- 在循环中附加事件处理程序时出现浏览器性能问题
- JavaScript-===vs===运算符性能
- 超时功能的性能
- 围绕圆环的Javascript粒子动画
- Pg承诺性能提升:在冲突中
- immutable.js与嵌套映射/对象的比较/相等性能
- NodeJ中的注释会影响性能吗
- 提高 HTML5 Canvas 中 10,000 个粒子的性能
- javascript粒子性能背后的原因与其他软件和程序相比有很多
- 创建具有多个粒子大小的bufferGeometry.最佳性能