【问题标题】:Efficiently snap to vertices in threejs有效地捕捉到threejs中的顶点
【发布时间】:2016-06-30 16:38:17
【问题描述】:

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

一种解决方案是为场景中的所有顶点添加THREE.Sprite 实例,然后使用rayCaster 来确定@​​987654326@ 数组中是否存在snap 点。它工作得很好;这里is a fiddle with a demo.
这个想法是在最终解决方案中隐藏精灵,这样它们就不会被渲染,但是我的场景非常大,所以它仍然意味着向我的场景添加大量精灵(对于每个顶点,可能有数千个精灵)来检测使用我的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';
}

我还想到了一个替代解决方案,即使用rayCaster 的结果进行数学运算。该解决方案在in this fiddle 进行了演示。
这里的想法是从相交的object(网格)的几何中测试所有vertices,然后检查相交point和几何中的vertices之间的distance是否小于捕捉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';
    }
}

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

我的问题是,我是否使事情过于复杂,是否有更好/更简单/更有效的方法来做到这一点?欢迎对替代方法提出任何建议。

【问题讨论】:

  • 我假设您想点击点击?如果是这样,我可以帮助你,但我想在回答之前先确定一下。另外,当你捕捉到什么角度时,你想看什么?如果是立方体,那很明显,但如果你有一个顶点平面,你想从哪个角度看它就不太明显了
  • 是的,这就是最终的想法。但补充说这不是问题,我更加努力地寻找正确的顶点以有效地捕捉到。该模型将有 1000 多个顶点,我需要以某种方式计算哪个顶点在鼠标的阈值距离内。
  • Raycaster.intersects[0] 应该总是返回它相交的最近的对象
  • @Rush2112 我明白这一点,我不确定您想在评论中指出什么。也许我的问题不够清楚,我会稍微编辑一下我的帖子......
  • 您能否为每个对象的顶点构建一个八叉树或 kd 树(假设使用 sprites 方法)并通过它进行光线投射以找到您的顶点?或者,使用第二种方法,创建一个比您可以相交的网格稍大的盒子或球体,这样光线投射就不必一定要击中网格?我对 three.js 不太熟悉,但希望这会有所帮助。

标签: javascript three.js


【解决方案1】:

我查看了@meepzh 他关于使用八叉树的建议,并使用this threeoctree repository from github 提出了以下解决方案。 THREE.Octree 类并没有解决我所有的问题开箱即用所以 我在THREE.Octree 类中添加了自定义方法findClosestVertex,可以这样使用。

var snap = octree.findClosestVertex(position, radius);

如果positionradius 内没有顶点,则snapnull,否则返回世界空间中的最近点(THREE.Vector3)。

我为新方法提出了拉取请求here on github

Here is a demo in a fiddle

【讨论】:

    猜你喜欢
    • 2016-09-13
    • 2011-07-04
    • 1970-01-01
    • 2019-05-25
    • 2012-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-29
    相关资源
    最近更新 更多