Draw Order, Depth, and Blending
Draw order, depth, and blend modes.
2D
Shapes draw in the order they were queued, later on top: tree order for nodes, call order for a script.
A canvas has no depth buffer, so BLEND_TRANSPARENT_DEPTH behaves like
BLEND_TRANSPARENT.
3D
Shapes sort against other meshes in a scene by position, in every blend mode. Between geom shapes, the mode decides which one is on top:
| mode | writes depth | sorted by position |
|---|---|---|
BLEND_OPAQUE | yes | yes, with hard edges |
BLEND_TRANSPARENT_DEPTH | yes | shapes with alpha 1 |
BLEND_TRANSPARENT | no | no, draw order |
BLEND_ADDITIVE, BLEND_MULTIPLY, BLEND_SUBTRACT | no | no, draw order |
The default is BLEND_TRANSPARENT, which draws in call order, the same as
2D. For shapes that should sort by position, use
BLEND_TRANSPARENT_DEPTH with opaque colors. A translucent color in that mode
behaves like BLEND_TRANSPARENT.
BLEND_OPAQUE sorts by position too, but without anti-aliasing.
extends Node3D
func _process(_delta: float) -> void:
GeomDraw.reset_all_draw_states()
# Draw order wins.
GeomDraw.blend_mode = Geom.BLEND_OPAQUE
GeomDraw.cuboid_colored(Vector3(-3.05, 0.0, 0.0), Vector3(0.35, 1.6, 0.1), Color(0.55, 0.98, 0.78))
GeomDraw.blend_mode = Geom.BLEND_TRANSPARENT
GeomDraw.disc_colored(Vector3(-2.85, 0.15, 0.4), 0.5, Color(0.42, 0.85, 1.0))
GeomDraw.disc_colored(Vector3(-2.65, -0.2, -0.4), 0.6, Color(1.0, 0.78, 0.36))
# Position wins, with anti-aliased edges.
GeomDraw.blend_mode = Geom.BLEND_OPAQUE
GeomDraw.cuboid_colored(Vector3(-1.25, 0.0, 0.0), Vector3(0.35, 1.6, 0.1), Color(0.55, 0.98, 0.78))
GeomDraw.blend_mode = Geom.BLEND_TRANSPARENT_DEPTH
GeomDraw.disc_colored(Vector3(-1.05, 0.15, 0.4), 0.5, Color(0.42, 0.85, 1.0))
GeomDraw.disc_colored(Vector3(-0.85, -0.2, -0.4), 0.6, Color(1.0, 0.78, 0.36))
# Draw order wins. Translucent shapes do not write depth.
GeomDraw.blend_mode = Geom.BLEND_OPAQUE
GeomDraw.cuboid_colored(Vector3(0.55, 0.0, 0.0), Vector3(0.35, 1.6, 0.1), Color(0.55, 0.98, 0.78))
GeomDraw.blend_mode = Geom.BLEND_TRANSPARENT_DEPTH
GeomDraw.disc_colored(Vector3(0.75, 0.15, 0.4), 0.5, Color(0.42, 0.85, 1.0, 0.6))
GeomDraw.disc_colored(Vector3(0.95, -0.2, -0.4), 0.6, Color(1.0, 0.78, 0.36))
# Position wins, with hard edges.
GeomDraw.blend_mode = Geom.BLEND_OPAQUE
GeomDraw.cuboid_colored(Vector3(2.35, 0.0, 0.0), Vector3(0.35, 1.6, 0.1), Color(0.55, 0.98, 0.78))
GeomDraw.disc_colored(Vector3(2.55, 0.15, 0.4), 0.5, Color(0.42, 0.85, 1.0))
GeomDraw.disc_colored(Vector3(2.75, -0.2, -0.4), 0.6, Color(1.0, 0.78, 0.36))
using Godot;
public partial class Depth : Node3D
{
public override void _Process(double delta)
{
Geom.Draw.ResetAllDrawStates();
// Draw order wins.
Geom.Draw.BlendMode = Geom.BlendMode.Opaque;
Geom.Draw.CuboidColored(new Vector3(-3.05f, 0.0f, 0.0f), new Vector3(0.35f, 1.6f, 0.1f), new Color(0.55f, 0.98f, 0.78f));
Geom.Draw.BlendMode = Geom.BlendMode.Transparent;
Geom.Draw.DiscColored(new Vector3(-2.85f, 0.15f, 0.4f), 0.5f, new Color(0.42f, 0.85f, 1.0f));
Geom.Draw.DiscColored(new Vector3(-2.65f, -0.2f, -0.4f), 0.6f, new Color(1.0f, 0.78f, 0.36f));
// Position wins, with anti-aliased edges.
Geom.Draw.BlendMode = Geom.BlendMode.Opaque;
Geom.Draw.CuboidColored(new Vector3(-1.25f, 0.0f, 0.0f), new Vector3(0.35f, 1.6f, 0.1f), new Color(0.55f, 0.98f, 0.78f));
Geom.Draw.BlendMode = Geom.BlendMode.TransparentDepth;
Geom.Draw.DiscColored(new Vector3(-1.05f, 0.15f, 0.4f), 0.5f, new Color(0.42f, 0.85f, 1.0f));
Geom.Draw.DiscColored(new Vector3(-0.85f, -0.2f, -0.4f), 0.6f, new Color(1.0f, 0.78f, 0.36f));
// Draw order wins. Translucent shapes do not write depth.
Geom.Draw.BlendMode = Geom.BlendMode.Opaque;
Geom.Draw.CuboidColored(new Vector3(0.55f, 0.0f, 0.0f), new Vector3(0.35f, 1.6f, 0.1f), new Color(0.55f, 0.98f, 0.78f));
Geom.Draw.BlendMode = Geom.BlendMode.TransparentDepth;
Geom.Draw.DiscColored(new Vector3(0.75f, 0.15f, 0.4f), 0.5f, new Color(0.42f, 0.85f, 1.0f, 0.6f));
Geom.Draw.DiscColored(new Vector3(0.95f, -0.2f, -0.4f), 0.6f, new Color(1.0f, 0.78f, 0.36f));
// Position wins, with hard edges.
Geom.Draw.BlendMode = Geom.BlendMode.Opaque;
Geom.Draw.CuboidColored(new Vector3(2.35f, 0.0f, 0.0f), new Vector3(0.35f, 1.6f, 0.1f), new Color(0.55f, 0.98f, 0.78f));
Geom.Draw.DiscColored(new Vector3(2.55f, 0.15f, 0.4f), 0.5f, new Color(0.42f, 0.85f, 1.0f));
Geom.Draw.DiscColored(new Vector3(2.75f, -0.2f, -0.4f), 0.6f, new Color(1.0f, 0.78f, 0.36f));
}
}

Blending
BLEND_ADDITIVEadds this color to what is behind.BLEND_MULTIPLYmultiplies what is behind by this color.BLEND_SUBTRACTsubtracts this color from what is behind.
extends Node2D
func _process(_delta: float) -> void:
GeomDraw.reset_all_draw_states()
var cyan := Color(0.42, 0.85, 1.0)
var amber := Color(1.0, 0.78, 0.36)
GeomDraw.disc_2d_colored(Vector2(70, 170), 50.0, cyan)
GeomDraw.disc_2d_colored(Vector2(120, 170), 50.0, amber)
GeomDraw.disc_2d_colored(Vector2(230, 170), 50.0, cyan)
GeomDraw.blend_mode = Geom.BLEND_ADDITIVE
GeomDraw.disc_2d_colored(Vector2(280, 170), 50.0, amber)
GeomDraw.blend_mode = Geom.BLEND_TRANSPARENT
GeomDraw.disc_2d_colored(Vector2(390, 170), 50.0, cyan)
GeomDraw.blend_mode = Geom.BLEND_MULTIPLY
GeomDraw.disc_2d_colored(Vector2(440, 170), 50.0, amber)
GeomDraw.blend_mode = Geom.BLEND_TRANSPARENT
GeomDraw.disc_2d_colored(Vector2(550, 170), 50.0, cyan)
GeomDraw.blend_mode = Geom.BLEND_SUBTRACT
GeomDraw.disc_2d_colored(Vector2(600, 170), 50.0, amber)
using Godot;
public partial class Blending : Node2D
{
public override void _Process(double delta)
{
Geom.Draw.ResetAllDrawStates();
var cyan = new Color(0.42f, 0.85f, 1.0f);
var amber = new Color(1.0f, 0.78f, 0.36f);
Geom.Draw.Disc2DColored(new Vector2(70, 170), 50.0f, cyan);
Geom.Draw.Disc2DColored(new Vector2(120, 170), 50.0f, amber);
Geom.Draw.Disc2DColored(new Vector2(230, 170), 50.0f, cyan);
Geom.Draw.BlendMode = Geom.BlendMode.Additive;
Geom.Draw.Disc2DColored(new Vector2(280, 170), 50.0f, amber);
Geom.Draw.BlendMode = Geom.BlendMode.Transparent;
Geom.Draw.Disc2DColored(new Vector2(390, 170), 50.0f, cyan);
Geom.Draw.BlendMode = Geom.BlendMode.Multiply;
Geom.Draw.Disc2DColored(new Vector2(440, 170), 50.0f, amber);
Geom.Draw.BlendMode = Geom.BlendMode.Transparent;
Geom.Draw.Disc2DColored(new Vector2(550, 170), 50.0f, cyan);
Geom.Draw.BlendMode = Geom.BlendMode.Subtract;
Geom.Draw.Disc2DColored(new Vector2(600, 170), 50.0f, amber);
}
}

Cost
Each blend mode is a separate shader program and a separate draw call. Alternating blend modes between shapes splits the batch; see the performance guide.