Skip to main content

纹理

¥Textures

我们正在慢慢地从高水平下降到低水平。我们已经讨论了场景图,以及其中的显示对象。我们即将讨论精灵和其他简单的显示对象。但在此之前,我们需要先讨论一下纹理。

¥We're slowly working our way down from the high level to the low. We've talked about the scene graph, and in general about display objects that live in it. We're about to get to sprites and other simple display objects. But before we do, we need to talk about textures.

在 PixiJS 中,纹理是显示对象使用的核心资源之一。从广义上讲,纹理表示用于填充屏幕上某个区域的像素源。最简单的例子是精灵 - 完全由单一纹理填充的矩形。但事情可能会变得更加复杂。

¥In PixiJS, textures are one of the core resources used by display objects. A texture, broadly speaking, represents a source of pixels to be used to fill in an area on the screen. The simplest example is a sprite - a rectangle that is completely filled with a single texture. But things can get much more complex.

纹理的生命周期

¥Life-cycle of a Texture

让我们通过跟踪图片数据到达屏幕的路径来检查纹理的实际工作原理。

¥Let's examine how textures really work, by following the path your image data travels on its way to the screen.

这是我们要遵循的流程:源图片 > 加载器 > 基础纹理 > 纹理

¥Here's the flow we're going to follow: Source Image > Loader > BaseTexture > Texture

服务形象

¥Serving the Image

首先,你拥有要显示的图片。第一步是使其在你的服务器上可用。这看起来似乎是显而易见的,但如果你从其他游戏开发系统转向 PixiJS,那么值得记住的是,所有内容都必须通过网络加载。如果你在本地进行开发,请注意你必须使用网络服务器进行测试,否则由于浏览器对待本地文件安全的方式,你的图片将无法加载。

¥To start with, you have the image you want to display. The first step is to make it available on your server. This may seem obvious, but if you're coming to PixiJS from other game development systems, it's worth remembering that everything has to be loaded over the network. If you're developing locally, please be aware that you must use a webserver to test, or your images won't load due to how browsers treat local file security.

加载图片

¥Loading the Image

要使用图片,第一步是将图片文件从网络服务器提取到用户的网络浏览器中。为此,我们可以使用 Assets.load('myTexture.png')Assets 封装并处理告诉浏览器获取图片、转换它,然后在完成后通知你。这个过程是异步的 - 你请求加载,然后时间流逝,然后 promise 完成以让你知道加载已完成。我们将在后面的指南中更深入地介绍加载程序。

¥To work with the image, the first step is to pull the image file from your webserver into the user's web browser. To do this, we can use Assets.load('myTexture.png'). Assets wraps and deals with telling the browser to fetch the image, convert it and then let you when that has been completed. This process is asynchronous - you request the load, then time passes, then a promise completes to let you know the load is completed. We'll go into the loader in a lot more depth in a later guide.

const texture = await Assets.load('myTexture.png');

// pass a texture explicitly
const sprite = new Sprite(texture);
// as options
const sprite2 = new Sprite({texture});
// from the cache as the texture is loaded
const sprite3 = Sprite.from('myTexture.png')

TextureSources 拥有数据

¥TextureSources Own the Data

纹理加载后,加载的 <IMG> 元素包含我们需要的像素数据。但要使用它来渲染某些内容,PixiJS 必须获取原始图片文件并将其上传到 GPU。这给我们带来了纹理系统的真正主力 - TextureSource 级。每个 TextureSource 管理一个像素源 - 通常是图片,但也可以是 Canvas 或 Video 元素。TextureSources 允许 PixiJS 将图片转换为像素并在渲染中使用这些像素。此外,它还包含控制纹理数据渲染方式的设置,例如环绕模式(对于 0.0-1.0 范围之外的 UV 坐标)和缩放模式(缩放纹理时使用)。

¥Once the texture has loaded, the loaded <IMG> element contains the pixel data we need. But to use it to render something, PixiJS has to take that raw image file and upload it to the GPU. This brings us to the real workhorse of the texture system - the TextureSource class. Each TextureSource manages a single pixel source - usually an image, but can also be a Canvas or Video element. TextureSources allow PixiJS to convert the image to pixels and use those pixels in rendering. In addition, it also contains settings that control how the texture data is rendered, such as the wrap mode (for UV coordinates outside the 0.0-1.0 range) and scale mode (used when scaling a texture).

TextureSource 会自动缓存,因此对同一个 URL 重复调用 Texture.from() 每次都会返回相同的 TextureSource。销毁 TextureSource 会释放与其关联的图片数据。

¥TextureSource are automatically cached, so that calling Texture.from() repeatedly for the same URL returns the same TextureSource each time. Destroying a TextureSource frees the image data associated with it.

纹理是 BaseTextures 上的视图

¥Textures are a View on BaseTextures

最后,我们进入 Texture 课程本身!此时,你可能想知道 Texture 对象的作用。毕竟,BaseTexture 管理像素和渲染设置。答案是,它的作用并不大。纹理是底层 BaseTexture 上的轻量级视图。它们的主要属性是 TextureSource 中从中提取的源矩形。

¥So finally, we get to the Texture class itself! At this point, you may be wondering what the Texture object does. After all, the BaseTexture manages the pixels and render settings. And the answer is, it doesn't do very much. Textures are light-weight views on an underlying BaseTexture. Their main attribute is the source rectangle within the TextureSource from which to pull.

如果 PixiJS 绘制的所有内容都是精灵,那将是相当多余的。但考虑 SpriteSheets。SpriteSheet 是一个包含多个精灵图片的单个图片。在 精灵表 对象中,单个纹理源由一组纹理引用,每个纹理对应原始精灵表中的每个源图片。通过共享单个纹理源,浏览器仅下载一个文件,并且我们的批处理渲染器可以快速绘制精灵,因为它们都共享相同的底层像素数据。SpriteSheet 的纹理仅拉出每个精灵所需的像素矩形。

¥If all PixiJS drew were sprites, that would be pretty redundant. But consider SpriteSheets. A SpriteSheet is a single image that contains multiple sprite images arranged within. In a Spritesheet object, a single TextureSource is referenced by a set of Textures, one for each source image in the original sprite sheet. By sharing a single TextureSource, the browser only downloads one file, and our batching renderer can blaze through drawing sprites since they all share the same underlying pixel data. The SpriteSheet's Textures pull out just the rectangle of pixels needed by each sprite.

这就是为什么我们同时拥有纹理和纹理源 - 允许精灵表、动画、按钮状态等作为单个图片加载,同时仅显示主图片中需要的部分。

¥That is why we have both Textures and TextureSource - to allow sprite sheets, animations, button states, etc to be loaded as a single image, while only displaying the part of the master image that is needed.

加载纹理

¥Loading Textures

我们将在后面的指南中讨论资源加载,但新用户在构建 PixiJS 项目时面临的最常见问题之一是如何最好地加载纹理。

¥We will discuss resource loading in a later guide, but one of the most common issues new users face when building a PixiJS project is how best to load their textures.

这是一个好的解决方案的快速备忘单:

¥here's a quick cheat sheet of one good solution:

  1. 显示加载图片

    ¥Show a loading image

  2. 使用 资源 确保所有纹理都已加载

    ¥Use Assets to ensure that all textures are loaded

  3. 根据进度回调可选择更新加载图片

    ¥optionally update your loading image based on progress callbacks

  4. 加载完成后,运行所有对象并使用 Texture.from() 将加载的纹理从纹理缓存中提取出来

    ¥On loader completion, run all objects and use Texture.from() to pull the loaded textures out of the texture cache

  5. 准备你的纹理(可选 - 见下文)

    ¥Prepare your textures (optional - see below)

  6. 隐藏加载图片,开始渲染场景图

    ¥Hide your loading image, start rendering your scene graph

使用此工作流程可确保你的纹理已预先加载,以防止弹出,并且相对容易编码。

¥Using this workflow ensures that your textures are pre-loaded, to prevent pop-in, and is relatively easy to code.

关于准备纹理:即使在加载纹理之后,图片仍然需要被推送到 GPU 并进行解码。对大量源图片执行此操作可能会很慢,并且在项目首次加载时会导致延迟峰值。为了解决这个问题,你可以使用 准备 插件,它允许你在显示项目之前的最后一步中预加载纹理。

¥Regarding preparing textures: Even after you've loaded your textures, the images still need to be pushed to the GPU and decoded. Doing this for a large number of source images can be slow and cause lag spikes when your project first loads. To solve this, you can use the Prepare plugin, which allows you to pre-load textures in a final step before displaying your project.

卸载纹理

¥Unloading Textures

使用完纹理后,你可能希望释放它使用的内存(WebGL 管理的缓冲区和基于浏览器的缓冲区)。为此,你应该在拥有数据的 BaseTexture 上调用 destroy()。请记住,纹理不管理像素数据!

¥Once you're done with a Texture, you may wish to free up the memory (both WebGL-managed buffers and browser-based) that it uses. To do so, you should call destroy() on the BaseTexture that owns the data. Remember that Textures don't manage pixel data!

对于短暂的图片(例如大型且仅使用一次的过场动画)来说,这是一个特别好的主意。如果通过 Assets 加载的纹理被破坏,则资源类将自动为你将其从缓存中删除。

¥This is a particularly good idea for short-lived imagery like cut-scenes that are large and will only be used once. If a texture is destroyed that was loaded via Assets then the assets class will automatically remove it from the cache for you.

超越图片

¥Beyond Images

正如我们上面提到的,你不仅可以使用图片来制作纹理:

¥As we alluded to above, you can make a Texture out of more than just images:

视频:将 HTML5 <VIDEO> 元素传递给 TextureSource.from() 以允许你在项目中显示视频。由于它是纹理,因此你可以对其进行着色、添加滤镜,甚至将其应用到自定义几何体。

¥Video: Pass an HTML5 <VIDEO> element to TextureSource.from() to allow you to display video in your project. Since it's a texture, you can tint it, add filters, or even apply it to custom geometry.

画布:同样,你可以将 HTML5 <CANVAS> 元素封装在 BaseTexture 中,以便你使用 canvas 的绘制方法动态创建纹理。

¥Canvas: Similarly, you can wrap an HTML5 <CANVAS> element in a BaseTexture to let you use canvas's drawing methods to dynamically create a texture.

SVG:传入 <SVG> 元素或加载 .svg URL,PixiJS 将尝试对其进行光栅化。对于网络高度受限的项目,这可以以最短的网络加载时间实现漂亮的图形。

¥SVG: Pass in an <SVG> element or load a .svg URL, and PixiJS will attempt to rasterize it. For highly network-constrained projects, this can allow for beautiful graphics with minimal network load times.

渲染纹理:一个更高级(但非常强大!)的功能是从 RenderTexture 构建纹理。这可以允许使用 几何学 对象构建复杂的几何体,然后将该几何体烘焙为简单的纹理。

¥RenderTexture: A more advanced (but very powerful!) feature is to build a Texture from a RenderTexture. This can allow for building complex geometry using a Geometry object, then baking that geometry down to a simple texture.

这些纹理源中的每一个都有我们无法在本指南中涵盖的注意事项和细微差别,但它们应该让你感受到 PixiJS 纹理系统的强大功能。

¥Each of these texture sources has caveats and nuances that we can't cover in this guide, but they should give you a feeling for the power of PixiJS's texture system.

看看 渲染纹理示例代码

¥Check out the render texture example code.