@bitruvius/point-symbols
v0.3.1
Published
Bitruvius point-symbol renderer: instanced icon/billboard quads (sprite atlas, screen-space sizing, RGBA8UI picking) for I3S Point-feature symbology, in the shared ENU frame
Readme
@bitruvius/point-symbols
One instanced WebGL2 draw path for every screen-facing symbol in a 3D scene: icons, markers and text labels.
Internal building block. This package exists so that
@bitruvius/sdk-maplibreand the Bitruvius codecs can resolve their dependencies on npm. It has no standalone product story. Unless you are deliberately building against it, install the SDK instead.
Why it is its own package
The renderer has to draw an I3S Point layer's drawingInfo icons, but it must not know what I3S is.
Its entire input contract is a sprite atlas: one RGBA image plus a symbol table of atlas sub-rects,
on-screen sizes, tints and rotations, indexed by a per-feature symbolId. Nothing in that shape
names a service, a format or a map.
That decoupling is what lets unrelated callers share one draw path. An I3S layer builds an atlas from
drawingInfo sprites, a label pass rasterises text into cells as tiles stream in, and an application
can hand over its own icon sheet. All three get the same instanced quads and the same picking. If the
renderer lived inside the I3S package, the label and marker paths would have to depend on I3S in
order to draw a quad.
It depends only on @bitruvius/geo-core (the shared ENU frame and the packed tile type) and
@bitruvius/render-runtime (GL plumbing). It takes a WebGL2RenderingContext and a matrix, not a
map, so it stays viewer-agnostic.
What is in it
PointBillboardRenderer draws many tiles of screen-facing quads from one shared atlas. Positions ride
a PackedPointTile unchanged and are dequantized in the vertex shader (world = q·scale + offset),
so a streaming engine uploads its integer buffers with no repacking.
const r = new PointBillboardRenderer(gl);
r.setAtlas(atlas); // BillboardSpriteAtlas, once
const h = r.upload(tile, symbolIds, featureIds);
// per frame:
r.render({ mvpWorld, viewportWidth, viewportHeight, devicePixelRatio }, [h]);
// on click:
const hit = r.pick(frame, [h], cssX, cssY);
// on tile eviction / teardown:
r.release(h);
r.dispose();The decisions worth knowing about:
- Alpha-tested opaque, never blended. Fragments below the cutoff are discarded and the rest write depth, so billboards z-buffer correctly against mesh, point clouds and splats with no global back-to-front sort.
- Screen-space sizing. Symbol sizes are CSS px, scaled by device pixel ratio and a global
sizeScale, applied after projection and divided byclip.w, so a symbol keeps its pixel size at any depth. - Labels as well as icons.
anchorBottomseats a quad above its point instead of centring it on the point,marginPxfloats it a few pixels higher, and the anchor offset is not rotated, so labels stay upright while icons still rotate with a per-feature heading. - GPU picking.
pick()renders ids into anRGBA8UItarget scissored to a small box around the cursor and reads back one texel. Transparent texels do not pick. A hit reports the tile handle, the index within that tile, the feature's ENU position in metres, the symbol id, and thefeatureIdyou joined at upload. - Nothing draws as NaN.
packBillboardInstancesis pure and unit-tested without a GL context; asymbolIdoutside the table falls back to symbol 0, or to a 16 px white quad if the table is empty.
One constraint to plan around: upload bakes the atlas sub-rect into each instance buffer. Growing an
atlas reflows its cells, so resident tiles must be re-uploaded against the new one.
Who should depend on it
Almost nobody directly. Install @bitruvius/sdk-maplibre:
its I3S Point layer wires this renderer for icon and label symbology, BillboardInstancesLayer places
your own atlas at a set of lng/lat points, and the SDK re-exports BillboardSpriteAtlas,
SymbolEntry and BillboardPickHit so you can build an atlas without adding this package to your
dependencies.
Depend on it directly only when you drive WebGL2 yourself and want the same billboard pass inside your own renderer.
Trademarks
Esri, ArcGIS and I3S are trademarks of Environmental Systems Research Institute, Inc. MapLibre is a trademark of the MapLibre organization. All other marks are the property of their respective owners.
These names are used solely to describe the data formats this software interoperates with. Bitruvius is not affiliated with, sponsored by, or endorsed by any of them, and no such relationship is implied.
License
Proprietary. The full terms ship as LICENSE inside this package, and are readable
before installing at cdn.bitruvius.com/legal/sdk-license-v1.txt.
© Bitruvius, Inc.
