// Babylon.js 形态键适配器 class BabylonMorphTargetAdapter { constructor() { this.morphTargetCache = {}; } buildCache(meshes) { this.morphTargetCache = {}; this.meshes = meshes; let totalTargets = 0; meshes.forEach(mesh => { const mtm = mesh.morphTargetManager; if (!mtm) return; for (let i = 0; i < mtm.numTargets; i++) { const mt = mtm.getTarget(i); if (!mt?.name) continue; const lowerName = mt.name.toLowerCase(); if (!this.morphTargetCache[lowerName]) { this.morphTargetCache[lowerName] = []; } this.morphTargetCache[lowerName].push(mt); totalTargets++; } }); return totalTargets; } async warmupInvisible(scene) { console.log('开始预热...'); const startTime = performance.now(); const allTargets = Object.values(this.morphTargetCache).flat(); const totalTargets = allTargets.length; console.log(`预热 ${totalTargets} 个 morph targets`); // 多轮预热,用不同值组合 const rounds = 10; for (let r = 0; r < rounds; r++) { const val = (r % 2 === 0) ? 1.0 : 0; allTargets.forEach(mt => mt.influence = val); scene.render(); await new Promise(r => requestAnimationFrame(r)); } // 重置 allTargets.forEach(mt => mt.influence = 0); scene.render(); // 等待几帧让 GPU 完全稳定 for (let i = 0; i < 5; i++) { await new Promise(r => requestAnimationFrame(r)); } console.log(`预热完成,耗时 ${(performance.now() - startTime).toFixed(2)}ms`); } warmupShaders(scene) { console.log('开始shader预热...'); const startTime = performance.now(); // 强制同步更新所有 morph target managers this.meshes?.forEach(mesh => { const mtm = mesh.morphTargetManager; if (mtm) { mtm.enableNormalMorphing = true; mtm.enableTangentMorphing = true; } }); // 预热:强制触发着色器编译 // 使用多种值组合来触发所有可能的shader变体 const testValues = [0, 0.2, 0.4, 0.6, 0.8, 1.0]; for (let pass = 0; pass < testValues.length; pass++) { const value = testValues[pass]; for (const targets of Object.values(this.morphTargetCache)) { targets.forEach(mt => { mt.influence = value; }); } // 每次设置后都渲染,确保shader编译 if (scene) { scene.render(); } } // 重置所有影响值 for (const targets of Object.values(this.morphTargetCache)) { targets.forEach(mt => { mt.influence = 0; }); } // 最后渲染一次确保重置生效 if (scene) { scene.render(); } const elapsed = performance.now() - startTime; console.log(`shader预热完成,耗时 ${elapsed.toFixed(2)}ms`); } setInfluence(name, value) { const lowerName = name.toLowerCase(); const targets = this.morphTargetCache[lowerName]; if (targets?.length) { targets.forEach(mt => { mt.influence = value; }); } } getInfluence(name) { const lowerName = name.toLowerCase(); const targets = this.morphTargetCache[lowerName]; if (targets?.length) { return targets[0].influence; } return 0; } resetAll() { for (const targets of Object.values(this.morphTargetCache)) { targets.forEach(mt => { mt.influence = 0; }); } } getCacheSize() { return Object.keys(this.morphTargetCache).length; } } // 导出到全局 if (typeof window !== 'undefined') { window.BabylonMorphTargetAdapter = BabylonMorphTargetAdapter; }