2

我正在做的一个实验有问题。

我的计划是在整个页面上都有一个美丽而闪亮的星星背景。使用那个精彩的教程(http://timothypoon.com/blog/2011/01/19/html5-canvas-particle-animation/)我设法获得了完美的背景。我使用静态画布显示静态星星,使用动画画布显示闪亮星星。

事实是它非常消耗内存!在 chrome 和 opera 上它运行得非常顺利,但在 Firefox IE 或平板电脑上,渲染每一帧等都是一团糟……在 HEIGHT 很大的页面上更糟。

所以我进行了一些优化:

- 使用缓冲画布,问题是每帧调用 1500 次的 createRadialGradient

- 使用一个大的缓冲画布,每个星星 1 个画布,在初始化时只调用 createRadialGradient。

- 删除缓冲画布并将每个星星画布绘制到主画布

最后的优化是我能做到的最好的,所以我写了一个小提琴来展示代码现在的情况。

   //Buffering the star image
    this.scanvas = document.createElement('canvas');
    this.scanvas.width=2*this.r;
    this.scanvas.height=2*this.r;
    this.scon=this.scanvas.getContext('2d');
    g = this.scon.createRadialGradient(this.r,this.r,0,this.r,this.r,this.r);
    g.addColorStop(0.0, 'rgba(255,255,255,0.9)');
    g.addColorStop(this.stop, 'rgba('+this.color.r+','+this.color.g+','+this.color.b+','+this.stop+')');
    g.addColorStop(1.0, 'rgba('+this.color.r+','+this.color.g+','+this.color.b+',0)');
    this.scon.fillStyle = g;
    this.scon.fillRect(0,0,2*this.r,2*this.r);

这就是我需要你的地方:

- 一种根据用户表现调整闪亮星星数量的方法

- 优化提示

在此先感谢所有愿意帮助我的人,如果我犯了语法错误,我深表歉意,我的英语并不完美。

编辑 感谢您的反馈,让我解释整个过程,每颗星星都有自己不同的渐变和大小,这就是为什么我将它存储到个人画布中,闪亮的效果只能通过使用 drawImage 在主画布上缩放该画布来完成。

我认为最好的办法是在缓冲画布中预渲染 50 或 100 颗不同的星星,然后随机挑选并绘制一颗,你不觉得吗?

编辑2

根据术士的建议更新了小提琴,一颗预渲染的星星,缩放以匹配当前大小。星星不那么漂亮,但整个事情运行得更顺畅。

编辑3

更新小提琴以使用精灵表。华丽的!!!!

 //generate the star strip
    var len=(ttlm/rint)|0;
    scanvas = document.createElement('canvas');
    scanvas.width=len*2*r;
    scanvas.height=2*r;
    scon=scanvas.getContext('2d');
    for(var i=0;i<len;i++){
        var newo = (i/len);
        var cr = r*newo;
        g = scon.createRadialGradient(2*r*i+r,r,0,2*r*i+r,r,(cr <= 2 ? 2 : cr));
        g.addColorStop(0.0, 'rgba(200,220,255,'+newo+')');
        g.addColorStop(0.2, 'rgba(200,220,255,'+(newo*.7)+')');
        g.addColorStop(0.4, 'rgba(150,170,205,'+(newo*.2)+')');
        g.addColorStop(0.7, 'rgba(150,170,205,0)');
        scon.fillStyle = g;
        scon.fillRect(2*r*i,0,2*r,2*r);         
    }

编辑 4(最终)

动态明星创作

function draw() {
    frameTime.push(Date.now());    
    con.clearRect(0,0,WIDTH,HEIGHT);
    for(var i = 0, len = pxs.length; i < len; i++) {
        pxs[i].fade();
        pxs[i].draw();
    }   
    requestAnimationFrame(draw);
    if(allowMore === true && frameTime.length == monitoredFrame)
    {
        if(getAvgTime()<threshold && pxs.length<totalStars ) 
        {
            addStars();         
        }
        else
        {
            allowMore=false;
            static=true;
            fillpxs(totalStars-pxs.length,pxss);
            drawstatic();
            static=false;
        }
    }
}

这是更新的和最终的小提琴,带有精灵表、动态星星创建和一些优化。如果您看到其他我应该更新的内容,请不要犹豫。

POST EDIT重新启用流星/原型对象/摆脱 Jquery

http://jsfiddle.net/macintox/K8YTu/32/

感谢所有帮助过我的人,这真的很友善和有启发性,我希望它有时会对某些人有所帮助。

埃斯多特。PS:我很高兴。经过测试,该脚本在每个浏览器甚至 IE9 上都能流畅运行。亚塔!!

4

3 回答 3

2

采用浏览器性能

要衡量用户设置的能力,您可以实现一个在某个阈值处停止的动态星创建器。

例如,在您的代码中,您定义了要绘制的最小星数。然后在主循环中测量时间,如果绘制星星的时间小于最大阈值,则再添加 10 颗星星(我只是在这里抛出一个数字)。

没有多少人知道它为它调用的函数requestAnimationFrame提供了一个参数(DOMHighResTimeStamp ),以及自上次请求以来花费的时间(以毫秒为单位)。这将帮助您跟踪负载,并且我们知道 60 fps 大约是每帧 16.7 毫秒,我们可以在此值下设置一个阈值以达到最佳状态,并且仍然允许其他浏览器的一些开销。

代码可能如下所示:

var minCount = 100,   /// minimum number of stars
    batchCount = 10,  /// stars to add each frame
    threshold= 14,    /// milliseconds for each frame used
    allowMore = true; /// keep adding

/// generate initial stars
generateStarts(minCount);

/// timeUsed contains the time in ms since last requestAnimationFrame was called
function loop(timeUsed) {

    if (allowMore === true && timeUsed < threshold) {
        addMoreStars(batchNumber);
    } else {
        allowMore = false;
    }

    /// render stars

    requestAnimationFrame(loop);
}

请注意,这有点简化。您将需要先运行几轮并测量平均值以尽可能地使这项工作更好,并且在添加星标时会达到峰值(以及由于其他浏览器操作)。

所以添加星星,测量几轮,如果平均值低于阈值,添加星星并重复。

优化

精灵表

至于优化精灵表是要走的路。他们不必只是明星(我将在下面尝试解释)。

梯度和弧线是此应用程序中成本高昂的部分。即使在预渲染单个星星时,由于插值等原因,调整这么多星星的大小也是有成本的。

当出现大量昂贵的操作时,最好在内存使用方面做出妥协,并尽可能预渲染所有内容。

例如:通过首先使用渐变和弧线渲染一个大星星来渲染各种尺寸。使用该星将其他尺寸绘制为具有相同单元格大小的星条。

现在,使用 sprite-sheet 仅绘制一半的星星并绘制 sprite-sheet的剪裁部分(而不是重新调整大小)。然后将画布旋转 90 度并将画布本身绘制在其自身顶部的不同位置(画布本身成为一个大的“精灵表”)。

旋转 90 度不像其他度数那样需要性能(优化了 0、90、180、270)。这会给你一种拥有实际恒星数量的错觉,并且由于它是旋转的,我们无法轻易检测到重复模式。

一次drawImagecanvas的操作比所有星星的许多小绘制操作都要快。

(当然,您可以多次执行此操作,而不仅仅是在您开始看到模式之前的某个点——对于多少、什么大小等没有关键答案,因此找到正确的平衡始终是一个实验)。

整数

其他优化可以仅使用整数位置和大小。当您使用浮点数时,子像素化被激活,这是昂贵的,因为浏览器需要为偏移像素计算抗锯齿。

使用整数值会有所帮助,因为不需要子像素化(但这并不意味着如果不是 1:1 尺寸,图像将不会被插值)。

内存界限

您还可以通过使用可在 4 上整除的大小和位置来帮助底层低级别位图处理一点点。这与内存复制和低级别剪辑有关。您始终可以制作多个精灵表来改变可在 4 上分割的单元格内的位置。

这个技巧在速度较慢的计算机(即典型的消费者指定的计算机)上更有价值。

关闭抗锯齿

关闭图像的抗锯齿。这将有助于性能,但会给出更粗略的星星结果。要关闭图像抗锯齿,请执行以下操作:

ctx.webkitEnableImageSmoothing = false;
ctx.mozEnableImageSmoothing = false;
ctx.enableImageSmoothing = false;

只要您用于drawImage渲染星星,您就会看到性能显着提高。

缓存所有内容

缓存您可以缓存的所有内容,包括星图和变量。

当您这样做时stars.length,浏览器的解析器需要首先查找stars然后遍历该树以查找length- 对于每一轮(这可能在某些浏览器中进行了优化)。

如果你首先将它缓存到一个变量var len = stars.length中,浏览器只需要遍历树和分支一次,并且在循环中它只需要查找本地范围来查找len更快的变量。

分辨率降低

您还可以将分辨率降低一半,即。以目标大小的一半做所有事情。在最后一步中,将渲染放大到全尺寸。这将在最初为您节省 75% 的渲染区域,但结果会给您带来一点低分辨率的外观。

在专业视频世界中,当物体被动画(主要是移动)时,我们经常使用低分辨率,因为当物体移动时眼睛/大脑会修补(或无法检测到)如此多的细节,因此并不那么明显。如果这可以帮助这里必须进行测试 - 也许不是因为星星实际上并没有移动,但值得一试第二个好处:提高性能。

于 2013-09-06T21:36:04.787 回答
2

不如只创建一个处于径向发光不同阶段的恒星的精灵表。

您甚至可以使用画布最初创建精灵表。

然后使用 context.drawImage(spritesheet,spriteX,spriteY,starWidth,starHeight) 来显示星星。

Spritesheet 图像可以非常快速地绘制到屏幕上,而且开销很小。

您可以通过将 spritesheet 分解为单个星形图像来进一步优化。

祝你的项目好运:)

于 2013-09-06T17:31:15.927 回答
1

1、最小化操作,与DOM相关;

在第 93 行中,您正在创建画布:

this.scanvas = document.createElement('canvas');

你只需要一个画布而不是这个。将画布创建移至初始化步骤。

2.画布使用整数坐标;

3.使用对象池设计模式来提高性能。

4. 在 for 循环中缓存长度变量:

for(var i = 0; i < pxs.length; i++) {...
}

更好的:

for(var i = 0, len = pxs.length; i < len; i++) {
...
}

注意:不要将 jquery 与本机 js 混合使用。

于 2013-09-06T17:25:52.730 回答