国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > HTML > 正文

使用分層畫布來優(yōu)化HTML5渲染的教程

2020-03-24 17:09:00
字體:
來源:轉載
供稿:網友
簡介通常情況下,在玩 2D 游戲或渲染 HTML5 畫布時,需要執(zhí)行優(yōu)化,以便使用多個層來構建一個合成的場景。在 OpenGL 或 WebGL 等低級別渲染中,通過逐幀地清理和繪制場景來執(zhí)行渲染。實現渲染之后,需要優(yōu)化游戲,以減少渲染的量,所需成本因情況而異。因為畫布是一個 DOM 元素,它使您能夠對多個畫布進行分層,以此作為一種優(yōu)化方法。
常用的縮寫 CSS: Cascading Style Sheets(級聯樣式表)
DOM: Document Object Model(文檔對象模型)
HTML: HyperText Markup Language(超文本標記語言)本文將探討對畫布進行分層的合理性。了解 DOM 設置,從而實現分層的畫布。使用分層進行優(yōu)化需要各種實踐。本文還將探討一些優(yōu)化策略的概念和技術,它們擴展了分層方法。您可以下載在本文中使用的示例的源代碼。
選擇優(yōu)化策略選擇最佳優(yōu)化策略可能很難。在選擇分層的場景時,需要考慮場景是如何組成的。大屏幕上固定物的渲染經常需要重用若干個組件,它們是進行研究的極佳候選人。視差或動畫實體等效果往往需要大量的變化的屏幕空間。在探索您的最佳優(yōu)化策略時,最好注意這些情況。雖然畫布的分層優(yōu)化需要采用幾種不同的技術,但在正確應用這些技術后,往往會大幅提升性能。
設置層在使用分層的方法時,第一步是在 DOM 上設置畫布。通常情況下,這很簡單,只需定義畫布元素,將其放入 DOM 中即可,但畫布層可能需要一些額外的樣式。在使用 CSS 時,成功地實現畫布分層有兩個要求: 各畫布元素必須共存于視區(qū) (viewport) 的同一位置上。
每個畫布在另一個畫布下面必須是可見的。圖 1顯示了層設置背后的通用重疊概念。
圖 1. 層示例

設置層的步驟如下: 將畫布元素添加到 DOM。
添加畫布元素定位樣式,以便支持分層。
樣式化畫布元素,以便生成一個透明的背景。設置畫布重疊堆棧在 CSS 中創(chuàng)建一個重疊堆棧 (overlay stack) 可能需要少量的樣式。使用 HTML 和 CSS 有許多方法進行重疊。本文中的示例使用一個 div 標簽來包含畫布。 div 標簽指定了一個惟一 ID,它將樣式應用于其子 HTML5 畫布元素,如清單 1所示。
清單 1. 畫布定位樣式

CSS Code復制內容到剪貼板
/** *Positionrelativesothatcanvaselements *insideofitwillberelativetotheparent */ position:relative; } #viewportcanvas{ /** *Positionabsoluteprovidescanvasestobeable *tobelayeredontopofeachother *Besuretorememberaz-index! */ position:absolute; }
容器 div 通過將所有子畫布元素樣式化為使用絕對定位來完成重疊要求。通過選擇讓#viewport使用相對定位,您可以適應未來的發(fā)展,因此,應用于子樣式的絕對布局樣式將會是相對于#viewport容器的樣式。這些 HTML5 畫布元素的順序也很重要。可以按元素出現在 DOM 上的順序進行順序管理,也可以按照畫布應該顯示的順序來樣式化 z-index 樣式,從而管理順序。雖然并非總是如此,但其他樣式可能也會影響渲染;在引入額外的樣式(比如任何一種 CSS 轉換)時要小心。
透明的背景通過使用重疊可見性來實現層技術的第二個樣式要求。該示例使用這個選項來設置 DOM 元素背景顏色,如清單 2所示。
清單 2. 設置透明背景的樣式表規(guī)則

XML/HTML Code復制內容到剪貼板
/** *Settransparenttoletanyothercanvasesrenderthrough */ background-color:transparent; }
將畫布樣式化為擁有一個透明背景,這可以實現第二個要求,即擁有可見的重疊畫布?,F在,您已經構造了標記和樣式來滿足分層的需要,所以您可以設置一個分層的場景。
分層方面的考慮因素在選擇優(yōu)化策略時,應該注意使用該策略時的所有權衡。對 HTML5 畫布場景進行分層是一個側重于運行時內存的策略,用于獲得運行時速度方面的優(yōu)勢。您可以在頁面的瀏覽器中增加更多的權重,以獲得更快的幀速率。一般來說,畫布被視為是瀏覽器上的一個圖形平面,其中包括一個圖形 API。通過在 Google Chrome 19 進行測試,并記錄瀏覽器的選項卡內存使用情況,您可以看到內存使用的明顯趨勢。該測試使用了已經樣式化的 div (正如上一節(jié)中討論的那樣),并生成了放置在 div 上的用單一顏色填充的畫布元素。畫布的大小被設定為 1600 x 900 像素,并從 Chrome1 的html' target='_blank'>任務管理器實用程序收集數據。表 1顯示了一個示例。在 Google Chrome 的 Task Manager 中,您可以看到某個頁面所使用的內存量(也稱為 RAM)。Chrome 也提供 GPU 內存,或者是 GPU 正在使用的內存。這是常見信息,如幾何形狀、紋理或計算機將您的畫布數據推送到屏幕可能需要的任何形式的緩存數據。內存越低,放在計算機上的權重就會越少。雖然目前還沒有任何確切的數字作為依據,但應始終對此進行測試,確保您的程序不會超出極限,并使用了過多的內存。如果使用了過多的內存,瀏覽器或頁面就會因為缺乏內存資源而崩潰。GPU 處理是一個遠大的編程追求,已超出本文的討論范圍。您可以從學習 OpenGL 或查閱 Chrome 的文檔(請參閱參考資料)開始。
表 1. 畫布層的內存開銷
在表 1中,隨著在頁面上引入和使用了更多的 HTML5 畫布元素,使用的內存也越多。一般的內存也存在線性相關,但每增加一層,內存的增長就會明顯減少。雖然這個測試并沒有詳細說明這些層對性能帶來的影響,但它確實表明,畫布會嚴重影響 GPU 內存。一定要記得在您的目標平臺上執(zhí)行壓力測試,以確保平臺的限制不會導致您的應用程序無法執(zhí)行。當選擇更改某個分層解決方案的單一畫布渲染周期時,需考慮有關內存開銷的性能增益。盡管存在內存成本,但這項技術可以通過減小每一幀上修改的像素數量來完成其工作。下一節(jié)將說明如何使用分層來組織一個場景。
對場景進行分層:游戲在本節(jié)中,我們將通過重構一個滾動平臺跑步風格的游戲上的視差效果的單畫布實現,了解一個多層解決方案。圖 2顯示了游戲視圖的組成,其中包括云、小山、地面、背景和一些交互實體。
圖 2. 合成游戲視圖
在游戲中,云、小山、地面和背景都以不同的速度移動。本質上,背景中較遠的元素移動得比在前面的元素慢,因此形成了視差效果。為了讓情況變得更為復雜,背景的移動速度會足夠慢,它每半秒鐘才重新渲染一次。通常情況下,好的解決方案會將所有幀都清除并重新渲染屏幕,因為背景是一個圖像并且在不斷變化。在本例中,由于背景每秒只需變化兩次,所以您不需要重新渲染每一幀。目前,您已經定義了工作區(qū),所以可以決定場景的哪些部分應該在同一個層上。組織好各個層之后,我們將探討用于分層的各種渲染策略。首先,需要考慮如何使用單個畫布來實現該解決方案,如清單 3所示。
清單 3. 單畫布渲染循環(huán)的偽代碼

XML/HTML Code復制內容到剪貼板
* *@param{CanvasRenderingContext2D}contextCanvascontext */ functionrenderLoop(context) { context.clearRect(0,0,width,height); background.render(context); ground.render(context); hills.render(context); cloud.render(context); player.render(context); }
像清單 3中的代碼一樣,該解決方案會有一個render函數,每個游戲循環(huán)調用或每個更新間隔都會調用它。在本例中,渲染是從主循環(huán)調用和更新每個元素的位置的更新調用中抽象出來。遵循 清除到渲染 解決方案,render會調用清除上下文,并通過調用屏幕上的實體各自的render函數來跟蹤它。清單 3遵循一個程序化的路徑,將元素放置到畫布上。雖然該解決方案對于渲染屏幕上的實體是有效的,但它既沒有描述所使用的所有渲染方法,也不支持任何形式的渲染優(yōu)化。為了更好地詳細說明實體的渲染方法,需要使用兩種類型的實體對象。清單 4顯示了您將使用和細化的兩個實體。
清單 4. 可渲染的Entity偽代碼

XML/HTML Code復制內容到剪貼板
/** *Rendercalltodrawtheentity * *@param{CanvasRenderingContext2D}context */ this.render=function(context){ context.drawImage(this.image,this.x,this.y); } };
/** *Rendercalltodrawthepannedentity * *@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中的對象存儲實體的圖像、x、y、寬度和高度的實例變量。這些對象遵循 JavaScript 語法,但為了簡潔起見,僅提供了目標對象的不完整的偽代碼。目前,渲染算法非常貪婪地在畫布上渲染出它們的圖像,完全不考慮游戲循環(huán)的其他任何要求。為了提高性能,需要重點注意的是,panning渲染調用輸出了一個比所需圖像更大的圖像。本文忽略這個特定的優(yōu)化,但是,如果使用的空間比您的圖像提供的空間小,那么請確保只渲染必要的補丁。
確定分層現在您知道如何使用單一畫布實現該示例,讓我們看看有什么辦法可以完善這種類型的場景,并加快渲染循環(huán)。要使用分層技術,則必須通過找出實體的渲染重疊,識別分層所需的 HTML5 畫布元素。
重繪區(qū)域為了確定是否存在重疊,要考慮一些被稱為重繪區(qū)域的不可見區(qū)域。重繪區(qū)域是在繪制實體的圖像時需要畫布清除的區(qū)域。重繪區(qū)域對于渲染分析很重要,因為它們使您能夠找到完善渲染場景的優(yōu)化技術,如圖 3所示。
圖 3. 合成游戲視圖與重繪區(qū)域
為了可視化圖 3中的效果,在場景中的每個實體都有一個表示重繪區(qū)域的重疊,它跨越了視區(qū)寬度和實體的圖像高度。場景可分為三組:背景、前景和交互。場景中的重繪區(qū)域有一個彩色的重疊,以區(qū)分不同的區(qū)域: 背景 黑色
云 紅色
小山 綠色
地面 藍色
紅球 藍色
黃色障礙物 藍色對于除了球和障礙物以外的所有重疊,重繪區(qū)域都會橫跨視區(qū)寬度。這些實體的圖像幾乎填滿整個屏幕。由于它們的平移要求,它們將渲染整個視區(qū)寬度,如圖 4所示。預計球和障礙物會穿過該視區(qū),并且可能擁有通過實體位置定義的各自的區(qū)域。如果您刪除渲染到場景的圖像,只留下重繪區(qū)域,就可以很容易地看到單獨的圖層。
圖 4. 重繪區(qū)域
初始層是顯而易見的,因為您可以注意到互相重疊的各個區(qū)域。由于球和障礙物區(qū)域覆蓋了小山和地面,所以可將這些實體分組為一層,該層被稱為交互層。根據游戲實體的渲染順序,交互層是頂層。找到附加層的另一種方法是收集沒有重疊的所有區(qū)域。占據視區(qū)的紅色、綠色和藍色區(qū)域并沒有重疊,并且它們組成了第二層 前景。云和交互實體的區(qū)域沒有重疊,但因為球有可能跳躍到紅色區(qū)域,所以您應該考慮將該實體作為一個單獨的層。對于黑色區(qū)域,可以很容易地推斷出,背景實體將會組成最后一層。填充整個視區(qū)的任何區(qū)域(如背景實體)都應視為填充整個層中的該區(qū)域,雖然這對本場景并不適用。在定義了我們的三個層次之后,我們就可以開始將這層分配給畫布,如圖 5所示。
圖 5. 分層的游戲視圖
現在已經為每個分組的實體定義了層,現在就可以開始優(yōu)化畫布清除。此優(yōu)化的目標是為了節(jié)省處理時間,可以通過減少每一步渲染的屏幕上的固定物數量來實現。需要重點注意的是,使用不同的策略可能會使圖像獲得更好的優(yōu)化。下一節(jié)將探討各種實體或層的優(yōu)化方法。
渲染優(yōu)化優(yōu)化實體是分層策略的核心。對實體進行分層,使得渲染策略可以被采用。通常,優(yōu)化技術會試圖消除開銷。正如表 1所述,由于引入了層,您已經增加了內存開銷。這里討論的優(yōu)化技術將減少處理器為了加快游戲而必須執(zhí)行的大量工作。我們的目標是尋找一種減少要渲染的空間量的方法,并盡可能多地刪除每一步中出現的渲染和清除調用。
單一實體清除第一個優(yōu)化方法針對的是清除空間,通過只清除組成該實體的屏幕子集來加快處理。首先減少與區(qū)域的各實體周圍的透明像素重疊的重繪區(qū)域量。使用此技術的包括相對較小的實體,它們填充了視區(qū)的小區(qū)域。第一個目標是球和障礙物實體。單一實體清除技術涉及到在將實體渲染到新位置之前清除前一幀渲染該實體的位置。我們會引入一個清除步驟到每個實體的渲染,并存儲實體的圖像的邊界框。添加該步驟會修改實體對象,以包括清除步驟,如清單 5所示。
清單 5. 包含單框清除的實體

XML/HTML Code復制內容到剪貼板
/** *Rendercalltodrawtheentity * *@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函數的更新引入了一個常規(guī)drawImage之前發(fā)生的clearRect調用。對于該步驟,對象需要存儲前一個位置。圖 6顯示了對象針對前一個位置所采取的步驟。
圖 6. 清除矩形
您可以為每個實體創(chuàng)建一個在更新步驟前被調用的clear方法,實現此渲染解決方案(但本文將不會使用clear方法)。您還可以將這個清除策略引入到PanningEntity,在地面和云實體上添加清除,如清單 6所示。
清單 6. 包含單框清除的PanningEntity

XML/HTML Code復制內容到剪貼板
/** *Rendercalltodrawthepannedentity * *@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); } };
因為PanningEntity橫跨了整個視區(qū),所以您可以使用畫布寬度作為清除矩形的大小。如果使用此清除策略,則會為您提供已為云、小山和地面實體定義的重繪區(qū)域。為了進一步優(yōu)化云實體,可以將云分離為單獨的實體,使用它們自己的重繪區(qū)域。這樣做會大幅減少在云重繪區(qū)域內要清除的屏幕空間量。圖 7顯示了新的重繪區(qū)域。
圖 7. 具有單獨重繪區(qū)域的云
單一實體清除策略產生的解決方案可以解決像本例這樣的分層畫布游戲上的大多數問題,但仍然可以對它進行優(yōu)化。為了尋找針對該渲染策略的極端情況,我們假設球會與三角形碰撞。如果兩個實體碰撞,實體的重繪區(qū)域就有可能發(fā)生重疊,并創(chuàng)建一個不想要的渲染構件。另一個清除優(yōu)化,更適合于可能會碰撞的實體,它也將有益于分層。
臟矩形清除若沒有單一清除策略,臟矩形清除策略可以是一個功能強大的替代品。您可以對有重繪區(qū)域的大量實體使用這種清除策略,這種實體包括密集的粒子系統,或有小行星的空間游戲。從概念上講,該算法會收集由算法管理的所有實體的重繪區(qū)域,并在一個清除調用中清除整個區(qū)域。為了增加優(yōu)化,此清除策略還會刪除每個獨立實體產生的重復清除調用,如清單 7所示。
清單 7.DirtyRectManager

XML/HTML Code復制內容到剪貼板
varDirtyRectManager=function(){ //Settheleftandtopedgetothemaxpossible //(thecanvaswidth)amdrightandbottomtoleast-most //Leftandtopwillshrinkasmoreentitiesareadded this.left=canvas.width; this.top=canvas.height; //Rightandbottomwillgrowasmoreentitiesareadded this.right=0; this.bottom=0; //Dirtychecktoavoidclearingifnoentitieswereadded this.isDirty=false; //OtherInitializationCode /** *Otherutilitymethods */ /** *Addsthedirtyrectparametersandmarkstheareaasdirty * *@param{number}x *@param{number}y *@param{number}width *@param{number}height */ this.addDirtyRect=function(x,y,width,height){ //Calculateouttherectangleedges varleft=x; varright=x+width; vartop=y; varbottom=y+height; //Minofleftandentityleft this.left=left this.leftleft:this.left; //Maxofrightandentityright this.right=right this.rightright:this.right; //Minoftopandentitytop this.top=top this.toptop:this.top; //Maxofbottomandentitybottom this.bottom=bottom this.bottombottom:this.bottom; this.isDirty=true; }; /** *Clearstherectangleareaifthemanagerisdirty * *@param{CanvasRenderingContext2D}context */ this.clearRect=function(context){ if(!this.isDirty){ return; } //Clearthecalculatedrectangle context.clearRect( this.left, this.top, this.right-this.left, this.bottom-this.top); //Resetbasevalues this.left=canvas.width; this.top=canvas.height; this.right=0; this.bottom=0; this.isDirty=false; } };
將臟矩形算法集成到渲染循環(huán),這要求在進行渲染調用之前調用清單 7中的管理器。將實體添加到管理器,使管理器可以在清除時計算清除矩形的維度。雖然管理器會產生預期的優(yōu)化,但根據游戲循環(huán),管理器能夠針對游戲循環(huán)進行優(yōu)化,如圖 8所示。
圖 8. 交互層的重繪區(qū)域
幀 1 實體在碰撞,幾乎重疊。
幀 2 實體重繪區(qū)域是重疊的。
幀 3 重繪區(qū)域重疊,并被收集到一個臟矩形中。
幀 4 臟矩形被清除。圖 8顯示了由針對在交互層的實體的算法計算出的重繪區(qū)域。因為游戲在這一層上包含交互,所以臟矩形策略足以解決交互和重疊的重繪區(qū)域問題。
作為清除的重寫對于在恒定重繪區(qū)域中動畫的完全不透明實體,可以使用重寫作為一項優(yōu)化技術。將不透明的位圖渲染為一個區(qū)域(默認的合成操作),這會將像素放在該區(qū)域中,不需要考慮該區(qū)域中的原始渲染。這個優(yōu)化消除了渲染調用之前所需的清除調用,因為渲染會覆蓋原來的區(qū)域。通過在之前的渲染的上方重新渲染圖像,重寫可以加快地面實體。也可以通過相同的方式加快最大的層,比如背景。通過減少每一層的重繪區(qū)域,您已經有效地為層和它們所包含的實體找到優(yōu)化策略。
結束語對畫布進行分層是一個可以應用于所有交互式實時場景的優(yōu)化策略。如果想利用分層實現優(yōu)化,您需要通過分析場景的重繪區(qū)域來考慮場景如何重疊這些區(qū)域。一些場景是具有重疊的重繪區(qū)域的集合,可以定義層,因此它們是渲染分層畫布的良好候選。如果您需要粒子系統或大量物理對象碰撞在一起,對畫布進行分層可能是一個很好的優(yōu)化選擇。
html教程

鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 通道| 彭山县| 左权县| 隆林| 江源县| 卢氏县| 磐石市| 子洲县| 宜昌市| 宜兰市| 苍南县| 富宁县| 麟游县| 馆陶县| 瑞昌市| 文登市| 广东省| 汝城县| 福泉市| 信阳市| 绍兴市| 绥德县| 阳朔县| 新化县| 淮阳县| 黄大仙区| 新巴尔虎左旗| 富民县| 商都县| 清远市| 长阳| 平邑县| 德昌县| 长治市| 鹰潭市| 邵武市| 景洪市| 芜湖市| 新巴尔虎右旗| 南安市| 辽宁省|