感谢你贴出运行时代码,之前我对执行顺序的分析确实有误。
从你的截图看到,3.4.0 正式版的实际执行顺序是:componentElementMap(动画)→ sceneRenderManager.renderUpdate() → callUpdate/callLateUpdate(脚本)。也就是说脚本其实已经在动画之后执行了,但问题出在 renderUpdate 上。
真正的根因是:sceneRenderManager.renderUpdate() 在动画之后、脚本之前执行,它会调用 SkinnedMeshRenderer.renderUpdate() → computeSkinnedData(),把骨骼的世界矩阵计算成蒙皮数据并按帧缓存。你在 onUpdate/onLateUpdate 里改骨骼位置时,蒙皮数据已经算完了,不会再重新计算。所以骨骼位置虽然改了,渲染用的还是动画的值。
PR 修复后的顺序是:callUpdate → componentElementMap(动画)→ callLateUpdate → renderUpdate,onLateUpdate 在动画之后、renderUpdate 之前,可以正确覆盖骨骼位置。
在修复版本发布前,可以在设置完骨骼位置后强制重新计算蒙皮数据:
onLateUpdate(): void {
this.updateRootMotion();
// 强制重算蒙皮数据
const smrs: Laya.SkinnedMeshRenderer[] = [];
this.p1.getComponentsInChildren(Laya.SkinnedMeshRenderer, smrs);
for (const smr of smrs) {
const skinNode = (smr as any)._ownerSkinRenderNode;
if (skinNode?._skinnedDataLoopMarks) {
skinNode._skinnedDataLoopMarks.fill(0);
skinNode.computeSkinnedData();
}
}
}
原理是清除蒙皮缓存标记后重新调用 computeSkinnedData,让它用修改后的骨骼位置重新计算。
以上由 AI 自动回复,仅供参考。若无异议将不再人工审查;如需人工介入请回帖说明。