【Fanvas技術解密】HTML5 canvas實現臟區重繪

先說明一下,fanvas是筆者在企鵝公司開發的,即將開源的flash轉canvas工具。

?

臟區重繪(dirty rectangle)并不是一門新鮮的技術了,這在最早2D游戲誕生的時候就已經存在。

復雜的術語或概念就不多說,簡單說,臟區重繪就是每一幀繪制圖形界面的時候,只重新繪制有變化的區域,而不是全屏刷新。很明顯,這肯定能帶來性能的提升。

舉個例子,看下邊兩個圖:

wps771D.tmp[8]? wps771E.tmp[4]

假設這里是動畫的連續2幀,那么從第一幀到第二幀,其實變化的只有蝴蝶的區域。那么所謂的臟區就是兩個圖片的紅色框之和,要把上一幀的蝴蝶擦掉,然后把新區域的蝴蝶位置也擦掉,接著才能繪制新的背景和蝴蝶。這相比整屏重繪,重繪的面積小了幾十倍,由于canvas 2d使用的是CPU處理,那么相應地,CPU處理的像素個數就少了很多倍,順理成章,動畫的效率就會提高。

?

看起來非常簡單,大概來說,只需要2步:

1、找出這一幀變化的矩形區域;

2、利用canvas的api實現臟區重繪。

?

但是,問題來了,怎么計算變化區域呢?canvas又是否提供了現成的接口呢?我們拿上述蝴蝶的例子,逐步來看看。

?

首先,我們看關于臟區的計算。

如果動畫非常簡單,沒有使用“顯示列表”,所有圖案都是一層繪制的,那么“也許”繪制者,也就是開發者了,可能會知道蝴蝶的位置,然后手工指定重繪的區域。呃。。。等等,好像有點什么問題,不可能每次都手工指定重繪的區域!!!

再看看Fanvas里的情況,Fanvas采用了顯示列表,把圖案拆分為多個元件,元件和元件之間以“顯示列表”的形式組織起來,這參考了Flash的技術。這里,蝴蝶被封裝為一個Shape,蝴蝶在畫面飛舞,抽象為Shape在父元件中移動、旋轉。最初,在Shape中繪制蝴蝶的時候,可能占據的矩形區域是(x:0,y:0,width:100,height:50),這里參考的是Shape內部的坐標系(還沒放到舞臺上)。然后,蝴蝶被添加到舞臺上時,需要位移和旋轉,例如做了(x:400,y:100)的位移,和旋轉了60度。這時候如何計算新的矩形呢?

wps772F.tmp[4]

?

這個過程其實就是局部坐標系映射到全局坐標系的問題,涉及到矩陣計算,可以參考我之前寫的文章,這里就不多說了。http://km.oa.com/articles/show/238103。另外,提一下,這里其實還有一個難點,初始繪制時(x:0,y:0,width:100,height:50),這個矩形是如何計算得到的呢?如果繪制的是一個圖片,那當然好計算;如果是一系列的矢量線條,這個就略麻煩了,不過這個不在這里討論了,因為Fanvas是Flash導出Canvas動畫,在導出的時候Flash自帶了這個矩陣信息。

?

上述的計算都在一個前提情況下:我們已知蝴蝶是唯一一個變化的元件,但在實際動畫過程中,如何自動識別變化的內容呢?

要從動畫的原理說起,動畫過程無非分為4種操作:

1. 新建一個元件(例如蝴蝶),添加到舞臺上;

2. 移動、旋轉、放縮原有的元件;

3. 刪除已有的元件;

4. 修改元件的遮罩關系,這點有點特殊,如果對flash動畫不熟悉的同學可能不大理解,不過不重要,我們知道有這回事就可以了,不影響文章的繼續閱讀。

?

那么,在Fanvas中,我們就需要對上述4種情況分別處理。

1. 新建:只有1個臟矩形,就是這個元件本身;

2. 移動/旋轉/放縮:元件上一幀的矩形區域是臟區,新一幀的矩形區域也是臟區;

3. 刪除:跟新建情況一樣;

4. 遮罩變化:跟2一樣。

?

理清楚這些細節之后,如何實現就比較好辦了,無非就是每一幀繪制前把臟區列表情況,然后計算出所有臟區矩形,再開始繪制。

?

接著,我們再來看第二步,canvas如何具體操作,是否有臟區重繪接口?

?

其實,canvas并沒有真正的臟區重繪接口,不過有一個clip,這個一般用于實現遮罩,不過也可以取巧的用來實現臟區重繪。經筆者測試,簡單使用clip雖然性能優化不是太明顯,但還是有20%的提升的。再復雜一些,當然大家可以自行根據臟區列表,重寫每個元件的繪制方法,自行實現臟區重繪,不過筆者估計啊,js寫這么多邏輯,最終還是吃力不討好。

我們來看看代碼:

for (var i = 0; i < dirtyRectList.length; i++) { var rect = dirtyRectList[i]; ctx.clearRect(rect.x, rect.y, rect.width, rect.height); 
} 
ctx.beginPath();
for (var i = 0; i < dirtyRectList.length; i++) {var rect = dirtyRectList[i];ctx.rect(rect.x, rect.y, rect.width, rect.height);
}
ctx.clip();

?

相信變量名已經很明顯的暴露了自己的用途,大家應該明白,實現臟區重繪非常簡單,只需要在全部繪制前加那么一段clip,搞掂。

不過啊,這里可有一個很大的坑,估計有同學也知道。

wps7730.tmp[4]

正如上圖所示,會出現一些1px白線或者沒清干凈的bug,尤其是舞臺本身有拉伸的情況下,這種bug更明顯。經過筆者多次摸索,大概搞清楚了,主要就是臟區要算仔細(如果舞臺有拉伸,很容易算出來有1、2px差別),畫面要等比例拉伸,另外就是清除和重繪時,大方點,給1px的放寬。

最后變成:

for (var i = 0; i < dirtyRectList.length; i++) { var rect = dirtyRectList[i];ctx.clearRect(rect.x-1, rect.y-1, rect.width+2, rect.height+2);}ctx.beginPath(); for (var i = 0; i < dirtyRectList.length; i++) {var rect = dirtyRectList[i];ctx.rect(rect.x-1, rect.y-1, rect.width+2, rect.height+2);                }ctx.clip();

?

至此,Fanvas臟區重繪的秘密就徹底曝光了。。。

最后來看看實際的效果(第一張是沒有使用臟區重繪,第二張使用臟區重繪):

wps7740.tmp[4]?? wps7751.tmp[4]

wps7752.tmp[4]?

wps7762.tmp[4]

當然,這并不是每個動畫都有效果,因為一些動畫本來就大范圍變化,所以Fanvas針對這些情況也做了兼容處理,如果發現臟區太多或者面積太大,就繼續使用原來的全屏重繪。

轉載于:https://www.cnblogs.com/kenkofox/p/4506592.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/257302.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/257302.shtml
英文地址,請注明出處:http://en.pswp.cn/news/257302.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

javascript 學習教程

1&#xff0c;JavaScript 是一種輕量級的編程語言&#xff0c;是可插入 HTML 頁面的編程代碼。 2,以<script>標簽開始&#xff0c;以</script>標簽結束。 3,引用放在外部文件的擴展名為.js的腳本文件 <script src"myScript.js"></script> 4&…

我國非按勞分配收入

我國現階段非按勞分配收入探討 我國社會主義初級階段的個人消費品分配&#xff0c;是通過多種分配方式實現的。除了占主體地位的按勞分配方式之外&#xff0c;還存在許多種類的非按勞分配方式。因此&#xff0c;在我國城鄉居民個人收入總額中&#xff0c;除了一部分按勞分配收入…

html調用js里面的函數,html如何調用js函數

html調用js函數的方法&#xff1a;1、用控件本身進行調用&#xff1b;2、通過javascript中的時間控件定時執行&#xff1b;3、通過getElementById調用&#xff1b;4、通過document.getElementsByName調用。本文操作環境&#xff1a;Windows7系統、html5&&javascript1.8…

大部分人都會做錯的經典JS閉包面試題

2019獨角獸企業重金招聘Python工程師標準>>> 由工作中演變而來的面試題 JS中有幾種函數 創建函數的幾種方式 三個fun函數的關系是什么&#xff1f; 函數作用域鏈的問題 到底在調用哪個函數&#xff1f; 后話 轉載于:https://my.oschina.net/u/3687565/blog/1549046

STM32片上Flash內存映射、頁面大小、寄存器映射

轉自&#xff1a;http://blog.chinaunix.net/uid-20617446-id-3847242.html 一、怎么看Flash大小 1.1 通過型號 型號會印在MCU表面&#xff0c;可以通過觀察獲得&#xff0c;我的是STM32F103RBT6(以下分析基于這個型號)&#xff0c;對照下圖的STM32產品命名&#xff0c;可知STM…

如何設計實現一個地址反解析服務?

http://www.cnblogs.com/LBSer/p/4507829.html 一、什么是地址反解析 我們都知道手機定位服務&#xff0c;其本質是匯總各種信號得出一個經緯度坐標&#xff08;x,y&#xff09;&#xff08;具體定位原理可以參考&#xff1a;LBS定位技術、基于樸素貝葉斯的定位算法&#xff09…

html5 hr代碼縮減比例,HTML HR size用法及代碼示例

DOM HR size屬性用于設置或返回元素的size屬性的vlue。用法:它返回HR大小屬性。hrobject.size用于設置HR大小屬性。hrobject.size"value"屬性值&#xff1a;value:它包含指定HR元素高度的像素值。返回值&#xff1a;它返回一個字符串值&#xff0c;該值代表HR元素的高…

【轉】C++標準轉換運算符static_cast

static_cast<new_type> (expression) 雖然const_cast是用來去除變量的const限定&#xff0c;但是static_cast卻不是用來去除變量的static引用。其實這是很容易理解的&#xff0c;static決定的是一個變量的作用域和生命周期&#xff0c;比如&#xff1a;在一個文件中將變量…

MySQL Binlog Mixed模式記錄成Row格式

背景&#xff1a; 一個簡單的主從結構&#xff0c;主的binlog format是Mixed模式&#xff0c;在執行一條簡單的導入語句時&#xff0c;通過mysqlbinlog導出發現記錄的Binlog全部變成了Row的格式&#xff08;明明設置的是Mixed&#xff09;&#xff0c;現在就說說在什么情況下Bi…

update語句中使用子查詢

55. 更改 108 員工的信息: 使其工資變為所在部門中的最高工資, job 變為公司中平均工資最低的 job 1). 搭建骨架 update employees set salary (), job_id () where employee_id 108; 2). 所在部門中的最高工資 select max(salary) from employees where department_id ( s…

html后臺數據分類管理,細分數據.html

&#xfeff;細分數據$axure.utils.getTransparentGifPath function() { return resources/images/transparent.gif; };$axure.utils.getOtherPath function() { return resources/Other.html; };$axure.utils.getReloadPath function() { return resources/reload.html; };…

SpringBoot的配置文件加載順序和使用方式

1、bootstrap.properties bootstrap.properties 配置文件是由“根”上下文優先加載&#xff0c;程序啟動之初就感知 如&#xff1a;Spring Cloud Config指定遠程配置中心地址&#xff0c;就要在這個文件中指定。這樣才能在啟動之初發現遠程配置中心&#xff0c;并從遠程獲取配置…

Get請求

寫在前面的話 XMLHttpRequest對象的open方法的第一個參數為request-type,取值可以為get或post.本篇介紹get請求. get請求的目的,主要是為了獲取數據.雖然get請求可以傳遞數據,但傳遞數據的目的是為了告訴服務器,給我們什么內容. 使用get請求時,參數都是隨url進行傳遞的. 使用ge…

css3中的BFC,IFC,GFC和FFC(轉載)

作者原文網址&#xff1a;http://www.cnblogs.com/dingyufenglian/p/4845477.html What‘s FC&#xff1f; 一定不是KFC&#xff0c;FC的全稱是&#xff1a;Formatting Contexts&#xff0c;是W3C CSS2.1規范中的一個概念。它是頁面中的一塊渲染區域&#xff0c;并且有一套渲染…

javaweb學習總結——Filter高級開發

在filter中可以得到代表用戶請求和響應的request、response對象&#xff0c;因此在編程中可以使用Decorator(裝飾器)模式對request、response對象進行包裝&#xff0c;再把包裝對象傳給目標資源&#xff0c;從而實現一些特殊需求。 一、Decorator設計模式 1.1、Decorator設計模…

html期末網頁設計,求網頁設計的期末作業一份 HTML的

1&#xff0e; 課程設計建議主題方向&#xff1a;電子商務類網站、門戶類網站、專題類網站。整體要求&#xff1a;主題鮮明、健康&#xff1b;風格自然、內容充實、完整&#xff1b;布局合理&#xff0c;配色和諧。(5分)2&#xff0e; 網站至少包括15張頁面(包括首頁)&#x…

Android(java)學習筆記10:同步中的死鎖問題以及線程通信問題

1. 同步弊端&#xff1a; &#xff08;1&#xff09;效率低 &#xff08;2&#xff09;如果出現了同步嵌套&#xff0c;就容易產生死鎖問題 死鎖問題及其代碼 &#xff1a; &#xff08;1&#xff09;是指兩個或者兩個以上的線程在執行的過程中&#xff0c;因爭奪資源產生的一種…

4源代碼的下載和編譯

1、Android移植主要就是Linux內核移植&#xff0c;而Linux內核移植主要是Linux驅動移植&#xff0c;為了開發和測試Linux驅動&#xff0c;要在Ubuntu下搭建兩套開發環境&#xff1a;Android應用程序開發環境和Linux內核開發環境&#xff1b; 2、Android源代碼包括&#xff1a;內…

在html中三個圖片切換,輕松搞定網頁中的圖片切換

生活中經常看到&#xff0c;像新浪等很多門戶網站的首頁都有滾動圖片的展示&#xff0c;如下圖所示&#xff1a;某網站首頁滾動切換圖片這樣不但可以減少文字的單一、乏味&#xff0c;而且可以直觀內容&#xff0c;更好的吸引用戶。那在我們做軟件系統時&#xff0c;是否也可以…

python 進程編程速成

python具有thread多線程庫&#xff0c;但多線程并不是真正的多線程&#xff0c;不能充分利用多核CPU資源。 在大多數情況下&#xff0c;python可以使用multiprocessing多進程庫&#xff0c;可以輕松完成從單進程到并發執行的轉換。 multiprocessing庫支持子進程、通信和共享數據…