3

我有一个正在播放动画的 Three.js 项目,我想在不同的时间找到骨架骨骼的位置。

例如,如果我去:https://modelviewer.dev/examples/animation/index.html 并找到 Three.js 场景:

  const modelViewer = document.querySelector("model-viewer");
  const scene = modelViewer[Object.getOwnPropertySymbols(modelViewer)[14]];

然后我可以访问例如LowerArmR在这种情况下动画的位置:

scene.children[0].children[0].children[0].children[0].children[1].children[0].skeleton.bones.find(b => b.name == "LowerArmR").position

如果我这样做,在动画的不同点,我总是得到相同的位置:

{x: 1.86264503820865e-10, y: 0.00575238140299916, z: -1.02445485428149e-9}

如何在动画期间访问当前骨骼位置?

如果我在人形化身动画上执行此过程,然后尝试绘制骨骼的位置,我只会得到 T 姿势,而不是每个给定时间的实际位置: 在此处输入图像描述

这里我可以看到:

骨骼动画在 GPU 上处理,因此在运行时无法在 js 代码中完全访问这些数据。

也许有人知道一些解决方法,但据我所知,没有。

我正在寻找解决方法或规范的方法来做到这一点。

4

1 回答 1

2

骨骼动画(或“蒙皮”)应用于 GPU 1上的各个网格顶点,因为顶点通常比骨骼多得多,并且在 CPU 上全部更新它们的计算成本很高。

然而,骨骼本身的变换是three.js 中的CPU 上计算的。这里可能不明显的区别是:

  1. 骨骼的.position属性,继承自THREE.Object3D 的 .position属性,是一个本地位置,相对于其父级和其父级的位置,依此类推。
  2. 大多数骨骼动画是通过旋转而不是平移单个骨骼来操作的。例如,肩部的旋转将具有平移和旋转该骨骼的后代(即手臂的其余部分)的效果。

将所有这些放在一起,您想要找到的是世界位置,而不是特定骨骼的本地位置。Object3D 父类有一个方法可以帮助解决这个问题,object.getWorldPosition

const position = new THREE.Vector3();

bone.getWorldPosition( position );

请注意,此方法会产生一些性能开销,因为它首先更新骨骼的世界矩阵(遍历其祖先),然后再计算当前世界位置。如果您需要许多骨骼的位置,或世界旋转和缩放等其他属性,最好确保所有全局变换都是最新的一次(scene.updateMatrixWorld()如果需要),然后分解对象的.matrixWorld

const position = new THREE.Vector3();

position.setFromMatrixPosition( bone.matrixWorld );

1如果您确实需要计算特定顶点在 CPU 上的位置,three.js SkinnedMesh 类为此提供了一个辅助方法:.boneTransform()

于 2021-05-19T03:09:05.080 回答