有效地捕捉到三个顶点

Wil*_*ilt 6 javascript three.js

我想制作一个捕捉功能来捕捉我的网格顶点.我尝试了几种解决方案.

一种解决方案是为THREE.Sprite场景中的所有顶点添加实例,然后使用a rayCaster来确定数组中是否snap有点intersects.它工作得很好; 这是一个演示的小提琴.
我的想法是在最终的解决方案中隐藏精灵,这样它们就不会被渲染,但我的场景非常大,所以它仍然意味着在我的场景中添加大量的精灵(对于每个顶点,可能有数千个精灵)来检测用我的点击点rayCaster.

var intersects = rayCaster.intersectObject(scene, true);
var snap = null;
if (intersects.length > 0) {
    var index = 0;
    var intersect = intersects[index];
    while (intersect && intersect.object.name === 'snap') {
        snap = sprite.localToWorld(sprite.position.clone());
        index++
        intersect = intersects[index];
    }
    if (intersect) {
        var face = intersect.face;
        var point = intersect.point;
        var object = intersect.object;
        mouse3D.copy(point);
    }
}
if (snap) {
    renderer.domElement.style.cursor = 'pointer';
} else {
    renderer.domElement.style.cursor = 'no-drop';
}
Run Code Online (Sandbox Code Playgroud)

我还想到了一个替代解决方案,通过使用结果进行数学计算rayCaster.在这个小提琴中演示了这个解决方案.
这里的想法是verticesobject交叉的(网格)的几何测试所有,然后检查distance相交pointvertices几何之间是否小于快照threshold.

var intersects = rayCaster.intersectObject(mesh, true);
if (intersects.length > 0) {
    var distance, intersect = intersects[0];
    var face = intersects[0].face;
    var point = intersects[0].point;
    var object = intersects[0].object;
    var snap = null;
    var test = object.worldToLocal(point);
    var points = object.geometry.vertices;
    for (var i = 0, il = points.length; i < il; i++) {
        distance = points[i].distanceTo(test);
        if (distance > threshold) {
            continue;
        }
        snap = object.localToWorld(points[i]);
    }
    if (snap) {
        sphereHelper.position.copy(snap);
        sphereHelper.visible = true;
        renderer.domElement.style.cursor = 'pointer';
    } else {
        sphereHelper.visible = false;
        renderer.domElement.style.cursor = 'no-drop';
    }
}
Run Code Online (Sandbox Code Playgroud)

令人遗憾的是,在第二个解决方案中,只有当鼠标从相交对象的表面移向顶点时才会执行捕捉.如果鼠标从对象外部移动(因此没有交叉点),则捕捉将不起作用.在这方面,第一个带有精灵的解决方案更加实用......

我的问题是,我是否过于复杂,是否有更好/更简单/更有效的方法来做到这一点?欢迎任何有关替代方法的建议.

Wil*_*ilt 2

我研究了 @meepzh 他关于使用八叉树的建议,并使用来自github 的三八叉树存储库制定了以下解决方案。该类THREE.Octree并没有立即解决我的所有问题,因此我findClosestVertex向该类添加了THREE.Octree可以像这样使用的自定义方法。

var snap = octree.findClosestVertex(position, radius);
Run Code Online (Sandbox Code Playgroud)

snap如果中null没有顶点,则返回世界空间中最近的点 ( )。radiuspositionTHREE.Vector3

我在 github 上为新方法提出了 Pull-Request 。

这是小提琴中的演示