Most of the graphic elements on the platform need some form of optimization. In this article, we will learn how to optimize hierarchical Canvas elements. This article uses a simple example to teach you how to identify layers and how to explore unique rendering methods to optimize layers. Layered canvas is a real-time interactive canvas that you can use in any way ...,. Generally, optimization is required when you are playing a 2D game or rendering an HTML5 canvas, so that multiple layers can be used to build a compositing scenario. In low-level rendering such as OpenGL or WebGL, rendering is performed by frame-by-frame cleaning and rendering scenarios. After rendering, You need to optimize the game to reduce the rendering volume, and the required costs vary depending on the situation. The canvas is a DOM element that enables you to layer multiple canvases as an optimization method.
This article will discuss the rationality of layering the canvas. Understand DOM settings to implement hierarchical canvases. Various practices are required to optimize using layers. This article will also discuss the concepts and technologies of some optimization strategies, which extend the hierarchical method.
Select optimization policy
It may be difficult to select the best optimization policy. When selecting a layered scenario, you must consider how the scenario is made up. Rendering of fixed objects on a large screen often requires reuse of several components, which are excellent candidates for research. Parallax or animated objects often require a large amount of changed screen space. Pay attention to these situations when exploring your best optimization strategy. Although the hierarchical optimization of the canvas requires several different technologies, the performance is often greatly improved after these technologies are correctly applied.
Setting Layer
When using the layered method, the first step is to set the canvas on the DOM. In general, this is simple. You only need to define the Canvas Element and put it into the DOM, but the canvas layer may need some extra styles. When using CSS, there are two requirements for successful canvas layering:
Each canvas element must coexist in the same position of the view area (viewport.
Each canvas must be visible under another canvas. Figure 1 shows the general overlap concept behind layer settings.
Figure 1. layer example
To set the layer, follow these steps:
- Add the canvas element to the DOM.
- Add a canvas element positioning style to support layering.
- Style Canvas elements to generate a transparent background.
Set canvas overlapping stacks
Creating an overlay stack in CSS may require a few styles. There are many ways to overlap HTML and CSS. The example in this article uses
Label to include the canvas.
The tag specifies a unique ID, which applies the style to its HTML5 Canvas elements, as shown in Listing 1.
Listing 1. Canvas positioning Style
# 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;
}
Container
You can use absolute positioning to style all child Canvas elements to fulfill overlap requirements. By selecting # viewport to use relative positioning, you can adapt to future development. Therefore, the absolute layout style applied to the child style will be relative to the # viewport container style.
The order of these HTML5 Canvas elements is also important. You can manage the elements in the order they appear on the DOM, or you can style the z-index style in the order they should be displayed on the canvas to manage the order. Although not always, other styles may affect rendering. Be careful when introducing additional styles (such as any CSS conversion.
Transparent background
The second style requirement of layer technology is achieved by using overlapping visibility. This example uses this option to set the background color of the DOM element, as shown in Listing 2.
List 2. Set style sheet rules for transparent backgrounds
Canvas {
/**
* Set transparent to let any other canvases render through
*/
Background-color: transparent;
}
To have a transparent background, you can implement the second requirement, that is, to have a visible overlapping canvas. Now you have constructed tags and styles to meet the need for layering, so you can set a layered scenario.
Stratified considerations
When selecting an optimization policy, pay attention to all the trade-offs when using this policy. Layering HTML5 canvas scenarios is a strategy that focuses on runtime memory and is used to gain the advantage of runtime speed. You can add more weights to the browser of the page to get a faster frame rate. Generally, a canvas is regarded as a graphic plane on the browser, including a graphic API.
By testing on Google Chrome 19 and recording the browser's tab memory usage, you can see a significant trend in memory usage. This test uses the already styled
(As discussed in the previous section ),
Canvas elements filled with a single color. The canvas size is set to 1600x900 pixels and data is collected from the Chrome1 Task Manager Utility. Table 1 shows an example.
In Google Chrome's Task Manager, you can see the memory usage (also called RAM) of a page ). Chrome also provides GPU memory or memory in use by the GPU. This is common information, such as geometric shapes, textures, or computers that push your canvas data to any form of cache data that may be needed on the screen. The lower the memory, the less weight the computer has. Although no exact number is yet used as a basis, you should always test this to ensure that your program does not exceed the limit and uses too much memory. If too much memory is used, the browser or page will crash due to lack of memory resources. GPU processing is a great programming pursuit and beyond the scope of this article.
Table 1. memory overhead at the canvas Layer
In table 1, as more HTML5 Canvas elements are introduced and used on the page, more memory is used. The general memory also has linear correlation, but the memory growth will be significantly reduced every time a layer is added. Although this test does not detail the impact of these layers on performance, it does indicate that the canvas seriously affects GPU memory. Be sure to perform stress testing on your target platform to ensure that the platform restrictions do not cause your application to fail.
When you choose to change the single canvas rendering cycle for a layered solution, you need to consider the performance gains related to memory overhead. Despite the memory cost, this technology can reduce the number of modified pixels per frame to complete its work.
The next section describes how to use layers to organize a scenario.
Layer scene: Game
In this section, we will reconstruct a single canvas Implementation of the parallax effect on a running-style game on a rolling platform to learn about a multi-layer solution. Figure 2 shows the composition of the game view, including the cloud, Hill, ground, background, and some interactive entities.
Figure 2. Merging game views
In the game, the cloud, Hill, ground, and background all move at different speeds. In essence, elements that are far away from the background move slowly than the preceding elements, thus forming a parallax effect. To make the situation more complex, the background movement speed is slow enough, and it is re-rendered every half second.
Normally, a good solution will clear all frames and re-render the screen, because the background is an image and is constantly changing. In this example, the background only needs to change twice per second, so you do not need to re-render each frame.
Currently, you have defined the workspace, so you can decide which parts of the scenario should be on the same layer. After each layer is organized, we will explore various rendering strategies for layering. First, consider how to use a single canvas to implement the solution, as shown in listing 3.
Listing 3. pseudocode of a single canvas rendering Loop
/**
* 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 );
}
Like the code in listing 3, the solution has a render function, which is called by every game loop call or every update interval. In this example, rendering is abstracted from the update call for calling the main loop and updating the position of each element.
Following the "clear to rendering" solution, render will call to clear the context and trace it by calling the respective render functions of the entities on the screen. Listing 3 follows a procedural path and places the elements on the canvas. Although this solution is effective for rendering objects on the screen, it neither describes all the rendering methods used nor supports any form of rendering optimization.
Two object types are required to better describe the object rendering method. Listing 4 shows the two entities you will use and refine.
Listing 4. rendered Entity pseudocode
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 );
}
};
In Listing 4, objects store instance variables for object images, x, y, width, and height. These objects follow the JavaScript syntax, but for simplicity, only incomplete pseudo code of the target object is provided. Currently, rendering algorithms are greedy to render their images on the canvas without considering any other requirements of the game loop.
To improve performance, you must note that the panning rendering call outputs an image larger than the image you want. This article ignores this specific optimization. However, if the space used is smaller than the space provided by your image, make sure that only necessary patches are rendered.
Determine Layers
Now you know how to use a single canvas to implement this example. Let's see how we can improve this type of scenario and speed up the rendering loop. To use the layering technology, you must identify the HTML5 Canvas elements required for layering by identifying the rendering overlaps of objects.
Redraw Area
To determine whether there are overlapping areas, consider some invisible areas called re-painting areas. The redraw area is the area that needs to be cleared when drawing an object image. Re-painting areas are important for rendering analysis because they allow you to find optimization techniques that improve rendering scenarios, as shown in figure 3.
Figure 3. Merging game views and repainting Areas
To visualize the effect in Figure 3, each entity in the scenario has an overlap that represents the re-painting area, which spans the width of the view area and the height of the object image. Scenarios can be divided into three groups: Background, foreground, and interaction. The redraw area in a scenario has a color overlap to distinguish different areas:
- Background-black
- Cloud-red
- Hill-green
- Ground-blue
- Red-Blue
- Yellow obstacle-blue
For all overlaps except the ball and obstacle, the re-painting area will span across the area width. The images of these entities almost fill the entire screen. Due to their translation requirements, they render the entire area width, as shown in figure 4. It is expected that the ball and obstacle will pass through the view area and may have their respective areas defined by the object location. If you delete the image rendered to the scene and leave only the re-painting area, you can easily see the individual layers.
Figure 4. redraw Area
The initial layer is obvious because you can notice the overlapping areas. Because the ball and obstacle areas cover the hill and the ground, these entities can be grouped into one layer, which is called the interaction layer. Based on the Rendering sequence of game entities, the interaction layer is the top layer.
Another way to find an additional layer is to collect all areas that do not overlap. The red, green, and blue areas that occupy the view area do not overlap, and they form the second layer-foreground. The areas of the cloud and the Interaction entity do not overlap, but because the ball may jump to the red area, you should consider this entity as a separate layer.
For the black area, it can be easily inferred that the background entity will form the last layer. Any area (such as the background entity) that fills the entire view area should be considered to fill the area in the whole layer, although this is not applicable to this scenario. After defining the three layers, we can start to allocate this layer to the canvas, as shown in Figure 5.
Figure 5. Layered game view
Now you have defined layers for the entities of each group. Now you can optimize canvas cleanup. The goal of this optimization is to save processing time by reducing the number of fixed things on the screen rendered each step. It is important to note that different policies may optimize the image. The next section describes how to optimize various entities or layers.
Rendering Optimization
Optimizing entities is the core of a layered policy. Layer the object so that the rendering policy can be used. Optimization Techniques usually try to eliminate overhead. As described in table 1, you have increased the memory overhead because of the introduction of layers. The optimization technology discussed here will reduce the amount of work that the processor must perform to speed up the game. Our goal is to find a way to reduce the amount of space to be rendered, and delete as many rendering and clearing calls as possible in each step.
Clear a single object
The first optimization method is to clear the space and speed up processing by only clearing the screen subsets of the object. First, we need to reduce the amount of re-painting areas that overlap the transparent pixels around each object in the region. This technique is used to include relatively small entities that fill the small area of the view area.
The first target is the ball and obstacle entity. The single object clearing technique involves clearing the previous frame before rendering the object to a new position to render the position of the object. We will introduce a clearing step to the rendering of each object and store the boundary boxes of the object's images. Adding this step modifies the object to include the clearing step, as shown in listing 5.
Listing 5. contains objects cleared in a single box
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;
}
};
The update of the render function introduces a clearRect call before conventional drawImage. For this step, the object must be stored in the previous location. Figure 6 shows the steps taken by the object for the previous position.
Figure 6. Clear the rectangle
You can create a clear method called before the update step for each object to implement this Rendering solution (but this article will not use the clear method ). You can also introduce this clearing policy to PanningEntity and add cleanup on the ground and cloud entities, as shown in Listing 6.
Listing 6. Include the PanningEntity cleared in the single box
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 );
}
};
Because PanningEntity spans the entire view area, you can use the canvas width to clear the size of the rectangle. If you use this clearing policy, You will be provided with a redrawing area that has been defined for cloud, Hill, and ground entities.
To further optimize cloud entities, you can separate them into separate entities and use their own re-painting areas. This will greatly reduce the amount of screen space to be cleared in the cloud re-painting area. Figure 7 shows the new re-painting area.
Figure 7. Cloud with a separate redraw Area
The solution generated by a single entity clearing policy can solve most problems in Layered canvas games such as this example, but it can still be optimized. In order to find the extreme conditions for this rendering policy, we assume that the ball will collide with the triangle. If two objects collide, the re-painting areas of the objects may overlap and create a rendering component that you do not want. Another cleanup optimization is more suitable for entities that may collide, and it will also benefit from layering.
Clear dirty rectangle
Without a single cleanup policy, the dirty rectangle cleanup policy can be a powerful alternative. You can use this clearing policy for a large number of entities in a repainted area, including dense particle systems, or space games with minor planets.
In terms of concept, the algorithm collects the repainting areas of all entities managed by the algorithm, and clears the entire area in a clear call. To increase optimization, this clearing policy also deletes repeated clearing calls generated by each independent entity, as shown in listing 7.
Listing 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;
}
};
The dirty rectangle algorithm is integrated into the rendering loop, which requires that the manager in listing 7 be called before the rendering call is made. Add the entity to the manager so that the manager can calculate the dimension of the rectangle when clearing. Although the manager produces the expected optimization, the manager can optimize the game loop based on the game loop, as shown in figure 8.
Figure 8. redraw area of the Interaction Layer
- Frame 1-the object is in collision and almost overlaps.
- Frame 2-the actual weight area is overlapped.
- Frame 3-The re-painting area overlaps and is collected into a dirty rectangle.
- Frame 4-The dirty rectangle is cleared.
Figure 8 shows the re-painting area calculated by the algorithm for the objects in the interaction layer. Because the game contains interaction on this layer, the dirty rectangle policy is enough to solve the problem of interaction and overlapping re-painting areas.
Rewrite as a purge
Rewrite can be used as an optimization technique for completely opaque objects that are animated in a constant re-painting area. Renders an opaque bitmap into an area (the default merging operation). This places pixels in the area and does not need to consider the original rendering in the area. This optimization eliminates the purge call required before rendering calls, because the rendering will overwrite the original region.
By re-rendering the image above the previous rendering, rewriting can speed up the ground entity. You can also speed up the largest layer, such as the background, in the same way.
By reducing the repainting area of each layer, you have effectively found optimization policies for the layer and the entities they contain.
Conclusion
Layering a canvas is an optimization strategy that can be applied to all interactive real-time scenarios. If you want to optimize by layering, You need to analyze the re-painting areas of the scenario to consider how the scenes overlap these areas. Some scenarios are collections of overlapping re-painting areas that can define layers. Therefore, they are good candidates for rendering layered canvases. If you need a particle system or a large number of physical objects to collide, layering the canvas may be a good choice.