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. 代码执行(用户逻辑)

    ¥Tickers are executed (user logic)

  2. 场景图已更新(变换和剔除)

    ¥Scene graph is updated (transforms and culling)

  3. 渲染发生(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

  • 基于 minFPSmaxFPS 进行限制

    ¥Caps it based on minFPS and maxFPS

  • 调用每个在 ticker.add()app.ticker.add() 中注册的监听器

    ¥Calls every listener registered with ticker.add() or 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:

  • 重新计算变换(世界矩阵更新)

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

  1. 应用全局和局部变换

    ¥Applies global and local transformations

  2. 尽可能批量绘制调用

    ¥Batches draw calls when possible

  3. 上传几何体、纹理和 uniform

    ¥Uploads geometry, textures, and uniforms

  4. 发出 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