Skip to main content

渲染循环

🌐 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:

  1. Ticker 已执行(用户逻辑)
  2. 场景图已更新(变换和剔除)
  3. 渲染发生(GPU 绘制调用)

只要你的应用正在运行且其代码块处于活动状态,此循环就会重复。

🌐 This cycle repeats as long as your application is running and its ticker is active.

步骤 1:运行 Ticker 回调

🌐 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:

  • 测量自上一帧以来经过的时间
  • 基于 minFPSmaxFPS 设置上限
  • 调用注册到 ticker.add()app.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:

  • 重新计算变换(世界矩阵更新)
  • 通过 onRender 处理程序应用自定义逻辑
  • 如果启用,则应用剔除

第3步:渲染场景

🌐 Step 3: Rendering the Scene

一旦场景图准备好,渲染器就从 app.stage 开始遍历显示列表:

🌐 Once the scene graph is ready, the renderer walks the display list starting at app.stage:

  1. 应用全局和局部变换
  2. 尽可能批量绘制调用
  3. 上传几何体、纹理和 uniform
  4. 发送 GPU 命令

所有渲染都是保留模式:对象会跨帧保持,除非被明确移除。

🌐 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