javascript - Canvas Shiny 星星背景性能问题

标签 javascript performance canvas drawimage

我正在进行的实验存在问题。

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

事实是它非常消耗内存!在chrome和Opera上,它运行非常平稳,但是在Firefox IE或平板电脑上,渲染每一帧等都一团糟。在高度很大的页面上,情况更糟。

因此,我进行了一些优化:

-使用缓冲 Canvas ,问题是createRadialGradient,每帧被调用1500次

-使用大缓冲 Canvas ,并为每个星星使用1个 Canvas ,并在初始化时仅调用createRadialGradient。

-删除缓冲 Canvas ,并将所有星星 Canvas 绘制到主 Canvas 上

最后的优化是我能达到的最佳效果,所以我写了一个小提琴,显示当前代码如何。

   //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);

那就是我需要你的地方:

-一种根据用户性能调整 Shiny 星星数量的方法

-优化技巧

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

编辑
感谢您的反馈,
让我解释一下整个过程,
每个星星都有自己不同的渐变和大小,这就是为什么我将其存储在个人 Canvas 中的原因,只有通过使用drawImage在主 Canvas 上缩放 Canvas 才能实现 Shiny 效果。

我认为最好的方法是在缓冲 Canvas 中预先渲染50或100个不同的星星,然后随机选择并绘制一个星星,您不是吗?

EDIT2

根据术士的忠告,更新的小提琴是一颗预渲染的星星,其大小与当前尺寸匹配。星星不太漂亮,但整个过程运行起来更加流畅。

EDIT3

更新了小提琴以使用精灵表。华丽!!!!
 //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 重新启用 meteor /原型(prototype)对象/摆脱Jquery

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

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

Aesdotjs。
PS:我很高兴。经过测试,该脚本可以在每个浏览器(甚至IE9)上顺利运行。亚塔!!

最佳答案

采用浏览器性能
要衡量用户设置的能力,您可以实现一个动态星型创建器,该星型创建器在某个阈值处停止。
例如,在您的代码中,您定义了要绘制的最小星形。然后在主循环中测量时间,如果绘制星星的时间少于最大阈值,则再增加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);
}
请注意,这有点简化。您将需要先进行几轮操作并测量平均值,以使这项工作更好,并且在添加星标时(由于其他浏览器操作)会达到峰值。
因此,添加星星,测量几轮,如果平均值低于阈值,则添加星星并重复。
最佳化
雪碧表
至于优化,精灵表是必经之路。而且它们不必只是星星(我将在下面尝试解释)。
渐变和弧度是此应用程序中昂贵的部分。即使预先渲染单个星星,由于插值等原因,调整这么多星星的大小也会产生成本。
当发生大量昂贵的操作时,最好妥协一下内存的使用并预渲染所有可能的内容。
例如:首先使用渐变和弧线渲染一颗大星星来渲染各种尺寸。
使用该星星将其他大小绘制为具有相同像元大小的星星带。
现在,使用精灵页面仅绘制星星数量的一半,并绘制精灵页面的裁剪部分(而不是调整大小)。然后将 Canvas 旋转90度,并在不同位置将其自身绘制在其顶部( Canvas 本身变成一个大的“sprite-sheet”)。
旋转90度并不像其他 Angular (优化0、90、180、270)那样使性能降低。这会给您一种幻想,那就是拥有实际的恒星数量,并且由于它已经旋转,因此我们无法轻松检测出重复的模式。
Canvas 的单​​个drawImage操作比所有星星的许多小绘制操作要快。
(当然,您可以多次执行此操作,而不是只一次执行一次,直到刚开始看到模式之前的某个点-没有多少,什么大小的关键答案,因此找到合适的平衡始终是一项实验)。
整数
其他优化可以仅使用整数位置和大小。使用浮点数时,会激活子像素化,这非常昂贵,因为浏览器需要为偏移像素计算抗锯齿。
使用整数值可以有所帮助,因为不需要子像素化(但这并不意味着如果不是1:1尺寸就不会对图像进行插值)。
记忆界限
您还可以通过使用可在4上划分的大小和位置来帮助底层的低位位图处理一点点。这与内存复制和低级裁剪有关。您始终可以制作几个Sprite-sheet来改变可在4上划分的单元格中的位置。
此技巧在速度较慢的计算机(即典型的消费者指定的计算机)上更有值(value)。
关闭抗锯齿
关闭图像的抗锯齿功能。这将有助于性能,但会给星星带来一些粗糙的结果。要关闭图像抗锯齿功能,请执行以下操作:
ctx.webkitEnableImageSmoothing = false;
ctx.mozEnableImageSmoothing = false;
ctx.enableImageSmoothing = false;
这样,只要使用drawImage渲染星星,您的性能就会得到明显改善。
缓存一切
缓存所有可以缓存的内容,包括星图和变量。
当您执行stars.length时,浏览器的解析器需要首先找到stars,然后遍历该树以找到length-对于每个回合(在某些浏览器中可能已优化)。
如果首先将其缓存到变量var len = stars.length中,则浏览器仅需要遍历树和分支一次,并且在循环中,只需查找本地作用域即可找到更快的变量len
分辨率降低
您还可以将分辨率降低一半,即。做到目标尺寸的一半。在最后一步中,将渲染放大到全尺寸。最初将为您节省75%的渲染区域,但结果是分辨率较低。
在专业视频世界中,当物体被动画化(主要是移动)时,我们经常使用低分辨率,因为当物体移动时,眼睛/大脑会修补(或无法检测到)太多细节,因此并不那么引人注目。如果可以这样做,则必须进行测试-也许不是因为恒星实际上并没有移动,而是值得尝试获得第二个好处:提高性能。

关于javascript - Canvas Shiny 星星背景性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18662930/

相关文章:

Android解析ints效率

ubuntu - 为什么在 GNU/Linux 上停止(或重新启动)squid3 如此缓慢?

javascript - HTML5 Canvas 模拟绕轴旋转的行星?

Android 绘制模糊

javascript - 选择 #targetElem sibling (div class ="content")动画

javascript - JSTree 上下文菜单不显示

javascript - 为什么这个 Javascript 警报会触发?

MySQL查询优化,大表,使用临时文件排序

使用 Canvas 进行矩形操作的 JavaScript 库

javascript - 如何根据下拉框中选择的项目 ID 将文本框(循环)的值从 View 传递到 Controller ?