Ajuste eficientemente aos vértices em threejs
Eu queria criar uma funcionalidade de encaixe para encaixar nos meus vértices de malha. Eu experimentei várias soluções.
Uma solução é adicionarTHREE.Sprite
instâncias para todos os vértices na minha cena e, em seguida, usando umrayCaster
para decidir se existe umsnap
ponto nointersects
array. Funciona muito bem; aquié um violino com uma demo.
A idéia é ocultar os sprites na solução final para que eles não sejam renderizados, mas minhas cenas são muito grandes, então ainda significaria adicionar muitos sprites à minha cena (para cada vértice, possivelmente milhares de sprites) para detectar tirar pontos com o meurayCaster
.
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';
}
Eu também pensei em uma solução alternativa, fazendo as contas usando os resultados dorayCaster
. Essa solução é demonstradaneste violino.
A idéia aqui é testar todosvertices
a partir da geometria doobject
(malha) cruzada e, em seguida, verifique se odistance
entre a interseçãopoint
e aquelesvertices
a partir da geometria é menor que o snapthreshold
.
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';
}
}
O triste é que, na segunda solução, o snap só funcionará quando o mouse for movido da superfície do objeto cruzado para um vértice. Caso o mouse seja movido de fora do objeto (para que não haja interseção), o encaixe não funcionará. Nesse aspecto, a primeira solução com sprites é muito mais útil ...
Minha pergunta, estou complicando demais as coisas e existe uma maneira melhor / mais simples / mais eficiente de fazer isso? Quaisquer sugestões para abordagens alternativas são bem-vindas.