渲染循环
¥Render Loop
PixiJS 的核心在于其渲染循环,这是一个重复的循环,它会每帧更新并重新绘制场景。与基于事件(例如基于用户输入)渲染的传统 Web 开发不同,PixiJS 使用连续动画循环,可以完全控制实时渲染。
¥At the core of PixiJS lies its render loop, a repeating cycle that updates and redraws your scene every frame. Unlike traditional web development where rendering is event-based (e.g. on user input), PixiJS uses a continuous animation loop that provides full control over real-time rendering.
本指南深入探讨了 PixiJS 如何构建这个内部循环,从帧开始到渲染到屏幕。理解这一点将有助于你编写性能更佳、结构更合理的应用。
¥This guide provides a deep dive into how PixiJS structures this loop internally, from the moment a frame begins to when it is rendered to the screen. Understanding this will help you write more performant, well-structured applications.
概述
¥Overview
PixiJS 每帧都会执行以下顺序:
¥Each frame, PixiJS performs the following sequence:
-
代码执行(用户逻辑)
¥Tickers are executed (user logic)
-
场景图已更新(变换和剔除)
¥Scene graph is updated (transforms and culling)
-
渲染发生(GPU 绘制调用)
¥Rendering occurs (GPU draw calls)
只要你的应用正在运行且其代码块处于活动状态,此循环就会重复。
¥This cycle repeats as long as your application is running and its ticker is active.
步骤 1:运行股票代码回调
¥Step 1: Running Ticker Callbacks
渲染循环由 Ticker
类驱动,该类使用 requestAnimationFrame
来调度工作。每次 tick:
¥The render loop is driven by the Ticker
class, which uses requestAnimationFrame
to schedule work. Each tick:
-
测量自上一帧以来经过的时间
¥Measures elapsed time since the previous frame
-
基于
minFPS
和maxFPS
进行限制¥Caps it based on
minFPS
andmaxFPS
-
调用每个在
ticker.add()
或app.ticker.add()
中注册的监听器¥Calls every listener registered with
ticker.add()
orapp.ticker.add()
示例
¥Example
app.ticker.add((ticker) => {
bunny.rotation += ticker.deltaTime * 0.1;
});
每个回调都会接收当前的 Ticker
实例。你可以访问 ticker.deltaTime
(缩放的帧增量)和 ticker.elapsedMS
(未缩放的增量,以毫秒为单位)来控制动画的时间。
¥Every callback receives the current Ticker
instance. You can access ticker.deltaTime
(scaled frame delta) and ticker.elapsedMS
(unscaled delta in ms) to time animations.
步骤 2:更新场景图
¥Step 2: Updating the Scene Graph
PixiJS 使用分层场景图来表示所有可视对象。渲染前,需要遍历图形:
¥PixiJS uses a hierarchical scene graph to represent all visual objects. Before rendering, the graph needs to be traversed to:
-
重新计算变换(世界矩阵更新)
¥Recalculate transforms (world matrix updates)
-
通过
onRender
处理程序应用自定义逻辑¥Apply custom logic via
onRender
handlers -
如果启用,则应用剔除
¥Apply culling if enabled
步骤 3:渲染场景
¥Step 3: Rendering the Scene
场景图准备就绪后,渲染器将从 app.stage
开始遍历显示列表:
¥Once the scene graph is ready, the renderer walks the display list starting at app.stage
:
-
应用全局和局部变换
¥Applies global and local transformations
-
尽可能批量绘制调用
¥Batches draw calls when possible
-
上传几何体、纹理和 uniform
¥Uploads geometry, textures, and uniforms
-
发出 GPU 命令
¥Issues GPU commands
所有渲染均采用保留模式:除非明确移除,否则对象会跨帧保留。
¥All rendering is retained mode: objects persist across frames unless explicitly removed.
渲染通过 WebGL 或 WebGPU 完成,具体取决于你的环境。渲染器将差异抽象到通用 API 背后。
¥Rendering is done via either WebGL or WebGPU, depending on your environment. The renderer abstracts away the differences behind a common API.
完整帧生命周期图
¥Full Frame Lifecycle Diagram
requestAnimationFrame
│
[Ticker._tick()]
│
├─ Compute elapsed time
├─ Call user listeners
│ └─ sprite.onRender
├─ Cull display objects (if enabled)
├─ Update world transforms
└─ Render stage
├─ Traverse display list
├─ Upload data to GPU
└─ Draw