簡介
通常情況下,在玩 2D 游戲或渲染 HTML5 畫布時(shí),需要執(zhí)行優(yōu)化,以便使用多個(gè)層來構(gòu)建一個(gè)合成的場景。在 OpenGL 或 WebGL 等低級別渲染中,通過逐幀地清理和繪制場景來執(zhí)行渲染。實(shí)現(xiàn)渲染之后,需要優(yōu)化游戲,以減少渲染的量,所需成本因情況而異。因?yàn)楫嫴际且粋€(gè) DOM 元素,它使您能夠?qū)Χ鄠€(gè)畫布進(jìn)行分層,以此作為一種優(yōu)化方法。
常用的縮寫
- CSS: Cascading Style Sheets(級聯(lián)樣式表)
DOM: Document Object Model(文檔對象模型)
HTML: HyperText Markup Language(超文本標(biāo)記語言)
本文將探討對畫布進(jìn)行分層的合理性。了解 DOM 設(shè)置,從而實(shí)現(xiàn)分層的畫布。使用分層進(jìn)行優(yōu)化需要各種實(shí)踐。本文還將探討一些優(yōu)化策略的概念和技術(shù),它們擴(kuò)展了分層方法。
您可以下載在本文中使用的示例的源代碼。
選擇優(yōu)化策略
選擇最佳優(yōu)化策略可能很難。在選擇分層的場景時(shí),需要考慮場景是如何組成的。大屏幕上固定物的渲染經(jīng)常需要重用若干個(gè)組件,它們是進(jìn)行研究的極佳候選人。視差或動(dòng)畫實(shí)體等效果往往需要大量的變化的屏幕空間。在探索您的最佳優(yōu)化策略時(shí),最好注意這些情況。雖然畫布的分層優(yōu)化需要采用幾種不同的技術(shù),但在正確應(yīng)用這些技術(shù)后,往往會(huì)大幅提升性能。
設(shè)置層
在使用分層的方法時(shí),第一步是在 DOM 上設(shè)置畫布。通常情況下,這很簡單,只需定義畫布元素,將其放入 DOM 中即可,但畫布層可能需要一些額外的樣式。在使用 CSS 時(shí),成功地實(shí)現(xiàn)畫布分層有兩個(gè)要求:
各畫布元素必須共存于視區(qū) (viewport) 的同一位置上。
每個(gè)畫布在另一個(gè)畫布下面必須是可見的。
圖 1顯示了層設(shè)置背后的通用重疊概念。
圖 1. 層示例
設(shè)置層的步驟如下:
- 將畫布元素添加到 DOM。
添加畫布元素定位樣式,以便支持分層。
樣式化畫布元素,以便生成一個(gè)透明的背景。
設(shè)置畫布重疊堆棧
在 CSS 中創(chuàng)建一個(gè)重疊堆棧 (overlay stack) 可能需要少量的樣式。使用 HTML 和 CSS 有許多方法進(jìn)行重疊。本文中的示例使用一個(gè)<div>標(biāo)簽來包含畫布。<div>標(biāo)簽指定了一個(gè)惟一 ID,它將樣式應(yīng)用于其子 HTML5 畫布元素,如清單 1所示。
清單 1. 畫布定位樣式
CSS Code復(fù)制內(nèi)容到剪貼板
- #viewport {
-
-
-
-
- position: relative;
- }
-
- #viewport canvas {
-
-
-
-
-
- position: absolute;
- }
容器<div>通過將所有子畫布元素樣式化為使用絕對定位來完成重疊要求。通過選擇讓#viewport使用相對定位,您可以適應(yīng)未來的發(fā)展,因此,應(yīng)用于子樣式的絕對布局樣式將會(huì)是相對于#viewport容器的樣式。
這些 HTML5 畫布元素的順序也很重要。可以按元素出現(xiàn)在 DOM 上的順序進(jìn)行順序管理,也可以按照畫布應(yīng)該顯示的順序來樣式化 z-index 樣式,從而管理順序。雖然并非總是如此,但其他樣式可能也會(huì)影響渲染;在引入額外的樣式(比如任何一種 CSS 轉(zhuǎn)換)時(shí)要小心。
透明的背景
通過使用重疊可見性來實(shí)現(xiàn)層技術(shù)的第二個(gè)樣式要求。該示例使用這個(gè)選項(xiàng)來設(shè)置 DOM 元素背景顏色,如清單 2所示。
清單 2. 設(shè)置透明背景的樣式表規(guī)則
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- canvas {
- /**
- * Set transparent to let any other canvases render through
- */
- background-color: transparent;
- }
將畫布樣式化為擁有一個(gè)透明背景,這可以實(shí)現(xiàn)第二個(gè)要求,即擁有可見的重疊畫布。現(xiàn)在,您已經(jīng)構(gòu)造了標(biāo)記和樣式來滿足分層的需要,所以您可以設(shè)置一個(gè)分層的場景。
分層方面的考慮因素
在選擇優(yōu)化策略時(shí),應(yīng)該注意使用該策略時(shí)的所有權(quán)衡。對 HTML5 畫布場景進(jìn)行分層是一個(gè)側(cè)重于運(yùn)行時(shí)內(nèi)存的策略,用于獲得運(yùn)行時(shí)速度方面的優(yōu)勢。您可以在頁面的瀏覽器中增加更多的權(quán)重,以獲得更快的幀速率。一般來說,畫布被視為是瀏覽器上的一個(gè)圖形平面,其中包括一個(gè)圖形 API。
通過在 Google Chrome 19 進(jìn)行測試,并記錄瀏覽器的選項(xiàng)卡內(nèi)存使用情況,您可以看到內(nèi)存使用的明顯趨勢。該測試使用了已經(jīng)樣式化的<div>(正如上一節(jié)中討論的那樣),并生成了放置在<div>上的用單一顏色填充的畫布元素。畫布的大小被設(shè)定為 1600 x 900 像素,并從 Chrome1 的任務(wù)管理器實(shí)用程序收集數(shù)據(jù)。表 1顯示了一個(gè)示例。
在 Google Chrome 的 Task Manager 中,您可以看到某個(gè)頁面所使用的內(nèi)存量(也稱為 RAM)。Chrome 也提供 GPU 內(nèi)存,或者是 GPU 正在使用的內(nèi)存。這是常見信息,如幾何形狀、紋理或計(jì)算機(jī)將您的畫布數(shù)據(jù)推送到屏幕可能需要的任何形式的緩存數(shù)據(jù)。內(nèi)存越低,放在計(jì)算機(jī)上的權(quán)重就會(huì)越少。雖然目前還沒有任何確切的數(shù)字作為依據(jù),但應(yīng)始終對此進(jìn)行測試,確保您的程序不會(huì)超出極限,并使用了過多的內(nèi)存。如果使用了過多的內(nèi)存,瀏覽器或頁面就會(huì)因?yàn)槿狈?nèi)存資源而崩潰。GPU 處理是一個(gè)遠(yuǎn)大的編程追求,已超出本文的討論范圍。您可以從學(xué)習(xí) OpenGL 或查閱 Chrome 的文檔(請參閱參考資料)開始。
表 1. 畫布層的內(nèi)存開銷
在表 1中,隨著在頁面上引入和使用了更多的 HTML5 畫布元素,使用的內(nèi)存也越多。一般的內(nèi)存也存在線性相關(guān),但每增加一層,內(nèi)存的增長就會(huì)明顯減少。雖然這個(gè)測試并沒有詳細(xì)說明這些層對性能帶來的影響,但它確實(shí)表明,畫布會(huì)嚴(yán)重影響 GPU 內(nèi)存。一定要記得在您的目標(biāo)平臺(tái)上執(zhí)行壓力測試,以確保平臺(tái)的限制不會(huì)導(dǎo)致您的應(yīng)用程序無法執(zhí)行。
當(dāng)選擇更改某個(gè)分層解決方案的單一畫布渲染周期時(shí),需考慮有關(guān)內(nèi)存開銷的性能增益。盡管存在內(nèi)存成本,但這項(xiàng)技術(shù)可以通過減小每一幀上修改的像素?cái)?shù)量來完成其工作。
下一節(jié)將說明如何使用分層來組織一個(gè)場景。
對場景進(jìn)行分層:游戲
在本節(jié)中,我們將通過重構(gòu)一個(gè)滾動(dòng)平臺(tái)跑步風(fēng)格的游戲上的視差效果的單畫布實(shí)現(xiàn),了解一個(gè)多層解決方案。圖 2顯示了游戲視圖的組成,其中包括云、小山、地面、背景和一些交互實(shí)體。
圖 2. 合成游戲視圖
在游戲中,云、小山、地面和背景都以不同的速度移動(dòng)。本質(zhì)上,背景中較遠(yuǎn)的元素移動(dòng)得比在前面的元素慢,因此形成了視差效果。為了讓情況變得更為復(fù)雜,背景的移動(dòng)速度會(huì)足夠慢,它每半秒鐘才重新渲染一次。
通常情況下,好的解決方案會(huì)將所有幀都清除并重新渲染屏幕,因?yàn)楸尘笆且粋€(gè)圖像并且在不斷變化。在本例中,由于背景每秒只需變化兩次,所以您不需要重新渲染每一幀。
目前,您已經(jīng)定義了工作區(qū),所以可以決定場景的哪些部分應(yīng)該在同一個(gè)層上。組織好各個(gè)層之后,我們將探討用于分層的各種渲染策略。首先,需要考慮如何使用單個(gè)畫布來實(shí)現(xiàn)該解決方案,如清單 3所示。
清單 3. 單畫布渲染循環(huán)的偽代碼
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- /**
- * Render call
- *
- * @param {CanvasRenderingContext2D} context Canvas context
- */
- function renderLoop(context)
- {
- context.clearRect(0, 0, width, height);
- background.render(context);
- ground.render(context);
- hills.render(context);
- cloud.render(context);
- player.render(context);
- }
像清單 3中的代碼一樣,該解決方案會(huì)有一個(gè)render函數(shù),每個(gè)游戲循環(huán)調(diào)用或每個(gè)更新間隔都會(huì)調(diào)用它。在本例中,渲染是從主循環(huán)調(diào)用和更新每個(gè)元素的位置的更新調(diào)用中抽象出來。
遵循 “清除到渲染” 解決方案,render會(huì)調(diào)用清除上下文,并通過調(diào)用屏幕上的實(shí)體各自的render函數(shù)來跟蹤它。清單 3遵循一個(gè)程序化的路徑,將元素放置到畫布上。雖然該解決方案對于渲染屏幕上的實(shí)體是有效的,但它既沒有描述所使用的所有渲染方法,也不支持任何形式的渲染優(yōu)化。
為了更好地詳細(xì)說明實(shí)體的渲染方法,需要使用兩種類型的實(shí)體對象。清單 4顯示了您將使用和細(xì)化的兩個(gè)實(shí)體。
清單 4. 可渲染的Entity偽代碼
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- var Entity = function() {
- /**
- Initialization and other methods
- **/
-
- /**
- * Render call to draw the entity
- *
- * @param {CanvasRenderingContext2D} context
- */
- this.render = function(context) {
- context.drawImage(this.image, this.x, this.y);
- }
- };
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- var PanningEntity = function() {
- /**
- Initialization and other methods
- **/
-
- /**
- * Render call to draw the panned entity
- *
- * @param {CanvasRenderingContext2D} context
- */
- this.render = function(context) {
- context.drawImage(
- this.image,
- this.x - this.width,
- this.y - this.height);
- context.drawImage(
- this.image,
- this.x,
- this.y);
- context.drawImage(
- this.image,
- this.x + this.width,
- this.y + this.height);
- }
- };
清單 4中的對象存儲(chǔ)實(shí)體的圖像、x、y、寬度和高度的實(shí)例變量。這些對象遵循 JavaScript 語法,但為了簡潔起見,僅提供了目標(biāo)對象的不完整的偽代碼。目前,渲染算法非常貪婪地在畫布上渲染出它們的圖像,完全不考慮游戲循環(huán)的其他任何要求。
為了提高性能,需要重點(diǎn)注意的是,panning渲染調(diào)用輸出了一個(gè)比所需圖像更大的圖像。本文忽略這個(gè)特定的優(yōu)化,但是,如果使用的空間比您的圖像提供的空間小,那么請確保只渲染必要的補(bǔ)丁。
確定分層
現(xiàn)在您知道如何使用單一畫布實(shí)現(xiàn)該示例,讓我們看看有什么辦法可以完善這種類型的場景,并加快渲染循環(huán)。要使用分層技術(shù),則必須通過找出實(shí)體的渲染重疊,識(shí)別分層所需的 HTML5 畫布元素。
重繪區(qū)域
為了確定是否存在重疊,要考慮一些被稱為重繪區(qū)域的不可見區(qū)域。重繪區(qū)域是在繪制實(shí)體的圖像時(shí)需要畫布清除的區(qū)域。重繪區(qū)域?qū)τ阡秩痉治龊苤匾?,因?yàn)樗鼈兪鼓軌蛘业酵晟其秩緢鼍暗膬?yōu)化技術(shù),如圖 3所示。
圖 3. 合成游戲視圖與重繪區(qū)域
為了可視化圖 3中的效果,在場景中的每個(gè)實(shí)體都有一個(gè)表示重繪區(qū)域的重疊,它跨越了視區(qū)寬度和實(shí)體的圖像高度。場景可分為三組:背景、前景和交互。場景中的重繪區(qū)域有一個(gè)彩色的重疊,以區(qū)分不同的區(qū)域:
- 背景 – 黑色
云 – 紅色
小山 – 綠色
地面 – 藍(lán)色
紅球 – 藍(lán)色
黃色障礙物 – 藍(lán)色
對于除了球和障礙物以外的所有重疊,重繪區(qū)域都會(huì)橫跨視區(qū)寬度。這些實(shí)體的圖像幾乎填滿整個(gè)屏幕。由于它們的平移要求,它們將渲染整個(gè)視區(qū)寬度,如圖 4所示。預(yù)計(jì)球和障礙物會(huì)穿過該視區(qū),并且可能擁有通過實(shí)體位置定義的各自的區(qū)域。如果您刪除渲染到場景的圖像,只留下重繪區(qū)域,就可以很容易地看到單獨(dú)的圖層。
圖 4. 重繪區(qū)域
初始層是顯而易見的,因?yàn)槟梢宰⒁獾交ハ嘀丿B的各個(gè)區(qū)域。由于球和障礙物區(qū)域覆蓋了小山和地面,所以可將這些實(shí)體分組為一層,該層被稱為交互層。根據(jù)游戲?qū)嶓w的渲染順序,交互層是頂層。
找到附加層的另一種方法是收集沒有重疊的所有區(qū)域。占據(jù)視區(qū)的紅色、綠色和藍(lán)色區(qū)域并沒有重疊,并且它們組成了第二層——前景。云和交互實(shí)體的區(qū)域沒有重疊,但因?yàn)榍蛴锌赡芴S到紅色區(qū)域,所以您應(yīng)該考慮將該實(shí)體作為一個(gè)單獨(dú)的層。
對于黑色區(qū)域,可以很容易地推斷出,背景實(shí)體將會(huì)組成最后一層。填充整個(gè)視區(qū)的任何區(qū)域(如背景實(shí)體)都應(yīng)視為填充整個(gè)層中的該區(qū)域,雖然這對本場景并不適用。在定義了我們的三個(gè)層次之后,我們就可以開始將這層分配給畫布,如圖 5所示。
圖 5. 分層的游戲視圖
現(xiàn)在已經(jīng)為每個(gè)分組的實(shí)體定義了層,現(xiàn)在就可以開始優(yōu)化畫布清除。此優(yōu)化的目標(biāo)是為了節(jié)省處理時(shí)間,可以通過減少每一步渲染的屏幕上的固定物數(shù)量來實(shí)現(xiàn)。需要重點(diǎn)注意的是,使用不同的策略可能會(huì)使圖像獲得更好的優(yōu)化。下一節(jié)將探討各種實(shí)體或?qū)拥膬?yōu)化方法。
渲染優(yōu)化
優(yōu)化實(shí)體是分層策略的核心。對實(shí)體進(jìn)行分層,使得渲染策略可以被采用。通常,優(yōu)化技術(shù)會(huì)試圖消除開銷。正如表 1所述,由于引入了層,您已經(jīng)增加了內(nèi)存開銷。這里討論的優(yōu)化技術(shù)將減少處理器為了加快游戲而必須執(zhí)行的大量工作。我們的目標(biāo)是尋找一種減少要渲染的空間量的方法,并盡可能多地刪除每一步中出現(xiàn)的渲染和清除調(diào)用。
單一實(shí)體清除
第一個(gè)優(yōu)化方法針對的是清除空間,通過只清除組成該實(shí)體的屏幕子集來加快處理。首先減少與區(qū)域的各實(shí)體周圍的透明像素重疊的重繪區(qū)域量。使用此技術(shù)的包括相對較小的實(shí)體,它們填充了視區(qū)的小區(qū)域。
第一個(gè)目標(biāo)是球和障礙物實(shí)體。單一實(shí)體清除技術(shù)涉及到在將實(shí)體渲染到新位置之前清除前一幀渲染該實(shí)體的位置。我們會(huì)引入一個(gè)清除步驟到每個(gè)實(shí)體的渲染,并存儲(chǔ)實(shí)體的圖像的邊界框。添加該步驟會(huì)修改實(shí)體對象,以包括清除步驟,如清單 5所示。
清單 5. 包含單框清除的實(shí)體
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- var Entity = function() {
- /**
- Initialization and other methods
- **/
-
- /**
- * Render call to draw the entity
- *
- * @param {CanvasRenderingContext2D} context
- */
- this.render = function(context) {
- context.clearRect(
- this.prevX,
- this.prevY,
- this.width,
- this.height);
- context.drawImage(this.image, this.x, this.y);
- thisthis.prevX = this.x;
- thisthis.prevY = this.y;
- }
- };
render函數(shù)的更新引入了一個(gè)常規(guī)drawImage之前發(fā)生的clearRect調(diào)用。對于該步驟,對象需要存儲(chǔ)前一個(gè)位置。圖 6顯示了對象針對前一個(gè)位置所采取的步驟。
圖 6. 清除矩形
您可以為每個(gè)實(shí)體創(chuàng)建一個(gè)在更新步驟前被調(diào)用的clear方法,實(shí)現(xiàn)此渲染解決方案(但本文將不會(huì)使用clear方法)。您還可以將這個(gè)清除策略引入到PanningEntity,在地面和云實(shí)體上添加清除,如清單 6所示。
清單 6. 包含單框清除的PanningEntity
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- var PanningEntity = function() {
- /**
- Initialization and other methods
- **/
-
- /**
- * Render call to draw the panned entity
- *
- * @param {CanvasRenderingContext2D} context
- */
- this.render = function(context) {
- context.clearRect(
- this.x,
- this.y,
- context.canvas.width,
- this.height);
- context.drawImage(
- this.image,
- this.x - this.width,
- this.y - this.height);
- context.drawImage(
- this.image,
- this.x,
- this.y);
- context.drawImage(
- this.image,
- this.x + this.width,
- this.y + this.height);
- }
- };
因?yàn)镻anningEntity橫跨了整個(gè)視區(qū),所以您可以使用畫布寬度作為清除矩形的大小。如果使用此清除策略,則會(huì)為您提供已為云、小山和地面實(shí)體定義的重繪區(qū)域。
為了進(jìn)一步優(yōu)化云實(shí)體,可以將云分離為單獨(dú)的實(shí)體,使用它們自己的重繪區(qū)域。這樣做會(huì)大幅減少在云重繪區(qū)域內(nèi)要清除的屏幕空間量。圖 7顯示了新的重繪區(qū)域。
圖 7. 具有單獨(dú)重繪區(qū)域的云
單一實(shí)體清除策略產(chǎn)生的解決方案可以解決像本例這樣的分層畫布游戲上的大多數(shù)問題,但仍然可以對它進(jìn)行優(yōu)化。為了尋找針對該渲染策略的極端情況,我們假設(shè)球會(huì)與三角形碰撞。如果兩個(gè)實(shí)體碰撞,實(shí)體的重繪區(qū)域就有可能發(fā)生重疊,并創(chuàng)建一個(gè)不想要的渲染構(gòu)件。另一個(gè)清除優(yōu)化,更適合于可能會(huì)碰撞的實(shí)體,它也將有益于分層。
臟矩形清除
若沒有單一清除策略,臟矩形清除策略可以是一個(gè)功能強(qiáng)大的替代品。您可以對有重繪區(qū)域的大量實(shí)體使用這種清除策略,這種實(shí)體包括密集的粒子系統(tǒng),或有小行星的空間游戲。
從概念上講,該算法會(huì)收集由算法管理的所有實(shí)體的重繪區(qū)域,并在一個(gè)清除調(diào)用中清除整個(gè)區(qū)域。為了增加優(yōu)化,此清除策略還會(huì)刪除每個(gè)獨(dú)立實(shí)體產(chǎn)生的重復(fù)清除調(diào)用,如清單 7所示。
清單 7.DirtyRectManager
XML/HTML Code復(fù)制內(nèi)容到剪貼板
- var DirtyRectManager = function() {
- // Set the left and top edge to the max possible
- // (the canvas width) amd right and bottom to least-most
-
- // Left and top will shrink as more entities are added
- this.left = canvas.width;
- this.top = canvas.height;
-
- // Right and bottom will grow as more entities are added
- this.right = 0;
- this.bottom = 0;
-
- // Dirty check to avoid clearing if no entities were added
- this.isDirty = false;
-
- // Other Initialization Code
-
- /**
- * Other utility methods
- */
-
- /**
- * Adds the dirty rect parameters and marks the area as dirty
- *
- * @param {number} x
- * @param {number} y
- * @param {number} width
- * @param {number} height
- */
- this.addDirtyRect = function(x, y, width, height) {
- // Calculate out the rectangle edges
- var left = x;
- var right = x + width;
- var top = y;
- var bottom = y + height;
-
- // Min of left and entity left
- this.left = left < this.left left : this.left;
- // Max of right and entity right
- this.right = right > this.right right : this.right;
- // Min of top and entity top
- this.top = top < this.top top : this.top;
- // Max of bottom and entity bottom
- this.bottom = bottom > this.bottom bottom : this.bottom;
-
- this.isDirty = true;
- };
-
- /**
- * Clears the rectangle area if the manager is dirty
- *
- * @param {CanvasRenderingContext2D} context
- */
- this.clearRect = function(context) {
- if (!this.isDirty) {
- return;
- }
-
- // Clear the calculated rectangle
- context.clearRect(
- this.left,
- this.top,
- this.right - this.left,
- this.bottom - this.top);
-
- // Reset base values
- this.left = canvas.width;
- this.top = canvas.height;
- this.right = 0;
- this.bottom = 0;
- this.isDirty = false;
- }
- };
將臟矩形算法集成到渲染循環(huán),這要求在進(jìn)行渲染調(diào)用之前調(diào)用清單 7中的管理器。將實(shí)體添加到管理器,使管理器可以在清除時(shí)計(jì)算清除矩形的維度。雖然管理器會(huì)產(chǎn)生預(yù)期的優(yōu)化,但根據(jù)游戲循環(huán),管理器能夠針對游戲循環(huán)進(jìn)行優(yōu)化,如圖 8所示。
圖 8. 交互層的重繪區(qū)域
- 幀 1 – 實(shí)體在碰撞,幾乎重疊。
幀 2 – 實(shí)體重繪區(qū)域是重疊的。
幀 3 – 重繪區(qū)域重疊,并被收集到一個(gè)臟矩形中。
幀 4 – 臟矩形被清除。
圖 8顯示了由針對在交互層的實(shí)體的算法計(jì)算出的重繪區(qū)域。因?yàn)橛螒蛟谶@一層上包含交互,所以臟矩形策略足以解決交互和重疊的重繪區(qū)域問題。
作為清除的重寫
對于在恒定重繪區(qū)域中動(dòng)畫的完全不透明實(shí)體,可以使用重寫作為一項(xiàng)優(yōu)化技術(shù)。將不透明的位圖渲染為一個(gè)區(qū)域(默認(rèn)的合成操作),這會(huì)將像素放在該區(qū)域中,不需要考慮該區(qū)域中的原始渲染。這個(gè)優(yōu)化消除了渲染調(diào)用之前所需的清除調(diào)用,因?yàn)殇秩緯?huì)覆蓋原來的區(qū)域。
通過在之前的渲染的上方重新渲染圖像,重寫可以加快地面實(shí)體。也可以通過相同的方式加快最大的層,比如背景。
通過減少每一層的重繪區(qū)域,您已經(jīng)有效地為層和它們所包含的實(shí)體找到優(yōu)化策略。
結(jié)束語
對畫布進(jìn)行分層是一個(gè)可以應(yīng)用于所有交互式實(shí)時(shí)場景的優(yōu)化策略。如果想利用分層實(shí)現(xiàn)優(yōu)化,您需要通過分析場景的重繪區(qū)域來考慮場景如何重疊這些區(qū)域。一些場景是具有重疊的重繪區(qū)域的集合,可以定義層,因此它們是渲染分層畫布的良好候選。如果您需要粒子系統(tǒng)或大量物理對象碰撞在一起,對畫布進(jìn)行分層可能是一個(gè)很好的優(yōu)化選擇。