Renders very large sets of styled polylines in a single instanced draw call. More...
| Import Statement: | import Clayground.Canvas3D |
LineBatch3D draws 100k+ polylines, each with its own color and width, as one instanced draw call. Every line segment becomes one GPU instance over a unit-quad base mesh; the vertex shader expands each segment into a camera-facing ribbon with round caps, and the per-line style rides in the instance attributes. This makes it suitable for map lanes, road overlays, flow fields and other cases where thousands of independently styled lines must be updated and drawn cheaply.
There are two ways to feed data:
Individual lines can be moved cheaply with updateLinePoints, which patches only that line's region of the instance table.
Example usage:
import QtQuick3D import Clayground.Canvas3D View3D { id: view LineBatch3D { viewportSize: Qt.vector2d(view.width, view.height) widthUnits: LineBatch3D.Pixel lines: [ { points: [Qt.vector3d(0,0,0), Qt.vector3d(100,50,0)], color: "#00d9ff", width: 3, styleId: 0 }, { points: [Qt.vector3d(0,0,0), Qt.vector3d(0,80,60)], color: "#ff3366", width: 5, styleId: 0 } ] } }
Note: In Pixel width mode the shader needs the View3D pixel size, so bind viewportSize to the enclosing View3D's width/height.
See also MultiLine3D, LineBatchInstancing, and LineBatchGeometry.
count : int |
The number of lines currently in the batch.
depthBias : real |
Pulls the lines toward the camera to win depth fights.
A positive bias shifts the rendered depth toward the near plane, so overlay lines floating just above other geometry (for example a lane model above roads) draw on top without a separate render pass. Defaults to 0.
flowAutoPlay : bool |
Convenience clock that advances flowTime automatically.
When true, an internal FrameAnimation drives flowTime so flowing and pulsing styles animate without any external clock. Defaults to false so a batch is never self-animating (Qt renders on demand); leave it off and drive flowTime yourself when you need to pause, timescale or inspect deterministically.
flowTime : real |
Animation clock (seconds) driving every flowing/pulsing style.
A single value shared by the whole batch: each style's flow scales it to march its pattern, and pulse oscillates its opacity from it. The batch never ticks itself (rendering stays on-demand); bind this to your own clock (typically a FrameAnimation's elapsedTime) or set flowAutoPlay to true for the built-in one. Set it explicitly for deterministic, frame-exact inspection.
lines : list |
Declarative list of styled polylines (convenience path).
Each element is an object { points: [Qt.vector3d, ...], color: <color>, width: <real>, styleId: <int> }. A polyline with N points produces N-1 segment instances sharing that line's style. For large generated data sets prefer setBulk.
opaque : bool |
Renders the batch as opaque geometry with early depth rejection.
When false (the default) the batch draws alpha-blended: a style's opacity multiplier applies and overlapping lines composite by draw order. When true the batch draws without alpha blending and with depth writes, so overlapping lines resolve by depth (the nearer line wins) instead of blending. This lets the GPU reject occluded fragments early and cuts overdraw where many opaque lines stack up (dense lane overlays, road networks).
Visual semantics in opaque mode:
opacity below 1.0 does not fade the line; the line draws fully opaque (dash gaps still cut out via discard, and round caps/joints are unchanged).Leave false for translucent or additive styling; set true for dense opaque overlays where depth-correct occlusion and lower overdraw matter more than per-line opacity.
orientation : int |
The active ribbon orientation, one of the Orientation values.
Defaults to LineBatch3D.Billboard. Only applies in World width mode.
styles : list |
Per-styleId table of pattern, cap shape, opacity and effects.
Each element is an object. Only dash / capRound / opacity are required; every other key is optional and defaults to the plain solid or dashed behaviour, so existing style lists keep rendering unchanged.
dash - [dashLen, gapLen] in world units ([0, 0] = solid). Also sets the repeat period for dot and chevron patterns.capRound - round caps when true (default), square when false.opacity - opacity multiplier (blended mode only).pattern - "solid"/"dash" (default), "dot" (round dots), "chevron" (V glyphs pointing from a line's start to its end) or "triangle" (filled isoceles direction glyphs, tip toward the end).glyphWidth - for the triangle pattern, the base width as a fraction of the ribbon width, range (0, 1]; 0 or absent means the full ribbon width. Ignored by the other patterns.patternUnits - "world" (default) or "screen": whether the pattern period is measured in world units or in screen pixels (zoom-stable, for HUD/overlay lines).flow - marches the pattern along the line; the on-screen speed is flow scaled by flowTime (0 = static, the default).glow - soft edge falloff across the ribbon instead of a hard edge (0 = hard, the default; ~0.3-1.0 for a neon look).pulse - opacity oscillation driven by flowTime (0 = none).head - [length, width] arrowhead at the line's flagged end(s), in multiples of line width; absent = no head. Drawn as a classic triangle with a real shoulder. The proportions are regulated so the head stays arrow-like whatever the request: width is clamped to [1.5, 8] (base is always wider than the shaft) and the effective length is min(request, 2 x head width, segment length), defaulting to ~1.1 x head width when length is 0 or invalid. On a segment shorter than the head the whole head scales down with its proportions preserved, so an over-large fill-the-segment length (e.g. 40) still yields a well-formed head rather than a needle. The tip sits exactly at the segment end and the diagonal edges are anti-aliased at every zoom (composes with glow and pulse).The table is baked into a small RGBA32F texture the shader samples per fragment; the pattern phase runs continuously along each polyline. Style index 0 always defaults to solid, round-capped and fully opaque, so lines work unchanged when styles is left empty.
Example:
styles: [ { dash: [0, 0], capRound: true, opacity: 1.0 }, // 0: solid { dash: [12, 8], capRound: false, opacity: 1.0 }, // 1: dashed { dash: [6, 34], pattern: "dot" }, // 2: round dots { dash: [10, 30], pattern: "chevron", flow: 40, glow: 0.5 }, // 3: flowing chevrons { dash: [0, 0], glow: 0.8, head: [3.0, 2.5] } // 4: glowing arrow ]
See also flowTime and flowAutoPlay.
viewportSize : vector2d |
The pixel size of the enclosing View3D.
Required in Pixel width mode to keep on-screen width constant. Bind it to Qt.vector2d(view3D.width, view3D.height).
widthUnits : int |
The active width interpretation, one of the WidthUnits values.
Defaults to LineBatch3D.Pixel.
real pathLength(int lineId) |
Returns the total length of line lineId in world units.
Read-only query over the batch geometry (0 for an unknown index or a line with fewer than two points). Together with positionAt this lets objects and labels ride along a line without duplicating its geometry.
vector3d positionAt(int lineId, real distance) |
Returns the point distance world units along line lineId.
The distance is clamped to the line, so 0 gives its first point and any value past pathLength gives its last. Unknown indices return Qt.vector3d(0, 0, 0).
void setBulk(ByteArray positions, ByteArray startIndices, ByteArray colors, ByteArray widths, ByteArray styleIds) |
Fast path for building the batch from packed binary buffers.
[startIndices[i], startIndices[i+1]).void updateEndpointsBulk(ByteArray positions) |
Rewrites the endpoints of every single-segment line in one pass.
positions is a packed float32 buffer with 6 floats per line (p0.xyz, p1.xyz) in line order. This is the fast per-frame path used by ConnectorLayer3D: it patches the affected instance entries in place and triggers a single upload, with no geometry rebuild. Lines that are not single-segment (two points) are skipped.
See also ConnectorLayer3D.
void updateLinePoints(int lineIndex, list points) |
Moves a single line by patching only its instance-table region.
Rewrites line lineIndex from points (a list of Qt.vector3d). When the point count keeps the same number of segments, only that line's entries are rewritten; otherwise the whole table is rebuilt.
void updatePolylinesBulk(ByteArray positions, int pointsPerLine) |
Rewrites the points of every uniform-topology line in one pass.
positions is a packed float32 buffer with pointsPerLine * 3 floats per line (p0.xyz, p1.xyz, ...) in line order. This is the fast per-frame path used by ConnectorLayer3D for curved connectors: it rewrites the matching lines' points and re-uploads once, recomputing per-segment path distances so patterns stay continuous along the new curve. Lines whose topology does not match (instanceCount != pointsPerLine - 1) are skipped.
See also ConnectorLayer3D.