Files
a2f-service/examples/3d/babylonAdapter.js
2025-12-29 11:22:51 +08:00

110 lines
2.9 KiB
JavaScript

// 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;
}
warmupShaders(scene) {
console.log('开始shader预热...');
const startTime = performance.now();
// 预热:强制触发着色器编译
// 使用多种值组合来触发所有可能的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;
}