图形
图形 是 PixiJS 工具箱中一个复杂且容易被误解的工具。 乍一看,它像是一个绘制形状的工具。 确实如此! 但它也可以用来生成掩模。 这是如何运作的?
英:Graphics is a complex and much misunderstood tool in the PixiJS toolbox. At first glance, it looks like a tool for drawing shapes. And it is! But it can also be used to generate masks. How does that work?
在本指南中,我们将从如何思考它的用途开始,揭开 Graphics 对象的神秘面纱。
英:In this guide, we're going to de-mystify the Graphics object, starting with how to think about what it does.
看看 图形示例代码。
英:Check out the graphics example code.
图形是关于构建 - 而不是绘图
PIXI.Graphics 类的首次用户常常对其工作原理感到困惑。 让我们看一个创建 Graphics 对象并绘制矩形的示例片段:
英:First-time users of the PIXI.Graphics class often struggle with how it works. Let's look at an example snippet that creates a Graphics object and draws a rectangle:
// Create a Graphics object, set a fill color, draw a rectangle
let obj = new PIXI.Graphics();
obj.beginFill(0xff0000);
obj.drawRect(0, 0, 200, 100);
// Add it to the stage to render
app.stage.addChild(obj);
该代码将起作用 - 你最终会在屏幕上看到一个红色矩形。 但当你开始思考它时,你就会感到非常困惑。 为什么我在构造对象时要绘制一个矩形? 画画不是一次性的行为吗? 第二帧如何绘制矩形? 当你使用一堆 drawThis 和 drawThat 调用创建一个 Graphics 对象,然后将其用作遮罩时,情况会变得更加奇怪。 什么???
英:That code will work - you'll end up with a red rectangle on the screen. But it's pretty confusing when you start to think about it. Why am I drawing a rectangle when constructing the object? Isn't drawing something a one-time action? How does the rectangle get drawn the second frame? And it gets even weirder when you create a Graphics object with a bunch of drawThis and drawThat calls, and then you use it as a mask. What???
问题在于函数名称以绘图为中心,绘图是将像素放置在屏幕上的操作。 但尽管如此,Graphics 对象实际上是关于构建的。
英:The problem is that the function names are centered around drawing, which is an action that puts pixels on the screen. But in spite of that, the Graphics object is really about building.
让我们更深入地了解一下 drawRect()
调用。 当你调用 drawRect()
时,PixiJS 实际上并没有绘制任何东西。 相反,它将你 "drew" 的矩形存储到几何图形列表中以供以后使用。 如果你随后将 Graphics 对象添加到场景中,渲染器将会出现,并要求 Graphics 对象渲染自身。 此时,你的矩形实际上已被绘制 - 以及你添加到几何列表中的任何其他形状、线条等。
英:Let's look a bit deeper at that drawRect()
call. When you call drawRect()
, PixiJS doesn't actually draw anything. Instead, it stores the rectangle you "drew" into a list of geometry for later use. If you then add the Graphics object to the scene, the renderer will come along, and ask the Graphics object to render itself. At that point, your rectangle actually gets drawn - along with any other shapes, lines, etc. that you've added to the geometry list.
一旦你明白发生了什么,事情就开始变得更有意义。 例如,当你使用 Graphics 对象作为遮罩时,遮罩系统使用几何列表中的图形基元列表来限制哪些像素进入屏幕。 没有涉及绘图。
英:Once you understand what's going on, things start to make a lot more sense. When you use a Graphics object as a mask, for example, the masking system uses that list of graphics primitives in the geometry list to constrain which pixels make it to the screen. There's no drawing involved.
这就是为什么将 Graphics 类视为几何构建工具而不是绘图工具会有所帮助。
英:That's why it helps to think of the Graphics class not as a drawing tool, but as a geometry building tool.
原语类型
PIXI.Graphics 类中有很多函数,但作为快速入门,这里列出了你可以添加的基本基元:
英:There are a lot of functions in the PIXI.Graphics class, but as a quick orientation, here's the list of basic primitives you can add:
- 线
- 矩形
- RoundRect
- 圆圈
- 椭圆
- 弧
- 贝塞尔曲线和二次曲线
此外,Graphics Extras 包 (@pixi/graphics-extras
) 可选地包括以下复杂基元:
英:In addition, the Graphics Extras package (@pixi/graphics-extras
) optionally includes the following complex primitives:
- 环面
- 倒角矩形
- 圆角矩形
- 正多边形
- 星星
- 圆角多边形
几何列表
每个 Graphics 对象内部都有一个 GraphicsGeometry 对象。 GraphicsGeometry 类管理 Graphics 父对象创建的几何图元列表。 大多数情况下,你不会直接使用该对象。 拥有它的 Graphics 对象创建并管理它。 但是,有两种相关的情况需要你使用该列表。
英:Inside every Graphics object is a GraphicsGeometry object. The GraphicsGeometry class manages the list of geometry primitives created by the Graphics parent object. For the most part, you will not work directly with this object. The owning Graphics object creates and manages it. However, there are two related cases where you do work with the list.
首先,你可以在另一个 Graphics 对象中重复使用一个 Graphics 对象中的几何图形。 无论你是一遍又一遍地重新绘制相同的形状,还是一遍又一遍地将其重新用作遮罩,共享相同的 GraphicsGeometry 会更有效。 你可以这样做:
英:First, you can re-use geometry from one Graphics object in another. No matter whether you're re-drawing the same shape over and over, or re-using it as a mask over and over, it's more efficient to share identical GraphicsGeometry. You can do this like so:
// Create a master graphics object
let template = new PIXI.Graphics();
// Add a circle
template.drawCircle(100, 100, 50);
// Create 5 duplicate objects
for (let i = 0; i < 5; i++) {
// Initialize the duplicate using our template's pre-built geometry
let duplicate = new PIXI.Graphics(template.geometry);
}
这导致你第二次需要了解底层的 GraphicsGeometry 对象 - 避免内存泄漏。 由于 Graphics 对象可以共享几何图形,因此当不再需要它们时必须调用 destroy()
。 如果不这样做,将阻止其拥有的 GraphicsGeometry 对象被正确取消引用,并会导致内存泄漏。
英:This leads to the second time you need to be aware of the underlying GraphicsGeometry object - avoiding memory leaks. Because Graphics objects can share geometry, you must call destroy()
when you no longer need them. Failure to do so will prevent the GraphicsGeometry object it owns from being properly de-referenced, and will lead to memory leaks.
显示图形
好的,现在我们已经介绍了 PIXI.Graphics 类的工作原理,接下来让我们看看如何使用它。 Graphics 对象最明显的用途是将动态生成的形状绘制到屏幕上。
英:OK, so now that we've covered how the PIXI.Graphics class works, let's look at how you use it. The most obvious use of a Graphics object is to draw dynamically generated shapes to the screen.
这样做很简单。 创建对象,调用各种构建器函数来添加自定义基元,然后将对象添加到场景图中。 每个帧,渲染器都会出现,要求 Graphics 对象渲染自身,并且每个图元以及关联的线条和填充样式将被绘制到屏幕上。
英:Doing so is simple. Create the object, call the various builder functions to add your custom primitives, then add the object to the scene graph. Each frame, the renderer will come along, ask the Graphics object to render itself, and each primitive, with associated line and fill styles, will be drawn to the screen.
图形作为蒙版
你还可以使用 Graphics 对象作为复杂蒙版。 为此,请照常构建对象和基元。 接下来创建一个将包含屏蔽内容的 PIXI.Container 对象,并将其 mask
属性设置为 Graphics 对象。 现在,容器的子项将被剪裁为仅在你创建的几何体内部显示。 该技术适用于 WebGL 和基于 Canvas 的渲染。
英:You can also use a Graphics object as a complex mask. To do so, build your object and primitives as usual. Next create a PIXI.Container object that will contain the masked content, and set its mask
property to your Graphics object. The children of the container will now be clipped to only show through inside the geometry you've created. This technique works for both WebGL and Canvas-based rendering.
看看 屏蔽示例代码。
英:Check out the masking example code.
注意事项和陷阱
Graphics 类是一个复杂的野兽,因此在使用它时需要注意很多事情。
英:The Graphics class is a complex beast, and so there are a number of things to be aware of when using it.
内存泄漏: 第一个已经提到过 - 在不再需要的任何 Graphics 对象上调用 destroy()
以避免内存泄漏。
英:Memory Leaks: The first has already been mentioned - call destroy()
on any Graphics object you no longer need to avoid memory leaks.
洞: 你创建的孔必须完全包含在形状中,否则可能无法正确进行三角测量。
英:Holes: Holes you create have to be completely contained in the shape or else it may not be able to triangulate correctly.
改变几何形状: 如果要更改 Graphics 对象的形状,则无需删除并重新创建它。 相反,你可以使用 clear()
函数重置几何列表的内容,然后根据需要添加新的图元。 每帧执行此操作时请注意性能。
英:Changing Geometry: If you want to change the shape of a Graphics object, you don't need to delete and recreate it. Instead you can use the clear()
function to reset the contents of the geometry list, then add new primitives as desired. Be careful of performance when doing this every frame.
性能: 图形对象通常具有相当高的性能。 但是,如果你构建高度复杂的几何体,则可能会超过渲染期间允许批处理的阈值,这可能会对性能产生负面影响。 对于批处理来说,最好使用多个 Graphics 对象,而不是使用具有多个形状的单个 Graphics。
英:Performance: Graphics objects are generally quite performant. However, if you build highly complex geometry, you may pass the threshold that permits batching during rendering, which can negatively impact performance. It's better for batching to use many Graphics objects instead of a single Graphics with many shapes.
透明度: 由于 Graphics 对象按顺序渲染其基元,因此在使用混合模式或具有重叠几何体的部分透明度时要小心。 诸如 ADD
和 MULTIPLY
之类的混合模式将适用于每个图元,而不是最终的合成图片。 同样,部分透明的 Graphics 对象将显示图元重叠。 要将透明度或混合模式应用到单个展平表面,请考虑使用 AlphaFilter 或 RenderTexture。
英:Transparency: Because the Graphics object renders its primitives sequentially, be careful when using blend modes or partial transparency with overlapping geometry. Blend modes like ADD
and MULTIPLY
will work on each primitive, not on the final composite image. Similarly, partially transparent Graphics objects will show primitives overlapping. To apply transparency or blend modes to a single flattened surface, consider using AlphaFilter or RenderTexture.