geom

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:

modewrites depthsorted by position
BLEND_OPAQUEyesyes, with hard edges
BLEND_TRANSPARENT_DEPTHyesshapes with alpha 1
BLEND_TRANSPARENTnono, draw order
BLEND_ADDITIVE, BLEND_MULTIPLY, BLEND_SUBTRACTnono, 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));
    }
}

depth

Blending

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);
    }
}

blending

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.