久久久久久久av_日韩在线中文_看一级毛片视频_日本精品二区_成人深夜福利视频_武道仙尊动漫在线观看

利用分層優化 HTML5 畫布渲染

平臺上的大部分圖形元素都需要某種形式的優化。在本文中,將了解分層畫布元素的優化技巧。本文通過一個簡單的示例,教您如何識別層,以及如何探索獨特的渲染方法,從而優化層
       通常情況下,在玩 2D 游戲或渲染 HTML5 畫布時,需要執行優化,以便使用多個層來構建一個合成的場景。在 OpenGL 或 WebGL 等低級別渲染中,通過逐幀地清理和繪制場景來執行渲染。實現渲染之后,需要優化游戲,以減少渲染的量,所需成本因情況而異。因為畫布是一個 DOM 元素,它使您能夠對多個畫布進行分層,以此作為一種優化方法。

       本文將探討對畫布進行分層的合理性。了解 DOM 設置,從而實現分層的畫布。使用分層進行優化需要各種實踐。本文還將探討一些優化策略的概念和技術,它們擴展了分層方法。

       選擇優化策略

       選擇最佳優化策略可能很難。在選擇分層的場景時,需要考慮場景是如何組成的。大屏幕上固定物的渲染經常需要重用若干個組件,它們是進行研究的極佳候選人。視差或動畫實體等效果往往需要大量的變化的屏幕空間。在探索您的最佳優化策略時,最好注意這些情況。雖然畫布的分層優化需要采用幾種不同的技術,但在正確應用這些技術后,往往會大幅提升性能。

       設置層

       在使用分層的方法時,第一步是在 DOM 上設置畫布。通常情況下,這很簡單,只需定義畫布元素,將其放入 DOM 中即可,但畫布層可能需要一些額外的樣式。在使用 CSS 時,成功地實現畫布分層有兩個要求:

       各畫布元素必須共存于視區 (viewport) 的同一位置上。

       每個畫布在另一個畫布下面必須是可見的。圖 1 顯示了層設置背后的通用重疊概念。

圖 1. 層示例 

       設置層的步驟如下:

  • 將畫布元素添加到 DOM。
  • 添加畫布元素定位樣式,以便支持分層。
  • 樣式化畫布元素,以便生成一個透明的背景。

       設置畫布重疊堆棧

       在 CSS 中創建一個重疊堆棧 (overlay stack) 可能需要少量的樣式。使用 HTML 和 CSS 有許多方法進行重疊。本文中的示例使用一個 <div> 標簽來包含畫布。<div> 標簽指定了一個惟一 ID,它將樣式應用于其子 HTML5 畫布元素,如 清單 1 所示。

       清單 1. 畫布定位樣式

#viewport {
/**
* Position relative so that canvas elements
* inside of it will be relative to the parent
*/
position: relative;
}

#viewport canvas {
/**
* Position absolute provides canvases to be able
* to be layered on top of each other
* Be sure to remember a z-index!
*/
position: absolute;
}


       容器 <div> 通過將所有子畫布元素樣式化為使用絕對定位來完成重疊要求。通過選擇讓 #viewport 使用相對定位,您可以適應未來的發展,因此,應用于子樣式的絕對布局樣式將會是相對于 #viewport 容器的樣式。

       這些 HTML5 畫布元素的順序也很重要。可以按元素出現在 DOM 上的順序進行順序管理,也可以按照畫布應該顯示的順序來樣式化 z-index 樣式,從而管理順序。雖然并非總是如此,但其他樣式可能也會影響渲染;在引入額外的樣式(比如任何一種 CSS 轉換)時要小心。

       透明的背景

       通過使用重疊可見性來實現層技術的第二個樣式要求。該示例使用這個選項來設置 DOM 元素背景顏色,如 清單 2 所示。

       清單 2. 設置透明背景的樣式表規則 

canvas {
/**
* Set transparent to let any other canvases render through
*/
background-color: transparent;
}

       將畫布樣式化為擁有一個透明背景,這可以實現第二個要求,即擁有可見的重疊畫布。現在,您已經構造了標記和樣式來滿足分層的需要,所以您可以設置一個分層的場景。

       分層方面的考慮因素

       在選擇優化策略時,應該注意使用該策略時的所有權衡。對 HTML5 畫布場景進行分層是一個側重于運行時內存的策略,用于獲得運行時速度方面的優勢。您可以在頁面的瀏覽器中增加更多的權重,以獲得更快的幀速率。一般來說,畫布被視為是瀏覽器上的一個圖形平面,其中包括一個圖形 API。

       通過在 Google Chrome 19 進行測試,并記錄瀏覽器的選項卡內存使用情況,您可以看到內存使用的明顯趨勢。該測試使用了已經樣式化的 <div>(正如上一節中討論的那樣),并生成了放置在 <div> 上的用單一顏色填充的畫布元素。畫布的大小被設定為 1600 x 900 像素,并從 Chrome1 的任務管理器實用程序收集數據。表 1 顯示了一個示例。

       在 Google Chrome 的 Task Manager 中,您可以看到某個頁面所使用的內存量(也稱為 RAM)。Chrome 也提供 GPU 內存,或者是 GPU 正在使用的內存。這是常見信息,如幾何形狀、紋理或計算機將您的畫布數據推送到屏幕可能需要的任何形式的緩存數據。內存越低,放在計算機上的權重就會越少。雖然目前還沒有任何確切的數字作為依據,但應始終對此進行測試,確保您的程序不會超出極限,并使用了過多的內存。如果使用了過多的內存,瀏覽器或頁面就會因為缺乏內存資源而崩潰。GPU 處理是一個遠大的編程追求,已超出本文的討論范圍。

表 1. 畫布層的內存開銷

       在 表 1 中,隨著在頁面上引入和使用了更多的 HTML5 畫布元素,使用的內存也越多。一般的內存也存在線性相關,但每增加一層,內存的增長就會明顯減少。雖然這個測試并沒有詳細說明這些層對性能帶來的影響,但它確實表明,畫布會嚴重影響 GPU 內存。一定要記得在您的目標平臺上執行壓力測試,以確保平臺的限制不會導致您的應用程序無法執行。

       當選擇更改某個分層解決方案的單一畫布渲染周期時,需考慮有關內存開銷的性能增益。盡管存在內存成本,但這項技術可以通過減小每一幀上修改的像素數量來完成其工作。

       下一節將說明如何使用分層來組織一個場景。

       對場景進行分層:游戲

       在本節中,我們將通過重構一個滾動平臺跑步風格的游戲上的視差效果的單畫布實現,了解一個多層解決方案。圖 2 顯示了游戲視圖的組成,其中包括云、小山、地面、背景和一些交互實體。

圖 2. 合成游戲視圖

       在游戲中,云、小山、地面和背景都以不同的速度移動。本質上,背景中較遠的元素移動得比在前面的元素慢,因此形成了視差效果。為了讓情況變得更為復雜,背景的移動速度會足夠慢,它每半秒鐘才重新渲染一次。

       通常情況下,好的解決方案會將所有幀都清除并重新渲染屏幕,因為背景是一個圖像并且在不斷變化。在本例中,由于背景每秒只需變化兩次,所以您不需要重新渲染每一幀。

目前,您已經定義了工作區,所以可以決定場景的哪些部分應該在同一個層上。組織好各個層之后,我們將探討用于分層的各種渲染策略。首先,需要考慮如何使用單個畫布來實現該解決方案,如 清單 3 所示。

       清單 3. 單畫布渲染循環的偽代碼


/**
* 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 中的代碼一樣,該解決方案會有一個 render 函數,每個游戲循環調用或每個更新間隔都會調用它。在本例中,渲染是從主循環調用和更新每個元素的位置的更新調用中抽象出來。

       遵循 “清除到渲染” 解決方案,render 會調用清除上下文,并通過調用屏幕上的實體各自的 render 函數來跟蹤它。清單 3 遵循一個程序化的路徑,將元素放置到畫布上。雖然該解決方案對于渲染屏幕上的實體是有效的,但它既沒有描述所使用的所有渲染方法,也不支持任何形式的渲染優化。

       為了更好地詳細說明實體的渲染方法,需要使用兩種類型的實體對象。清單 4 顯示了您將使用和細化的兩個實體。

       清單 4. 可渲染的 Entity 偽代碼

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

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 中的對象存儲實體的圖像、x、y、寬度和高度的實例變量。這些對象遵循 JavaScript 語法,但為了簡潔起見,僅提供了目標對象的不完整的偽代碼。目前,渲染算法非常貪婪地在畫布上渲染出它們的圖像,完全不考慮游戲循環的其他任何要求。

       為了提高性能,需要重點注意的是,panning 渲染調用輸出了一個比所需圖像更大的圖像。本文忽略這個特定的優化,但是,如果使用的空間比您的圖像提供的空間小,那么請確保只渲染必要的補丁。

       確定分層

       現在您知道如何使用單一畫布實現該示例,讓我們看看有什么辦法可以完善這種類型的場景,并加快渲染循環。要使用分層技術,則必須通過找出實體的渲染重疊,識別分層所需的 HTML5 畫布元素。

       重繪區域

       為了確定是否存在重疊,要考慮一些被稱為重繪區域的不可見區域。重繪區域是在繪制實體的圖像時需要畫布清除的區域。重繪區域對于渲染分析很重要,因為它們使您能夠找到完善渲染場景的優化技術,如 圖 3 所示。

圖 3. 合成游戲視圖與重繪區域

       為了可視化 圖 3 中的效果,在場景中的每個實體都有一個表示重繪區域的重疊,它跨越了視區寬度和實體的圖像高度。場景可分為三組:背景、前景和交互。場景中的重繪區域有一個彩色的重疊,以區分不同的區域:

  • 背景 - 黑色
  • 云 - 紅色
  • 小山 - 綠色
  • 地面 - 藍色
  • 紅球 - 藍色
  • 黃色障礙物 - 藍色

       對于除了球和障礙物以外的所有重疊,重繪區域都會橫跨視區寬度。這些實體的圖像幾乎填滿整個屏幕。由于它們的平移要求,它們將渲染整個視區寬度,如 圖 4 所示。預計球和障礙物會穿過該視區,并且可能擁有通過實體位置定義的各自的區域。如果您刪除渲染到場景的圖像,只留下重繪區域,就可以很容易地看到單獨的圖層。

圖 4. 重繪區域

       初始層是顯而易見的,因為您可以注意到互相重疊的各個區域。由于球和障礙物區域覆蓋了小山和地面,所以可將這些實體分組為一層,該層被稱為交互層。根據游戲實體的渲染順序,交互層是頂層。

       找到附加層的另一種方法是收集沒有重疊的所有區域。占據視區的紅色、綠色和藍色區域并沒有重疊,并且它們組成了第二層——前景。云和交互實體的區域沒有重疊,但因為球有可能跳躍到紅色區域,所以您應該考慮將該實體作為一個單獨的層。

       對于黑色區域,可以很容易地推斷出,背景實體將會組成最后一層。填充整個視區的任何區域(如背景實體)都應視為填充整個層中的該區域,雖然這對本場景并不適用。在定義了我們的三個層次之后,我們就可以開始將這層分配給畫布,如 圖 5 所示。

圖 5. 分層的游戲視圖

       現在已經為每個分組的實體定義了層,現在就可以開始優化畫布清除。此優化的目標是為了節省處理時間,可以通過減少每一步渲染的屏幕上的固定物數量來實現。需要重點注意的是,使用不同的策略可能會使圖像獲得更好的優化。下一節將探討各種實體或層的優化方法。

       渲染優化

       優化實體是分層策略的核心。對實體進行分層,使得渲染策略可以被采用。通常,優化技術會試圖消除開銷。正如 表 1 所述,由于引入了層,您已經增加了內存開銷。這里討論的優化技術將減少處理器為了加快游戲而必須執行的大量工作。我們的目標是尋找一種減少要渲染的空間量的方法,并盡可能多地刪除每一步中出現的渲染和清除調用。

       單一實體清除

       第一個優化方法針對的是清除空間,通過只清除組成該實體的屏幕子集來加快處理。首先減少與區域的各實體周圍的透明像素重疊的重繪區域量。使用此技術的包括相對較小的實體,它們填充了視區的小區域。

       第一個目標是球和障礙物實體。單一實體清除技術涉及到在將實體渲染到新位置之前清除前一幀渲染該實體的位置。我們會引入一個清除步驟到每個實體的渲染,并存儲實體的圖像的邊界框。添加該步驟會修改實體對象,以包括清除步驟,如 清單 5 所示。

       清單 5. 包含單框清除的實體

    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);
    this.prevX = this.x;
    this.prevY = this.y;
    }
    };

       render 函數的更新引入了一個常規 drawImage 之前發生的 clearRect 調用。對于該步驟,對象需要存儲前一個位置。圖 6 顯示了對象針對前一個位置所采取的步驟。

圖 6. 清除矩形

       您可以為每個實體創建一個在更新步驟前被調用的 clear 方法,實現此渲染解決方案(但本文將不會使用 clear 方法)。您還可以將這個清除策略引入到 PanningEntity,在地面和云實體上添加清除,如 清單 6 所示。

       清單 6. 包含單框清除的 PanningEntity 

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

       因為 PanningEntity 橫跨了整個視區,所以您可以使用畫布寬度作為清除矩形的大小。如果使用此清除策略,則會為您提供已為云、小山和地面實體定義的重繪區域。

       為了進一步優化云實體,可以將云分離為單獨的實體,使用它們自己的重繪區域。這樣做會大幅減少在云重繪區域內要清除的屏幕空間量。圖 7 顯示了新的重繪區域。

圖 7. 具有單獨重繪區域的云

       單一實體清除策略產生的解決方案可以解決像本例這樣的分層畫布游戲上的大多數問題,但仍然可以對它進行優化。為了尋找針對該渲染策略的極端情況,我們假設球會與三角形碰撞。如果兩個實體碰撞,實體的重繪區域就有可能發生重疊,并創建一個不想要的渲染構件。另一個清除優化,更適合于可能會碰撞的實體,它也將有益于分層。

       臟矩形清除

       若沒有單一清除策略,臟矩形清除策略可以是一個功能強大的替代品。您可以對有重繪區域的大量實體使用這種清除策略,這種實體包括密集的粒子系統,或有小行星的空間游戲。

       從概念上講,該算法會收集由算法管理的所有實體的重繪區域,并在一個清除調用中清除整個區域。為了增加優化,此清除策略還會刪除每個獨立實體產生的重復清除調用,如 清單 7 所示。

       清單 7. DirtyRectManager

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

       將臟矩形算法集成到渲染循環,這要求在進行渲染調用之前調用 清單 7 中的管理器。將實體添加到管理器,使管理器可以在清除時計算清除矩形的維度。雖然管理器會產生預期的優化,但根據游戲循環,管理器能夠針對游戲循環進行優化,如 圖 8 所示。

圖 8. 交互層的重繪區域

  • 幀 1 - 實體在碰撞,幾乎重疊。
  • 幀 2 - 實體重繪區域是重疊的。
  • 幀 3 - 重繪區域重疊,并被收集到一個臟矩形中。
  • 幀 4 - 臟矩形被清除。

       圖 8 顯示了由針對在交互層的實體的算法計算出的重繪區域。因為游戲在這一層上包含交互,所以臟矩形策略足以解決交互和重疊的重繪區域問題。

       作為清除的重寫

       對于在恒定重繪區域中動畫的完全不透明實體,可以使用重寫作為一項優化技術。將不透明的位圖渲染為一個區域(默認的合成操作),這會將像素放在該區域中,不需要考慮該區域中的原始渲染。這個優化消除了渲染調用之前所需的清除調用,因為渲染會覆蓋原來的區域。

       通過在之前的渲染的上方重新渲染圖像,重寫可以加快地面實體。也可以通過相同的方式加快最大的層,比如背景。

       通過減少每一層的重繪區域,您已經有效地為層和它們所包含的實體找到優化策略。

       結束語

       對畫布進行分層是一個可以應用于所有交互式實時場景的優化策略。如果想利用分層實現優化,您需要通過分析場景的重繪區域來考慮場景如何重疊這些區域。一些場景是具有重疊的重繪區域的集合,可以定義層,因此它們是渲染分層畫布的良好候選。如果您需要粒子系統或大量物理對象碰撞在一起,對畫布進行分層可能是一個很好的優化選擇。
【網站聲明】本站除付費源碼經過測試外,其他素材未做測試,不保證完整性,網站上部分源碼僅限學習交流,請勿用于商業用途。如損害你的權益請聯系客服QQ:2655101040 給予處理,謝謝支持。

相關文檔推薦

由于實際運行環境是在瀏覽器中,因此性能還取決于JavaScript解釋器的效率,指定的FPS幀速在低性能解釋器中可能不會達到,所以這部分不是開發者能夠決定的,開發者能作的是盡可能通
本文將使用HTML5提供的VideoAPI做一個自定義的視頻播放器,需要用到HTML5提供的video標簽、以及HTML5提供的對JavascriptAPI的擴展。,HTML5中國,中國最大的HTML5中文門戶。
隨著 Hybrid 應用的豐富,HTML5 工程師們已經不滿足于把桌面端體驗簡單移植到移動端,他們覬覦移動原生應用人性化的操作體驗,特別是原生應用與生俱來的豐富的手勢系統。HTML5 沒有提
你想要在自己網站上分享一個產品,或者是一個作品集,又或者僅僅只是一個靈感。在你發布到網上之前,你想讓它看起來有吸引力,專業,或者至少得看起來像那么回事。那么你接下
H5廣告,包括H5廣告的設計流程,究竟有什么講究,和階段。為了能幫助更多的人了解H5廣告,我專門做了一個講義。同時,也讓我意外的收到了非常好反饋和認!這是對我的極大鼓勵!我的
本文主要內容有:框架與組件、構建生態、開發技巧與調試、html、css與重構、native/hybrid/桌面開發、前端/H5優化、全棧/全端開發、研究實驗、數據分析與監控、其它軟技能、前端技術網
主站蜘蛛池模板: 亚洲视频欧美视频 | 久久精品一区 | 中文字幕日韩欧美一区二区三区 | 四虎影视 | 久久激情视频 | 99热精品在线 | 国产亚洲精品美女久久久久久久久久 | 欧美日韩大陆 | 日韩综合一区 | 男女视频在线免费观看 | 在线欧美视频 | 精品亚洲一区二区三区四区五区 | 天天干干 | 91麻豆产精品久久久久久夏晴子 | 久久久久国 | 国产中文 | 日韩精品一区二区三区 | 久久久成人免费视频 | 欧美精品一区三区 | 美女艹b | 国产免费一区二区三区 | 国产精品一区二区三区在线 | 亚洲精品日韩欧美 | 奇米影视在线 | 黄色一级免费 | 中文字幕日韩欧美一区二区三区 | 成人妇女免费播放久久久 | 欧美日韩精品久久久免费观看 | 91av在线不卡 | 日韩视频国产 | av中文字幕在线播放 | 91成人在线| 亚洲精品乱码久久久久久久久 | 免费国产一区 | 久久精品国产一区二区三区不卡 | 操久久| 欧美精品福利视频 | 国产亚洲精品精品国产亚洲综合 | 欧美午夜精品久久久久久浪潮 | 久久天天| 成人高清视频在线观看 |