The Node3D Editor is a built-in editor plugin that provides interactive 3D scene editing within the Godot Editor. It is implemented primarily in editor/plugins/node_3d_editor_plugin.h and editor/plugins/node_3d_editor_plugin.cpp. The main classes are:
| Class | Role |
|---|---|
Node3DEditorPlugin | EditorPlugin subclass; registers the editor and its UI |
Node3DEditor | Root UI container; owns viewports, tools, and gizmo plugin registry |
Node3DEditorViewport | One of up to four independent 3D viewport panels |
Node3DEditorViewportContainer | Splits the editor panel into 1–4 viewports |
EditorNode3DGizmoPlugin | Factory/controller for per-node gizmo types |
EditorNode3DGizmo | Per-Node3D visual handles and collision shapes |
For details on the gizmo system, see page 9.3 For general editor plugin architecture, see page 8.4
Sources: editor/plugins/node_3d_editor_plugin.h, editor/plugins/node_3d_editor_plugin.cpp
Node3DEditorPlugin is registered as a built-in EditorPlugin. On activation it builds the Node3DEditor UI panel and adds it to the editor's main screen. Node3DEditor owns all sub-systems: viewports, transformation toolbar, gizmo plugin registry, and the selection state container Node3DEditorSelectedItem.
Class Hierarchy and Ownership
Sources: editor/plugins/node_3d_editor_plugin.h, editor/plugins/node_3d_editor_plugin.cpp
Node3DEditorViewportContainer hosts between one and four Node3DEditorViewport instances depending on the layout selected by the user. Each Node3DEditorViewport is independent and owns its own Camera3D and SubViewport.
| Layout constant | Viewports | Default assignments |
|---|---|---|
VIEW_USE_1_VIEWPORT | 1 | Perspective |
VIEW_USE_2_VIEWPORTS | 2 | Perspective + Top |
VIEW_USE_2_VIEWPORTS_ALT | 2 | Perspective + Front |
VIEW_USE_3_VIEWPORTS | 3 | Top + Front + Perspective |
VIEW_USE_3_VIEWPORTS_ALT | 3 | Top + Left + Perspective |
VIEW_USE_4_VIEWPORTS | 4 | Top + Front + Left + Perspective |
Each Node3DEditorViewport maintains:
Camera3D at a fixed path within a SubViewportview_type (perspective or orthographic)Node3DEditorViewport internal structure
Sources: editor/plugins/node_3d_editor_plugin.h, editor/plugins/node_3d_editor_plugin.cpp
Navigation is handled inside Node3DEditorViewport::_nav_pan(), _nav_orbit(), _nav_zoom(), and _nav_freelook(). The active navigation mode is stored per-viewport and switches based on input.
| Mode | Trigger | Handler method |
|---|---|---|
| Orbit | Middle mouse + drag | _nav_orbit() |
| Pan | Middle mouse + Shift + drag | _nav_pan() |
| Zoom | Scroll wheel or zoom keys | _nav_zoom() |
| Freelook | Right mouse button held | _nav_freelook() |
The viewport Cursor struct stores the orbit pivot (pos), spherical angles (x_rot, y_rot), and distance from pivot. All navigation methods update cursor and then call _update_camera() to push the new transform to the scene's Camera3D.
Each Node3DEditorViewport can switch between:
Camera3D::PROJECTION_PERSPECTIVECamera3D::PROJECTION_ORTHOGONAL, locked to one of the six canonical axis-aligned views (Top, Bottom, Front, Back, Left, Right)Switching view type is done via the viewport's View menu, setting the view_type field and updating the Camera3D projection.
Sources: editor/plugins/node_3d_editor_plugin.cpp
Selection is processed inside Node3DEditorViewport::_gui_input(). On a mouse press the viewport performs:
EditorNode3DGizmo instances and calls _subgizmos_intersect_ray() / collision segment testing.PhysicsDirectSpaceState3D or the visual-server ray to find which Node3D is under the cursor.editor_selection->add_node() / clear() on EditorSelection to update the global selection.Selection flow
Box (frustum) selection calls _subgizmos_intersect_frustum() on each active gizmo and intersects_convex_shape() on the physics space.
Sources: editor/plugins/node_3d_editor_plugin.cpp, doc/classes/EditorNode3DGizmo.xml100-115 doc/classes/EditorNode3DGizmoPlugin.xml152-169
Node3DEditor has a tool_mode enum that controls which transform gizmo is active:
tool_mode value | Display | Axes |
|---|---|---|
TOOL_MODE_SELECT | No transform gizmo | – |
TOOL_MODE_MOVE | Arrow handles | X / Y / Z + plane squares |
TOOL_MODE_ROTATE | Circle handles | X / Y / Z |
TOOL_MODE_SCALE | Box handles | X / Y / Z + uniform |
A transform_type enum selects Local or Global coordinate space. In global mode gizmo axes align to world axes; in local mode they align to the node's own Basis.
All handle interaction (whether through the built-in transform gizmo or a custom EditorNode3DGizmoPlugin) follows the same three-phase protocol:
_commit_handle() receives the stored restore value so that the UndoRedo action can revert the change. If cancel is true (e.g., Escape pressed), the restore value is applied directly without creating an undo entry.
Sources: editor/plugins/node_3d_editor_plugin.cpp, doc/classes/EditorNode3DGizmoPlugin.xml14-41 doc/classes/EditorNode3DGizmoPlugin.xml75-84 doc/classes/EditorNode3DGizmoPlugin.xml130-142
Every Node3D in the edited scene may have one or more EditorNode3DGizmo instances attached to it. Node3DEditor maintains a list gizmo_plugins_by_priority (a Vector<Ref<EditorNode3DGizmoPlugin>>). When a node is added to the scene, the editor iterates the list in priority order and calls _has_gizmo(node) on each plugin.
Built-in gizmo plugins return priority -1; custom plugins default to 0, giving them automatic precedence. A plugin may return null from _create_gizmo() to suppress the gizmo for specific node types while still handling others.
| Element | EditorNode3DGizmo method | Purpose |
|---|---|---|
| Lines | add_lines() | Visualisation wireframe |
| Mesh | add_mesh() | Solid visualization |
| Billboard | add_unscaled_billboard() | Camera-facing icon |
| Collision segments | add_collision_segments() | Mouse picking |
| Collision triangles | add_collision_triangles() | Mouse picking |
| Handles | add_handles() | Draggable control points |
For the complete gizmo API and custom gizmo authoring, see page 9.3
Sources: doc/classes/EditorNode3DGizmoPlugin.xml101-107 doc/classes/EditorNode3DGizmoPlugin.xml53-59 doc/classes/EditorNode3DGizmoPlugin.xml86-92 doc/classes/EditorNode3DGizmo.xml116-172
Node3DEditor maintains snap settings stored in snap_translate_value, snap_rotate_value, and snap_scale_value. When snapping is active (toggle via Snap toolbar button or S key), movement, rotation, and scale increments are rounded to these values. The grid planes rendered in each viewport are XZ by default, with optional YZ and XY planes; visibility is toggled per-viewport.
Each Node3DEditorViewport has a display_flags bitmask that maps to Viewport::DEBUG_DRAW_* constants:
| Flag | Viewport constant | Effect |
|---|---|---|
| Wireframe | DEBUG_DRAW_WIREFRAME | All meshes as wireframe |
| Overdraw | DEBUG_DRAW_OVERDRAW | Blend depth layers |
| Lighting | (lighting disable) | Unshaded rendering |
| Shadows | (shadow disable) | No shadow maps |
| Grid | (editor overlay) | XZ grid plane rendered |
| Origin | (editor overlay) | World-space XYZ axis arrows |
Node3DEditor checks node->has_meta("_edit_lock_") before allowing selection or transformation. Grouped nodes (node->has_meta("_edit_group_")) propagate selection to the topmost group ancestor rather than the individual node.
Sources: editor/plugins/node_3d_editor_plugin.cpp, editor/plugins/node_3d_editor_plugin.h
When a Node3D enters the edited SceneTree, Node3DEditor receives a node_added notification and triggers gizmo attachment. When the node is removed, gizmos are detached and freed.
Priority ordering: built-ins return -1, custom plugins default to 0. A plugin that returns a higher integer from _get_priority() is consulted first and can shadow lower-priority plugins.
Sources: doc/classes/EditorNode3DGizmoPlugin.xml86-107 editor/plugins/node_3d_editor_plugin.cpp
Handles are 3D control points registered with EditorNode3DGizmo::add_handles() during _redraw(). Each handle has an integer ID. The secondary flag allows multiple overlapping handles with Shift toggling their priority.
| Phase | Called method | Who calls it |
|---|---|---|
| Display | add_handles(positions, material, ids) | Plugin's _redraw() |
| Begin drag | _begin_handle_action(gizmo, id, secondary) | Node3DEditorViewport |
| Snapshot | _get_handle_value(gizmo, id, secondary) | Node3DEditorViewport |
| Live update | _set_handle(gizmo, id, secondary, camera, screen_pos) | Node3DEditorViewport on mouse move |
| Commit | _commit_handle(gizmo, id, secondary, restore, cancel) | Node3DEditorViewport on release |
Subgizmos allow selection and independent transform of sub-elements (e.g., skeleton bones, path control points). Each subgizmo is identified by a non-negative integer ID.
Common uses:
Path3D — individual Curve3D control pointsCSGPolygon3D — polygon verticesSkeleton3D — individual bone transformsSources: doc/classes/EditorNode3DGizmoPlugin.xml130-169 doc/classes/EditorNode3DGizmo.xml31-115
EditorNode3DGizmoPlugin maintains an internal dictionary of named StandardMaterial3D objects. Helper methods create materials and store them under a string key with automatic selected/editable variant generation.
| Method | Stored as | Used by gizmo method |
|---|---|---|
create_material(name, color, ...) | name, name@selected, name@editable | add_lines(), add_mesh() |
create_handle_material(name, billboard, texture) | name, variants | add_handles() |
create_icon_material(name, texture, ...) | name, variants | add_unscaled_billboard() |
add_material(name, material) | name | Direct storage |
Retrieve with get_material(name, gizmo). When a gizmo argument is provided, the method automatically selects the appropriate variant (@selected if the node is selected, @editable if the gizmo is in edit mode).
Call the create_* methods once during plugin initialization, not inside _redraw().
Sources: doc/classes/EditorNode3DGizmoPlugin.xml170-216
Transform operations in the Node3D Editor operate in different coordinate spaces:
| Space | Description | Usage |
|---|---|---|
| World Space | Global coordinate system | Positioning in scene |
| Local Space | Node's own coordinate system | Rotation and scale relative to parent |
| View Space | Camera-relative coordinates | Screen-space calculations |
Gizmo handles and subgizmo transforms are always specified in local space relative to the Node3D being edited. The Node3D Editor handles conversion between spaces:
This design allows gizmo plugins to work independently of the node's position in the scene hierarchy.
Sources: doc/classes/EditorNode3DGizmoPlugin.xml42-51 doc/classes/EditorNode3DGizmo.xml92-99
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.