Three.js - получить текущее положение костей скелета во время анимации

У меня есть проект 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}

Как я могу получить доступ к текущим позициям скелета во время анимации?

Если я выполню этот процесс с анимацией гуманоидного аватара, а затем попытаюсь изобразить положение костей, я просто получу Т-образную позу, но не фактическое положение в каждый момент времени:

1 ответ

Скелетная анимация (или «скиннинг») применяется к отдельным вершинам меша на GPU1, потому что часто вершин намного больше, чем костей, и обновление их всех на CPU было бы дорогостоящим в вычислительном отношении.

Тем не менее, преобразование самих костей которые вычисляются на процессоре в three.js. Различия, которые могут быть здесь не очевидны:

  1. В .positionСвойство кости, унаследованное от свойства .position THREE.Object3D , является локальным положением относительно положения его родителя, его родителя и т. д.
  2. Most skeletal animation operates by rotating, not translating, individual bones. For example, a rotation of the shoulder will have the effect of both translating and rotating the descendants of that bone (i.e. the rest of the arm).

Putting all of this together, what you want to find is the world position rather than the local position of a particular bone. The Object3D parent class has a method to help with this, object.getWorldPosition:

      const position = new THREE.Vector3();

bone.getWorldPosition( position );

Note that this method incurs a bit of a performance overhead, because it first updates the bone's world matrix — traversing its ancestors — before computing the current world position. If you need the positions of many bones, or other properties like world rotation and scale, it's better to ensure all global transforms are up to date once ( scene.updateMatrixWorld(), if needed) and then decompose the object's .matrixWorld:

      const position = new THREE.Vector3();

position.setFromMatrixPosition( bone.matrixWorld );

1 If you do happen to need to compute the position of a particular vertex on the CPU, the three.js SkinnedMesh class has a helper method for this: .boneTransform().

Другие вопросы по тегам