HTML5 캔버스는 여러 가지 방법으로 성능을 향상

간략한 소개

HTML5 캔버스는 지금에 광범위하게 지원 2D 웹이되었다 애플 (애플) 실험에서 유래 고속 모드 그래픽 (2D의  모드 그래픽 즉시 부하 기준). 많은 개발자들은 이제 멀티미디어 프로젝트의 수뿐만 아니라, 시선을 사로 잡는 비주얼 게임을 달성하기 위해 그것을 사용할 수 있습니다. 그러나, 우리가 만들 애플리케이션의 복잡성 증가와 함께, 우리는 필연적으로 소위 성능 문제가 발생합니다.

여러 가지 방법이 캔버스의 성능이 이미 존재 최적화 할 수 있지만 문서에서는 이러한 방법을 정리하지 않을 것이다 및 시스템 분석된다. 이 논문의 목적은, 소화, 이해하기 더 쉬운 자원을 흡수 개발자를 통합 할 수 있도록, 이러한 방법을 구성하는 것입니다. 이 문서 덮여 기본적인 최적화 방법은 모든 환경의 컴퓨터 그래픽 (컴퓨터 그래픽 환경), 그리고 캔버스를 최적화하는 구체적인 방법에 적용 할 수있다. 달성 할 수있는 캔버스와 함께 특정 업데이트 방법은 캔버스의 최적화를위한 다양하다. 캔버스 GPU 가속, 우리는 약간의 최적화가 특히 효과적 보이지 않을 수도 탐험 때 브라우저 개발자들이 깨달았을 때 특히, 이러한 경우 우리는 특정 장소에서 표시했다.

이 문서는 HTML5 캔버스 사용의 초점을 논의하기 위해 아님을 유의하시기 바랍니다. 당신이 HTML5 바위 사이트 캔버스 구체적인 사용법을 알고 싶다면에서 찾을 수 있습니다 캔버스에 관한 기사 . 같은 HTML5의 장에 뛰어  및 MDN이 자습서 .

성능 테스트

빠르게 변화하는 캔버스 HTML5에 대처하기 위해, JSPerf ( jsperf.com ) 시험은 우리가 본문에서 언급 한 모든 방법은 여전히 현재 효과가 있음을 입증했다. JSPerf는 매우 유용한 웹 응용 프로그램, 웹 개발자들이 자바 스크립트 성능 테스트 케이스를 작성하기 위해이 프로그램을 사용할 수 있습니다. 각 테스트 케이스의 문제 (예를 들어, 캔버스를 지우)에 도달하도록 시도의 특정 측면의 결과는, 그러한 각각의 테스트 케이스는 동일한 결과를 달성하기 위해 다양한 방법을 포함한다. 많은 실행 각 방법은, 초당 반복 횟수에 대한 통계를 제공하지 않은 짧은 시간 동안 상당한 JSPerf가있다. 평균보다 높은 성능을 점수.

시청자 브라우저에서 JSPerf 성능 테스트 페이지를 열고, 표준화 된 시험 결과에 저장됩니다에 JSPerf을 할 수 Browserscope ( broserscope.org )에서. 이 문서에 언급 된 최적화 기술이 JSPerf의 결과에 백업 된, 그래서 당신이 할 수 있기 때문에 다시 실행은 대응하는 방법도 효과가 있는지 여부를 확인하기 위해 최신 정보를 볼 수 있습니다. 나는 작은 작성한 도우미 응용 프로그램 ( 도우미 applicatin 전체 문서에 포함 된 차트 할 시험의 결과를).

특정 브라우저 버전이 문서의 성능 테스트 결과는 매우 중요한 관계가있다. 우리가 더 중요한 것이 무엇인지에 운영 체제와 브라우저를 실행하는 알 수 없기 때문에 당신이이 시험을 할 때 하드웨어 가속되었다 여부 HTML5 캔버스를 알고 있지 않습니다. 크롬의 HTML5 캔버스 하드웨어 가속되어 있는지 GPU 명령 : 당신은 크롬 브라우저의 주소 표시 줄에 대해 사용할 수 있습니다.

 

오프 스크린 캔버스 1.PRE은 렌더링

 우리는 종종 연속적인 프레임의 복수의 객체를 다시 그릴 때 비슷한 상황을 작성하는 게임에서 발생합니다. 이에 경우에, 당신은 대부분의 개체의 미리 렌더링 된 장면으로 상당한 성능 향상을 얻을 수 있습니다. 즉, 하나 이상의 임시 캔버스 임시 미리 렌더링 된 이미지를 렌더링하는 화면에 표시되지 않고, 이들 투명 캔버스 이미지로 캔버스 가시화. 더 익숙한 친구들이 모두 알아야 할 컴퓨터 그래픽의 경우,이 기술은 또한 호출 된 실행을 표시 목록 .

예를 들어, 초당 60 프레임의 속도로 실행 마리오를 다시 그리기 가정합니다. 당신은 하나의 프레임은 애니메이션을 실행하기 전에 마리오를 사전 렌더링 할 수있는 각에 그의 모자, 콧수염, 그리고 "M"을 다시 그릴 수 있습니다.

미리 렌더링의 어떤 경우는 없습니다 :

[스크립트]   보기 일반 복사
  1. // 캔버스, 컨텍스트 정의  
  2. 기능  렌더링 () {  
  3.   drawMario (컨텍스트);  
  4.   requestAnimationFrame (렌더링);  
  5. }  

전 상황은 렌더링 :

[스크립트]   보기 일반 복사
  1. VAR  m_canvas = document.createElement ( '캔버스' );  
  2. m_canvas.width = 64;  
  3. m_canvas.height = 64;  
  4. var에  m_context = m_canvas.getContext ( '2D');  
  5. drawMario (m_context);  
  6. 기능  렌더링 () {  
  7.   context.drawImage (m_canvas, 0, 0);  
  8.   requestAnimationFrame (렌더링);  
  9. }  

후속 절에서 설명한 상세한 사용에 RequestAnimationFrame. 다음은 아이콘이 미리 렌더링 기술의 사용은 성능 향상을 제공합니다 보여줍니다. (에서 JSPerf ) :

(예를 들어 위의 예 drawmario) 큰 오버 헤드를 렌더링 작업시에있어서 매우 효과적이다 때. 있는 텍스트는 매우 리소스 집약적 렌더링 작업이 좋은 예입니다. 당신이 볼 수 아래 표에서 미리 렌더링 된 강력한 영업 실적 개선의 사용에 대해 가져왔다. (에서 JSPerf ) :

그러나, 예를 들어 우리는 상부 느슨하게 미리 렌더링 (프리 renderde 느슨한) 성능 저하를 관찰 볼 수있다. 때 작업의 또 다른 캔버스에 대형 캔버스를 복사 미리 렌더링, 우리는 준비가 임시 캔버스 정확하게 렌더링 사진의 크기 또는 성능 향상을 위해 우리를 이끌 너무 큰 캔버스에 맞게 있는지 확인하려면되어 사용 오프셋 성능 손실을 가져온다.

작은 소형 상대적으로 캔버스 위의 테스트에서 :

[스크립트]   보기 일반 복사
  1. can2.width = 100;  
  2. can2.height는 40 =;  

느슨한 캔버스 성능이 저하 될 것입니다 :

[스크립트]   보기 일반 복사
  1. can3.width = 300;  
  2. can3.height = 100;  

 

2.BATCH CANVAS 함께 CALLS

도면 도면로드 상태 머신로드 명령어 세트 긴 따라서 고가의 동작이며, 상기 비디오 버퍼에 속하는 다음 때문에 모든 기록된다. 이것은 더 나은 효율성 될 것입니다.

별도로 모든 라인을 그리는 것보다 모든 라인은 다음 무승부로 호출 할 때 경로를 포함하는 라인의 그림을 만들 필요가 예를 들어, 훨씬 더 효율적입니다 :

[스크립트]   보기 일반 복사
  1. 또는 ( VAR  I = 0; I는 points.length <- 1; 내가 ++) {  
  2.   VAR의  P1은 = 포인트 [I];  
  3.   VAR의  P2 지점은 = [I + 1];  
  4.   context.beginPath ();  
  5.   context.moveTo (을 P1.x, p1.y);  
  6.   context.lineTo (p2.x, p2.y);  
  7.   context.stroke ();  
  8. }  

복수의 라인을 포함하는 경로를 그리기함으로써 우리는 더 나은 성능을 얻을 수 있습니다 :

[스크립트]   보기 일반 복사
  1. ontext.beginPath ();  
  2. 위한  ( VAR  I = 0; i가 points.length <- 1; 내가 ++) {  
  3.   VAR의  P1은 = 포인트 [I];  
  4.   VAR의  P2 지점은 = [I + 1];  
  5.   context.moveTo (을 P1.x, p1.y);  
  6.   context.lineTo (p2.x, p2.y);  
  7. }  
  8. context.stroke ();  

이 방법은 또한 HTML5 캔버스에 적용됩니다. 우리는 복잡한 경로를 그릴 때 예를 들어, 모든 지점의 경로로 훨씬 더 효율적 (별도 각 부분 렌더링보다 것이다 JSPerf을 ) :

캔버스에 중요한 예외가된다, 그러나, 참고 Ruoyu 부재 그린 물체 경계 박스가 작은 (예를 들면, 수직 라인, 수평 라인)을 포함하고 행은 렌더링 분리 할 수도 그것은 더 효과적 일 것입니다 ( JSPerf ) :

 

3.AVOID UNNECESSARY CANVAS 상태 변경

HTML5 캔버스 요소는 상태 머신의 상단에 구현된다. 상태 머신은 채우기, 뇌졸중 스타일 및 이전 점 등의 현재 경로의 구성 등의 정보를 추적 할 수 있습니다. 그래픽 성능을 최적화하려고 할 때, 우리는에 그래픽 렌더링에 집중하는 경향이있다. 사실, 상태 머신을 조작하면 성능 오버 헤드가 발생할 수 있습니다.

例如,如果你使用多种填充色来渲染一个场景,按照不同的颜色分别渲染要比通过canvas上的布局来进行渲染要更加节省资源。为了渲染一副条纹的图案,你可以这样渲染:用一种颜色渲染一条线条,然后改变颜色,渲染下一条线条,如此反复:

[javascript]  view plain copy
  1. for (var i = 0; i < STRIPES; i++) {  
  2.   context.fillStyle = (i % 2 ? COLOR1 : COLOR2);  
  3.   context.fillRect(i * GAP, 0, GAP, 480);  
  4. }  

也可以先用一种颜色渲染所有的偶数线条再用另外一种染色渲染所有的基数线条:

[javascript]  view plain copy
  1. context.fillStyle = COLOR1;  
  2. for (var i = 0; i < STRIPES/2; i++) {  
  3.   context.fillRect((i*2) * GAP, 0, GAP, 480);  
  4. }  
  5. context.fillStyle = COLOR2;  
  6. for (var i = 0; i < STRIPES/2; i++) {  
  7.   context.fillRect((i*2+1) * GAP, 0, GAP, 480);  
  8. }  

下面的性能测试用例分别用上边两种方法绘制了一副交错的细条纹图案(jsperf):

正如我们预期的,交错改变状态的方法要慢的多,原因是变化状态机是有额外开销的。

 

4.RENDER SCREEN DIFFERENCES ONLY, NOT THE WHOLE  NEW STATE

这个很容易理解,在屏幕上绘制较少的东西要比绘制大量的东西节省资源。重绘时如果只有少量的差异你可以通过仅仅重绘差异部分来获得显著的性能提升。换句话说,不要在重绘前清除整个画布。:

[javascript]  view plain copy
  1. context.fillRect(0, 0, canvas.width, canvas.height);  

跟踪已绘制部分的边界框,仅仅清理这个边界之内的东西:

[javascript]  view plain copy
  1. context.fillRect(last.x, last.y, last.width, last.height);  

下面的测试用例说明了这一点。该测试用例中绘制了一个穿过屏幕的白点(jsperf):

如果您对计算机图形学比较熟悉,你或许应该知道这项技术也叫做“redraw technique”,这项技术会保存前一个渲染操作的边界框,下一次绘制前仅仅清理这一部分的内容。

这项技术也适用于基于像素的渲染环境。这篇名为JavaScript NIntendo emulator tallk的文章说明了这一点。

 

5.USE MUTIPLE LAYERED CANVASES FOR COMPLEX SCENES

我们前边提到过,绘制一副较大的图片代价是很高昂的因此我们应尽可能的避免。除了前边讲到的利用另外得不可见的canvas进行预渲染外,我们也可以叠在 一起的多层canvas。图哦你的过利用前景的透明度,我们可以在渲染时依靠GPU整合不同的alpha值。你可以像如下这么设置,两个绝对定位的 canvas一个在另一个的上边:

[javascript]  view plain copy
  1. <canvas id="bg" width="640" height="480" style="position: absolute; z-index: 0">  
  2. </canvas>  
  3. <canvas id="fg" width="640" height="480" style="position: absolute; z-index: 1">  
  4. </canvas>  

相对于仅仅有一个canvas的情况来讲,这个方法的优势在于,当我们需要绘制或者清理前景canvas时,我们不需要每次都修改背景 canvas。如果你的游戏或者多媒体应用可以分成前景和背景这样的情况,那么请考虑分贝渲染前景和背景来获取显著的性能提升。下面的图表比较了只有一个 canvas的情况和有前景背景两个canvas而你只需要清理和重绘前景的情况(jsperf):

你可以用相较慢的速度(相对于前景)来渲染背景,这样便可利用人眼的一些视觉特性达到一定程度的立体感,这样会更吸引用户的眼球。比如,你可以在每一帧中渲染前景而仅仅每N帧才渲染背景。

注意,这个方法也可以推广到包含更多canvas曾的复合canvas。如果你的应用利用更多的曾会运行的更好时请利用这种方法。

 

6.AVOID SHADOWBLUR

跟其他很多绘图环境一样,HTML5 canvas允许开发者对绘图基元使用阴影效果,然而,这项操作是相当耗费资源的。

[javascript]  view plain copy
  1. context.shadowOffsetX = 5;  
  2. context.shadowOffsetY = 5;  
  3. context.shadowBlur = 4;  
  4. context.shadowColor = 'rgba(255, 0, 0, 0.5)';  
  5. context.fillRect(20, 20, 150, 100);  

下面的测试显示了绘制同一场景使用何不使用阴影效果所带来的显著的性能差异(jsperf):

 

7.KNOW VARIOUS WAYS TO CLEAR THE CANVAS

因为HTML5 canvas 是一种即时模式immediate mode)的绘图范式(drawing paradigm),因此场景在每一帧都必需重绘。正因为此,清楚canvas的操作对于 HTML5 应用或者游戏来说有着根本的重要性。

正如在 避免 canvas 状态变化的一节中提到的,清楚整个canvas的操作往往是不可取的。如果你必须这样做的话有两种方法可供选择:调用

[javascript]  view plain copy
  1. context.clearRect(0, 0, width, height)  

或者使用 canvas特定的一个技巧

[javascript]  view plain copy
  1. canvas.width = canvas.width  

在书写本文的时候,cleaRect方法普遍优越于重置canvas宽度的方法。但是,在某些情况下,在Chrome14中使用重置canvas宽度的技巧要比clearRect方法快很多(jsperf):

请谨慎使用这一技巧,因为它很大程度上依赖于底层的canvas实现,因此很容易发生变化,欲了解更多信息请参见 Simon Sarris 的关于清除画布的文章

 

8.AVOID FLOATING POINT COORDINATES

HTML5 canvas 支持子像素渲染(sub-pixel rendering),而且没有办法关闭这一功能。如果你绘制非整数坐标他会自动使用抗锯齿失真以使边缘平滑。以下是相应的视觉效果(参见Seb Lee-Delisle的关于子像素画布性能的文章

如果平滑的精灵并非您期望的效果,那么使用 Math.floor方法或者Math.round方法将你的浮点坐标转换成整数坐标将大大提高运行速度(jsperf):

为使浮点坐标抓换为整数坐标你可以使用许多聪明的技巧,其中性能最优越的方法莫过于将数值加0.5然后对所得结果进行移位运算以消除小数部分。

[javascript]  view plain copy
  1. // With a bitwise or.  
  2. rounded = (0.5 + somenum) | 0;  
  3. // A double bitwise not.  
  4. rounded = ~~ (0.5 + somenum);  
  5. // Finally, a left bitwise shift.  
  6. rounded = (0.5 + somenum) << 0;  

两种方法性能对比如下(jsperf):

9.OPTIMIZE YOUR ANIMATIONS WITH ‘REQUESTANIMATIONFRAME’

相对较新的 requeatAnimationFrame API是在浏览器中实现交互式应用的推荐标准。与传统的以固定频率命令浏览器进行渲染不同,该方法可以更友善的对待浏览器,它会在浏览器可用的时候使其来 渲染。这样带来的另外一个好处是当页面不可见的时候,它会很聪明的停止渲染。

requestAnimationFrame调用的目标是以60帧每秒的速度来调用,但是他并不能保证做到。所以你要跟踪从上一次调用导线在共花了多长时间。这看起来可能如下所示:

[javascript]  view plain copy
  1. var x = 100;  
  2. var y = 100;  
  3. var lastRender = new Date();  
  4. function render() {  
  5.   var delta = new Date() - lastRender;  
  6.   x += delta;  
  7.   y += delta;  
  8.   context.fillRect(x, y, W, H);  
  9.   requestAnimationFrame(render);  
  10. }  
  11. render();  

注意requestAnimationFrame不仅仅适用于canvas 还适用于诸如WebGL的渲染技术。

在书写本文时,这个API仅仅适用于Chrome,Safari以及Firefox,所以你应该使用这一代码片段

MOST MOBILE CANVAS IMPLEMENTATION ARE SLOW

让我们来讨论一下移动平台。不幸的是在写这篇文章的时候,只有IOS 5.0beta 上运行的Safari1.5拥有GPU加速的移动平台canvas实现。如果没有GPU加速,移动平台的浏览器一般没有足够强大的CPU来处理基于 canvas的应用。上述的JSperf测试用例在移动平台的运行结果要比桌面型平台的结果糟糕很多。这极大的限制了跨设备类应用的成功运行。

CONCLUSION

j简要的讲,本文较全面的描述了各种十分有用优化方法以帮助开发者开发住性能优越的基于HTML5 canvas的项目。你已经学会了一些新的东西,赶紧去优化你那令人敬畏的创造吧!如果你还没有创建过一个应用或者游戏,那么请到Chrome Experiment 和Creative JS看看吧,这里能够激发你的灵感。

 

REFFERENCE

 

(원본 링크 : http://www.html5rocks.com/en/tutorials/canvas/performance/ )

HTTPS : //my.oschina.net/zhepama/blog/265034 재현

추천

출처blog.csdn.net/weixin_34292959/article/details/91927353