Object edges on selection
When a user picks an object, a clear way to confirm which object they hit is to outline it. Instead of a post-process outline shader, Twinfinity can extract the object's actual edges and draw them with its line renderer — crisp, screen-space lines that stay sharp at any zoom.
The pieces
There are three pieces to this:
loadProductEdges(product)pulls the object's edge segments. Each segment is a flat[x1, y1, z1, x2, y2, z2]in world space, the edges load asynchronously, and the result is cached per object.The line API (
api.lines) draws them.api.lines.add(slab)registers a set of segments and returns aLineHandle; aSegmentBuildercollects segments into the slab, and everything renders in a single instanced GPU draw.You add one handle up front, then on each pick replace its content with
setSlab. Reusing one handle means every new pick simply replaces the previous object's outline — no bookkeeping.
Picking and drawing the edges
Create the handle up front, then on a tap pick the object, load its edges, build
the segments, and hand them to the handle with setSlab:
import { PointerEventTypes } from '@babylonjs/core';
import { PickResultType, loadProductEdges } from '@twinfinity/core';
import { SegmentBuilder } from '@twinfinity/core/lines';
const outline = api.lines.add(new SegmentBuilder(0).finish(), { id: 'selected-edges' });
api.onPointerObservable.add((eventData) => {
// POINTERTAP fires only on a genuine tap, so a camera drag won't trigger a pick.
if (eventData.type !== PointerEventTypes.POINTERTAP) return;
const pick = eventData.twinfinity.pick(false);
if (pick.type !== PickResultType.IfcProductMesh) return;
void loadProductEdges(pick.ifcProductMesh.ifcProduct).then((edges) => {
const builder = new SegmentBuilder(edges.length);
for (const [x1, y1, z1, x2, y2, z2] of edges) {
builder.add({ start: [x1, y1, z1], end: [x2, y2, z2], color: [1, 0, 0], width: 2 });
}
outline.setSlab(builder.finish());
});
});The line width is in screen-space pixels, so the outline reads the same whether
you're zoomed out over a whole building or in close on a single fitting.
The handle is also how you take the outline away again — outline.visible = false
hides it, outline.remove() disposes it for good.
Try it in the playground: Object edges on selection.
See also
Understanding Pointer Events in Twinfinity — the picking this builds on.