首次播放不掉帧

This commit is contained in:
yinsx
2026-01-04 14:06:14 +08:00
parent 2bd183463d
commit f98ff21394
7 changed files with 4856 additions and 33 deletions

View File

@ -54,36 +54,13 @@ function init() {
} else {
console.log(`✓ 构建缓存完成,共 ${totalTargets} 个形态键`);
// 预热:直接调用生成动画流程(和用户点击按钮完全一样)
// 预热:使用写死的预热数据,不请求接口
showStatus("预热中...", "info");
const apiUrl = document.getElementById('apiUrl').value;
const streamEnabled = document.getElementById('streamEnabled')?.checked;
console.log('预热 apiUrl:', apiUrl, 'stream:', streamEnabled);
if (apiUrl) {
try {
// 和 generateAnimation 走完全一样的路径
if (streamEnabled) {
await generateAnimationStream('你好', apiUrl);
} else {
await generateAnimationBatch('你好', apiUrl);
playAnimation();
}
// 等播放完
await new Promise(resolve => {
const check = () => animator.isPlaying ? requestAnimationFrame(check) : resolve();
check();
});
// 完全重置状态
animator.stopAnimation();
animator.loadAnimationFrames([]);
animator.endStreaming();
morphAdapter.resetAll();
console.log('✓ 预热完成');
} catch (e) {
console.warn('预热失败:', e);
}
} else {
console.warn('预热跳过: apiUrl 为空');
try {
await warmupWithLocalData();
console.log('✓ 预热完成');
} catch (e) {
console.warn('预热失败:', e);
}
showStatus("就绪", "success");
@ -95,6 +72,47 @@ function init() {
);
}
// 使用本地预热数据进行预热(不请求接口)
async function warmupWithLocalData() {
console.log('=== warmupWithLocalData 开始 ===');
// 加载预热数据
const response = await fetch('预热数据.json');
const frames = await response.json();
console.log(`加载预热数据: ${frames.length}`);
// 保存原始播放速度设置预热倍速4倍速快速预热
const originalSpeed = animator.playbackSpeed;
animator.playbackSpeed = 4.0;
console.log(`预热倍速: ${animator.playbackSpeed}x`);
// 加载并播放
animator.loadAnimationFrames(frames);
animator.playAnimation();
// 等待播放完成
await new Promise(resolve => {
const checkDone = () => {
if (!animator.isPlaying) {
resolve();
} else {
requestAnimationFrame(checkDone);
}
};
requestAnimationFrame(checkDone);
});
// 重置状态
animator.stopAnimation();
animator.loadAnimationFrames([]);
morphAdapter.resetAll();
// 恢复原始播放速度
animator.playbackSpeed = originalSpeed;
console.log('✓ 本地数据预热完成');
}
// 偷偷调接口预热 - 完全走一遍生成动画流程
async function warmupWithApi() {
console.log('=== warmupWithApi 开始 ===');
@ -133,7 +151,7 @@ async function warmupWithApi() {
}
}
async function generateAnimation() {
async function generateAnimation() {
const text = document.getElementById('textInput').value.trim();
const apiUrl = document.getElementById('apiUrl').value;
const btn = document.getElementById('generateBtn');
@ -176,6 +194,19 @@ async function generateAnimationBatch(text, apiUrl) {
animator.loadAnimationFrames(data.frames);
console.log("动画数据:", data.frames);
// 打印可复制的 JSON 格式过滤掉值为0的字段
const filteredFrames = data.frames.map(frame => {
const filtered = { timeCode: frame.timeCode, blendShapes: {} };
for (const [key, value] of Object.entries(frame.blendShapes)) {
if (value !== 0) {
filtered.blendShapes[key] = value;
}
}
return filtered;
});
console.log("========== 复制以下内容作为预热数据 ==========");
console.log(JSON.stringify(filteredFrames));
console.log("========== 复制结束 ==========");
showStatus(`动画生成成功!共 ${data.frames.length}`, "success");
}
@ -355,6 +386,11 @@ function updateFps(value) {
document.getElementById('fpsValue').textContent = value;
}
function updatePlaybackSpeed(value) {
animator.updateConfig('playbackSpeed', parseFloat(value));
document.getElementById('speedValue').textContent = value + 'x';
}
function testBlendShape() {
if (morphAdapter.getCacheSize() === 0) {
showStatus("模型未加载", "error");