Leap 点的位置与 THREEJS 场景不同步

Position of Leap point not in sync with THREEJS Scene

我一直在竭尽全力获取 RiggedHand 网格呈现的位置,以便在 THREEJS 场景中准确创建小球体。我正在尝试在给定指尖的位置执行此操作。 X 和 Y 似乎是正确的,但 Z 几乎总是关闭。更重要的是,它离中心越远,倾斜就越明显(即 X 和 Y 也关闭)。

我能做的最好的事情就是使用以下代码计算出 'right' 坐标:

var handMesh = hand.data('riggedHand.mesh'); 
//This is the best I've gotten so far with the position of the fingertip
var position = handMesh.fingers[1].tip.getWorldPosition();

不太确定最好的方法是什么,但到目前为止我已经尝试了几种方法。转换 hand.finger[x].tipPosition,使用交互框并乘以窗口大小以尝试获得准确的位置。我开始怀疑它是否与我在 THREEJS 中使用 PerspectiveCamera 以及我需要以某种方式补偿它这一事实有更多关系(?) - 真的不确定该怎么做但希望有人能指出我在正确的方向。

使用上述代码的完整示例代码片段如下:

    var renderer, scene, camera, riggedHandPlugin, fadingSpheres
    var sphereTTL = 7;

    function initScene() {
        camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 1, 1000);
        camera.position.z = 200;
        scene = new THREE.Scene();
        scene.fog = new THREE.FogExp2(0xcccccc, 0.002);

        var light = new THREE.DirectionalLight(0xffffff);
        light.position.set(1, 1, 1);
        scene.add(light);

        // renderer
        renderer = new THREE.WebGLRenderer({ antialias: false });

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

        container = document.getElementById('container');
        container.appendChild(renderer.domElement);

        fadingSpheres = [];
    }

    function render() {
        requestAnimationFrame(render);
        renderer.render(scene, camera);
        if (fadingSpheres) {
            fadingSpheres.forEach(removeDeadSpheres);
        }
    }

    function FadingSphere(position, size, meshColor) {
        //Draw the sphere at the position of the indexfinger tip position
        var geometry = new THREE.SphereGeometry(3, 8, 8);
        var material = new THREE.MeshLambertMaterial({ color: meshColor});

        var mesh = new THREE.Mesh(geometry, material);

        mesh.material.ambient = mesh.material.color;

        mesh.position.x = position.x;
        mesh.position.y = position.y;
        mesh.position.z = position.z;

        this.sphere = mesh;

        scene.add(this.sphere);
        fadingSpheres.push(this);

        this.ttl = sphereTTL;
        this.updateToRemove = function () {
            this.ttl--;
            return (this.ttl <= 0);
        }
    }

    function removeDeadSpheres(fadingSphere, number, array) {
        if (fadingSphere) {
            if (fadingSphere.updateToRemove()) {
                scene.remove(fadingSphere.sphere);
                var index = array.indexOf(fadingSphere);
                array.splice(index, 1);
            }
        }
    }

    //Within the leap draw loop
    //Leap loop to call drawing functions
    Leap.loop(
      function (frame) {
          frame.hands.forEach(
            function (hand) {
                var handMesh = hand.data('riggedHand.mesh');

                function createSphereAtFingerTip(fingerIndex, colorHex) {
                    new FadingSphere(handMesh.fingers[fingerIndex].tip.getWorldPosition(), 3, colorHex);
                }

                createSphereAtFingerTip(0, 0xF57E20) //Thumb
                createSphereAtFingerTip(1, 0xFFCC00) //Index
                createSphereAtFingerTip(2, 0xCCCC51) //Middle
                createSphereAtFingerTip(3, 0x8FB258) //Ring
                createSphereAtFingerTip(4, 0x336699) //pinky
            }
       )
      }
    )
    .use('riggedHand')
    .use('handEntry')

    riggedHandPlugin = Leap.loopController.plugins.riggedHand;

    initScene();
    render();

非常感谢任何可能有帮助的suggestions/advice。

操纵手部插件存在一个已知问题:不幸的是,蒙皮网格模型与 Leap Motion API 返回的手部数据的比例(略有)不同。这意味着对于给定的姿势,网格骨骼的尖端和 API 返回的尖端位置数据将彼此靠近,但不同。

(在内部,插件通过计算从骨骼到骨骼的正确角度来工作,然后将其馈送到 THREE.js 蒙皮 API)

您可以使用此示例实际查看偏移量:http://leapmotion.github.io/leapjs-rigged-hand/?dots=1

这是您遇到的情况吗?我认为知道了这一点,您应该能够获得正确的 LM 位置,或者在视觉上正确的蒙皮网格位置。网格也可以通过编程方式变形或重新建模,以更准确地适应 LM 数据。 (参见creating rigged hands wiki。)

感谢 Peter 的最后一个示例,最终修复了它。是测试 3 帮助我找出了问题所在。

问题实际上是我似乎一直在使用与被操纵的手使用的场景不同的 'scene'(变量名恰如其分)。我没有意识到他们是不同的(doh!)。我将其切换为使用 riggedHand.parent 作为 'scene' 而不是我在 initScene() 中手动创建的场景实例,它现在有一个参数,我将 riggedHand.parent 作为场景传入第一次使用它可用。

function initScene(basisScene) {
    camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, sceneArea / 100,
      sceneArea * 4);
    camera.position.z = sceneArea;
    scene = basisScene;

另一件事是不调用 renderer.render(场景,相机);在 render() 循环中 - 即使在从 riggedHand.parent 设置 'scene' 之后。我没有意识到跳跃框架(?)使得不必再调用 renderer.render 了。

    function render() {
        //Next line no longer needed:
        //renderer.render(scene, camera);
        requestAnimationFrame(render);
    }

带有渐变球体的更新代码位于:http://codepen.io/GMelencio/pen/EaWqjZ

再次感谢彼得!