描述 Bug
设置里的「最大帧率」(maxFPS)无法限制实际渲染帧率。设为 60 后,Live2D 模型仍然按显示器刷新率渲染 —— 我的屏幕是 240Hz,实测模型就是稳定跑在 240 fps,每秒约 39,600 次 WebGL 绘制调用。
在高刷屏上这意味着 GPU 负载是预期值的 4 倍,玩游戏时桌宠会跟游戏抢 GPU 提交队列。
重现步骤
-
偏好设置 → 猫咪 → 最大帧率 设为 60,重启 BongoCat,确认 cat.json 里确实是 "maxFPS": 60
-
给 WebView2 开远程调试(因为 bongo-cat.exe 被设为管理员运行,WebView2 Runtime ≥150 只认 HKLM 策略):
HKLM\Software\Policies\Microsoft\Edge\WebView2\AdditionalBrowserArguments
bongo-cat.exe = --remote-debugging-port=9222
-
通过 CDP 连到桌宠页面 http://tauri.localhost/index.html/#/,给 WebGLRenderingContext.prototype.drawElements / drawArrays 打计数补丁
-
统计「绘制批次」:每渲染一帧会连续发一串 draw call,批与批之间必有 >2ms 空隙(等下一次 rAF),批数即真实渲染帧率
实测数据
maxFPS 设为 60,连续 8 秒每秒采样一次,数值几乎没有抖动:
| 指标 |
实测值 |
| 真实渲染帧率(绘制批次/秒) |
240.0 |
| requestAnimationFrame 频率 |
240.0(= 屏幕刷新率) |
| 每次渲染的绘制调用数 |
165 |
| 每秒绘制调用数 |
约 39,600 |
| 画布尺寸 |
420×420 后备缓冲(CSS 280×280,dpr 1.5) |
| BongoCat 占 GPU 3D 引擎 |
2.44%(空闲桌面,RTX 4060 Laptop) |
把 maxFPS 设为 60 / 120 都是同样的结果,渲染帧率始终等于刷新率。
预期行为
maxFPS 设为 60 时,模型的渲染帧率应为 60,绘制调用数相应降到约 1/4。
原因分析
问题出在 Ticker.shared 和 app.ticker 不是同一个 Ticker。
src/utils/live2d.ts:
// L29-L37:创建 Application 时没有传 sharedTicker
this.app = new Application()
return this.app.init({
view,
resizeTo: window,
backgroundAlpha: 0,
autoDensity: true,
resolution: devicePixelRatio,
})
// L67:Live2DSprite 用的是共享 Ticker
this.model = new Live2DSprite({ modelSetting, ticker: Ticker.shared })
// L133-L135:但限速只设了共享 Ticker
public setMaxFPS(fps: number) {
Ticker.shared.maxFPS = fps
}
PixiJS v8 的 ApplicationOptions.sharedTicker 默认值是 false,也就是 Application 会新建一个自己的 Ticker 来驱动渲染循环,而不是用 Ticker.shared。
所以 Ticker.shared.maxFPS = fps 只能限制挂在共享 Ticker 上的回调(Live2DSprite 的 update),渲染循环跑在 app.ticker 上,完全不受限制,于是一直按 rAF 的节奏(= 屏幕刷新率)重绘。
建议修复
任选其一:
// 方案 1:让 Application 直接用共享 Ticker
return this.app.init({
view,
resizeTo: window,
backgroundAlpha: 0,
autoDensity: true,
resolution: devicePixelRatio,
sharedTicker: true,
})
// 方案 2:限速时两个 Ticker 都设
public setMaxFPS(fps: number) {
Ticker.shared.maxFPS = fps
if (this.app) this.app.ticker.maxFPS = fps
}
软件信息
{
"appName": "BongoCat",
"appVersion": "1.1.0",
"platform": "windows",
"platformArch": "x86_64",
"platformVersion": "10.0.26200",
"webview2Runtime": "153.0.4234.48",
"display": "2560x1600 @ 240Hz, HDR on",
"gpu": "NVIDIA GeForce RTX 4060 Laptop GPU"
}
对应源码为 master 分支当前状态(44f44bc,2026-04-28)。
附加信息
相关 issue:
刷新率越高的屏幕受影响越大:60Hz 屏上限速 60 看不出问题,240Hz 屏上实际负载就是设定值的 4 倍。
描述 Bug
设置里的「最大帧率」(
maxFPS)无法限制实际渲染帧率。设为 60 后,Live2D 模型仍然按显示器刷新率渲染 —— 我的屏幕是 240Hz,实测模型就是稳定跑在 240 fps,每秒约 39,600 次 WebGL 绘制调用。在高刷屏上这意味着 GPU 负载是预期值的 4 倍,玩游戏时桌宠会跟游戏抢 GPU 提交队列。
重现步骤
偏好设置 → 猫咪 → 最大帧率 设为
60,重启 BongoCat,确认cat.json里确实是"maxFPS": 60给 WebView2 开远程调试(因为
bongo-cat.exe被设为管理员运行,WebView2 Runtime ≥150 只认 HKLM 策略):通过 CDP 连到桌宠页面
http://tauri.localhost/index.html/#/,给WebGLRenderingContext.prototype.drawElements/drawArrays打计数补丁统计「绘制批次」:每渲染一帧会连续发一串 draw call,批与批之间必有 >2ms 空隙(等下一次 rAF),批数即真实渲染帧率
实测数据
maxFPS设为 60,连续 8 秒每秒采样一次,数值几乎没有抖动:把
maxFPS设为 60 / 120 都是同样的结果,渲染帧率始终等于刷新率。预期行为
maxFPS设为 60 时,模型的渲染帧率应为 60,绘制调用数相应降到约 1/4。原因分析
问题出在
Ticker.shared和app.ticker不是同一个 Ticker。src/utils/live2d.ts:PixiJS v8 的
ApplicationOptions.sharedTicker默认值是false,也就是Application会新建一个自己的 Ticker 来驱动渲染循环,而不是用Ticker.shared。所以
Ticker.shared.maxFPS = fps只能限制挂在共享 Ticker 上的回调(Live2DSprite的 update),渲染循环跑在app.ticker上,完全不受限制,于是一直按 rAF 的节奏(= 屏幕刷新率)重绘。建议修复
任选其一:
软件信息
对应源码为 master 分支当前状态(
44f44bc,2026-04-28)。附加信息
相关 issue:
maxFPS应该就是这次加的刷新率越高的屏幕受影响越大:60Hz 屏上限速 60 看不出问题,240Hz 屏上实际负载就是设定值的 4 倍。