Add vertex snapping to the 3D editor#117235
Add vertex snapping to the 3D editor#117235ryevdokimov wants to merge 2 commits intogodotengine:masterfrom
Conversation
|
Works with imported meshes? |
Anything that uses |
|
I worked on the ux of https://github.com/jgillich/godot-snappy and the snapper has bitrotted, but I hope it can inspire enhancements to this pull request. |
If I understand correctly this means you can only move one mesh at a time? It would be better to highlight nearest vertex on any visible mesh, then move all of the selected nodes using it as a reference point. This will allow moving multiple at once and moving non-meshes along with them. This is how it works in blender: blendersnapping.mp4 |
Done. 2026-03-09.08-29-39.mp4 |
| Vector3 source_display = vertex_snap_source; | ||
| if (vertex_snap_dragging) { | ||
| for (const KeyValue<ObjectID, Vector3> &E : vertex_snap_original_positions) { | ||
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); |
There was a problem hiding this comment.
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); | |
| Node3D *node = ObjectDB::get_instance<Node3D>(E.key); |
|
|
||
| if (has_displacement) { | ||
| for (const KeyValue<ObjectID, Vector3> &E : vertex_snap_original_positions) { | ||
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); |
There was a problem hiding this comment.
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); | |
| Node3D *node = ObjectDB::get_instance<Node3D>(E.key); |
| vertex_snap_has_target = false; | ||
|
|
||
| for (const KeyValue<ObjectID, Vector3> &E : vertex_snap_original_positions) { | ||
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); |
There was a problem hiding this comment.
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); | |
| Node3D *node = ObjectDB::get_instance<Node3D>(E.key); |
| EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton(); | ||
| undo_redo->create_action(TTR("Vertex Snap")); | ||
| for (const KeyValue<ObjectID, Vector3> &E : original_positions) { | ||
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); |
There was a problem hiding this comment.
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); | |
| Node3D *node = ObjectDB::get_instance<Node3D>(E.key); |
|
|
||
| void Node3DEditorViewport::_vertex_snap_commit() { | ||
| for (const KeyValue<ObjectID, Vector3> &E : vertex_snap_original_positions) { | ||
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); |
There was a problem hiding this comment.
| Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(E.key)); | |
| Node3D *node = ObjectDB::get_instance<Node3D>(E.key); |
9437f8b to
d1d0c17
Compare
There was a problem hiding this comment.
Tested locally with a mix of CSG nodes, MeshInstance3Ds, Decals and Marker3Ds, it works as expected.
Some feedback:
-
It's possible to enable vertex snapping while dragging gizmos or using Blender-style manipulation shortcuts. However, it has no visible effect other than drawing the yellow circle gizmo around a vertex.
-
It should be possible to release B after starting a dragging operation, so you don't have to keep it held down the whole way. Right now, releasing B while dragging will stop moving the selected node (but won't cancel the operation).
-
The vertex snap gizmo could be drawn twice (once opaque with normal depth, once translucent with depth test disabled), so that you can be aware that you're snapping to a vertex that is occluded by another object:
| Current | Proposed (mockup) |
|---|---|
![]() |
![]() |
We use the same trick for the 3D selection box, so it appears translucent when occluded.
-
Non-geometry nodes like Decal, ReflectionProbe and Marker3D behave a bit oddly. You can enable vertex snapping and move the node according to the snapped vertex, but the node won't center around the vertex like one would probably expect. Instead, it will move relative to your mouse movement, taking the snapped vertex into account.
- I can't think of a lot of use cases for this, so I think it would make more sense to move the node's origin to the snapped vertex instead. This makes sense for Marker3D nodes in particular, which may be used as "shot origins" on weapon models, characters, etc.
-
Out of curiosity, is edge/face snapping planned in the future?
d1d0c17 to
6af41be
Compare
|
Feedback applied: 2026-03-09.21-37-52.mp4
Yes, I do intend to provide, to the best of my ability, all the tools and features someone would expect from a 3D editor. 🙂 |


Closes: Add object snapping to the floor/vertices for the 3D editor viewport godot-proposals#755
Requires and Includes: Fix 3D editor overlay not redrawing on camera navigation #116910
Hold the
Vertex Snapshortcut (default:B) to highlight the nearest vertex on the selected node's geometry. Click and drag to snap that vertex to vertices on other meshes. For nodes without geometry (Camera3D,Marker3D, etc.), the node's origin snaps directly to the target vertex.2026-03-08.21-00-36.mp4