This commit is contained in:
yinsx
2026-02-03 14:16:42 +08:00
parent f98ff21394
commit c10cfa7c33
12 changed files with 603 additions and 283 deletions

View File

@ -24,11 +24,7 @@ class BlendShapeAnimator {
this.deltaThreshold = typeof config.deltaThreshold === 'number'
? config.deltaThreshold
: 0.002; // Skip re-applying nearly identical values
this.prewarmFrameCount = typeof config.prewarmFrameCount === 'number'
? config.prewarmFrameCount
: 30;
this.lastFrameBlendShapes = {};
this._hasPrewarmed = false;
// 空闲动画参数
this.blinkParams = config.blinkParams || {
@ -97,7 +93,6 @@ class BlendShapeAnimator {
this.animationFrames = frames || [];
this.animationShapeNames = this._collectAnimationShapeNames(this.animationFrames);
this.lastFrameBlendShapes = {};
// 不重置 _hasPrewarmed因为全局预热只需要做一次
}
appendAnimationFrames(frames) {
@ -107,7 +102,6 @@ class BlendShapeAnimator {
this.animationFrames.push(...frames);
const newNames = this._collectAnimationShapeNames(frames);
// 不重置 _hasPrewarmed
if (newNames.length === 0) {
return;
@ -227,49 +221,6 @@ class BlendShapeAnimator {
this.lastFrameBlendShapes = {};
}
_prewarmAnimation() {
// 同步预热已移除,改用异步预热
this._hasPrewarmed = true;
}
// 异步分帧预热 - 预热所有 morph targets确保 GPU 真正渲染
async prewarmAsync(scene) {
if (!this.morphTargetAdapter) {
return;
}
// 获取所有可用的 morph targets而不只是当前动画用到的
const allShapes = this.morphTargetAdapter.morphTargetCache
? Object.keys(this.morphTargetAdapter.morphTargetCache)
: this.animationShapeNames;
const shapes = allShapes.filter(
name => !this.disabledShapesInAnimation.includes(name.toLowerCase())
);
if (shapes.length === 0) return;
console.log(`异步预热 ${shapes.length} 个 morph targets...`);
// 用不同的值组合预热,触发所有可能的 shader 变体
const testValues = [0.2, 0.5, 0.8, 1.0];
for (const val of testValues) {
shapes.forEach(name => this.morphTargetAdapter.setInfluence(name, val));
if (scene) scene.render();
await new Promise(r => requestAnimationFrame(r));
}
// 重置并等待几帧确保稳定
shapes.forEach(name => this.morphTargetAdapter.setInfluence(name, 0));
for (let i = 0; i < 5; i++) {
if (scene) scene.render();
await new Promise(r => requestAnimationFrame(r));
}
this._hasPrewarmed = true;
console.log('异步预热完成');
}
_primeFirstFrame() {
if (!this.morphTargetAdapter || this.animationFrames.length === 0) {
return;
@ -297,24 +248,6 @@ class BlendShapeAnimator {
}
}
_touchAnimationShapes() {
if (!this.morphTargetAdapter || !Array.isArray(this.animationShapeNames) || this.animationShapeNames.length === 0) {
return;
}
const touchValue = Math.max(this.minBlendShapeValue * 1.2, 0.05);
const touched = [];
this.animationShapeNames.forEach(name => {
this.morphTargetAdapter.setInfluence(name, touchValue);
touched.push(name);
});
touched.forEach(name => {
this.morphTargetAdapter.setInfluence(name, 0);
});
}
_scheduleAnimationStart() {
// 只设置开始时间,动画由统一的 RAF 循环驱动
this.animationStartTime = performance.now();