ForesightMiningSoftwareCorporation / bevy_polyline

Polyline Rendering for Bevy
https://crates.io/crates/bevy_polyline
Apache License 2.0
171 stars 43 forks source link

Feature request: Defining polyline starts and ends #20

Open piedoom opened 2 years ago

piedoom commented 2 years ago

Hey there - I'm building an L-system visualizer with bevy_polyline. With one component, I get great fps with a single polyline, even with complex shapes

image

However, the way that polyline is defined, I am unable to define start or end areas. To attempt to solve this on my own, I figured I could use child components whenever my L-system branched.

image

I did this by building a Vec<Vec<Vec3>> of lines, where each line would contain a new PolylineBundle. While it works, it is very slow. Looking at the docs, it appears there is 1 draw call per line which makes sense.

Is there a way to define multiple lines within a single PolylineBundle?

I am unsure if this is a goal of this crate, so I understand if this is not considered.

aevyrie commented 2 years ago

Hey, this is a cool use case.

I don't think implementing this would be particularly difficult, but I'm not sure the best way to do it without hurting performance in the current case.

Maybe we could define it something like

struct Polyline {
    vertices: Vec<Vec<Vec3>>
}

Where each entry in the outer vec is a contiguous polyline, then we could do something when we construct the vertex buffer to signal the end of lines. Would need to look into it.

As a short-term hack, what happens if you insert a point where you want a break in your line segments, but fill it with f32::NULL/INFINITY/NEG_INFINITY?

piedoom commented 2 years ago

Neat, the Null/Inf trick works like a charm, perfect for now! Thanks. I can still see the use case for my initial request but seeing as I can do what I needed, I'll let maintainers decide if this should stay open.

aevyrie commented 2 years ago

Wow, it actually worked 😆! That's good to know; I might be able to make use of that in an implementation. Let's keep this issue open in the meantime.

mtsr commented 2 years ago

Great idea, @aevyrie!

Degenerate triangles probably just get culled. It's not even a bad general solution, because I think the performance should be decent and it has the big upside of not needing any extra data in the buffer, which at least with updated polylines is the biggest bottleneck right now.

Actually it would also allow combining all polyline drawcalls into a single one. Where it becomes tricky is that if you have polylines that are updated often, you're forcing a full write of the complete buffer of all combined polylines. So maybe we can have like an optional BatchId that if 0 prevents batching completely and in other cases only batches with polylines with matching BatchId, or something.

mxgrey commented 1 year ago

To make the NaN trick more intuitive for users, it might be nice for bevy_polyline to provide something like a

const SEPARATE: Vec3 = Vec3::splat(std::f32::NAN);

so users can just

polylines.push(SEPARATE);

at each place where they want to start defining a new polyline.

One possible concern with the NaN trick is I wonder if the future joints and caps feature would get hosed when the buffer contains NaN values.

aevyrie commented 1 year ago

Ideally this would be an implementation detail that users would not see, and we would handle batching similar lines either by NaN separating, or by storing something like run length encoding. I have a branch that automatically batches polylines with the same material, but it needs more work.