I am using LineSystem to quickly render large amounts of lines. This can be 100K lines ranging from 2 points (straight line) to up to 32 points (curves). LineSystem is amazingly performant compared to CreateLines, however it does not allow me to define an ID to select individual meshes (e.g. via click events). LineSystem does create a unique faceId property that is returned in the pickInfo event object for each line/line segment, but I cannot reliably correlate that to individual lines in my rendering (at least based on how I have defined them).
I have experimented with invisible tubes/cubes over my lines, but this is still drastically affecting performance. I do like that it gives a larger âbounding boxâ over my lines on which to register click events, but some of my larger data sets will not render at all with this approach.
(Pick individual Lines from LineSystem?)
Does anyone have any tips on retaining the performance of LineSystem, while still offering a means to click and identify individual line segments?
I am not sure it would be possible to pick in 100k ârandomâ lines in a reasonable time to be at 60 fps. You would need some kind of octree like structure and so onâŚ
This is what I am afraid of, I just thought I may be overlooking a simple way to accomplish this. The engine is already creating unique âfaceIdâ values for each line/line segment, however since we pass in all the line data at once, I have no way of ensuring the order or correlating those values with what is actually rendered. Perhaps there is some way to manually create a mapping.
You should be able to this with decent performance via gpu picking.
There was a post a while back (GPU picking demo) that demos this (pg) for an instanced mesh.
Iâve modified that pg a bit to use an async version of readPixelshere, which improves performance somewhat (dramatically for some mobile/laptop gpus). This works for webgl2 only though, using engine._readPixelsAsync. It will however fallback to synchronous readPixels for webgl1.
You should be able to modify this method to work with the LineSystem - though picking may be a bit hard for 1px wide lines. In the past Iâve dealt with this by widening lines for picking (so pickable area is larger than visible line), but this wonât work for the LineSystem as it uses actual GL.Lines as opposed to triangles. The (fairly) new Greased Lines could be used, or tubes, if wider picking is needed.
Is there not a way to correlate the âfaceIdâ value from the pickInfo object to any information within the LineSystem mesh? Maybe via some mapping of the mesh indices? I feel like as long as the faceIds are deterministic with the input of CreateLineSystem, there has to be some way to accomplish this.
I realise this isnât at all what your last reply asked for, but I ended up making a pg that does gpu picking for a line system, and allows you to specify a pixel buffer around the mouse so each line doesnât have just a single pixel width to pick. It can also give you back the index into the original line array of the picked line.
Settings are at the top of the pg, currently set to 100k lines with each line having up to 4 vertices.
@sable I appreciate the response and detailed pg! That is above and beyond. Since my renderings are rather simple (just a ton of lines), I think it is overkill to leverage GPU picking and materials as youâve done here. If the project eventually evolves into something that can benefit this content, I am grateful to have it available. I ended up with just a âbrute forceâ linear solution to find the clicked vertex:
// find vertex closest to pickPoint
let index = 0;
let min = 10;
lines.forEach((line, i) => {
line.forEach((point, j) => {
const m = Math.min(min, BABYLON.Vector3.Distance(point, pickedPoint));
if (m < min) {
index = i;
min = m;
}
});
});
// idMap[index] holds my line ID
Elsewhere in the program I create a map to correlate the custom line IDs to the line array passed into CreateLineSystem.
It is an imperfect solution, because the closest vertex does not always fall on the clicked line. Any suggestions for refinement are welcome, but this is performant and accurate enough for now.
All good - it was a good exercise putting that pg together, and hopefully itâll prove to be a useful resource for future readers.
Going back to your previous thought of linking faceID to a line in a mesh, it sounds like a great idea, and actually seems to work well - see the below pg:
Should be a bit more performant as donât need to go back over the vertices calculating distances.
Thereâs also an intersectionThreshold property on the lineSystem, which can be used to increase picking area. This is in world units though, and will mean that closer (to the camera) lines are picked over those that a visually closer to the picked point (but further back in the scene).
Wow. I had something very close to this but couldnât quite get it working. I thought perhaps the faceId values were not generated in order and thatâs why it wasnât working. Looks like I just needed to use the âsubMeshFaceIdâ field from pickInfo (vs. faceId). TIL. Thanks again for everything!