Эффективно привязать к вершинам в три раза

Я хотел сделать функцию привязки, чтобы привязываться к моим вершинам меша. Я экспериментировал с несколькими решениями.

Одним из решений является добавлениеTHREE.Sprite экземпляры для всех вершин в моей сцене, а затем с помощью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';
}

Я также подумал об альтернативном решении, делая математику, используя результаты изrayCaster, Это решение продемонстрированов этой скрипке.
Идея здесь состоит в том, чтобы проверить всеvertices из геометрииobject (сетка), которая пересекается, а затем проверьте,distance между пересечениемpoint и теvertices от геометрии меньше оснастки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';
    }
}

Печально то, что во втором решении оснастка будет работать только тогда, когда мышь перемещается от поверхности пересекаемого объекта к вершине. В случае, если мышь перемещается извне объекта (поэтому пересечения нет), привязка не будет работать. В этом отношении первое решение со спрайтами гораздо удобнее ...

Мой вопрос, я слишком усложняю вещи и есть ли лучший / более простой / более эффективный способ сделать это? Любые предложения по альтернативным подходам приветствуются.

 Rush211230 июн. 2016 г., 19:11
Извините, я только что понял, что вы хотели. Я построил кубы, используя объекты вершин, но я забыл, что он выберет весь куб, то есть все вершины. Теперь я понимаю. Извините за другие комментарии. Так как я выкопал себя так далеко, я буду искать правильное решение
 Rush211230 июн. 2016 г., 18:47
Raycaster.intersects [0] всегда должен возвращать ближайший объект, который он пересек
 Rush211230 июн. 2016 г., 18:43
Я полагаю, вы хотите щелкнуть по клику? Если это так, я могу помочь вам, но я хочу убедиться, прежде чем я отвечу. ТАКЖЕ, какой угол вы хотели бы видеть, когда вы привязываетесь? Если это куб, это очевидно, но если у вас есть плоскость вершин, не так очевидно, под каким углом вы хотите его увидеть
 Wilt30 июн. 2016 г., 23:56
@meepzh этоthreeoctree выглядит действительно очень многообещающе. Я не знал об этом решении октри. Жаль, что он поддерживает только до r60, но у меня есть, по крайней мере, кое-что новое, чтобы рассмотреть. Благодарю.
 meepzh30 июн. 2016 г., 20:49
Не могли бы вы построить дерево октод или kd для вершин каждого объекта (с использованием метода спрайтов) и через него выполнить лучевую трансляцию, чтобы найти свою вершину? Или же, используя второй метод, создайте коробку или сферу, которая немного больше сетки, с которой вы можете пересекаться, чтобы лучевая трансляция не обязательно попадала в сетку? Я не слишком знаком с three.js, но, надеюсь, это поможет.
 Wilt30 июн. 2016 г., 18:45
Да, это будет в конце концов идея. Но, добавив, что это не проблема, я больше борюсь с тем, как найти правильную вершину, к которой можно привязаться эффективным способом. Модель будет иметь более 1000 вершин, и мне нужно как-то вычислить, какая вершина находится в пределах порогового расстояния моей мыши.
 Wilt30 июн. 2016 г., 18:59
@ Rush2112 Я понимаю, я не уверен, что вы хотите указать в своем комментарии. Может быть, мой вопрос недостаточно ясен, я немного отредактирую свой пост ...

Ответы на вопрос(1)

Решение Вопроса

Я посмотрел в @meepzh его предложение использовать октри и сделал следующее решение, используяэтотthreeoctree хранилище из github,THREE.Octree класс не решил все мои проблемывне коробки поэтому я добавил пользовательский методfindClosestVertex кTHREE.Octree класс, который можно использовать, как это.

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

snap являетсяnull если нет вершин в пределахradius изposition и возвращает ближайшую точку (THREE.Vector3в мировом пространстве иначе.

Я сделал Pull-запросздесь на GitHub для нового метода.

Вот демо в скрипке

Ваш ответ на вопрос