”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 最大化性能:深入探讨 PixiJS 优化

最大化性能:深入探讨 PixiJS 优化

发布于2024-11-08
浏览:369

利用先进的策略和技术将您的 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 个 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 



此方法通过引用相同的几何图形而不是为每个对象重复它,显着减少了内存使用量。

Maximising Performance: A Deep Dive into PixiJS Optimization

在一个图形对象中绘制所有内容

对于静态图形或复杂结构,在单个 Graphics 对象中绘制所有元素是另一种优化技术:

const graphics = new PIXI.Graphics();
// Draw 100 circles using the same PIXI.Graphics instance
for (let i = 0; i 



在这种方法中,我们不是创建新的 Graphics 对象,而是将新的几何图形添加到单个 Graphics 实例的 GeometryList 中。此方法对于更复杂的图形结构特别有效。

Maximising Performance: A Deep Dive into PixiJS Optimization


在 PixiJS 中利用 CacheAsBitmap 的强大功能

PixiJS 中最强大的功能之一是 CacheAsBitmap。本质上,它让引擎像精灵一样处理图形。在某些情况下,这可以显着提高性能。

  • 仅当对象不经常更新时才使用 CacheAsBitmap。

  • 大批量的图形可以作为位图缓存在容器中。 pixi 将拍摄快照并将其预渲染为位图,而不是重新渲染 100 个图形。

  • 始终考虑内存使用情况,缓存位图正在使用大量内存。

何时使用 CacheAsBitmap

应该明智地使用cacheAsBitmap。当应用于很少需要更新的对象时,它将是最有效的。例如,如果碰巧有数千个静态或只有很少变化的图形,则将它们缓存为位图可以从根本上减少渲染开销。

PixiJS 可以拍摄这些图形的“快照”并将它们渲染为单个位图,而不是重新渲染 100 个单独的图形。您可以这样实施:

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

内存使用注意事项

但是,注意内存使用情况很重要。缓存的位图可能会消耗大量内存。因此,虽然cacheAsBitmap可以大大减少渲染负载,但它会使用更多的内存来进行权衡。应根据应用程序的具体需求和限制仔细考虑这种权衡。

总之,cacheAsBitmap 是 PixiJS 中优化性能的有效工具,特别是对于静态或很少更新的图形。它通过将复杂图形视为单个位图来简化渲染,但必须平衡这一点与内存占用的影响。

为什么 PixiJS 中的精灵通常比图形更有效

当谈到 PixiJS 的内存效率时,精灵通常比图形更具优势。当处理共享相同形状或纹理的多个对象时,这一点尤其明显。让我们回顾一下创建 100 个圆形图形的示例,但这次使用精灵。

从单个纹理创建精灵

首先,我们根据单个圆形图形的几何形状创建纹理:

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 



在这种方法中,我们不是重新渲染图形并管理每个对象不断增长的几何列表,而是创建一个纹理并在多个精灵中重用它。这显着减少了渲染负载和内存使用。

局限性和创造性解决方案

此方法的一个限制是您受到所创建的纹理的限制。然而,这就是创造力变得关键的地方。您可以使用 PIXI.Graphics 生成各种形状的纹理并将它们应用到 Sprites。一种特别有效的方法是创建一个基本纹理(例如 1x1 像素位图),并将其重用于所有矩形精灵。通过将精灵大小调整为不同的尺寸,您可以在多个精灵中利用相同的基本纹理,而无需冗余。
例如:

// 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

使用此方法,.tint() 允许您在不触发完全重新渲染的情况下为精灵着色,因为色调将作为附加着色器效果直接应用在 GPU 上。

在粒子容器中使用 100k 精灵

为了说明此技术的威力,想象一下运行 100,000 个具有随机色调的单独精灵,每个精灵在每一帧上进行变换,同时保持平滑的 60 FPS。

Maximising Performance: A Deep Dive into PixiJS Optimization

Maximising Performance: A Deep Dive into PixiJS Optimization

为了进一步阅读有关优化 PixiJS 的内容,我强烈推荐 PixiJS 的原始创建者之一撰写的一篇富有洞察力的文章,该文章深入研究了 renderTexture 技术。 

你可以在这里找到它

哇! 如果您已经做到了这一步,我真诚地感谢您在深入研究 PixiJS 优化过程中与我一起坚持。我希望您发现这里分享的见解和技术对您的项目有价值。请继续关注我的下一篇文章,我将更详细地探讨实体组件系统 (ECS) 方法和 NativeArrays 的强大功能。这些方法将使您的 PixiJS 应用程序的性能和效率达到新的高度。感谢您的阅读,我们下一篇再见!

版本声明 本文转载于:https://dev.to/recursivevoid/maximising-performance-a-deep-dive-into-pixijs-optimization-4i0g?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 找到最大计数时,如何解决mySQL中的“组函数\”错误的“无效使用”?
    找到最大计数时,如何解决mySQL中的“组函数\”错误的“无效使用”?
    如何在mySQL中使用mySql 检索最大计数,您可能会遇到一个问题,您可能会在尝试使用以下命令:理解错误正确找到由名称列分组的值的最大计数,请使用以下修改后的查询: 计数(*)为c 来自EMP1 按名称组 c desc订购 限制1 查询说明 select语句提取名称列和每个名称...
    编程 发布于2025-04-18
  • CSS强类型语言解析
    CSS强类型语言解析
    您可以通过其强度或弱输入的方式对编程语言进行分类的方式之一。在这里,“键入”意味着是否在编译时已知变量。一个例子是一个场景,将整数(1)添加到包含整数(“ 1”)的字符串: result = 1 "1";包含整数的字符串可能是由带有许多运动部件的复杂逻辑套件无意间生成的。它也可以是故意从单个真理...
    编程 发布于2025-04-18
  • 如何使用Python有效地以相反顺序读取大型文件?
    如何使用Python有效地以相反顺序读取大型文件?
    在python 中,如果您使用一个大文件,并且需要从最后一行读取其内容,则在第一行到第一行,Python的内置功能可能不合适。这是解决此任务的有效解决方案:反向行读取器生成器 == ord('\ n'): 缓冲区=缓冲区[:-1] ...
    编程 发布于2025-04-18
  • 为什么我在Silverlight Linq查询中获得“无法找到查询模式的实现”错误?
    为什么我在Silverlight Linq查询中获得“无法找到查询模式的实现”错误?
    查询模式实现缺失:解决“无法找到”错误在Silverlight应用程序中,尝试使用LINQ建立LINQ连接以错误而实现的数据库”,无法找到查询模式的实现。”当省略LINQ名称空间或查询类型缺少IEnumerable 实现时,通常会发生此错误。 解决问题来验证该类型的质量是至关重要的。在此特定实例中...
    编程 发布于2025-04-18
  • 如何在无序集合中为元组实现通用哈希功能?
    如何在无序集合中为元组实现通用哈希功能?
    在未订购的集合中的元素要纠正此问题,一种方法是手动为特定元组类型定义哈希函数,例如: template template template 。 struct std :: hash { size_t operator()(std :: tuple const&tuple)const {...
    编程 发布于2025-04-18
  • 版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    版本5.6.5之前,使用current_timestamp与时间戳列的current_timestamp与时间戳列有什么限制?
    在时间戳列上使用current_timestamp或MySQL版本中的current_timestamp或在5.6.5 此限制源于遗留实现的关注,这些限制需要对当前的_timestamp功能进行特定的实现。 创建表`foo`( `Productid` int(10)unsigned not n...
    编程 发布于2025-04-18
  • 如何使用PHP从XML文件中有效地检索属性值?
    如何使用PHP从XML文件中有效地检索属性值?
    从php $xml = simplexml_load_file($file); foreach ($xml->Var[0]->attributes() as $attributeName => $attributeValue) { echo $attributeName,...
    编程 发布于2025-04-18
  • Python中何时用"try"而非"if"检测变量值?
    Python中何时用"try"而非"if"检测变量值?
    使用“ try“ vs.” if”来测试python 在python中的变量值,在某些情况下,您可能需要在处理之前检查变量是否具有值。在使用“如果”或“ try”构建体之间决定。“ if” constructs result = function() 如果结果: 对于结果: ...
    编程 发布于2025-04-18
  • 如何使用node-mysql在单个查询中执行多个SQL语句?
    如何使用node-mysql在单个查询中执行多个SQL语句?
    Multi-Statement Query Support in Node-MySQLIn Node.js, the question arises when executing multiple SQL statements in a single query using the node-mys...
    编程 发布于2025-04-18
  • 查找当前执行JavaScript的脚本元素方法
    查找当前执行JavaScript的脚本元素方法
    如何引用当前执行脚本的脚本元素在某些方案中理解问题在某些方案中,开发人员可能需要将其他脚本动态加载其他脚本。但是,如果Head Element尚未完全渲染,则使用document.getElementsbytagname('head')[0] .appendChild(v)的常规方...
    编程 发布于2025-04-18
  • 您如何在Laravel Blade模板中定义变量?
    您如何在Laravel Blade模板中定义变量?
    在Laravel Blade模板中使用Elegance 在blade模板中如何分配变量对于存储以后使用的数据至关重要。在使用“ {{}}”分配变量的同时,它可能并不总是最优雅的解决方案。幸运的是,Blade通过@php Directive提供了更优雅的方法: $ old_section =“...
    编程 发布于2025-04-18
  • 如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    如何为PostgreSQL中的每个唯一标识符有效地检索最后一行?
    postgresql:为每个唯一标识符在postgresql中提取最后一行,您可能需要遇到与数据集合中每个不同标识的信息相关的信息。考虑以下数据:[ 1 2014-02-01 kjkj 在数据集中的每个唯一ID中检索最后一行的信息,您可以在操作员上使用Postgres的有效效率: id dat...
    编程 发布于2025-04-18
  • 使用jQuery如何有效修改":after"伪元素的CSS属性?
    使用jQuery如何有效修改":after"伪元素的CSS属性?
    在jquery中了解伪元素的限制:访问“ selector 尝试修改“:”选择器的CSS属性时,您可能会遇到困难。 This is because pseudo-elements are not part of the DOM (Document Object Model) and are th...
    编程 发布于2025-04-18
  • Python不会对超范围子串切片报错的原因
    Python不会对超范围子串切片报错的原因
    在python中用索引切片范围:二重性和空序列索引单个元素不同,该元素会引起错误,切片在序列的边界之外没有。这种行为源于索引和切片之间的基本差异。索引一个序列,例如“示例” [3],返回一个项目。但是,切片序列(例如“示例” [3:4])返回项目的子序列。索引不存在的元素时,例如“示例” [9] ...
    编程 发布于2025-04-18
  • 如何从Python中的字符串中删除表情符号:固定常见错误的初学者指南?
    如何从Python中的字符串中删除表情符号:固定常见错误的初学者指南?
    从python import codecs import codecs import codecs 导入 text = codecs.decode('这狗\ u0001f602'.encode('utf-8'),'utf-8') 印刷(文字)#带有...
    编程 发布于2025-04-18

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3