CanvasItem is the abstract base class for all 2D-rendered nodes in Godot. It defines how nodes register with the rendering server, accumulate transforms, issue draw commands, control visibility and modulation, and sort relative to each other. Both Node2D (2D game objects) and Control (GUI nodes) inherit from it.
This page covers the CanvasItem class itself and the rendering infrastructure it connects to. For the 2D editor plugin that manipulates these nodes, see CanvasItem Editor. For the Control/GUI subsystem built on top of CanvasItem, see Control & UI System. For the 3D equivalent (Node3D), see Node Hierarchy.
CanvasItem sits between Node and the two major 2D subtrees.
CanvasItem Inheritance
Sources: scene/main/canvas_item.h46-220 scene/2d/node_2d.h1-80
Every CanvasItem node owns an RID canvas_item handle that identifies its corresponding object in the RenderingServer. All property mutations (visibility, transform, modulate, z-index, material) are transmitted to the server through this handle.
CanvasItem Scene-to-Server Data Flow
The RendererCanvasCull::Item struct (defined in servers/rendering/renderer_canvas_cull.h45-100) mirrors the scene-level properties: z_index, z_relative, sort_y, modulate, self_modulate, visible, visibility_layer, and the command list.
Sources: scene/main/canvas_item.h82-84 scene/main/canvas_item.cpp98 servers/rendering/renderer_canvas_cull.h44-100
When a CanvasItem enters the scene tree, _enter_canvas() is called. It determines the appropriate parent for the rendering server item — either a parent CanvasItem's server handle, or a canvas RID obtained from a CanvasLayer or World2D.
Canvas Registration Flow
The canvas_group string (e.g. "_root_canvas<id>") is used to call _top_level_raise_self() in sorted order when draw indices need updating.
On exit, _exit_canvas() sets the parent to a null RID and removes the canvas group scene/main/canvas_item.cpp292-300
Sources: scene/main/canvas_item.cpp239-290 scene/main/canvas_item.cpp292-300
CanvasItem maintains a cached global_transform (a Transform2D). It is lazily recomputed when marked dirty via _set_global_invalid(true).
| Method | Description |
|---|---|
get_transform() | Abstract; returns local transform (implemented by Node2D, Control) |
get_global_transform() | Walks the parent chain to compute the world transform, caches result |
get_global_transform_with_canvas() | Applies CanvasLayer::get_final_transform() on top |
get_screen_transform() | Further applies Viewport::get_popup_base_transform() |
global_transform is declared mutable and protected by an MTFlag global_invalid for thread-safe reads scene/main/canvas_item.h133-136
Node2D stores its own Transform2D transform (position/rotation/scale/skew) and calls RenderingServer::canvas_item_set_transform() whenever it changes scene/2d/node_2d.cpp137-143
Setting top_level = true makes get_parent_item() return nullptr, breaking the transform chain. The item re-registers as a root canvas item scene/main/canvas_item.cpp525-548
Sources: scene/main/canvas_item.cpp164-213 scene/main/canvas_item.h133-136 scene/2d/node_2d.cpp137-143
Canvas items use a deferred, demand-driven draw model. Draw commands are not issued every frame; instead, the item is only redrawn when queue_redraw() is called.
Draw Lifecycle
The drawing flag scene/main/canvas_item.h114 is set to true only during the _redraw_callback() window. All draw_*() methods are guarded by the ERR_DRAW_GUARD macro scene/main/canvas_item.cpp48-49 which asserts drawing == true.
All draw_* methods forward to RenderingServer canvas_item_add_* calls. Coordinates are always in local space.
| Method | Server Call |
|---|---|
draw_line() | canvas_item_add_line() |
draw_polyline() | canvas_item_add_polyline() |
draw_rect() | canvas_item_add_rect() or canvas_item_add_polyline() |
draw_circle() | draw_ellipse() → canvas_item_add_ellipse() |
draw_texture() | Texture2D::draw() → canvas_item_add_texture_rect() |
draw_polygon() | canvas_item_add_polygon() |
draw_mesh() | canvas_item_add_mesh() |
draw_multimesh() | canvas_item_add_multimesh() |
draw_string() | Font::draw_string() → text server glyph calls |
draw_style_box() | StyleBox::draw() → multiple rect/texture commands |
draw_set_transform() | canvas_item_add_set_transform() |
draw_set_transform() and draw_set_transform_matrix() insert an inline transform into the command list, affecting all subsequent draw calls within that _draw() invocation scene/main/canvas_item.cpp947-959
Sources: scene/main/canvas_item.cpp138-162 scene/main/canvas_item.cpp722-1066
Visibility is tracked by two boolean fields:
visible — the node's own local visibility flagparent_visible_in_tree — whether the parent chain is visibleis_visible_in_tree() returns visible && parent_visible_in_tree scene/main/canvas_item.cpp67-70
When set_visible() changes state, _handle_visibility_change() propagates the change to the rendering server and to all CanvasItem children via _propagate_visibility_changed() scene/main/canvas_item.cpp97-116
The visibility_layer property (a 32-bit bitmask) is independent of visible. It is compared against the viewport's canvas cull mask in RendererCanvasCull::_cull_canvas_item() servers/rendering/renderer_canvas_cull.cpp310
Sources: scene/main/canvas_item.cpp67-116 servers/rendering/renderer_canvas_cull.cpp303-492
Two separate color multipliers exist per item:
| Property | Type | Propagation |
|---|---|---|
modulate | Color | Multiplied with parent's modulate, affects the item and all children |
self_modulate | Color | Applied only to this item's own draw commands, not inherited |
In the renderer, ci->final_modulate = p_modulate * ci->self_modulate is computed during culling servers/rendering/renderer_canvas_cull.cpp268 where p_modulate already carries the inherited modulate from parents.
get_modulate_in_tree() walks parent items multiplying modultes together scene/main/canvas_item.cpp514-523
Sources: scene/main/canvas_item.cpp499-523 servers/rendering/renderer_canvas_cull.cpp265-270
z_index is an integer in the range [CANVAS_ITEM_Z_MIN, CANVAS_ITEM_Z_MAX]. The renderer groups items into per-z-layer linked lists and renders them in ascending z order servers/rendering/renderer_canvas_cull.cpp78-108
If z_relative is true (the default), the item's effective z-index is parent_z + z_index. If false, it is an absolute value. get_effective_z_index() computes this recursively scene/main/canvas_item.cpp699-709
When y_sort_enabled is set on a parent, its CanvasItem children are sorted by their Y coordinate before rendering. This is implemented in RendererCanvasCull::_collect_ysort_children() and _cull_canvas_item() servers/rendering/renderer_canvas_cull.cpp110-165
Within the same z-layer, items are ordered by their index in the parent's child list. Calling move_to_front() moves the node to the last child position scene/main/canvas_item.cpp491-497 update_draw_order() pushes the new index to the rendering server via canvas_item_set_draw_index() scene/main/canvas_item.cpp458-471
Sources: scene/main/canvas_item.cpp671-714 servers/rendering/renderer_canvas_cull.cpp78-108 servers/rendering/renderer_canvas_cull.cpp110-165
A Ref<Material> material can be assigned to any CanvasItem. If use_parent_material is true, the item inherits the nearest ancestor's material instead. This is mirrored server-side as ci->use_parent_material and ci->material_owner servers/rendering/renderer_canvas_cull.cpp319-324
CanvasItem also supports per-instance shader parameters — overrides for instance uniform variables in a ShaderMaterial. These are stored in instance_shader_parameters and exposed to the inspector via _get_property_list() scene/main/canvas_item.cpp642-661 They are set on the server via canvas_item_set_instance_shader_parameter().
Sources: scene/main/canvas_item.h129-131 scene/main/canvas_item.cpp609-661
CanvasItem has texture_filter and texture_repeat properties. Both default to PARENT_NODE, which means the effective value is inherited from the nearest ancestor that has a non-PARENT_NODE setting. The inheritance walk is performed in _refresh_texture_filter_cache() and _refresh_texture_repeat_cache().
| Enum | Values |
|---|---|
TextureFilter | PARENT_NODE, NEAREST, LINEAR, NEAREST_WITH_MIPMAPS, LINEAR_WITH_MIPMAPS, NEAREST_WITH_MIPMAPS_ANISOTROPIC, LINEAR_WITH_MIPMAPS_ANISOTROPIC |
TextureRepeat | PARENT_NODE, DISABLED, ENABLED, MIRROR |
These map to RSE::CanvasItemTextureFilter and RSE::CanvasItemTextureRepeat on the server. A change propagates down the CanvasItem child list via _update_texture_filter_changed(true) / _update_texture_repeat_changed(true) scene/main/canvas_item.h158-160
Sources: scene/main/canvas_item.h54-71 scene/main/canvas_item.h123-127
CanvasLayer (defined in scene/main/canvas_layer.cpp) is not a CanvasItem; it is a plain Node. It owns its own canvas RID and a layer integer that controls draw ordering relative to other layers. CanvasItem nodes that are not children of another CanvasItem look up the tree for a CanvasLayer ancestor to attach to.
Canvas Hierarchy Example
When CanvasLayer::set_layer() changes the layer value, viewport_set_canvas_stacking() is called to reorder canvases in the renderer scene/main/canvas_layer.cpp39-44
Sources: scene/main/canvas_item.cpp239-286 scene/main/canvas_layer.cpp39-67
The RendererCanvasCull class, implemented in servers/rendering/renderer_canvas_cull.cpp performs the actual traversal that converts the scene's CanvasItem tree into a flat, z-ordered list of render commands.
Culling Pipeline
_cull_canvas_item() servers/rendering/renderer_canvas_cull.cpp303 handles:
xform_curr / xform_prev)CanvasGroup (clip children) setupSources: servers/rendering/renderer_canvas_cull.cpp70-108 servers/rendering/renderer_canvas_cull.cpp303-492
| Constant | Value | Triggered When |
|---|---|---|
NOTIFICATION_TRANSFORM_CHANGED | SceneTree::NOTIFICATION_TRANSFORM_CHANGED | Transform was dirtied and the xform change list is flushed |
NOTIFICATION_DRAW | 30 | Item is being redrawn (inside _redraw_callback()) |
NOTIFICATION_VISIBILITY_CHANGED | 31 | visible or parent_visible_in_tree changed |
NOTIFICATION_ENTER_CANVAS | 32 | Item registered with a canvas (end of _enter_canvas()) |
NOTIFICATION_EXIT_CANVAS | 33 | Item deregistered from canvas (start of _exit_canvas()) |
NOTIFICATION_LOCAL_TRANSFORM_CHANGED | 35 | Local transform changed (opt-in via set_notify_local_transform()) |
NOTIFICATION_WORLD_2D_CHANGED | 36 | The World2D this item uses changed |
Sources: scene/main/canvas_item.h212-220
| Property | Type | Effect |
|---|---|---|
visible | bool | Local visibility toggle |
modulate | Color | Inherited color multiplier |
self_modulate | Color | Non-inherited color multiplier |
z_index | int | Render layer within canvas |
z_as_relative | bool | Whether z_index is relative to parent |
y_sort_enabled | bool | Sort children by Y position |
top_level | bool | Break transform/canvas inheritance |
light_mask | int | Bitmask for 2D light interaction |
visibility_layer | uint32_t | Bitmask for viewport cull mask |
texture_filter | TextureFilter | Texture filtering mode |
texture_repeat | TextureRepeat | Texture repeat mode |
material | Ref<Material> | Override material for draw commands |
use_parent_material | bool | Inherit material from parent |
clip_children_mode | ClipChildrenMode | Clip children to this item's bounds |
Sources: scene/main/canvas_item.h88-132
Refresh this wiki
This wiki was recently refreshed. Please wait 2 days to refresh again.