As I delved into creating a snapping feature to align with my mesh vertices, I embarked on multiple trial-and-error solutions.
One method involved introducing THREE.Sprite
instances for each vertex in the scene and utilizing a rayCaster
to determine if there exists a designated snap
point within the intersects
array. Although this approach proved effective (demonstrated in this demo fiddle), it posed a challenge due to the sheer scale of my scenes. Each vertex required a corresponding sprite, potentially resulting in an abundance of sprites being added to identify snap points using the 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';
}
An alternative solution I considered involved deriving calculations from the results obtained via the rayCaster
. This concept is exemplified through this fiddle. By testing all vertices
within the geometry of the intersected object
(mesh) and assessing if the distance
between the intersection point
and said vertices
falls below the specified snap threshold
, a potential snap point can be identified.
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';
}
}
A drawback of the second solution is that the snap functionality solely operates when the mouse traverses from the surface of the intersected object towards a vertex. Conversely, if the mouse initiates movement outside the object without an intersection occurring, snapping will not function. In comparison, the initial solution employing sprites showcases greater usability...
In light of these challenges, am I overcomplicating matters? Is there a more efficient or simplified approach available? I welcome any suggestions for alternate strategies.