首頁  >  文章  >  web前端  >  最大化效能:深入探討 PixiJS 最佳化

最大化效能:深入探討 PixiJS 最佳化

WBOY
WBOY原創
2024-09-04 18:33:00516瀏覽

利用先進的策略和技術將您的 PixiJS 應用程式提升到新的水平

前言

這篇文章介紹了在 CPU / 記憶體方面可以最好地優化 pixiJS 中多個元素的渲染的不同方法。例如,考慮在沒有任何快取的情況下重新渲染每一幀(在 CPU 使用率方面表現良好)或將渲染的圖形快取在記憶體中之間的差異。這將根據場景中的圖形數量按比例增加記憶體使用量。

有多種策略可以處理此類最佳化。特別值得注意的是以資料為導向的設計,它提供了一組與更傳統的常見物件導向程式設計方式完全不同的方法。

其他主要方法包括:例如,剔除和利用更結構化的格式 - C# 中的 NativeArrays 和 TypeScript 中的 TypedArrays。這些將允許更好地管理記憶體緩衝區,這可能會限制快取未命中,但這也需要大量的工程經驗和/或自訂。

在這篇文章中,我將重點介紹一種使用 PixiJS 優化 WebGL 環境的工作方法:物件導向的方法,包括最佳實踐。這將為您提供一種組織良好的方法來提高 PixiJS 應用程式的速度和效率。

在我的下一篇文章中,我將討論另一種強大的最佳化方法:實體組件系統方法。 ECS 方法非常以數據為導向,並且在高性能環境中優化 PixiJS 時提供了全新的外觀。在 Medium 上繼續閱讀本文,我將深入探討 ECS 方法的本質。

永遠記住,為了優化和進一步增強 Pixi 應用程式的效能,總有一些事情可以做得更好。更好並不意味著最優化或最快。最佳解決方案是在優化投入的時間和投資回報之間進行權衡的問題,以確保您能夠滿足專案期限,但有足夠的最佳化來滿足任何潛在用戶的需求,而不會過度擴展您的資源。

物件導向的方法

在本節中,我將引導您了解最佳化 PixiJS 應用程式的最佳方法。

此部分基於官方提示,值得查看!

我們的其餘討論將圍繞 Pixi 圖形、精靈、網格以及何時使用粒子容器而不是預設的 Pixi 容器。本章應該讓您清楚地了解如何在物件導向的上下文中最佳地使用所有內容,以便您的 PixiJS 專案正常運作並以最高效率進行渲染。

了解 Pixi 圖形的內部運作原理

為了有效地使用 Pixi 圖形,我們需要了解它們的內部功能。讓我們先展示一個在 Pixi 中創建圖形物件的非常基本的範例:

const graphics = new PIXI.Graphics();
graphics.beginFill(0xff0000);
graphics.drawRect(0, 0, 200, 100);
graphics.endFill();

然而,在這個簡單的實現中重要的是「幕後」發生的事情。在創建這種圖形時,Pixi 創建了一個稱為 GraphicsGeometry 物件的東西。該物件的形狀和大小取決於您為正在繪製的形狀指定的尺寸和屬性。然後,最終的 Geometry 物件儲存在 Graphics 物件內的 GeometryList 內。

請注意,每次您在 PIXI.Graphics 的幫助下繪製某些內容時,GeometryList 都會更新。有時,您只想清除此列表,但同時保持 Graphics 物件處於活動狀態 - 這就是 .clear() 方法發揮作用的地方。了解此過程的工作原理將對您使用 Pixi 時有很大幫助,因為它直接影響 Pixi 如何處理和渲染應用程式中的圖形。

Pixi 圖形最佳化技術

讓我們透過在 PixiJS 中建立 100 個 Graphics 物件的用例來探索最佳化策略。

function createGraphics(x, y) {
    const graphic = new PIXI.Graphics();
    graphic.beginFill(0xDE3249);
    graphic.drawCircle(x, y, 10);
    graphic.endFill();
    return graphic;
}

for (let i = 0; i < 100; i++) {
    const x = Math.random() * app.screen.width;
    const y = Math.random() * app.screen.height;
    const graphics = createGraphics(x, y);
    app.stage.addChild(graphic);
}

在這種情況下,如果所有 100 個 Graphics 物件共享相同的寬度和高度,我們可以透過重複使用幾何體進行最佳化。

Maximising Performance: A Deep Dive into PixiJS Optimization

傳遞 GraphicsGeometry 作為參考

為圓形建立單一幾何圖形並重複使用它:

// Create a single geometry for a circle
const circleGeometry = new PIXI.Graphics();
circleGeometry.beginFill(0xDE3249);
circleGeometry.drawCircle(0, 0, 10); // Draw a circle at the origin
circleGeometry.endFill();
// Function to create a graphic using the circle geometry
function createCircle(x, y) {
    const circle = new PIXI.Graphics(circleGeometry.geometry);
    circle.x = x;
    circle.y = y;
    return circle;
}
// Create 100 circles using the same geometry
for (let i = 0; i < 100; i++) {
    const x = Math.random() * app.screen.width;
    const y = Math.random() * app.screen.height;
    const circle = createCircle(x, y);
    app.stage.addChild(circle);
}

此方法透過引用相同的幾何圖形而不是為每個物件重複它,顯著減少了記憶體使用量。

Maximising Performance: A Deep Dive into PixiJS Optimization

Draw All in One Graphics Object

For static graphics or complex structures, drawing all elements in a single Graphics object is another optimization technique:

const graphics = new PIXI.Graphics();
// Draw 100 circles using the same PIXI.Graphics instance
for (let i = 0; i < 100; i++) {
    const x = Math.random() * app.screen.width;
    const y = Math.random() * app.screen.height;
    graphics.beginFill(0xDE3249);
    graphics.drawCircle(x, y, 10);
    graphics.endFill();
}
// Add the graphics to the stage
app.stage.addChild(graphics);

In this approach, instead of creating new Graphics objects, we add new geometries to the GeometryList of a single Graphics instance. This method is particularly efficient for more complex graphic structures.

Maximising Performance: A Deep Dive into PixiJS Optimization


Leveraging the Power of CacheAsBitmap in PixiJS

One of the most powerful features within PixiJS is CacheAsBitmap. Essentially, it lets the engine treat graphics like sprites. This can bring performance up substantially in certain cases.

  • Only use CacheAsBitmap if the object is not updated too often.

  • Big batch of Graphics can be cached as bitmap in container. Instead having 100 Graphics re-rendered, pixi will take a snapshot and pre-render it as a bitmap.

  • Always consider the memory usage, cached bitmaps are using a lot of memory.

When to Use CacheAsBitmap

One should use cacheAsBitmap judiciously. It will be most effective when applied to objects that need to update seldom. For instance, if one happens to have thousands of volume of Graphics that are static or have only a rare change, caching them as a bitmap radically reduces rendering overhead.

Instead of re-rendering 100 individual Graphics, PixiJS can take a 'snapshot' of these and render them as single bitmap. This is how you can implement:

const graphicsContainer = new PIXI.Container();
// Add your graphics to the container
// ...
// Cache the entire container as a bitmap
graphicsContainer.cacheAsBitmap = true;

Memory Usage Consideration

However, it's important to be mindful of memory usage. Cached bitmaps can consume a significant amount of memory. Therefore, while cacheAsBitmap can drastically reduce the rendering load, it trades off by using more memory. This trade-off should be carefully considered based on the specific needs and constraints of your application.

In summary, cacheAsBitmap is an effective tool for optimizing performance in PixiJS, particularly for static or seldom-updated graphics. It simplifies rendering by treating complex graphics as single bitmaps, but it's essential to balance this with the memory footprint implications.

Why Sprites Are Often More Efficient than Graphics in PixiJS

When it comes to memory efficiency in PixiJS, sprites generally have the upper hand over graphics. This is particularly evident when dealing with multiple objects that share the same shape or texture. Let's revisit the example of creating 100 circle graphics, but this time using sprites.

Creating Sprites from a Single Texture

First, we create a texture from the geometry of a single circle graphic:

const circleGraphic = new PIXI.Graphics();
circleGraphic.beginFill(0xDE3249);
circleGraphic.drawCircle(0, 0, 10);
circleGraphic.endFill();
// Generate a texture from the graphic
const circleTexture = app.renderer.generateTexture(circleGraphic);
Next, we use this texture to create sprites:
// Function to create a sprite using the circle texture
function createCircleSprite(x, y) {
    const sprite = new PIXI.Sprite(circleTexture);
    sprite.x = x;
    sprite.y = y;
    return sprite;
}

// Create and add 100 circle sprites to the stage
for (let i = 0; i < 100; i++) {
    const x = Math.random() * app.screen.width;
    const y = Math.random() * app.screen.height;
    const circleSprite = createCircleSprite(x, y);
    app.stage.addChild(circleSprite);
}

In this approach, instead of re-rendering graphics and managing a growing geometry list for each object, we create one texture and reuse it across multiple sprites. This significantly reduces the rendering load and memory usage.

Limitations and Creative Solutions

One limitation of this method is that you're constrained by the textures you've created. However, this is where creativity becomes key. You can generate various shaped textures using PIXI.Graphics and apply them to Sprites. An especially efficient approach is to create a baseTexture, like a 1x1 pixel bitmap, and reuse it for all rectangular sprites. By resizing the sprite to different dimensions, you can leverage the same baseTexture across multiple sprites without redundancy.
For instance:

// This creates a 16x16 white texture
const baseTexture = PIXI.Texture.WHITE;

// Use this baseTexture for all rectangular shapes
const sprite= new PIXI.Sprite(baseTexture);
sprite.tint = 0xDE3249; // Set the sprite color
sprite.position.set(x, y);
sprite.width = width;
sprite.height = height;

Maximising Performance: A Deep Dive into PixiJS Optimization

With this method, .tint() allows you to color the sprite without triggering a full re-render, as the tint is applied as an additional shader effect directly on the GPU.

Using 100k Sprites in Particle Container

To illustrate the power of this technique, imagine running 100,000 individual sprites with random tints, each transforming on every frame, all while maintaining a smooth 60 FPS.

Maximising Performance: A Deep Dive into PixiJS Optimization

Maximising Performance: A Deep Dive into PixiJS Optimization

For further reading on optimizing PixiJS, I highly recommend an insightful article by one of the original creators of PixiJS, which delves deeply into the renderTexture technique. 

You can find it here

哇! 如果您已經完成了這一步,我真誠地感謝您在 PixiJS 優化的深入研究中與我同行。我希望您發現這裡分享的見解和技術對您的專案有價值。請繼續關注我的下一篇文章,我將更詳細地探討實體組件系統 (ECS) 方法和 NativeArrays 的強大功能。這些方法將使您的 PixiJS 應用程式的效能和效率達到新的高度。感謝您的閱讀,我們下一篇再見!

以上是最大化效能:深入探討 PixiJS 最佳化的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn