Skip to content

Commit a368029

Browse files
wehosHongzhi Wenclaude
authored
feat(render): 帧率设置新增无限制(VSync)档位 (#581)
* feat(render): 帧率设置新增无限制(VSync)档位 在原有 30/45/60fps 三档基础上增加第四档「无限制(VSync)」, 去除人为帧率限制,让渲染跟随显示器垂直同步刷新率。 默认仍保持 60fps 以保护低端设备。 - Live2D: PIXI ticker maxFPS=0 即不限帧 - VRM: targetFrameRate=0 时跳过手动跳帧逻辑 - 修复 targetFrameRate=0 时 falsy 判断导致设置被跳过的问题 - 六语言 i18n 全覆盖 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(render): 修复帧率设置为 0/undefined 时的边界情况 - VRM: targetFrameRate 未定义时回退到 60fps,避免未加载设置时跑满刷新率 - Live2D: 事件监听改用 != null 判断,允许 fps=0 正确传递到 setTargetFPS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Hongzhi Wen <cartabio.coder1@gmail.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d75ab08 commit a368029

10 files changed

Lines changed: 23 additions & 15 deletions

File tree

static/app-settings.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@
309309
// 画质设置
310310
S.renderQuality = settings.renderQuality ?? 'medium';
311311
window.cursorFollowPerformanceLevel = U.mapRenderQualityToFollowPerf(S.renderQuality);
312-
// 帧率设置
312+
// 帧率设置(0 = 不限帧 / VSync)
313313
S.targetFrameRate = settings.targetFrameRate ?? 60;
314314
// 鼠标跟踪设置(严格转换为布尔值)
315315
if (typeof settings.mouseTrackingEnabled === 'boolean') {

static/avatar-ui-popup.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -774,15 +774,15 @@ function createAnimationSettingsSidePanel(manager, prefix) {
774774
const fpsSlider = document.createElement('input');
775775
fpsSlider.type = 'range';
776776
fpsSlider.min = '0';
777-
fpsSlider.max = '2';
777+
fpsSlider.max = '3';
778778
fpsSlider.step = '1';
779-
const fpsValues = [30, 45, 60];
780-
const curFps = window.targetFrameRate || 60;
781-
fpsSlider.value = curFps >= 60 ? '2' : curFps >= 45 ? '1' : '0';
779+
const fpsValues = [30, 45, 60, 0];
780+
const curFps = typeof window.targetFrameRate === 'number' ? window.targetFrameRate : 60;
781+
fpsSlider.value = curFps === 0 ? '3' : curFps >= 60 ? '2' : curFps >= 45 ? '1' : '0';
782782
Object.assign(fpsSlider.style, SLIDER_STYLE);
783783

784-
const fpsLabelKeys = ['settings.toggles.frameRateLow', 'settings.toggles.frameRateMedium', 'settings.toggles.frameRateHigh'];
785-
const fpsDefaults = ['30fps', '45fps', '60fps'];
784+
const fpsLabelKeys = ['settings.toggles.frameRateLow', 'settings.toggles.frameRateMedium', 'settings.toggles.frameRateHigh', 'settings.toggles.frameRateUnlimited'];
785+
const fpsDefaults = ['30fps', '45fps', '60fps', 'VSync'];
786786
const fpsValue = document.createElement('span');
787787
const curFIdx = parseInt(fpsSlider.value, 10);
788788
fpsValue.textContent = window.t ? window.t(fpsLabelKeys[curFIdx]) : fpsDefaults[curFIdx];

static/live2d-core.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ class Live2DManager {
232232

233233
this.isInitialized = true;
234234
this._lastPIXIContext = { canvasId, containerId };
235-
if (window.targetFrameRate && this.pixi_app.ticker) {
235+
if (typeof window.targetFrameRate === 'number' && this.pixi_app.ticker) {
236236
this.pixi_app.ticker.maxFPS = window.targetFrameRate;
237237
}
238238

@@ -362,12 +362,12 @@ class Live2DManager {
362362

363363
/**
364364
* 设置目标帧率
365-
* @param {number} fps - 目标帧率(30 或 60
365+
* @param {number} fps - 目标帧率,0 表示不限帧(跟随 VSync
366366
*/
367367
setTargetFPS(fps) {
368368
if (this.pixi_app && this.pixi_app.ticker) {
369369
this.pixi_app.ticker.maxFPS = fps;
370-
console.log(`[Live2D Core] 目标帧率设置为 ${fps}fps`);
370+
console.log(`[Live2D Core] 目标帧率设置为 ${fps === 0 ? 'VSync (无限制)' : fps + 'fps'}`);
371371
}
372372
}
373373

@@ -768,7 +768,7 @@ window.isMobileWidth = isMobileWidth;
768768
// 监听帧率变更事件
769769
window.addEventListener('neko-frame-rate-changed', (e) => {
770770
const fps = e.detail?.fps;
771-
if (fps && window.live2dManager) {
771+
if (fps != null && window.live2dManager) {
772772
window.live2dManager.setTargetFPS(fps);
773773
}
774774
});

static/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@
15201520
"frameRateLow": "30fps",
15211521
"frameRateMedium": "45fps",
15221522
"frameRateHigh": "60fps",
1523+
"frameRateUnlimited": "Unlimited(VSync)",
15231524
"mouseTracking": "Mouse Tracking",
15241525
"fullscreenTracking": "Fullscreen Tracking",
15251526
"localTracking": "Local Tracking"

static/locales/ja.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@
15201520
"frameRateLow": "30fps",
15211521
"frameRateMedium": "45fps",
15221522
"frameRateHigh": "60fps",
1523+
"frameRateUnlimited": "無制限(VSync)",
15231524
"mouseTracking": "マウス追跡",
15241525
"fullscreenTracking": "フルスクリーン追跡",
15251526
"localTracking": "ローカル追跡"

static/locales/ko.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@
15201520
"frameRateLow": "30fps",
15211521
"frameRateMedium": "45fps",
15221522
"frameRateHigh": "60fps",
1523+
"frameRateUnlimited": "무제한(VSync)",
15231524
"mouseTracking": "마우스 추적",
15241525
"fullscreenTracking": "전체 화면 추적",
15251526
"localTracking": "로컬 추적"

static/locales/ru.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1516,6 +1516,7 @@
15161516
"frameRateHigh": "60fps",
15171517
"frameRateLow": "30fps",
15181518
"frameRateMedium": "45fps",
1519+
"frameRateUnlimited": "Без ограничений(VSync)",
15191520
"renderQuality": "Качество рендеринга",
15201521
"renderQualityHigh": "Высокое",
15211522
"renderQualityLow": "Низкое",

static/locales/zh-CN.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@
15201520
"frameRateLow": "30fps",
15211521
"frameRateMedium": "45fps",
15221522
"frameRateHigh": "60fps",
1523+
"frameRateUnlimited": "无限制(VSync)",
15231524
"mouseTracking": "跟踪鼠标",
15241525
"fullscreenTracking": "全屏跟踪",
15251526
"localTracking": "局部跟踪"

static/locales/zh-TW.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,6 +1520,7 @@
15201520
"frameRateLow": "30fps",
15211521
"frameRateMedium": "45fps",
15221522
"frameRateHigh": "60fps",
1523+
"frameRateUnlimited": "無限制(VSync)",
15231524
"mouseTracking": "跟蹤滑鼠",
15241525
"fullscreenTracking": "全屏跟蹤",
15251526
"localTracking": "局部跟蹤"

static/vrm-manager.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -627,11 +627,13 @@ class VRMManager {
627627

628628
this._animationFrameId = requestAnimationFrame(animateLoop);
629629

630-
// 帧率限制:根据 targetFrameRate 跳帧
630+
// 帧率限制:根据 targetFrameRate 跳帧(0 = 不限帧,跟随 VSync)
631631
const now = performance.now();
632-
const targetFps = window.targetFrameRate || 60;
633-
const frameInterval = 1000 / targetFps;
634-
if (now - this._lastRenderTime < frameInterval * 0.9) return;
632+
const targetFps = typeof window.targetFrameRate === 'number' ? window.targetFrameRate : 60;
633+
if (targetFps > 0) {
634+
const frameInterval = 1000 / targetFps;
635+
if (now - this._lastRenderTime < frameInterval * 0.9) return;
636+
}
635637
this._lastRenderTime = now;
636638

637639
// 获取时间增量并限制最大值,防止切屏或卡顿导致物理"爆炸"

0 commit comments

Comments
 (0)