Open faassen opened 3 years ago
So looking at debug dim2.rs
as it is now as an example of something that needs access to Rapier shape data, it works as follows:
it uses &BodyHandle
within the Bevy query along with &Body
to get a handle
Then handle.collider()
is used to get the Rapier collider
Then collider.shape()
is used to get the Rapier shape. This is a dyn
object.
Finally this shape is used in body_builder
to obtain as_convex_polygon()
and if this succeeds, to use points()
with into_bevy()
to get the Bevy points.
This logic is required for ConvexHull
but not for the other body types so far as the complete shape data is available in the original heron_core::Body
.
What do we expect for Heightfield (#62), Cylinder (#63) and Cone (#64)? It looks like those can be entirely defined upon creation, though I'm not entirely clear about what Heightfield
does yet.
So we could treat ConvexHull
as an exception.
On the other hand, both ConvexHull
, Cuboid
and potentially in the future also Triangle
all can be treated as polygons with a vector of points. Would it be possible to generalize this as a Points
component? Perhaps:
struct Points {
points: Option<Vec<Vec3>>
}
which defines Points
only if such exist, and this is updated upon startup automatically after the physics engine is done initializing. If we added an additional optional border_radius
field, we could support round cuboids, round triangles, and round_convex_hull as well. This would allow, at least in 2d, for more general debug code which can draw all of these as polygons.
Yeah, what I did for the ConvexHull (#60) was more a "work-around" than the actual solution to the present issue.
What do we expect for Heightfield (#62), Cylinder (#63) and Cone (#64)? It looks like those can be entirely defined upon creation, though I'm not entirely clear about what Heightfield does yet.
Yes, I think we'll have all information we needs in the definition of the Body
variant.
So we could treat ConvexHull as an exception.
Yes. Alghough I'm never fan of having exceptions, I don't think there is much way around it. If we create a generalized approach for polygons, then the sphere, capsule, cylinder and cone would become the exceptions.
On the other hand, both ConvexHull, Cuboid and potentially in the future also Triangle all can be treated as polygons with a vector of points. Would it be possible to generalize this as a Points component?
Although technially possible, and maybe even "nice" for the debug renderer, I'm not eager to add public component for this. The thing is the debug render is only a debug tool. Ideally, I would like to extend the API (public components/resources, etc.) only to support the physics manipulation. Otherwise, it may make stuff confusing. For instance what should happen if the user mutate that Points
component?
Anyway, it would be possible to have a general approach in the debug render without such component:
fn base_builder(body: &Body, shape: &dyn Shape) -> GeometryBuilder {
let mut builder = GeometryBuilder::new();
// Try to display a polygon if possible (ignoring the content of Body)
if let Some(polygon) = shape.as_convex_polygon() {
builder.add(&shapes::Polygon {
points: polygon.points().into_bevy(),
closed: true,
});
return builder;
}
// It wasn't possible to draw a polygon. Inspect the `Body` component:
match body {
Body::Sphere { radius } => ...
Body::Capsule { half_segment, radius } => ...
_ -> eprintln!("Some collision shapes couldn't be rendered")
};
builder
}
To be clear: I'm not concerned with the debug renderer. I have a non-debug renderer that also uses this information, so I'd like there to be a public API for this. I thought Heron is all about exposing the Rapier APIs in a more friendly way, integrated with Bevy?
In your example shape
still comes from Rapier (in fact, Parry!) and you need to get it in the complex way I described, and then use into_bevy()
. That's not a great easy to use API to get this information.
Note that your example is not generic in the way I describe with Points
, as I was proposing to let other things such as Cuboid have points too. as_convex_polygon
as far as I understand it, wouldn't work for Cuboid
or Triangle
. But having this be generic is a secondary concern; the primary one is having an API at all that doesn't require a lot of knowledge about Rapier.
If there is no way to get this information, I wonder whether we should support ConvexHull
at all in Heron. ConvexPolyline
would be better as this can be reliably drawn without having to introspect Rapier. But it wouldn't work for 3d, only 2d.
Concerning mutating a points component - I guess read-only components aren't a thing then in Bevy? It strikes me those would be useful if you're integrating Bevy with external systems like physics engines in general.
Another way would be to expose a resource to get the points data for a body or entity. Is there is a way to get from a heron Body to a Rapier/Parry Shape? Or would you have to go through entity?
To be clear: I'm not concerned with the debug renderer. I have a non-debug renderer that also uses this information, so I'd like there to be a public API for this.
Ah, ok. I misunderstood then. Sorry.
That of course invalidate my previous comment.
I think I would call the component ShapeData
, or something like that.
And if we are to expose the shape data, I would try to do it for every shape, not only for the polygons. Maybe we need some SVG-like API:
struct ShapeData {
path: Vec<ShapeSegment>
}
enum ShapeSegment {
LineTo(Vec3),
ArcTo(...)
}
To answer myself about mutability of the component we have to:
If we provided a way to create a Body from a Mesh
(in 3d) or a bevy_prototype_lyon's polygon (in 2d), would that fullfill your use-case @faassen? Or would you still need to access the shape data?
If there were a way to create a body from a bevy_prototype_lyon polygon (which then would be a convex_polygon instead of a convex hull?) then I think that would fulfill my use case and in fact reduce some duplication (as I stole the regular polygon code from bevy_prototype_lyon in the first place to create a regular Rapier polygon).
The SVG-like API to draw any shape sounds attractive in general but wouldn't be required for my use case.
Maybe we could introduce a Body::FromConvexPolygon
and Body::FromConvexMesh
variants to Body
. Probably behind appropriate feature flags.
And it would create a collider that is the convex-hull of the polygon/mesh component found on the same entity.
I'm not yet sure if that is a good or a bad idea. I will think more about it.
We have a use case where we want to access shape data in the renderer code. For instance, ConvexHull creates a set of points that defines the convex hull depending on the points you give it. It should be possible to access this data through a Heron API. This issue is to remind us to think about this.
In Rapier, once you have the shape, you can call this:
Where
as_convex_polygon
is a typecast and then points is the method that returns the points to draw.Do we want to expose some kind of typecast API that can fail like this or is there another pattern that would work better? I know absolutely nothing about the reflection system of Bevy, is that relevant?
We need a Heron version of a convex polygon, that exposes Bevy vectors instead of Rapier points.
See also #43 as a fallback on how to get to the Rapier world. This could be a quick way to implement it without any new Heron APIs for the debug renderer, but in the longer term it would be better to expose this information in some nice Heron API.