Three.js - 如何使用姿势估计的数据来对3D模型进行动画处理。

5

我想使用姿态估计坐标在three.js中对一个带有骨骼的模型进行动画处理。我使用的姿态估计技术提供了来自视频源中人物的实时x、y、z坐标,我正在尝试将这些坐标用于相应地移动3D模型。我使用下面的代码(其中一部分是我在相关问题的答案中找到的)作为起点...

let camera, scene, renderer, clock, rightArm;

init();
animate();

function init() {

  camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 10);
  camera.position.set(2, 2, -2);

  clock = new THREE.Clock();

  scene = new THREE.Scene();
  scene.background = new THREE.Color(0xffffff);

  const light = new THREE.HemisphereLight(0xbbbbff, 0x444422);
  light.position.set(0, 1, 0);
  scene.add(light);

  // model
  const loader = new THREE.GLTFLoader();
  loader.load('https://threejs.org/examples/models/gltf/Soldier.glb', function(gltf) {

    const model = gltf.scene;

    rightArm = model.getObjectByName('mixamorigRightArm');

    scene.add(model);

  });

  renderer = new THREE.WebGLRenderer({
    antialias: true
  });
  renderer.setPixelRatio(window.devicePixelRatio);
  renderer.setSize(window.innerWidth, window.innerHeight);
  renderer.outputEncoding = THREE.sRGBEncoding;
  document.body.appendChild(renderer.domElement);

  window.addEventListener('resize', onWindowResize, false);

  const controls = new THREE.OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 1, 0);
  controls.update();

}

function onWindowResize() {

  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);

}

//This was my attempt at deriving the rotation from two vector3's and applying it to the model
//storedresults is simply an array where I store the pose estimation data for a given position
//getPosition is just a helper function for getting the vector three for a specific position
function setRightArmRotation() {
  if (rightArm) {
    if (storedresults === undefined || storedresults.length == 0) {
      return;
    } else {
      if (vectorarray.length < 2) {
        vectorarray.push(getPosition(12));
      } else {
        vectorarray.pop();
        vectorarray.push(getPosition(12));
        var quaternion = new THREE.Quaternion();
        quaternion.setFromUnitVectors(vectorarray[0], vectorarray[1]);
        var matrix = new THREE.Matrix4();
        matrix.makeRotationFromQuaternion(quaternion);
        rightArm.applyMatrix4(matrix);
      }
    }
  }
}

function animate() {

  requestAnimationFrame(animate);

  const t = clock.getElapsedTime();

  if (rightArm) {

    rightArm.rotation.z += Math.sin(t) * 0.005;
    //setRightArmRotation()

  }

  renderer.render(scene, camera);

}
<script src="https://cdn.jsdelivr.net/npm/three@0.125.2/build/three.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.125.2/examples/js/loaders/GLTFLoader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.125.2/examples/js/controls/OrbitControls.js"></script>

我也参考了这个答案来找到两个向量之间的旋转,但是我在实现时没有成功地达到期望的结果...... 如何在Three.js中找到两个向量之间的旋转矩阵 我可以轻松地从姿势估计技术中获得Vector3,并且我理解jsfiddle中的大部分内容,但我似乎无法将它们组合起来,以使我的3D模型使用姿势估计坐标“镜像”视频中的运动。 我基本上只能让模型“乱动”。
据我理解,我需要操作骨骼的旋转来实现所需的结果,并为此使用两个向量计算这些旋转,但是经过多次研究和试错后,我似乎无法把它们全部结合起来。 感谢任何帮助。
1个回答

1
这是一个相当庞大的答案,所以我将把它拆分成更小的部分。
我猜测你正在使用posenet(tensorflow库)。
我之前也遇到过这个问题,解决方案非常复杂,但以下是对我有效的方法。
首先,使用posenet,将网格中的每个骨骼与关键点数组中的骨骼匹配。
然后我创建了一个Skeleton类,用基本术语重新创建了一个骨架,每个骨头都有一个单独的类,例如肘关节等。这些都有最大的过度和收缩值,它采用了一系列Vector3值,基本上显示了最小和最大的xyz旋转值(类似于我们的运动范围),并将其从角度转换为弧度。
从那里开始,我将所有旋转应用到每个骨头上,但旋转远非完美,因为手臂经常会在身体内旋转。为了解决这个问题,我在每个骨头周围创建了一个边界框(到外部网格),并在每个部位上执行碰撞检测,直到骨头不再与网格的其他部分发生碰撞,我对每个身体部位设置了容差得分(即允许手臂交叉或腿)。
从那里开始,我有了一个“相对准确”的估计值,将其应用于3D网格。
如果你想看一个例子,我在github上有一些原始东西: https://github.com/hudson1998x/2D-To-3D-Pose-Estimation/

不错!看到这个实现会很酷,但我无法在本地运行该项目。安装过程中出现了对等依赖项的问题,并且一旦解决了这些问题,还有其他问题。我正在我的项目中使用blazepose,它提供了3D位置,所以我认为只需获取两个关节之间的方向向量并将旋转应用于骨骼即可,但我缺少某些东西。无论如何,感谢您分享您的见解! - posit labs
由于时间不够,该代码库的工作已经停止。但是我认为它与您所拥有的概念相匹配。 - John Hudson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接