PixiJS

Mon, 04 Mar 2024 07:34:50 GMT

Properties
Name Value
Identifier pixi-js
Name PixiJS
Type Topic
Creation timestamp Mon, 04 Mar 2024 07:34:50 GMT
Modification timestamp Mon, 04 Mar 2024 13:41:38 GMT


Architecture

PixiJS is a modular rendering engine. Each task required for generating, updating and displaying content is broken out into its own component.

Components

Assets

Pending

Containers

The Container class provides a simple display object that does what its name implies - collect a set of child objects together.

Containers as Groups Almost every type of display object is also derived from Container - even Sprites! This means that in many cases you can create a parent-child hierarchy with the objects you want to render.

However, it's a good idea not to do this. Standalone container objects are very cheap to render, and having a proper hierarchy of container objects, each containing one or more renderable objects, provides flexibility in rendering order.

So that's the primary use for containers - as groups of renderable objects in a hierarchy.

Masking Pending

Filtering Pending

Display Objects

Pending

Graphics

Pending

Interaction

Pending

Sprites

Pending

Spritesheets

Pending

Text

Pending

Textures

Pending

Render Loop

Unlike a web page, PixiJS is constantly updating and re-drawing itself, over and over. You update your objects, then PixiJS renders them to the screen, then the process repeats. We call this cycle the render loop.

The majority of any PixiJS project is contained in this update + render cycle. You code the updates, PixiJS handles the rendering.

Running Ticker Callbacks

The first step is to calculate how much time has elapsed since the last frame, and then call the Application object's ticker callbacks with that time delta. This allows your project's code to animate and update the sprites, etc. on the stage in preparation for rendering.

Updating the Scene Graph

The scene graph contains the things you're drawing - sprites, text, etc. - and that these objects are in a tree-like hierarchy. After you've updated your game objects by moving, rotating and so forth, PixiJS needs to calculate the new positions and state of every object in the scene, before it can start drawing.

Rendering the Scene Graph

Now that our game's state has been updated, it's time to draw it to the screen. The rendering system starts with the root of the scene graph (app.stage), and starts rendering each object and its children, until all objects have been drawn.

Scene Graph

Every frame, PixiJS is updating and then rendering the scene graph.

The Scene Graph Is a Tree

The scene graph's root node is a container maintained by the application, and referenced with app.stage. When you add a sprite or other renderable object as a child to the stage, it's added to the scene graph and will be rendered and interactable. Most PixiJS objects can also have children, and so as you build more complex scenes, you will end up with a tree of parent-child relationships, rooted at the app's stage.

Parents and Children

When a parent moves, its children move as well. When a parent is rotated, its children are rotated too. Hide a parent, and the children will also be hidden. If you have a game object that's made up of multiple sprites, you can collect them under a container to treat them as a single object in the world, moving and rotating as one.

Each frame, PixiJS runs through the scene graph from the root down through all the children to the leaves to calculate each object's final position, rotation, visibility, transparency, etc. If a parent's alpha is set to 0.5 (making it 50% transparent), all its children will start at 50% transparent as well. If a child is then set to 0.5 alpha, it won't be 50% transparent, it will be 0.5 x 0.5 = 0.25 alpha, or 75% transparent. Similarly, an object's position is relative to its parent, so if a parent is set to an x position of 50 pixels, and the child is set to an x position of 100 pixels, it will be drawn at a screen offset of 150 pixels, or 50 + 100.

The cumulative translation, rotation, scale and skew of any given node in the scene graph is stored in the object's worldTransform property. Similarly, the cumulative alpha value is stored in the worldAlpha property.

Render Order

PixiJS renders the tree from the root down. At each level, the current object is rendered, then each child is rendered in order of insertion. So the second child is rendered on top of the first child, and the third over the second.

If you'd like to re-order a child object, you can use setChildIndex(). To add a child at a given point in a parent's list, use addChildAt(). Finally, you can enable automatic sorting of an object's children using the sortableChildren option combined with setting the zIndex property on each child.

Culling

If you're building a project where a large proportion of your DisplayObject's are off-screen (say, a side-scrolling game), you will want to cull those objects. Culling is the process of evaluating if an object (or its children!) is on the screen, and if not, turning off rendering for it. If you don't cull off-screen objects, the renderer will still draw them, even though none of their pixels end up on the screen.

PixiJS doesn't provide built-in support for viewport culling, but you can find 3rd party plugins that might fit your needs. Alternately, if you'd like to build your own culling system, simply run your objects during each tick and set renderable to false on any object that doesn't need to be drawn.

Local vs Global Coordinates

If you add a sprite to the stage, by default it will show up in the top left corner of the screen. That's the origin of the global coordinate space used by PixiJS. If all your objects were children of the stage, that's the only coordinates you'd need to worry about. But once you introduce containers and children, things get more complicated. A child object at [50, 100] is 50 pixels right and 100 pixels down from its parent.

We call these two coordinate systems "global" and "local" coordinates. When you use position.set(x, y) on an object, you're always working in local coordinates, relative to the object's parent.

The problem is, there are many times when you want to know the global position of an object. For example, if you want to cull offscreen objects to save render time, you need to know if a given child is outside the view rectangle.

To convert from local to global coordinates, you use the toGlobal() function. Here's a sample usage:

// Get the global position of an object, relative to the top-left of the screen
let globalPos = obj.toGlobal(new PIXI.Point(0,0));

This snippet will set globalPos to be the global coordinates for the child object, relative to [0, 0] in the global coordinate system.

Global vs Screen Coordinates

When your project is working with the host operating system or browser, there is a third coordinate system that comes into play - "screen" coordinates (aka "viewport" coordinates). Screen coordinates represent position relative to the top-left of the canvas element that PixiJS is rendering into. Things like the DOM and native mouse click events work in screen space.

Now, in many cases, screen space is equivalent to world space. This is the case if the size of the canvas is the same as the size of the render view specified when you create you PIXI.Application. By default, this will be the case - you'll create for example an 800x600 application window and add it to your HTML page, and it will stay that size. 100 pixels in world coordinates will equal 100 pixels in screen space. BUT! It is common to stretch the rendered view to have it fill the screen, or to render at a lower resolution and up-scale for speed. In that case, the screen size of the canvas element will change (e.g. via CSS), but the underlying render view will not, resulting in a mis-match between world coordinates and screen coordinates.

Back to top