帆布闪亮的星背景性能问题

时间:2013-09-06 17:02:40

标签: javascript performance canvas drawimage

我对我正在进行的实验有疑问。

我的计划是在整个页面上拥有美丽闪亮的星星背景。 使用那个令人难以置信的教程(http://timothypoon.com/blog/2011/01/19/html5-canvas-particle-animation/),我设法得到了完美的背景。 我使用静态画布来显示静态星星和动画画布。

事实是它非常渴望记忆!在Chrome和Opera上它运行得相当顺利,但是在Firefox或IE平板电脑上,渲染每个帧等都是一团糟......在HEIGHT很大的页面上情况更糟。

所以我进行了一些优化:

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

- 使用一个大的缓冲画布,每个星星使用1个画布,只在init上调用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个不同的星星,然后挑选和绘制一个随机的星星,你认为不是吗?

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;
        }
    }
}

这是更新的最终小提琴,包括spritesheet,动态星星创作和几个优化。如果你看到别的什么我应该更新,不要犹豫。

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

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

感谢所有帮助过我的人,这非常友善和有教育意义,我希望有时会对某人有所帮助。

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

3 个答案:

答案 0 :(得分:2)

如何在径向发光的各个阶段创建一个恒星的spritesheet。

您甚至可以使用canvas来初始创建spritesheet。

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

可以非常快速地将Spritesheet图像绘制到屏幕上。

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

祝你的项目好运:))

答案 1 :(得分:2)

采用浏览器性能

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

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

没有多少人知道requestAnimationFrame给它所调用的函数一个参数(DOMHighResTimeStamp)给出了自上次请求以来花费的毫秒时间。这将帮助您跟踪负载,因为我们知道每帧60帧/秒约为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的片

至于优化精灵表是最佳选择。而且他们不必只是成为明星(我将在下面解释)。

梯度和弧是这种应用的昂贵部分。即使在预渲染单个恒星时,由于插值等原因也需要调整这么多星的大小。

当出现大量昂贵的操作时,最好对内存使用做出妥协并预先渲染所有内容。

例如:首先使用渐变和圆弧渲染大星,渲染各种尺寸。 使用该星形将其他尺寸绘制为具有相同单元尺寸的星条。

现在,使用精灵表仅绘制星数的一半并绘制精灵表的剪切部分(并且不会重新调整大小)。然后将画布旋转90度并将画布本身在其自身的顶部绘制在不同的位置(画布本身就变成了一个大的“精灵表”)。

旋转90度并不像其他角度(0,90,180,270被优化)那样性能饥渴。这将给你一个幻想,即拥有实际数量的恒星,并且由于它被旋转,我们无法检测到容易的重复模式。

帆布的单drawImage次操作比所有星星的许多小型绘制操作要快。

(当然,你可以多次这样做,而不是在你开始看到模式之前一次到达一个点 - 对于多少,大小等没有关键答案,所以找到正确的平衡是总是一个实验)。

整数

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

使用整数值有助于不需要子像素(但这并不意味着如果不是1:1维度,图像将不会被插值)。

内存界限

您还可以通过使用4上可分割的大小和位置来帮助底层的低 - 低位图处理一点点。这与内存复制和低级削波有关。您总是可以制作多个精灵表来变换可在4上分割的单元格中的位置。

这种技巧在较慢的计算机(即典型的消费者规格计算机)上更有价值。

关闭消除锯齿

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

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

只要您使用drawImage渲染星星,您就可以看到效果明显改善。

缓存所有内容

缓存您可以缓存的所有内容,即星形图像和变量。

执行此操作stars.length时,浏览器的解析器需要首先找到stars,然后遍历该树以查找length - 每轮(这可能会在某些浏览器中进行优化)。

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

降低分辨率

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

在专业视频领域,当物体动画(主要是移动)时,我们经常使用低分辨率作为眼睛/大脑补丁(或无法检测)当物体移动时如此多的细节,因此不那么引人注目。如果这可以帮助必须在这里测试 - 也许不是因为星星实际上没有移动,但值得尝试第二个好处:提高性能。

答案 2 :(得分:1)

<强> 1。最大限度地减少与DOM相关的操作;

在LINE 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混合使用。