← Back to Docs
  • index.html
  • Clayground
  • Clayground.Canvas3D
  • LabelBatch3D
  • Clayground 2026.2
  • LabelBatch3D QML Type

    Renders thousands of SDF text labels in a few instanced draw calls. More...

    Import Statement: import Clayground.Canvas3D

    Properties

    Methods

    Detailed Description

    LabelBatch3D draws very large sets of short text labels - tens of thousands - as instanced signed-distance-field glyphs, following deck.gl's TextLayer model: one GPU instance per glyph over a shared glyph atlas, so N labels cost one draw call for the glyphs (plus one for the optional pill backgrounds) rather than N items. Each label is a world-anchored point with its own text, color and size; glyphs stay crisp at any zoom because they are rendered from an SDF atlas, not a rasterized texture.

    LabelBatch3D is the mass-scale sibling of Label3D, not a replacement: rich per-label content, icons, leaders and per-frame billboard tracking stay Label3D's job. Reach for LabelBatch3D when you need many cheap, uniform text labels (data-point names, map features, particle tags).

    Feed it with the labels list or setLabels; move labels without re-shaping via updatePositionsBulk.

    Example usage:

    import QtQuick3D
    import Clayground.Canvas3D
    
    View3D {
        id: view
        LabelBatch3D {
            viewportSize: Qt.vector2d(view.width, view.height)
            sizeMode: LabelBatch3D.Screen
            halo: true
            labels: [
                { position: Qt.vector3d(0, 0, 0), text: "ALPHA", color: "#00d9ff", size: 22 },
                { position: Qt.vector3d(80, 0, 0), text: "BETA",  color: "#ff3366", size: 22 }
            ]
        }
    }

    Note: In Screen size mode the shader needs the View3D pixel size, so bind viewportSize to the enclosing View3D's width/height.

    See also Label3D, PathLabel3D, and LineBatch3D.

    Property Documentation

    ascentPx : real [read-only]

    Font ascent in atlas base pixels (for mapping a world text height onto setCurvedLabels sizes).


    atlasHeight : int [read-only]

    Current glyph-atlas height in texels.


    atlasWidth : int [read-only]

    Current glyph-atlas width in texels.


    batchOpacity : real

    Batch-wide opacity multiplier (0..1). Default 1.

    Named batchOpacity rather than opacity so it does not shadow the inherited Node opacity (which would fade the whole node tree instead of feeding the label shaders).


    capHeightPx : real [read-only]

    Font cap height in atlas base pixels.


    count : int [read-only]

    The number of labels currently in the batch.


    depthBias : real

    Shifts the glyph depth toward the camera (0..~0.001). Default 0.

    Positive values pull the rendered depth toward the near plane, the same sense as LineBatch3D.depthBias. Combined with writesDepth it lets ground-decal labels win the depth fight against a coplanar line they sit on. Default 0 leaves the built-in bias untouched, so an unset batch renders exactly as before.


    descentPx : real [read-only]

    Font descent in atlas base pixels.


    font : QtObject

    Grouped font config for the shared glyph atlas.

    Sub-propertyMeaning
    familyFont family (defaults to the platform monospace).
    weightFont weight (e.g. 400 normal, 700 bold).
    baseSizeAtlas rasterization size in px; higher is crisper when magnified but uses a larger atlas.

    Note: One atlas is baked per LabelBatch3D instance; changing any font sub-property clears and re-bakes it.


    glyphCount : int [read-only]

    The number of glyph instances currently drawn.


    halo : bool

    Whether glyphs get a halo outline for busy backgrounds. Default true.


    haloColor : color

    Halo color (a dark halo is the robust default on bright and dark).


    haloWidth : real

    Halo band width in SDF units past the glyph edge (0..0.5). Default 0.18.


    labels : list

    Declarative list of labels.

    Each element is an object { position: Qt.vector3d, text: <string>, color: <color>, size: <real>, priority: <int>, opacity: <real> }. Only position and text are required. For large generated sets prefer setLabels with a pre-built JS array.


    orientation : int

    The active orientation, one of the Orientation values. Default Billboard. Only applies in World size mode.


    pill : bool

    Whether a rounded background pill is drawn behind each label. Default false.


    pillColor : color

    Pill fill color (dark semi-transparent default).


    pillPadding : real

    Padding in base pixels between the text box and the pill edge.


    pillRadius : real

    Pill corner radius in base pixels.


    shapeMsLast : real [read-only]

    Wall-clock milliseconds spent shaping on the last setLabels.


    sizeMode : int

    The active size mode, one of the SizeMode values. Default Screen.


    viewportSize : vector2d

    The pixel size of the enclosing View3D.

    Required in Screen size mode to keep on-screen size constant. Bind it to Qt.vector2d(view3D.width, view3D.height).


    writesDepth : bool

    Whether inked glyph fragments write depth. Default false.


    Method Documentation

    list glyphAdvances(string text, real size)

    Per-code-point advance widths of text in world units at render size.

    Returns one advance per Unicode code point (spaces included), each equal to advanceBasePx * size / baseSize. PathLabel3D uses this to lay glyphs along a curve; missing glyphs are baked into the atlas first.


    list priorities()

    Returns the per-label priority values (for a future declutter manager). Priorities are stored and read back but not yet acted on.


    void setCurvedLabels(list labels)

    Sets pre-placed per-glyph labels (text-on-curve, maplibre's model).

    Each element is { text, color, size, opacity, positions: [vector3d per code point], angles: [real radians per code point] }. Every inking glyph is drawn at its own world anchor rotated by its angle (INSTANCE_DATA.z), so text can hug an arbitrary curve. This is the carrier behind PathLabel3D's glyphPlacement mode; no background pill is drawn in curved mode.


    void setLabels(list labels)

    Replaces the batch contents from a JS array (fast bulk path).

    Each element is an object { position, text, color, size, priority, opacity } (only position and text are required). Shaping runs once; shapeMsLast reports its cost.


    void updatePositionsBulk(ByteArray positions, int first)

    Moves labels without re-shaping.

    positions is a packed float32 buffer with 3 floats per label (x, y, z) in label order, applied starting at label first. Only the anchors are rewritten (glyph layout and UVs are untouched), so animating moving labels stays cheap.