#Avian Physics
1 messages · Page 2 of 1
About the rotations, what I want to do is take some arbitrary angle (the angle between player and mouse pointer) and just set the Rotation to that angle. I know the rotations work because I can do add_assign and add some degrees per second, but there is something I am not getting here. So, how would I most conveniently do that?
Basically, how do I do a "rotate_to"?
2.0 doesn't have that functionality, only the main branch does
Ah, I get it. Gotta get on that main branch, ASAP
Don't worry about the rotations, unless you've got a really good idiomatic example on how to do it; I managed to figure it out.
Transform::look_at would probably work
If you want an entity to just "look at" the mouse position
Yeah, I think so, but I screwed up what forward(), up() etc actually were... So I did it using rotation and some lerping.
Yeah up should generally be just Vec3::Y but that works as well
Btw this sounds related to the increasing load:
https://github.com/dimforge/rapier/issues/466
I can try if a full update instead of update_incremental would fix it when I have time, although I would expect it to be slower in general
Ofc it's a known bug 🙃 ... Only workarounds I can imagine are full update or doing a full update every Xth update
I'm not sure how much difference full makes compared to incremental when everything is always moving and there's those weird issues with rebalance 🤔
where can I schedule moving the camera? normally, I would put it in Update but I need to put it in PostUpdate so it can run after physics. I tried this but it causes jitter:
.add_systems(
PostUpdate,
transform_camera
.after(TransformSystem::TransformPropagate)
.before(CameraUpdateSystem),
);
i have a serialization/float accuracy question about bevy_xpbd's Rotation component..
my Position x,y stuff is syncing up fine - deterministically. since the full precision f32 values of x and y are sent over the wire.
When it comes to Rotation, the sin and cos fields of the struct are private, so i'm sending using Rotation::from_radians and Rotation::to_radians.. but this is giving me slight discrepencies between server and client, because i'm losing precision. (sending radians: f32 instead of cos: f32 and sin: f32)
One solution is to add Rotation::from_sin_cos() constructor. Then i could serialize and deserialize with full precision. Is that something you'd accept a patch for jondolf?
/// Creates a [`Rotation`] from sine and cosine
pub fn from_sin_cos(sin: Scalar, cos: Scalar) -> Self {
Self { sin, cos }
}
However, alternatively perhaps there's a way to quantize my simulation on both server and client so float accuracy isn't an issue.. anyone tried this? would probably cause other bugs in the physics code i guess
Welcome any suggestions!
if i patch in that constructor i can send rot.sin() and rot.cos() over the wire and reconstruct accurately, will give that a try.
yeah that works fine.. quantizing is premature i suppose, i can spare the few extra bytes to send position accurately heh
Yeah a method like this would be fine
You can make a PR if you have time, I probably can't today at least
Oh didn't notice, thanks :)
Hello ! I' m trying to replicate the behavior of the gear train of a watch and I have a weird behavior at some point :
In this video you can see that I have some extreme jittering when there too many gears connected. At some point, I remove the last gear collider and everything runs extremely smoothly.
Do you know what could cause these jittering ? My guess was the last gears rotate too fast, so I should increase the substeps (in the video, there are at 30) , but it actually make the simulation worse
On the plot you can see the actual evolution of the rotation for the two first gear of the wheel train, and without the last gear, it is a perfect straight line which is quite impressive !
@undone oyster Looks really cool! It's hard to tell what the problem is based on the video, but it could maybe be related to numerical imprecision at high speeds, or it could be related to collision instability https://github.com/Jondolf/bevy_xpbd/issues/93.
If the centers of masses are offset (not zero), it could also be https://github.com/Jondolf/bevy_xpbd/issues/108.
You could maybe try with the f64 feature (no default features) and with many substeps to see if it's a number precision issue. You might have to change some types to e.g. DVec3 instead of Vec3 though
thanks a lot, will try to switch to f64 and increase the substep. I'll keep you posted!
All the colliders are convex colliders, i generate a convex hull for each tooth of each gear at setup and then use the compound feature to join them
Again it is remarkably stable until the last gear, much better than any other simulation engine I've tested.
Is CameraUpdateSystem configured to run after TransformPropagate or physics, or can it run at any time during PostUpdate? If the order is ambiguous, it could sometimes run before physics, which could make your transform_camera system sometimes run before physics as well
It can run at any time in PostUpdate. Wouldn't CameraUpdateSystem run after physics because I run my system after TransformPropagate?
I don't think I actually need to run it before CameraUpdateSystem. It just appears to update the camera's projection when the viewport size changes.
I managed to fix it: https://discord.com/channels/691052431525675048/1143726581362204672
Hello again, just a follow up from my previous question, I'm still having instability issues and I managed to isolate the problem with the last two gears. If I zoom in at the contact zone, I have an explosive reaction on the small pinion as shown in the video.
I've tried to play with the restitution parameter but couldn't see any visible difference. Also I switched to f64 precision but again, no visible difference.
Hmm, hard to say what's causing it without a local repro. Did you try setting both restitution and friction to zero, either for all cogs or just for the small one using CoefficientCombine::Min? I doubt it's that though
*pinions
I suppose I could also experiment locally a bit if you're fine sharing the project via DM or something
Thanks ! Sending you a DM 🙂
i switched from using 0.2 (with a couple of patches) to main for my 2d thing, and now my triangle collider passes through my wall (a rectangle collider). it behaved correctly with 0.2.. i don't think i changed anything else. any ideas what might be going on?
OK, so say I have a bunch of entities, with some components defining "what" they are, players, enemies, bullets. Players shoot bullets at enemies and vice-versa. I have some collision layers to illustrate this as well, of course. So I then set up my little collision event-listening system where I can get a nice little iterator over all the collisions. Every contact has two entities. I need to figure out which is which of all of these. No problem, I could just have some queries for that, including their health components, score components and other necessary stuff, buuuut this is just three different types of entities, right now. I see a horrible mess of if let Ok(c1, c2, c3) = query_for_player(entity1) type of queries to figure out which entity is which and what type each entity is. What would be the "most conventient" way of doing this? I'm very new to Rust and Bevy so maybe there is something here I'm missing.
I think I will use query.contains to work this into something usable.
Oh, I kind of like rust - I can do this: let (bullet_entity, other_entity) = if bullet_query.contains(contact.entity1) { (&contact.entity1, &contact.entity2) } else { (&contact.entity1, &contact.entity2) };
I realize the code is wrong, but still - this makes it easier to do what I wanted. I will now stop spamming this channel, no one seems to be awake anyways.
i'm not sure if it's better or not, but you can use 1 query with eg Option<&Bullet> in your query, then check if it .is_some() or .is_none()
quite common to filter queries for specific marker components (ie components that don't really have data), eg: Query<(&Whatever,..), With<Player>> or With<Bullet> etc
asteroids_q: Query<Entity, With<Asteroid>>,
bullets_q: Query<(Entity, &Geid), With<Bullet>>,
What I did was that I caught all the contactstarted events, sorted out what type of collision they were and sent my own events, so they ended up being just queries for the marker components like so: player_query: Query<&Player>,´´´boid_query: Query<&Boid>,
bullet_query: Query<&Projectile>,
wall_query: Query<&Wall>,
OK, I am sorry for the poorly formatted code.
And then I did if bullet_query.contains(*entity1) || bullet_query.contains(*entity2) {
to check if this was indeed a collision with a bullet and worked from there... I don't think I have grasped the query system 100% yet.
I'll probably get back to that snippet of code again later.
Instead of using an Option<Something> and .is_none(), it can be nicer to use Has<Something> which returns a boolean directly
i mean, doesn't seem unreasonable as a first version. i do that sort of thing in various places. i wouldn't try and get too fancy unless you have evidence it's a bottleneck 🤷♂️
ah yes Has is better if you don't need the component value
OK, neat, I'll check that out in the docs. Thx!
But how do I use that when I have two given entities, already?
you'll need to do query.get(entity1) and .get(entity2) i believe, to check them both. either could be a bullet or whatever
so you might have
q: Query<(Has<Boid>, Has<Projectile>, Has<Wall>)>,
...
if let Ok((is_boid, is_projectile, is_wall)) = q.get(contact.entity1) {} ... // same for entity2
Or get_many to get both
Oops referenced wrong message lmao
ah yes get_many i should use that.. i'm still fairly new to all this too heh
Also I'm not exactly sure what's going on here, I haven't seen bodies phasing through each other like this on main. Making the wall thicker might help
I'm pretty busy with school for quite a while so I might not have much time but if I do, I can test if I can repro
Could be related to the contact manifold or narrow phase changes that were made some time ago but I don't see why it would cause this
np. I will switch back to main again soon and dig deeper. will make a test case for you if i can repro something useful. entirely possible i was doing something daft too.
is there a way to get the velocity at a point of a rigid body? i had a look on rigidbody and linearvelocity but didn't see any methods there
point velocity = linear velocity + angular velocity.cross(point - center of mass)
but I don't know if there is a specific method for it
@crystal cosmos ^
There's no method currently but it should be very easy to add
LinearVelocity and AngularVelocity are separate components though so users would have to manually pass the angular velocity and center of mass
is there a specific way to run the tests to avoid them failing with left = 9.700001 right = 9.7 and related floating point issues? i just ran cargo test (on mac m1) after making a seemingly innocent change.
They should prob be using approx or similar
Yeah assert_relative_eq! from approx should be used for tests with floating point issues, most of our tests should use it already but I might've missed some
I don't have a Mac so the tests work for me
ah, thanks. will swap any you missed until it passes on m1
I am silly and just realized I said angular velocity.dot(point - center of mass) which doesnt make sense lol
Am I using cast_ray wrong 😅
spatial_query.cast_ray(
p.translation + w,
p.down() * 1.0,
0.5,
true,
SpatialQueryFilter::default().without_entities([e]),
)
thread 'main' panicked at 'Matrix index out of bounds.', /Users/choc/.cargo/registry/src/index.crates.io-6f17d22bba15001f/parry3d-0.13.5/src/query/clip/clip_aabb_line.rs:141:13
14: bevy_xpbd_3d::plugins::spatial_query::system_param::SpatialQuery::cast_ray
at /Users/choc/.cargo/git/checkouts/bevy_xpbd-87d8ac3552aaa63b/d9d50bc/crates/bevy_xpbd_3d/../../src/plugins/spatial_query/system_param.rs:149:9
Thanks for your help aceeri ^_^ worked
Looks fine, did you find the issue yet? Also * 1.0 seems a bit redundant 🤔
Nah didn't find it, something to do with adding forces in certain directions 🤷
Just want to make sure it's evaluated properly
Hmmm, all I can think of is either of the values becoming NaN or p.down() being 0, otherwise you shouldn't get an out of bounds 🤔
(i'm having a go at changing parry so that SharedShape implements PartialEq btw)
there are a couple of shape types i'm not sure what to do with, like heightfields
I mean you can compare heightfields, but that's not the most efficient operation 🤔
I guess you could compare all the heights (not very efficient) and leave it up to sebcrozet to decide if that's fine or if it should just always return false or something
for TypedShape::Custom I think it's fine to always return false since you just can't know the shape in advance
I'm guessing that shapes like these are the reason SharedShape already doesn't impl PartialEq though so idk if it'll get accepted
could add a note on comparison performance of some shapes in the docs I suppose
yeah i'm not sure if it will either. i think with custom you'll know if you're using custom shapes, and can do a separate equality check
i think the other eq implementations are correct, none of them seem inefficient except heightfield, which i've left alone for now
For TriMesh, is it enough to compare indices? Shouldn't it iter and compare trimesh.triangles()?
hmm, yes it should probably compare triangles. will change it. i've only ever done 2d stuff so a bit clueless
You need to check both yea
or yeah TriMesh seems to have .vertices() so you can use that as well
impl PartialEq for TriMesh {
fn eq(&self, other: &Self) -> bool {
let triangles = self.triangles();
let other_triangles = other.triangles();
if triangles.len() != other_triangles.len() {
return false;
}
for (t1, t2) in triangles.zip(other_triangles) {
if t1 != t2 {
return false;
}
}
true
}
}
oh wait yes can't i just check if indices and vertices match
with .triangles() idk if it guarantees that indices match
if yes, you can use that, but otherwise check separately
They would technically be different if they didn't match ... But the same triangles in the same order could be considered the same shape 🤔
i've pushed the comparing triangles version for now
I think they'd be different because Triangle is this
#[derive(PartialEq, Debug, Copy, Clone, Default)]
#[repr(C)]
pub struct Triangle {
/// The triangle first point.
pub a: Point<Real>,
/// The triangle second point.
pub b: Point<Real>,
/// The triangle third point.
pub c: Point<Real>,
}
and the points are given by indexing into vertices
but yeah thanks for making the PR, we'll just have to wait and see if it gets accepted
I would probably be fine with adding it for bevy_xpbd regardless
cool, well it would be neater to push it down into parry so let's see..
i can progress with my patch locally that adds it to bevy_xpbd for now
Hello, I am trying to add bevy_xpdb to my project. I am testing on two cubioid entities, one static, one kinematic and both have collider component. I have added PhysicsPlugins, but I get no collision responses, only collision events. Is there something more that I need to do?
Dynamic bodies are similar to real life objects and are affected by forces and contacts.Kinematic bodies can only be moved programmatically, which is useful for things like character controllers and moving platforms.
Static bodies can not move, so they can be good for objects in the environment like the ground and walls.
Ok, thank you. I read that in documentation, yet I though that kinematic bodies would still not be allowed to intersect with other physics entities.
does anyone know if it would be possible to implement the collide and slide algorithm for kinematic bodies or do you need to use shape casting?
bevy_xpbd doesn't have a built-in character controller yet, but yeah it should definitely be possible to implement collide and slide for kinematic bodies. Afaik collide and slide uses shape casts, which we do support
this is a pretty good video on collide and slide
https://youtu.be/YR6Q7dUz2uk?si=krv4akOiD5vuPkSq
How to make actually decent collision for your custom character controller. Hopefully you find this helpful and people will finally stop saying "jUsT uSe DyNaMiC rIgIdBoDy!!!1!!11!!"
Chapters:
00:00 - Intro
01:09 - Algorithm
05:11 - Implementation
Improved Collision detection and Response (Fauerby Paper):
https://www.peroxide.dk/papers/collisi...
I saw that, I was just wondering if it was possible to implement a similar quality character controller without shapecasts
I'll go with shape casts for now though
There's a very basic kcc example that doesn't use shape casts for collisions and instead does simple collision resolution by just pushing the bodies apart
https://github.com/Jondolf/bevy_xpbd/blob/main/crates/bevy_xpbd_3d/examples/basic_kinematic_character.rs
so I suppose you could test that
it's not quite "collide and slide" in the same way though
Is there a way to get more accurate colliders from a mesh than via convex_decomposition_from_bevy_mesh
it's not exposed in the API yet but parry has VHACDParameters which controls the quality of the convex decomposition
you could make an extension trait to add this for Collider:
pub fn convex_decomposition_from_bevy_mesh_with_params(mesh: &Mesh, params: parry::VHACDParameters) -> Option<Self> {
let vertices_indices = extract_mesh_vertices_indices(mesh);
vertices_indices.map(|(v, i)| SharedShape::convex_decomposition_with_params(&v, &i, ¶ms).into())
}
the name is so long that I'll probably end up making a from_mesh method that takes in e.g. ComputedColliderType that determines if it's a trimesh, convex decomp or convex hull and has the extra parameters
What if the mesh is supposed to be the collision shape, is there a way to use the mesh itself as opposed to a decomposition
probably a convex hull but I don't have generation from mesh implemented for them yet
or a trimesh, but they're more prone to clipping issues since they don't have insides
Oh building a trimesh from the vertices & indices of the mesh worked perfectly
still working on getting the camera to chill but getting there 🚙
zoom zoom 🏎️
wroom wroom
is the track hand made or do you have some system that generates it from e.g. a list of points and track widths?
a year ago I was experimenting with a track system that used interpolation to make smooth tracks from some points
I made it in blender in 30 seconds, it's atrocious. I would like to try generate a track but I'm trying not to get caught in that rabbit hole for now xD
yeah 😆
a modular track system like in Trackmania would be pretty cool as well
if you don't need it to be fully organic
Yea.. the dream. It there was some blocks I could make as a blender file people could snap them together and just load the gltf into the game. budget track builder 😄
I also don't know how to use blender, all I know how to do is extrude and rotate
I'm sure there's a better way to proportionally rotate things along some axis to achieve this effect for real
is one of the existing bevy_xpbd_2d joints suitable for what i want? i'd like to fire a grappling line between my 2d ship and an asteroid. i want to be able to rotate and fly my ship around to drag the asteroid. i have a spatial_query doing a cast_ray to identify an asteroid behind the ship within range. not sure if any of the joint types are suitable.
DistanceJoint allows you to choose a given rest distance or a range for min/max distance
compliance is the inverse of stiffness that controls how hard or springy the joint is, 0 is perfectly stiff
i see joints::DistanceLimit, but that's not a component so can't insert it directly. i'm on 0.2 atm
ah main only?
Ah, it's on main. But you can copy the file and add the joint locally, I'll pull up links
maybe time to switch back to main.. looks like there are a slight differences in the Joint trait too
Add this somewhere: https://github.com/Jondolf/bevy_xpbd/blob/main/src/constraints/joints/distance.rs
And register the joint like this:
let substeps = app.get_schedule_mut(SubstepSchedule)
.expect("add SubstepSchedule first");
substeps.add_systems(
solve_constraint::<DistanceJoint, 2>.in_set(SubstepSet::SolveUserConstraints)
);
Still on 0.2? That's quite a brave decision. I feel like we've had hunderds of bug fixes since 0.2 😂
method local_anchor_1 is not a member of trait Joint .. i'll just switch to main. i have a few patches locally need to make sure i have them on my main fork too
thinkgs like randomly adding derive(Reflect) to stuff because i want to use the egui inspector to twiddle settings for testing etc
Lmao I should probably release 0.3, there's just so many things that are kinda done and that I'd like to add
would be nice to get a 0.3 yeah, even if you have to omit certain things
Tracking main on bevy_xpbd has luckily been pretty easy. I only use main on two crates, bevy_xpbd and bevy_hanabi. Both tend to get really big features/fixes shortly after any release
Watch 0.3 release and then the next day we have a PR to fix determinism 😂
note: there are probably other determinism issues
Since it's not deterministic on the same platform yet there's definitely more stuff yea
We kinda need to figure out a repro for that tho 🤔
yeah I'm working a bit with Johan on it since he has desyncs as noted here #showcase message
I have desyncs reproing when simulating lag using a program called clumsy
hard to tell if it's the physics or issues with rollback tho
I think in my game I at some point I ironed out all the issues from the prediction, but it still desynced after a long time
I wonder if it's cause in my case the deviations tend to cancel out, instead of add up and drift over time
is there a way to have the local_anchor rotate with the entity? i want the grapple to come out the back of the ship. i can add a system to do that i suppose
ah, now i'm on main i will switch to the debug renderer. i was rendering it myself
or do you mean that the entire joint (both "anchors") should be in line with the body, i.e. the attached asteroid will rotate with the ship
i just mean the line should be attached to the rear of my ship (and center of the asteroid is fine for now). here's what i'm rendering myself
i'm doing .with_local_anchor_1(Vec2::Y * -20.0) to account for the size of the ship, so the line attaches 20px below it
maybe i'm just rendering wrong, will switch to debug renderer
working for me
hard to tell the colors but pink is from center of mass to anchor and red is from anchor to anchor
Why does that simulation look so weird? It almost looks like the bottom one is also anchored at the edge 🤔
No wait are they both at the edge?
the bottom one is attached from the corner
is that from one of the examples?
yep
yeah with debug renderer the anchor point looks fine
it looks a bit wobbly because in the initial state both bodies are upright but the bottom one is attached from the corner so it wobbles
Yea that explains a lot ... Kind of confusing to have a line go from center of mass to the anchor point
Does this example even have any considerable amount of drag?
no
Then it being wobbly makes sense right? 🤔
can i get the point on the surface of where i cast_ray'ed to, to attach to my asteroid on the exterior? i don't see something like that in RayHitData
ray_origin + hit.time_of_impact * ray_direction to get global coords
ah, thanks
so need to do that then translate to relative coords of the target to be able to set local_anchor
yeah
I remember getting the actual point in rapier, and it was always wrong somehow. So this is what I ended up doing every time anyway 🤔
I think Rapier gives it in local space
like point1 is local point on entity 1
idk
parry's ray casts don't give the point directly so we'd have to compute it, which is easy but maybe unnecessary memory since it's easy to compute
could add a compute_point method that takes the ray origin tho
...or just mention how to get global/local point in docs
Honestly doing origin + toi * dir isn't too hard. But it could be a nice helper function if we already have that data around (do we really tho?, isn't dir in RayCaster and toi in the hit data?)
yeah dir and origin aren't in RayHitData so the helper would be kinda pointless
cool, that's working nicely. need to fiddle with the damping etc..
are rope or chain joints normally implemented as just a bunch of short distance fixed joints connected together?
i suppose the parts between the links would need to have colliders 🤔
A bunch of DistanceJoints should work. You can also use RevoluteJoints if you want to limit the relative angle to make the rope bend less
I'm not sure what the best way to handle collision would be, but you could just connect a bunch of small circles
if i wanted the chain to wrap around the asteroid, yeah small circle colliders between links maybe
there will be small gaps, but if you don't have very thin objects then they won't pass through
i may experiment with that before i go back to the netcode stuff..
BTW @vestal minnow, what happened to the soft body physics showcase from ages ago? 🤔
I probably have it stashed away somewhere but it was very unfinished and required some modifications to constraints and had poor performance
I'll return to it later tho, I really want soft bois
it was inspired by this absolute gem of a YouTube series by blackedout01, heavily recommend checking it out:
https://www.youtube.com/@blackedoutk
I had mostly the implementation from the first few vids (distance constraints + global volume constraints) working but it needs bending constraints and a tetrahedralizer
Making a tetrahedralizer (and triangulator for 2D) is another rabbit hole, so much so that they ended up using TetGen which is written in C so I'd prefer not to use it
and there aren't nice tetrahedralizers in Rust yet afaik
although tritet looks nice but it's just a Rust interface for Triangle and TetGen
https://github.com/cpmech/tritet
could at least try it though
on main it feels like the triangle collider is actually just a point at the center of the triangle when it hits something, instead of a triangle shape
very different behaviour to 0.2
how are you initializing it?
// triangle ship, pointing up the screen
let points = vec![
Vec2::new(0.0, SHIP_LENGTH / 2.),
Vec2::new(SHIP_WIDTH / 2., -SHIP_LENGTH / 2.),
Vec2::new(-SHIP_WIDTH / 2., -SHIP_LENGTH / 2.),
];
let collider = Collider::triangle(points[0], points[1], points[2]);
cmd.insert((collider, ....
SHIP_LEN is 32, WIDTH is 19
(asteroids are using Collider::convex_hull)
the many_shapes example has triangle colliders and they're working normally
let delta_rotation = Rotation::from_degrees(120.0);
let triangle_points = [
Vector::Y * 10.0,
delta_rotation.rotate(Vector::Y * 10.0),
delta_rotation.inverse().rotate(Vector::Y * 10.0),
];
let triangle = (
Collider::triangle(triangle_points[0], triangle_points[1], triangle_points[2]),
...
does the point order matter?
i'll try changing the point order
let collider = Collider::triangle(points[2], points[1], points[0]);
hm, this order seems to work
1,0,2 kinda works but looks like the front of the ship doesnt quite touch the asteroid when it collides. definitelty some weirdness. will make some recordings to show
actually no 1,0,2 the ship just went half over an asteroid
yeah I can repro weirdness with different orders
weird that it would change from 0.2 though since I haven't touched triangle colliders
odd, yeah. glad i'm not hallucinating anyway. off to bed, but happy to help debug (in the coming days) if you need me to do anything
yeah I need to sleep too, good night
Hi! First of all, thank you for this crate!
I’ve spent a couple of days poking around and found it very easy to follow what's going on so far!
I forked main a little while ago because I’ve been thinking of having a go at implementing collision filtering, which is the one feature I wanted from Rapier that XPBD didn’t have yet.
The major issue I had with Rapier’s collision filtering is that as far as I could figure out you had to pass the query you want for the filter as the generic arg when adding the plugin, so it seemed as though it was only possible to set up one SystemParams for all of your physics. I’ve been hoping to making something a little more flexible.
Has there been any discussion yet about how collision filtering should be implemented?
What I’ve got so far is extremely simplistic but it almost feels like it's enough to get things off the ground: I’ve added a new Substep after NarrowPhase that is blank by default, with the expectation that users would add their own systems to filter through the Collisions resource.
Note: I haven't experimented with collision filters at all yet, so take what I say with a grain of salt. Also, here's a wall of text :)
I would say that there are two types of collision filters that would be nice to support:
1. Global physics hooks that iterate through all contacts like Rapier and your proposed solution
Something similar to your solution would be nice, but just adding an empty set doesn't feel very user-friendly in the sense that people would need to make sure they're running the systems in SubstepSchedule and e.g. SubstepSet::ContactFilter, and I consider substeps to generally be more of an internal thing.
One way to do this could be to abstract this out with an extension trait that implements .add_contact_filters(my_system_configuration) for App. This would add the systems in the correct schedule and system set. Alternatively, we could add e.g. a ContactFilterSchedule that is run automatically in the appropriate place.
We could also have something like a ContactHook resource, but that feels more limited.
2. Entity-level filters with a component like ContactFilter
What I had in mind is to just have a ContactFilter or CollisionFilter component that allows you to exclude things like entities and RigidBody variants and supports a custom predicate for contact filtering and modification.
Something like this:
commands.spawn((
Collider::ball(0.5),
ContactFilter::new()
.with_excluded_entities([...])
.with_predicate(|mut contact: ContactData| {
// Modify contact (optional)
contact.penetration = 0.1;
// Return the contact or use None to ignore contact
Some(contact)
}),
));
You can pass the colliding entities to the closure, so the user could handle collisions between specific entity pairs differently. The two main issues here are:
- How to deal with cases where both entities have their own predicates? (maybe a
priorityproperty) - The filter can't use
Queryor otherwise have proper access to the world, so it's not very flexible.
2 could maybe be done using something like Bevy's (future) one-shot systems passed as the predicate similarly to callbacks, but I'm not sure if this would actually be possible.
I'm open to any other solutions or APIs though, these are just what I originally had in mind :)
2 could maybe be done using something like Bevy's (future) one-shot systems passed as the predicate similarly to callbacks, but I'm not sure if this would actually be possible.
Btw what I meant by this is that it would be cool if one-shot systems could be used to do something like this: (not sure if this would work, just an API idea)
fn setup(mut commands: Commands, contact_hook_pipeline: ContactHookPipeline) {
commands.spawn((
ContactHook::new(
&contact_hook_pipeline,
|In(mut contact): In<ContactData>, query: Query<&MyBundle>| {
// Modify contact, query for entities, do whatever
// Return new contact data to narrow phase; if None, skip contact
Some(contact)
}
),
));
}
Here, ContactHook is a component storing a callback system, and ContactHookPipeline is a system param giving access to the SystemRegistry.
ContactHook::new registers the callback, which is a normal system, so we can use normal queries, and the contact data can be given as an input (provided when running the callback system in the narrow phase)
The one shot PR is almost done, but it doesn't yet allow passing in input, so that wouldn't really work. There is however also a run_system_with api on World on bevy main, which could support it. Systems there are however not cached so I assume it would have a bunch of overhead
Yeah run_system_with is what I was referring to with "running the callback system in the narrow phase"
and overhead might be an issue as you said
Yea, generally that would be the only thing that would work anyway, oneshot systems wouldn't actually be able to take a reference to something I think
Could be interesting to see if it even technically works though and see how bad the overhead is
Yea it would be interesting to test. It might perform about the same as just doing stuff manually on &World
I doubt people will have tons of entities with their own entity-specific contact hooks anyway (just use the "global" hooks in that case) so it generally wouldn't be an outrageous amount of one-shot system calls
ooh systems called using world.run_system_with can apparently return data, so we could get rid of the mutable reference and return Option<ContactData> like in my earlier simpler predicate example
and if it's None, we ignore the contact
updated the code to reflect this
Thanks for getting back to me. I figured you'd at least have some thoughts on it so I'm glad I reached out.
It's pre-coffee morning for me so I apologise if the below doesn't make much sense.
I agree that just adding an empty set isn't very user-friendly.
I'm not super well-versed with Bevy, but does extension trait preclude being able to apply ordering to the systems you add?
If it does, an extra schedule like you suggested may be more flexible.
One reason I didn't start with the predicate approach was that I was aiming for was to avoid dynamic dispatch. I can see that having it as a possible option would definitely be useful, though.
Re your suggestion of being able to return Option<ContactData> in the predicate-style ones, that would open up the way to editing a contact in a very obvious way.
I'm sure there must be some valid use-case, but I'm unsure whether or not that is desirable as it would allow influencing the simulation.
(Edit: Having mutable access to Collisions in the schedule-based approach does the same anyway, so perhaps the point is moot.)
This is mostly a curiosity question, and I've really not looked into the solver at all because it mostly goes over my head, but:
I see that currently, contacts are all stored in a resource and then eventually copied onto the component during the send events step. Is there a reason they're not all on entity1 from the get-go? Is there something about storing them in a resource that makes the solver more efficient?
I'm struggling to figure out where my camera update logic should go to follow a dynamic rigid body. I've tried in FixedUpdate, Update, and PhysicsSchedule but there's jarring jitter in all of them. eg
.add_systems(
FixedUpdate, // PhysicsSchedule
parent_camera_to_car
.after(PhysicsSet::Sync)
.after(PhysicsStepSet::Substeps),
)
Noob here. How do I turn off bevy_xpbd mid game?
do I need to make a state with all it's default systems, or there is another way?
I guess I only need to disable collisions and motion integration
ok I think the solution is to set the timestep resource to 0
Yeah that works. There's also a PhysicsLoop resource with pause and resume methods, but it's not mentioned clearly in the docs currently
Probably in Update or PostUpdate, but before transform propagation and global transform updates.
These could be somewhat related:
- #1143726581362204672 message
- #1147121135285174303 message
Thanks
I'm not super well-versed with Bevy, but does extension trait preclude being able to apply ordering to the systems you add?
I think you could still apply ordering. The input would be similar to add_systems and allow multiple systems and ordering, but it would just add .in_set(...) and the appropriate schedule automatically.
That being said, a separate extension trait might be unnecessary for how simple it is. An easier and more explicit way would probably be just to have a custom schedule.
I'm sure there must be some valid use-case [for contact modification], but I'm unsure whether or not that is desirable as it would allow influencing the simulation.
Rapier supports this, and there's several potential use cases like conveyor belts, non-uniform friction/restitution, modifying contact normals to simulate "randomness" in surface contacts etc.
I see that currently, contacts are all stored in a resource and then eventually copied onto the component during the send events step. Is there a reason they're not all on entity1 from the get-go? Is there something about storing them in a resource that makes the solver more efficient?
Contacts are stored in the Collisions resource (on main). The data is copied for the Collision event currently so that people can conveniently listen to collisions, but the same data is not copied for entities. Entities only have CollidingEntities for conveniency, but it's not used by the engine itself.
Contacts are between two entities, so it wouldn't make sense to have the data on just one of them. We could copy the same data for both entities, but it would waste memory, queries would have duplicate data, and you would have to do potential contact modifications for both entities individually.
Having a "single source of truth" like Collisions is easier and more efficient to work with, and it allows us to add optimizations or custom methods like collisions_with_entity.
Once/if we eventually get entity relations 🌈 in Bevy, we could maybe describe collisions as relationships and have efficient queries like (Body1, CollidesWith(Contacts), Body2) (heavily simplified)
I have no idea if this would work in practise though, I haven't looked into relations that much
BTW @vestal minnow did you ever look into that thing of trying update instead of update_incremental? I've been keeping my game's server offline because it keeps going to 100%, which is probably a sign I should test some solutions 😂
Not yet, I'm very busy with school for this week and the next few weeks, so I'm trying (and somewhat failing) not to do code things that could turn into long debug sessions or derail my focus too much
You can ask me again at the end of the month when I have a lot more time haha
Ah no problem, I can probably test this myself too, I'll just have to get some baseline first ... I should probably set up some case that tests it, I guess if it breaks from updating having many colliders that constantly move should trigger this behavior fast 🤔
Logically if it takes ~24 hours to hit 100% load with 25 moving entities at 60 ticks/s it should speed up at either more ticks or more entities
Thanks again, Jondolf. I’ll have a bit more of a think, try some things, and then perhaps post an issue drawing from our conversation here.
Good luck with your schooling. I don’t want to take your mind away from that since that’s far more important than my questions!
Does it sound reasonable to use something like a distance joint to position a camera relative to the target
It might be a bit weird to have a rigid body on the camera entity, but if it works then I don't see why not
You can control the stiffness to get some kind of smoothing I suppose haha
With custom following logic you'll still have more control though
most 3rd person games use a spring arm to attach the camera to the player
so the camera doesn't clip through walls
Yea, was wondering how to get the 3rd person race car camera, so the car accelerates "away" from the camera initially to give you the feeling of speed, and it "catches up" as you brake
yes but they aren't usually rigidbodies, you don't want it to be stuck behind an object either
What most do is more so a ray or shape cast back from the player to position the camera
This is moreso done with easing functions, e.g. a lerp
when i spawn 10k almost identical entities (save for minor differences in collider shape and velocity) i end up with a few of them seemingly not having mass properly, despite a MassPropertiesBundle being in my spawn function:
Dynamic rigid body 2017v0 has no mass or inertia. This can cause NaN values. Consider adding a `MassPropertiesBundle` or a `Collider` with mass.
that message repeats for 5 entities after a 10k spawns. anyone else noticed this?
Not sure why you're getting the warning, but it's printed if mass <= 0.0, inertia <= 0.0, or either mass or inertia isn't finite (i.e. it's +/- infinite or NaN)
The message might be a bit misleading in that it doesn't mean that any components are missing, but rather the values are invalid which essentially means that the body has no mass
looks like my colliders for those entities are preposterously small, whoops. that'll do it.
I just posted a question I'm the wrong thread, it's just nonsensical there...
Anyways, here goes
OK, so I just switched to 3D instead of fiddling with the 2D stuff and... say I have a very very simple gltf model, basically a box. I can load this box from file and display it, got a little camera and a little light, and I want to create a collider for it. Now, the parry stuff has Collider::convex_decomposition_from_bevy_mesh - but when loading the model I get some GltfMesh resources... Anyways, what is the most obvious way of doing this? I'm going to check out the fox example, haven't been able to figure this one out myself...
I appreciate there's probably a million things going on, but how far do you think you are from implementing "On-demand simulation stepping" - I realised I need it so have been using rapier for now. Really excited to get back to using xpbd though in future
Depends on how you interpret "on-demand simulation stepping". If you want to advance the simulation by some time dt, that's already easy to do in a custom system
well right now I have a system that manually does (amongst other things) one or more steps of the rapier physics engine (I'm not using bevy_rapier). Sometimes I might want to go and revert some objects then run a few more steps. I manually extract out the collision data to do stuff with it on the network
so I'd like to literally call a .step function on xpbd
and .step would just take a (positive) dt and advance the sim accordingly?
yes, ideally allowing me to then get all the collision data back for that step. I have no idea if this would work with how xpbd ties in with the ECS
but it's how I'm manually using rapier, I am having to sync certain bits of data back ot the ECS for rendering etc
I appreciate it won't work with the events system (from my limited understanding of bevy so far) as it's not running on the normal Update flow
That should be as simple as setting DeltaTime to something and doing world.run_schedule(PhysicsSchedule) as I mentioned. On the main branch, collisions are stored in a Collisions resource, so you should be able to access them even if you can't listen to events
if I run world.run_schedule(PhysicsSchedule) can I wait for it, get the positions of certain entities, and then run it again?
i.e. if I need to do 5 steps and get the position of the entites as I go, to send off somewhere else
I would expect something like this to work
fn my_system(world: &mut World) {
// Set delta time to 60 Hz
world.resource::<DeltaTime>().0 = 1.0 / 60.0;
// Do 5 steps, printing positions each time
for i in 0..5 {
world.run_schedule(PhysicsSchedule);
let query = world.query::<&Position>();
for position in &query {
println!("Position at step {}: {:?}", i, position.0);
}
}
}
(could have errors, wrote it in discord directly lol)
amazing thank you, I will give it a try
The main thing here is that because the engine is ECS-based, we need exclusive world access to run the schedule. Otherwise we could have conflicts with data access
We could maybe add some system parameter like PhysicsRunner with utils like step, but it would still be doing essentially the same thing
@vestal minnow : is there a convenient way to create colliders from gltf-meshes using xpbd?
Cheers
Could either use Collider::convex_decomposition_from_bevy_mesh or something like this
let pos = mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap();
if let VertexAttributeValues::Float32x3(vertices) = pos {
let vertices = vertices.iter().map(|v| Vec3::from(*v)).collect::<Vec<_>>();
let indices = mesh
.indices()
.unwrap()
.iter()
.map(|v| v as u32)
.collect::<Vec<_>>();
let indices = indices
.chunks_exact(3)
.map(|v| [v[0], v[1], v[2]])
.collect::<Vec<_>>();
// println!("{:?}", pos);
let c = Collider::trimesh(vertices, indices);
// if let Some(c) = Collider::convex_decomposition_from_bevy_mesh(mesh) {
commands.entity(e).insert((c, RigidBody::Static));
// }
}
did u ever fix this?
im having this issue server side
sort of.. I changed some other things in the surrounding code and it stopped happening :/ it only happened occationally and I wasn't sure if I'd just gotten lucky for a while or I'd actually fixed it until I'd forgotten about it
it was workign completely fine for me till i networked it
and now it occasionally works
are you able to check for me please? this is a brick wall for me lol
It stopped happening a little while back sorry, I'll try and have a look at the code a bit later and see if I can remember what I changed
im gonna keep looking at the docs just incase im missing something
here is my code just incase
let x = (fastrand::f32() - 0.5) * 40.;
let z = (fastrand::f32() - 0.5) * 40.;
// Spawn new player
let transform = Transform::from_xyz(
x.clone(),
0.51,
z.clone(),
);
let ground_entity = commands
.spawn(
RayCaster::new(
Vec3::new(x.clone(), -1.0, z.clone()),
Vec3::new(0.0, -1.0, 0.0)
).with_max_time_of_impact(0.1)
)
.id();
let player_entity = commands
.spawn((
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Capsule::default())),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
transform,
..Default::default()
},
RigidBody::Dynamic,
LockedAxes::new().lock_rotation_x().lock_rotation_z(),
Position(Vec3::Y * 1.0),
LinearVelocity(Vec3::ZERO),
Collider::capsule(1.0, 0.5),
Player {
id: *client_id,
is_grounded: false,
},
PlayerInput::default(),
))
.add_child(ground_entity)
.id();
It was something to do with my car's steering angle or wheel raycast properties somehow. Like it was something to do with the current state of the world and the interaction with the day cast 🤣 but it was very vague, hard to describe
i think i know what u mean
the cases where it worked was when the player was closer to the x:0 z:0
Wait it breaks when you go further from 0, 0, 0? How far?
well doesnt seem to want to work now
mighta just been a coincidence
its not looking good 😭
Wait, so it happens due to empty colliders? 🤔
Or maybe rigid bodies without colliders?
rigidbody has a collider
the ground has a collider too
pub fn setup_level(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
commands.spawn((
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Plane::from_size(100.0))),
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
..default()
},
RigidBody::Static,
Collider::cuboid(100.0, 0.002, 100.0),
Friction::new(5.0),
));
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 1500.0,
shadows_enabled: true,
..default()
},
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});
}
gosh I'm having trouble with the camera jittering out of sync with the simulation again 😅
might try using Position instead of Transform.
.add_systems(
PostUpdate,
move_camera_to_car
.after(PhysicsSet::Sync)
.before(bevy::transform::TransformSystem::TransformPropagate),
)
Huh, it is scheduled correctly so that's definitely interesting
I moved it to PhysicsSchedule and it's much better, now instead of jittering the whole world 🤢 only the car jitters 🤔
.add_systems(
PhysicsSchedule,
move_camera_to_car.before(car_update),
)
Shouldn't it run after the car update?
heh you'd think so, but it doesn't matter, car_update just mutates ExternalForce, it doesn't move anything
not sure if you already doing it but i recommend you make the camera a child of the car
Hmm. Maybe I can combine that with camera movement. I don't want a static camera
Car_entity
-> car mesh
-> camera
anyways im off to bed its 4 am keep me updated on this please good night!
hmm now I need to figure out if Position is local or global xD
Position is always global iirc
ok well i somehow fixed the raycast issue i just changed -1.0 to -0.9 and TOI to 0.2
any idea on improving the performance of this? I used rigidbodies to demo it but I don't think I need rigidbodies. currently I'm spawning new ones inside others so it pushes those but that's not a feature I'm going for. so I need 2 things:
- prevent entities from moving into eachother
- collisions for hit detection
would kinematic body approach with shapecast better in this case? or some sort of custom implementation. any ideas?
Shape casting is not really gonna get you any big gains here. Either we'd need to speed up collisions, or you can do something to avoid collisions entirely, by using something like boids
(forgot to post this, sorry)
this is the profiling data btw, substeps are the most time consuming stuff. so I assumed it is not possible to handle this much entities with usual physics implementation
hmhm, never thought of boids
Oh and, you can reduce the number of substeps
The default is 12 iirc, I use 6
I remember jondolf saying the lower bound is probably 3
And yea that looks exactly like I'd expect, every step is mostly just penetration_constraint, which means it's solving collisions
ah, that would be great for demoing stuff for now
I see, using physics engine for this is probably overkill yeah
And I assume all of these are already just circle colliders?
yup
I wonder how factorio handles so many biter entities
it uses grids I suppose
There's definitely room to speed up collision, but I think the key to making it run fast is for things to not actually touch
If it doesn't pass the broad phase, it won't take up many cpu cycles
not actually touch
you mean using something like boids?
The collision avoidance would be similar to boids yea, depending on other AI behavior other steps might be unnecessary. Potentially you could use large shape intersections as a way to handle the spatial acceleration, but parry has some broken behavior so something like bevy_spatial might work better right now
also I previously found just rolling my own simple spatial hash grid (literally just a hashmap) was faster than bevy_spatial
ah, this came just in time! 😄 I was reading through the discord history to see what people came up with for the last hour
thanks!
I want to do something other than the hashmap, I'm just not sure what yet
what do you use for hash key? grid tile coordinates?
yeah I just set it to a pretty coarse grid
like 20x20 or something
and just do (position / grid_cell_size).floor()
to get the grid cell
still thinking about hashmap, do you want to use something else because it could perform better or something else?
yeah I'm pretty sure a decent quadtree would be faster
(i'm assuming you only need a 2d grid for the spatial stuff?)
the hashmap is super cheap to update and not super slow for queries, but I think someting else could be faster for queries
though to be fair it only really gets bad at ~50k units
but I'm not doing a lot of the queries i'll need to do, so it could probably handle ~10-20k units?
I might spitting nonsense at this hour but what about using a plain vector? with a known worldsize it shouldn't have too much memory overhead while granting fast access
especially for my usecase, I might despawn far away entities (2 times the screen resolution for example), so I could use a smaller grid for way bigger area I think
let's talk in #general if you don't mind this became a little out of context I think
(here is the link if anyone wants to follow up #1150296798062198887 message)
kk
@vestal minnow Can you guess what the difference between these two apps is?
Qbvh update stuff? or no spatial queries
Qbvh update stuff yea. I basically stole rapier's update and adapted it to bevy_xpbd. It had lower CPU load from frame one 🙃
does it fix add with overflow errors as well?
Haven't tried it but I don't think that code path even gets hit anymore 🤔
yeah true, if it doesn't do any incremental updates then it probably doesn't
if it works and doesn't seem to break anything, a PR would be nice
Yea I can clean up some of the code and make a PR ... Tho I'd imagine in the longer term a bvh that actually works would perform better. Can't see why recreating the bvh would perform better than incremental updates 😂
yeah, it'd be ideal to have it working properly with incremental
but having it not crash and burn is even better
also I think you mentioned gltf physics at some point so #math-and-physics might be interesting rn if you haven't seen it
https://github.com/Jondolf/bevy_xpbd/pull/152
Made a PR for it ... And also tested and I see no overflows 👀
Thanks, I'll review and test when I have time
It probably also fixes #110 because there's no unwrap anymore and it doesn't need removed colliders 👀
Fixing 2 crashes and improving performance by doing something that should've been slower, nice 😂
Someone should make a more stable collision library ... And while at it ... Without dyn Shapes
Yea it might be something like "it was removed but not detected because the wrong field was removed"
At some point I'd like to try and make a glam-based version without dyn shape and with some nicer APIs (PointCompositeShapeProjWithFeatureBestFirstVisitor, really?)
but then I look at how much stuff parry has and how little I currently know about GJK, EPA and other stuff...
for now I guess it would be best to just help improve parry
I mean fwiw you only need the features bevy_xpbd actually uses
Rename the types 😂
...if they would respond to issues and PRs and merge in under half a year
And that right there is my #1 reason for not making PRs on some crates
My PR on bevy_rapier got merged after I switched to bevy_xpbd, iirc like 2-3 days later
Also I really should've made this PR earlier, I've been keeping my game's server down for over a month because of it 😂
Well not like I made any interesting updates in the meantime anyway
@cinder summit I took a look at the PR and left a comment; looks good, but RemovedColliders could be removed since it's pointless now
could my jitteryness be due to the use of ExternalForce::ZERO.with_persistence(false) ?
if i'm not applying force every update or something
I doubt it since forces just increase velocity (or acceleration to be more precise) in some direction, so if you skip a frame, it's not going to suddenly slow you down in a jittery way
unless you have some massive damping/friction
Ah, I didn't even notice since it was in an entirely different file
At a loss of how to proceed 😅
I've tried moving my logic that does things based off physics positions into the Last schedule and I'm still getting jitter which seems impossible
I've tried referencing &Position of the rigid body, tried &Transform, tried in Update, PostUpdate, PhysicsSchedule, Last.
Going to try in a minimal reproduction in a new project as a last ditch haha, I wonder what I've done wrong
I think a propperly functioning spatial acceleration structure could be the easiest optimization for xbpd at this point. The broadphase currently also functions in an n choose n way iirc, tho maybe that could be optimized even further by only searching nearby enties from the perspective of a non-sleeping dynamic body 🤔
Yeah, but a simple spatial grid generally isn't ideal because it requires some uniform cell size that users would need to manually specify. Even then, it doesn't work well when there are many large and many small objects in the same world.
This is why Rapier has "Hierarchical-SAP" for the broad phase, which is a combination of a multi-layered spatial grid, and sweep and prune (which we use) #game-development message
there's also some other sweep and prune hybrids/variants, I think one does it on several axes or chooses the ideal axis for each iteration and uses quicksort or smth
I wonder what bepu physics uses, iirc it's the fastest opensource option
I think they have some kind of bvh, I can try to find it
their narrow phase is the more unorthodox one, the "tootbird"
Oh and I removed the RemovedComponents, CI seems to be struggling with the tests tho 😂
yeah the tests are really slow, it does a fresh recompile every time I think
I should optimize the CI
So many things to optimize 😂
yeah bepu seems to have a bvh judging from how the broad phase code has leaves, trees and bounding boxes
maybe check the Update/Update2 code for fixing parry's qbvh lol
"dynamically updated binary tree"
but yeah it's still a bvh, just a slightly different representation
so... this is what is causing the jitter
[profile.dev.package."*"]
opt-level = 3
going to try release mode and see what that does, Edit: also jitters in release
are you printing logs by chance?
nope, at least nothing that is being shown by bevys default log filter
no user code level logging happening
hmm yeah, weird if the opt-level has an effect 🤔
If opt-level has effect that suggests it's something that it's impacted by how long things are running, which is usually system ordering
Here is the smallest version https://github.com/tbillington/driving-physics-repro
I took vids of the effect in the issue https://github.com/tbillington/driving-physics-repro/issues/1
I tested and simd vs no simd doesn't impact anything
for me, release doesn't jitter
🙃 ...
what platform are you on? im on mac m1
windows
I will boot up my windows computer in the morning and try.
Tried to optimize CI with actions/cache@v3 similarly to Bevy, and also made tests run on windows, ubuntu and macos instead of just ubuntu, but ubuntu is still taking 20 min for some reason
https://github.com/Jondolf/bevy_xpbd/pull/153
MacOS is just 6 min tho
Hey guys, moving my question here from the physics channel. I'm having issues hitting a collider on origin using the SpatialQuery.shape_hits_callback with ignore_origin_penetration set to true. I'm wondering if the system is being placed in the wrong part of the whole pipeline. I'm also working on a collide and slide character controller
made a sample here on my fork https://github.com/dt665m/bevy_xpbd/blob/shapecasting-help/crates/bevy_xpbd_3d/examples/basic_shapecast.rs. I'm basically just casting in the directions mapped to WASD using the capsule already on the player entity
I had issues with this as well. I think you might be hitting your player entity, so you can try filtering it.
I know it's hitting the player entity. Maybe the ignore_origin_penetration isn't doing what the name implies or I'm misunderstanding what it means or I'm completely using the spatial api incorrectly (system order or other issues). Just trying to see which one it is.
It's just strange that certain directions hit the player and others do not (in the example)
On my computer, A and S do not hit the origin (player collider) but W and D does
Guys, there is a way to change the color of just one material in a object exported by blender?? I have to change just one part of my texture in bevy:
Did you mean to send that in a different channel?
Idk. I have one object in blender that have 5 materials, okay? But I need to change one of these materials in bevy. How can I do this??
I need to change a color of a part of my object. Ex: My object is a wall and I need to change a color of just one side.
Easiest way is probably to put the player and terrain/other entities on different collision layers and to use spatial query filters to ignore the player
ignore_origin_penetration is a bit fiddly, I'm not 100% sure how parry even handles it under the hood
No worries. As long as I’m not using it incorrectly I’m happy to work around it. Any suggestions on where to put the system that does the collision test for character movement?
Do you mean the kinematic_collision system in the kcc example, or where to handle spatial queries? You can probably put spatial queries pretty much anywhere
Well long story short I’m using leafwing input to gather inputs and plan on using my implementation of collide and slide, then applying the effects on xpbd components. If it all doesn’t matter much then I’ll just explicitly order these
In your examples you put the movement before the BroadPhase
For movement (and maybe spatial query) things, somewhere in the PhysicsSchedule is probably ideal to make things frame-rate independent
either at the start of the schedule (before BroadPhase) or the end (after SpatialQuery)
idk if it matters that much though, I haven't actually made a game with my own engine yet so I might not be aware of scheduling issues with input, movement etc. 😅
Best guess is good enough for me. I’m happy to be the lab rat here haha
I'd be very surprised if this isn't a system order ambiguity
I'm not sure what would cause it to be platform dependent though
Differences in compilation maybe? Have you checked for ambiguities?
I have this in my project, I fixed the ambiguity error I had when adding my system to the PhysicsSchedule
app.edit_schedule(bevy::prelude::Main, |schedule| {
schedule.set_build_settings(bevy::ecs::schedule::ScheduleBuildSettings {
ambiguity_detection: bevy::ecs::schedule::LogLevel::Error,
..bevy::prelude::default()
});
});
Wouldn't you need to set that on each schedule rather than just Main?
I tried it on physicsschedule too, didn't get anything
lol... I attached tracy profiler and the stutter stops 🤦
Usually when I can't figure out order issues I use bevy_mod_debugdump
tracy profiler is some plugin?
there is this feature which is quite interesting: "bevy/trace_chrome"
oh ok
I'm looking at the output of debugdump but I honestly have no idea what I would be looking for xD there's a lot of nodes in the graph pointing all over the place, and PostUpdate is a separate schedule to PhysicsSchedule so I don't know how to see if there's overlap
Somewhere in PostUpdate would be a system that runs PhysicsSchedule, so if your system is there you can just use that as a reference point for where physics runs
The system causing issues for you involved moving the camera right?
moving camera, drawing gizmos, anything not in physics schedule is out of sync. No matter if I put them in Update, PostUpdate, Last, doesn't seem to have any impact on the jitteryness.
https://github.com/tbillington/driving-physics-repro/blob/main/src/main.rs#L14
Is PhysicsSchedule running in FixedUpdate maybe?
Are you sure it's the camera moving jittery, and not the car updates getting jittery? What FPS ar you running at with opt-level 0 and opt-level 1?
PhysicsSchedule by default runs like FixedUpdate, but not in it.
If your FPS is over (or equal to) the update rate of physics at opt-level 1, and lower at opt-level 0 this could be because you use inputs inside the PhysicsSchedule. You could test to see if it's "solved" if you use variable physic updates instead of Fixed (the default)
It ignores the origin collider as long as the casting velocity wouldn't "tunnel" through I believe
otherwise it will still return it I think
so the magnitude of the "velocity" in parry's shape casting actually matters? i.e. it's not just a direction
or well, I believe it is mostly just direction here
thanks for the suggestions, didn't seem to affect anything though. I also tried moving input collection into a system in Update and putting the results in a component, and reading from the component in the physics system instead of Res<Input<Keycode>> but didn't have any effect
Hello! It is me, your friend. I have a problem that I think is not really an xpbd-problem, but more of a general Bevy-issue and I hope it is OK that I ask it here. When reading collision events, the structure has entity1 and entity2. What is the best way to see what components are on that entity? All my Google queries seem to favor using the Query-interface, but inside a system, is there a canonical way of doing it? Or some example code that shows it off. Sorry, I am new at both Bevy and xpbd, but I am making good time.
Why do you want to see which components are on the entity?
Because let's say I have a Player-component attached to an entity and a Crystal-component attached to another, I want to despawn the Crystal-component, if that makes sense.
They do not show up deterministically as entity1 and entity2, and that seems a little dubious to rely on anyway.
My Player-component is basically just pub struct Player; derived from Component, so it is a marker/tag. Keep in mind I am a noob so sorry if I am butchering the terminology.
Right, so you want to handle collisions differently based on which entities are colliding right?
I guess the short version would be, given this data: Entity Contact { entity1: 6v0, entity2: 5v0, point1: Vec2(0.0, 14.098724), point2: Vec2(0.0, 14.142136), normal: Vec2(0.0, -1.0), penetration: 0.04341221 } how do I know which entity is a Player and which one is a Crystal without knowing the IDs.
Yes. I would love to be able to consistently handle the case where a player collides with a crystal by despawning the crystal. And ideally without propagating magic IDs through the system.
I might be missing the point altogether, is there perhaps a way to tell the EventReader to filter this before I get the data?
So, when working with parry or other collision detection libraries directly, my strategy has been to add another system that looks for the player, and then checks its collisions to see if its colliding with an object of the correct type
I'm unsure about how exactly you'd want to do that with bevy_xpbd: maybe there's a per entity event list of collisions that you could then check against?
if crystal_query.contains(candidate)
is a useful snippet though
Ah, OK. So you basically query for all the crystals, see if it contains the entity in the collision structure. That makes a lot of sense to me. It is probably exactly what I am looking for.
Thank you so much, I will test that. Sounds very sound.
The way I handle my collisions is with the component that gets a list of collisions for that entity
Is there example code and/or documentation for that feature? I still have some issues reading typical Rust docs.
I would be happy to contribute an example for it if that is helpful and I can wrap my head around it.
idk about examples, but this is the component I'm referring to:
https://docs.rs/bevy_xpbd_3d/latest/bevy_xpbd_3d/components/struct.CollidingEntities.html
Contains the entities that are colliding with an entity.
Ah, cool. It is a different approach than using the EventReader. I will check it out.
Yea, you can just make systems that handle collisions for certain things. Like this system I have to set the team of a player if they step in it:
fn set_teams(query: Query<(&CollidingEntities, &SetTeam)>, mut teams: Query<&mut Team>) {
for (colliding_with, set_to) in query.iter() {
for entity in colliding_with.iter() {
let Ok(mut team) = teams.get_mut(*entity) else {continue;};
*team = set_to.0;
}
}
}
This is very convenient.
What is SetTeam in this context? Is that a Component you added to your entities?
Yea it's a component I made and added to the entities, it just holds which team the entities need to be added to
That looks just about what I wanted, thanks for sharing.
I tried a vector with magnitude as a parameter into parry. No effect.
I am super impressed by this physics engine. Sorry, I got lost and forgot where I just chatted. The input you guys gave me yesterday allowed me to fix mostly all my issues. The approach you have @cinder summit seems to only actually give information when objects come to rest, but that is super helpful in a lot of situations also. So, I just wanted to say thanks.
I was hoping I would paste my code here to see if you saw anything wrong with it, but I am learning Helix at the same time.
This is what I ended up doing. It seems a little naive, I am sure.
Would you write this differently?
It works. And I love that it is captured in a system. ECS is a gift that keeps giving.
It seems clunky to me, the way I approached it.
Has anyone manged to get bevy_xpbd and bevy_ggrs working together?
bevy_xpbd + bevy_ggrs + bevy_matchbox is a pretty common pairing
Johan has an example here: https://github.com/johanhelsing/bevy_gaff
There are occasional desyncs in that example though, we haven't verified yet if there's indeterminism from the engine or if it's maybe not rolling back enough data
This is helpful, thanks!
Why is it necessary to create a PhysicsSchedule and run it manually instead of doing: PhysicsPlugins::new(GgrsSchedule)?
What construct would I use to model an attractor? Let's say sort of a black hole.
I would do two queries:
Query<&Transform, With<Attractor>>Query<&mut ExternalForce, With<RigidBody>>
and for each attractor, apply a force to each rigid body
Ah, OK, so you sort of have to "roll your own", but it isn't that hard. That works for me.
you can make it more efficient by only applying forces to bodies in some radius with e.g. bevy_spatial
I am really looking for a simple use-case where it is only active on the player in the very beginning of the level, but I might want to expand it later so this is useful. This is probably great for me, thanks. Just wanted to see if it was something built-in.
Would it be possible to make a general abstraction for it? Unfortunately, I am a very weak visionary. I don't see what a game should really look like until I see the building blocks. But if I have the building blocks I try to assemble them. And now it feels like at some point I would like this as a general feature in some levels.
In my context I would probably want something where the attractors have no influence on the physics system, so to me it seems like just making a collider around the attractor could work.
Like "fall-off" turns into no influence, if that makes sense.
Like the attractor only works in some area or only affects specific entities?
I guess both, there are collision layers, but yeah, just a large collider to activate the attractor on a collision layer in, say, a circular collider shape.
Just curious if it seems like a viable level of abstraction.
You could give the attractor a Collider with a Sensor component (to make objects not bump into it) and give it optional CollisionLayers to choose which layers it affects. This could be wrapped in an AttractorBundle.
Then, you can make a system like the one I suggested, but use CollidingEntities to only get the entities in the collider's area, and apply forces to just those bodies
Ah great. I was actually going to ask about that, I didn't know about the difference between Collider and Sensor and while what I am currently doing works, I was thinking of a power-up or something that would turn the Collider into a Sensor.
But, yes, that sounds great.
But yeah I guess this could be made built-in (I think Godot has an attractor?) but I feel like it's high-level enough that it would make more sense as a third-party plugin than a physics engine feature
Sure. I am just trying to wrap my head around stuff, seeing what's there and how it fits in. I agree.
is there a convenient way to create a 2d bevy_xpbd collider from a sprite? (eg a png with transparency)
Nothing built-in, but you could adapt bevy_rapier_collider_gen for bevy_xpbd
https://github.com/shnewto/bevy_rapier_collider_gen
@severe urchin ^
Could xpbd get a feature to adopt serde for its components? I’m trying to build a game with bevy_replicon, and they switched from using reflect to serde in their latest release.
thanks, looks like the best option 👍
Yeah we could add a serialize feature for that
Is there a way to exclude entities that belong to a specific collision group using SpatialQueryFilter?
Add the layers you want to include using SpatialQueryFilter::new().with_masks([...]) or with_masks_from_bits, other layers should be excluded
@vestal minnow I've just sent in a small pull request that exposes filtering (+ editing, since collisions is mut) and adds a one-way-platform example. I've had some stuff come up so I've not been able to put much time in recently, so it's just a small change for now, I'm afraid
One question I do have: is there a reason that xpbd only exposes the first normal that the backend returns? As you can see in the example I added to go with, it's jumping through some hoops to calculate normal2, and it would have be nice to have access to it. I considered exposing it, but it was out-of-scope of the target so I didn't think it right to.
Thanks, I'll try to review it soon hopefully!
It's mostly because you can compute it from normal1 so I thought that it'd be unnecessary to store it, but I agree, we should probably expose it for convenience at least
It looks like the child colliders code is building the collision manifolds is pretty close so it's probably going to conflict, but I can make a pull request to expose it if you like
I can just expose it in this PR as well
https://github.com/Jondolf/bevy_xpbd/pull/156
even though it's not strictly related
Coolio. Once that is merged I'll update the one-way-platform example in #150, so I'll return it to draft state for now
I was more looking for a way to include all layers and then add exceptions.
I don't actually need it anymore, but I do think it would be a useful feature.
Probably a silly question, but what is the correct way to enable debug-plugin on command line with cargo run?
When I do cargo run --features "debug-plugin", I get error: none of the selected packages contains these features: debug-plugin. But the debug view works fine when I set it in the cargo.toml. Just curious how to do it the command line way.
does cargo run --features "bevy_xpbd_2d/debug-plugin work?
(or 3d)
oh yep that did it. thank you!
yeah if you use just debug-plugin, it'll look for the feature in your own Cargo.toml, not bevy_xpbd's Cargo.toml
ahh makes sense. figured it would be something small haha
Hi,
I looked at the example (https://github.com/Jondolf/bevy_xpbd/blob/main/crates/bevy_xpbd_2d/examples/move_marbles.rs) which seemed to be the simplest one from the 2D examples (but it's easier to guess with a name like "hello_world" or "cube")
And I was wondering, you spawn circles with :
commands.spawn((
marble_mesh.clone(),
RigidBody::Dynamic,
Position(position),
Collider::ball(marble_radius),
Marble,
));
but where is the LinearVelocity component added ? Is it something automatic ? (I didn't test Bevy since 0.9 I think)
bevy_xpbd automatically adds all required components for entities that have a RigidBody component. This is documented here: https://docs.rs/bevy_xpbd_2d/0.2.0/bevy_xpbd_2d/components/enum.RigidBody.html#creation
A non-deformable body used for the simulation of most physics objects.
bevy_rapier also does this
Oh nice thx, I didn't know it was possible
I would have thought it would work with things like Bundle
Yeah we used to have a RigidBodyBundle, and a ColliderBundle, but being able to add RigidBody::Dynamic and having it Just work™ is pretty ergonomic and also what bevy_rapier does
We just have systems that query for Added<RigidBody> and insert the missing components
I do think that bundles are more explicit though, so I'm open to revisiting the idea of having them
is it safe (for bevy_xpbd) to add a child entity to a regular physics entity, and the child has a big sensor collider? or do i need to move a separate sensor entity manually to keep it at the same pos?
The child sensor collider probably won't move with the body yet, but I have a PR for child colliders where it should work
(WIP PR)
ok thanks. i'll spawn a new entity for now
lmk if you want a 2d tester for the pr in future. i'm on main branch of xpbd now, mostly
btw with absolutely no attempt to optimize or profile it, seems like I can get to around 15,000 circle-collider bullets before things start to lag: https://www.youtube.com/watch?v=86NVuT0xRQI
No Audio. Running in local sandbox mode, so no networking or rollback.
disabled bullet expiry, curious when it would lag.. each bullet is a small rigidbody circle collider. went up to 15,000 or so. you can see the entity counter in the bottom right. I've not bothered profiling this scenario, but something in physics systems is hard at work.
N...
i don't know if that's good or not, but it's sufficient for my needs at the mo 🙂
(i will probably make it so bullets don't collide with bullets anyway, but they do for now)
Wow, cool! 15,000 is honestly more than I expected since a lot of things still haven't been optimized. I think in this case it's because the bullets are relatively sparse and don't have tons of narrow phase collisions, so the engine mainly needs to run position integration and broad phase collision detection, which aren't as expensive
A better broad phase along with a parallel solver would probably speed this up substantially though
makes sense yeah. certainly fun to see so much physics happening 😄
Is it normal if the debug-plugin draw ball shape as rectangle ?
It's written : debug-plugin enables the PhysicsDebugPlugin used for rendering physics objects and events like AABBs and contacts. in the doc
Nor is it mentioned in the README.md as "Future features"
In 0.2, it only renders the AABB and contacts. The main branch has debug rendering for colliders, joints etc.
Ok I'll try with it so
can you set a collider to be a trigger? or do you have to use spherecast or whateve
Like Sensor or something different?
dont know 🤷
in unity you can have a collider be a trigger or not
if its a trigger it wont collide but will let you make function calls
like onTriggerEnter and yada yada
but i imagine you can just shapecast
Sensor causes it to register collision events but not function as a physical object otherwise
yeah might just be that
also im still gettin that error with raycaster
but it happens randomly
spawning a monster every frame, xpbd doesn't even fill up half the screen before it starts to chug (rapier never impacted framerate as far as I could tell). am I doing something wrong, or is this expected given the algorithm? (It was more correct in terms of nonoverlapping then rapier for a lot longer)
I'm pretty sure bevy_xpbd hasn't been hugely optimized yet, and the broad-phase is checking all combinations (i.e. N*N-1 combinations).
I think I read somewhere that Rapier is using some form of spatial lookup table to minimize the number of combinations it has to check, which would explain the difference
https://github.com/Jondolf/bevy_xpbd/blob/main/src/plugins/broad_phase.rs#L163-L165
It may be that other things are contributing, but this is at least part of it
I'm a bit confused by how Mass works, I changed the mass of my car from 1 up to 1 million and it seemed to have very little impact
it should just be a multiplier during collisions
at least thats what I would assume
like if the 1 million mass car hits a 1 mass postbox, it will send the postbox flying without slowing down almost at all, while the 1 mass car would bounce back
I would also expect it to influence gravity, but it doesn't seem to
hah
(hint, thats not how gravity works in real life, but thats how people since time immemorial thought it would intuitively work til like around Galileo)
mass increases the force of gravity linearly, but also decreases the impact of that force linearly due to making the object harder to move, which cancels out and thus the affect is identical acceleration independent of mass
F = G * (m1 * m2) / r^2 where r is distance (in the case of a flat physics world, that part is considered to be constant)
F = m * a
m1 * a = G * m1 * m2 / r^2
a = G * m2 / r^2
a = (some constant not dependant on the mass of the object, only on the mass of the other object and distance to it)
so all forces are also relative?
I'm not sure what you mean my that question
I'm applying Transform.forward (normalized) to a rigidbody every tick, but the object still behaves the same with mass 1 or 1million. So I have to assume the force is multiplied by mass or something inside the physics sim
applying a transform isnt applying a force, its just teleporting the object
there is an ExternalForce that lets you apply a force
I'm calling apply_force_at_point on the ExternalForce
oh, ok then yeah
With a constant force. So I'm only changing mass
that should be scaled by mass yeah
afaik, I havent really used the lib much yet
but from physics, I would expect the change in velocity to be force / mass
so yeah, affected by mass
a bit odd
do you mind sharing your code?
The problem here isn't the broad phase but rather the narrow phase + solver since the entities are so tightly packed that they're basically all colliding at once. For reference, RJ could get 15,000 entities when they were more sparse and not all tightly colliding with each other like this
#1124043933886976171 message
We currently have to do a lot of query.get_many_mut([...]) in the solver, which is slow according to Tracy, and the solver is currently single-threaded. I have plans for optimizing this in the future though
Forces and impulses definitely should affect objects with different masses differently, and looking at the code this should be the case. I also recall it working correctly when I last tested
(using ExternalForce)
Also i got a question why isnt the physics world seperated?
would it not making controlling it easier? for example settings the physics world at 30 fps and the normal word 144 or whatever
You can change the physics frame rate freely with PhysicsTimestep and the substep count with SubstepCount
or run physics in a custom way by just setting DeltaTime to whatever you want and calling world.run_schedule(PhysicsSchedule)
As for having a fully separate physics world (i.e. data not in ECS), that's the main thing bevy_xpbd tries to avoid and does differently from bevy_rapier to see if it's a better approach for Bevy's physics. It makes things feel much more integrated and native, although in specific places (like the solver) it might currently be slower due to the additional querying
Thanks for the response. I liked the overall behavior of XPBD at smaller numbers more, but as this is a pretty normal case for Vampire Survivors clones, I'll use something else for now
Also have you lowered the substep count from the default of 12 to something more reasonable for your use case?
no, I wasn't really sure what to try
It can improve performance significantly, for you just a few should be enough
Like SubstepCount(3)
for example
Didn't @lament matrix also have performance issues with the closely bunched up enemies for a survivors clone? They went for making it more boids-like rather than making them all circle colliders
yeah. I just decided to test this way out. thing is, rapier manages to hold up reasonably well, without switching to boids
gimme like 20 min, ill test the lower substeps, push the comparable branches of code
Rapier definitely has more optimization, tho you really need some specific cases for rapier to not perform poorly due to various other issues
My game runs better now with xpbd, but it's heavily bottlenecked by those stupid trimesh colliders 🙃
I pushed my 2 branches, links to the relevant code:
https://github.com/kazagistar/boundry_dynamics/blob/xpbd/src/monster.rs
https://github.com/kazagistar/boundry_dynamics/blob/rapier/src/monster.rs
I tested SubstepCount(3) and it does make it so the entity count is approaching what would be fine for a VS-style game (almost the entire screen completely full of enemies, but I dont actually have a precise count sorry) and close the the point at which rapier starts to slow down as well. The biggest problem I have left I think is that once it does suffer, it goes off a cliff (my guess would be a quadratic time complexity somewhere) while rapier degrades linearly
interesting
Argh, re-reading the docs I can see why, collider is changing Mass
Are there any more convenient way to work with ColliderMassProperties without using density? I want to keep Mass stable while I experiment with the size/shape of the collider
What do I need for an entity to register a collision? I have a collider on it, but I seem to be messing something up, and it isn't working for me.
I have this system for checking the collision events
pub fn handle_bomb_collisions(
mut commands: Commands,
enemy_query: Query<&Enemy>,
explosion_query: Query<&Explosion>,
mut collision_event_reader: EventReader<Collision>
) {
for Collision(contact) in collision_event_reader.iter() {
println!("{:?} and {:?} are colliding", contact.entity1, contact.entity2);
if (enemy_query.contains(contact.entity1)) && (explosion_query.contains(contact.entity2)) {
commands.entity(contact.entity1).despawn();
}
if (enemy_query.contains(contact.entity2)) && (explosion_query.contains(contact.entity1)) {
commands.entity(contact.entity2).despawn();
}
}
}
And I add the collider simply like this:
commands.spawn((
enemy_sprite,
Enemy {
direction: Vec2::new(random_point.x, random_point.y).normalize(),
},
Collider::ball(ENEMY_SIZE)
));
The explosion is also an entity that is basically the same as the enemy spawn code
I also tried shape intersections
i thought if you add the mass component yourself it won't be overridden?
let mass = MassPropertiesBundle::new_computed(&collider, 10.0).mass.0; and then instert a Mass component using that value, or just hardcode it. you might need to insert all of ColliderMassProperties to avoid it being recomputed when changing colliders, not sure.
It is being added to, I was mistaken earlier when I said it was being overridden 😅
can I use bevy_xpbd just for collision detection without all the physics stuff?
What level of collision detection without physics do you expect?
just something simple for hit detection
It's possible to use sensors or just have colliders and use ray/shape casts or shape intersections
what would be the minimum required plugins to make that work?
But for some usecases it makes more sense to have the full physics and just not ever apply any physics forces. That way it also handles cases like not being able to move trough walls
On the main branch, BroadPhasePlugin, NarrowPhasePlugin and probably PreparePlugin and SyncPlugin. For spatial queries also SpatialQueryPlugin
thanks!
if i want to keep track of which entities are touching (in contact) should i just write a system to aggregate the collision started and ended events myself, or is that already maintained inside bevy_xpbd that I can get at for no extra cost?
CollidingEntities
oh, nice. so ican just filter that to detect what i need
I think I may have found my issue. Do collisions require a RigidBody on at least one of the pair? That's how it is in Unity, so I should have guessed it's the same here.
In 0.2 yes, but I think on the main branch it's not needed
might be remembering wrong tho
Ok thanks. I'm using 0.2
I'm gonna need to figure something out, because when I add a RigidBody::Static to the explosion (which is what I'm testing against, and it doesn't move), it now spawns in the bottom left corner of the window instead of where the bomb was dropped. I'll figure it out though, now at least I know I'm heading in the right direction!
Thanks
Isn't the normal approach to have the rest of the game be rigid bodies, and handle an explosion with a one time shape intersection test?
Yeah, that was my first thing I tried.
let intersections = spatial_query.shape_intersections(
&Collider::ball(BOMB_DET_RADIUS), // Shape
bomb_transform.translation.truncate(), // Shape position
f32::default(), // Shape rotation
SpatialQueryFilter::default(), // Query filter
);
for entity in intersections.iter() {
println!("Entity: {:?}", entity);
if enemy_query.contains(*entity) {
commands.entity(*entity).despawn();
}
}
Nothing had rigidbodies when I wrote that though, so that's probably the issue.
I can't seem to get my enemies to spawn or move correctly with rigidbodies as the code is written now
I'm doing the bevy-ball-game tutorial and it didn't use any physics (rapier nor xpbd), so just dropping this in was over-hopeful haha.
I'll be rewriting the movement and trying to add rigidbodies to the enemies and player
In 0.2 I remember having to use Position instead of trying to move them with the transform. Just having a transform set would spawn static things at the origin. It was probably something wrong with the system ordering on my end, but switching to Position instead of using transform solved it so I didn’t look into it further.
Ok, I'll try that out, thanks
I've been looking for the source of non-determinism and one thing I found is that the accumulator in run_physics_schedule will vary because of delta time. I think this can be fixed by moving your PhysicsSchedule to FixedUpdate. I'm guessing this is the reason that bevy_gaff isn't deterministic.
I think bevy_ggrs would have to update the Time resource if that's possible.
@lime hatch
It's already in a schedule that I step in the rollback schedule: https://github.com/johanhelsing/bevy_gaff/blob/c8f22ec11fb3e19c84e6501d038239f95a59a634/src/main.rs#L227
but thanks for the tip 🙂
You set the time in that schedule?
bevy_xpbd is using the client's frame rate delta time because it's not scheduled in FixedUpdate
I though bevy_xpbd had a fixed step mode, that i set it in, but maybe i forgot/made that up
It does, but it accumulates time with the Time resource
that would be a huge 🤦 on my part
i do this:
.insert_resource(PhysicsTimestep::FixedOnce(1. / FPS as f32))
But I haven't actually looked into what it does
just assumed that should make it ignore the time resource
ooh, that might work actually. I use Fixed, let me test that
Yeah, that got rid of my desyncs. That's my bad, I thought bevy_gaff used PhysicsTimestep::Fixed.
oh, that's nice. so you're running bevy_xpbd without desyncs now?
Yeah, I haven't had a desync yet
I'm not using a ton of features though, I have rotation disabled, and I'm using dynamic rigid bodies rn
Hello! I am at the point where I am seeing some odd behavior in the physics engine, and I am pretty sure it is me, like 99% sure. Does anyone here do paid work? Sorry if this is the wrong forum for this. I am not talking about consistent and/or long term, just trading some moolah for eyeballs.
It just has to do with despawning on collision and it makes the objects sometimes bounce back and sometimes just pass through.
And I need it to be deterministic.
Where is the despawning system scheduled? I'm guessing it's a system ordering issue where sometimes the physics runs first and sometimes after
I was pretty sure that was the issue. Currently it is like this:
Sorry, I am using Helix so copy/paste doesn't work reasonably for me.
If anyone would be willing to give it a quick glance that would be great. Also I understand if that is a tall order.
Again, I am pretty certain this is just me fumbling things.
I'm using xpbd 2D and I have a dynamic cuboid dropping directly on top of a kinematic cuboid. The cuboids have no rotation. Any clue why the dynamic cuboid is bouncing left?
https://gist.github.com/tjamaan/7c8b3deeeea9015419b31f1dfe219581
Hmmm..... it seems for a frame there is an overlap of colliders.
Yep, in 0.1 and 0.2 this is an issue, but it's fixed on the main branch.
Previously we only used one contact point per collision, and for numerical reasons / implementation reasons it could be at the corner. In your case all of the initial contact force is applied at the bottom right corner, which causes the rotation.
We now use multiple contact points per contact, in this case one for each corner, which makes the collision much more stable and even.
Thanks! I will check it out.
Also I think this should be fixed now as well. There was previously a one-frame delay in the instantiation, but iirc we fixed this
i know it's a bit of a crap error report, but i'm occasionally seeing things not correctly being removed from CollidingEntities. i haven't figured out how to reporoduce it or why it happens yet.
anything known?
eg my player entity moves far away from a sensor collider, but still has it in it's CollidingEntities
i need to check the inverse too, and see if it got removed from the sensor collider
Yeah, I'm aware of some issues regarding collision events and CollidingEntities. They should be fixed by this PR
https://github.com/Jondolf/bevy_xpbd/pull/112
It just has a collision stability regression that I still need to fix
ah ok. so if i disabled the sleeping plugin that would "fix" it for the time being?
No, I think sleeping is unrelated for that issue
ok
i can't seem to get CollidingEntities to show in egui world inspector, despite registering the types
Yeah it's saying that HashSet<Entity> needs to be registered but it doesn't seem to work
maybe it needs some manual impl or something
But ya I'll revisit the sleeping + collision event + CollidingEntities PR in a few days hopefully
I am making something that is made for speed-running, and I love the idea of having a ghost to play against. Tracking the position of a "ghost" seems almost trivial, but how would you account for frame-time issues doing it like that? Does this make sense? Imagine super-meat boy, or a racing game where you see your previous deaths.
what kind of issues are you imagining?
if I were to come up with a design off the top of my head, I would just record every position and animation at a fixed update, and set velocity of each ghost towards the next one in their list. you can easily fit a hundred recordings in under a Mb, and linear approximation should be fine for the handful of frames that might render between the fixed ticks?
(though I know that the normal method for this is to record inputs and replay them, but that seems risky, and not like that much of a memory savings, and you could also time travel more easily if you wanted that)
How viable would it be to piggyback off of bevy query filters for SpatialQuery instead of using CollisionLayers? Basically, SpatialQuery could have a generic ROWorldQuery parameter so you could do SpatialQuery<(With<Solid>, Without<Player>)> in your system param. Instead of having each layer be declared as variants of a single enum, you would just make them as marker components. Aside from simplification, this would have two useful benefits: one is that it would make it less of a pain to use SpatialQuery in any system that needs to mutate position by excluding them from the filter, the other is making it easier for other systems to make use of these flags without needing to sync marker components with flags. It may be necessary though to implement a flag trait on the components you want to do this for though, as I imagine many bevy projects will use more than 32 different components especially if they have any generic components.
It would still be necessary to have a filter for excluded entities, but instead of being a SpatialQueryFilter type it could just be any entity iterator so [] would work as an empty filter.
Yeah I had the idea of allowing Query filters for spatial queries, just never tried if it would work. I think it would definitely be the most natural and flexible approach for Bevy and its ECS, so we should definitely try.
One issue here is that the spatial query pipeline currently maintains a collider HashMap that maps the collider entity indices with some data that we need to give to Parry and the spatial query filters (the collider's shape, position and collision layers). This means that we can't just apply Bevy's Query filters for that, since it's just a HashMap. IIRC this was for performance reasons or something, but I might be misremembering
But I do think it can be refactored to work
Here's a quick n' dirty implementation as a wrapper in case you want to see
#[derive(SystemParam)]
pub struct SuperSpatialQuery<'w, 's, F: Filter> {
spatial_query: SpatialQuery<'w, 's>,
filter: Query<'w, 's, (), F>
}
impl<'w, 's, F: Filter> SuperSpatialQuery<'w, 's, F> {
fn cast_ray(
&self,
mut origin: V3,
direction: V3,
mut max_time_of_impact: Real,
solid: bool,
mut exclude: Vec<Entity>
) -> Option<RayHitData> {
while let Some(hit) = self.spatial_query.cast_ray(
origin,
direction,
max_time_of_impact,
solid,
SpatialQueryFilter::new().without_entities(exclude.clone())
) {
if self.filter.contains(hit.entity) { return Some(hit) }
origin += direction * hit.time_of_impact;
max_time_of_impact -= hit.time_of_impact;
exclude.push(hit.entity);
}
None
}
}
It would still be necessary to have a filter for excluded entities
If we keep the excluded entities thing, then yes; however we could also just allow users to do this manually through predicates/callbacks
Yeah that would be good too, would be compatible with the same loop structure I implemented there
Ah yeah this should work. I'd imagine that it's not super performant to just redo ray casts when it doesn't match the query though; ideally the filtering would be here I think, that way Parry can skip the Qbvh leaves without having to redo work
But that's slightly trickier, because the pipeline currently doesn't have access to the ECS unlike SpatialQuery
My thinking there was to move the origin forward to each erroneous hit and reducing the max_toi accordingly, but I don't know how qbvh works so it may not be that helpful
And you have to readjust the toi at the end, which I didn't do there, but it should return this:
Some( RayHitData { entity, normal, time_of_impact: max_time_of_impact - time_of_impact})
and instead of mutating the max_toi, make a copy to mutate
Yeah it's definitely worth testing and benchmarking, I think it'd be a great usability improvement and make things more flexible
I don't personally have time to do it for 0.3 (coming in a couple of weeks probably) but I can try after that, or if you have time then you could make a PR as well
Awesome, I will first see how this lazy wrapper fares and if it fits in convenient enough I'll try implementing it properly and see the performance.
Different engine entirely, but we tried something similar in Unity previously and the issue with moving the origin forwards was that it could skip a collider entirely if you had two colliders in exactly the same position and intended to skip one and not the other. Just something to keep in mind there
I see, that would be a pretty insidious issue so thanks for sharing. Was your solution to just move the origin 99% of the way forward?
We actually gave up in the end
We were trying to recreate a feature from a future version of Unity which didn’t exist in the version of Unity we had, but did in the next LTS. We were trying to avoid updating because we were so far in, but ended up updating just to get this feature
I see, thanks!
Now that I'm not on mobile I can see the code properly.
If I understand the code correctly, it looks as though -- as you suggested -- moving the origin only 99% of the way forward (give or take some float inaccuracies) would probably work fine here since you're pushing onto the exclude vec.
@fallen citrus hmm, another potential issue is that people will still probably want to filter by collision layers as well. Collisions would still have to use CollisionLayers, so it'd be useful to reuse those instead of having to add both a collision layer and a separate marker component, like Layer::Ground and a Ground component.
Not sure if this is actually an issue though, since we could just allow users to manually handle layers in callbacks, and RayCaster and ShapeCaster could maybe still store masks as an optional property or component
Replacing CollisionLayers honestly doesn't seem like it would be all that much of a gain in terms of DX. Also you should be careful with moving things to a callback, if that can't get inlined somehow you might end up with a bunch of extra function call overhead
Got the wheel suspension hooked up based on raycast, feels much nicer now
nice
Yeah, I think I agree overall, and I'm not planning to replace CollisionLayers as of now.
However, if it can be done efficiently, I do think it could be very powerful and perhaps more ECS-like to be able to e.g. "cast ray against every collider with component X" or even "cast ray against everything that moved" instead of having to manage collision layers and masks everywhere. With the current setup, you also need to do some extra work; for example, you probably have a Player or Enemy component anyways, but for spatial queries you would still need to manually define and add separate collision layers for them.
I think an ideal ECS-like API could be to replace CollisionLayers with some other component that uses plain query filters like With<T> for collision masks (no idea how this would be done tho), and spatial queries would also just use query filters like suggested here. I feel like this is difficult to do efficiently though, so I don't know how viable this is.
This might not be a perfectly fair comparison, but I do think I like the API without CollisionLayers a bit more:
With CollisionLayers:
#[derive(PhysicsLayer)]
enum Layer {
Ground,
// ...
}
fn setup(mut commands: Commands) {
commands.spawn((
Collider::cuboid(5.0, 1.0, 5.0),
CollisionLayers::all_masks::<Layer>().add_group(Layer::Ground),
));
}
fn raycast(spatial_query: SpatialQuery) {
let query_filter = SpatialQueryFilter::new().with_masks([Layer::Ground]);
spatial_query.cast_ray(Vec3::ZERO, Vec3::NEG_Y, 1000.0, true, query_filter);
}
Without CollisionLayers:
#[derive(Component)]
struct Ground;
fn setup(mut commands: Commands) {
commands.spawn((Collider::cuboid(5.0, 1.0, 5.0), Ground));
}
fn raycast(spatial_query: SpatialQuery<With<Ground>>) {
spatial_query.cast_ray(Vec3::ZERO, Vec3::NEG_Y, 1000.0, true);
}
Wow that became long 😅
i like that. in my code my collision layers are basically just copying names of marker components that everythign has anyway, and i expect that's fairly common. if it can be done efficiently i think it would feel more ECSy
but being able to do spatial queries against Added<Something> would be cool
"what spawned near to my player" -> SpatialQuery<(Added<Powerup>)> ...
Yeah that's another benefit, things like Added<Powerup> or Changed<Transform> should "just work" for spatial queries (and collisions if we implemented it there as well)
The main concern would probably be performance, so it should definitely be compared to the current approach tho
But it would also only affect the entities/queries that do have these filters, for everything else it wouldn't have any cost I think
Is there a way to define the orientation (rotation) for fixed joints?
The latios framework uses components to construct collision layers for its find pairs algorithm.
Looking for some debugging pointers; I've got a 2d game set up where there's a ball; it has a rigidbody::dynamic, restitution of 1.0 and ball:collider; when it runs into various other colliders that i have in the scene it doesn't actually "bounce" at all, i have set the combination mode thing to "max" and i'm using the main branch currently. any pro tips on where to go figuring out what ive screwed up?
That seems to be a bug caused by a commit from a month ago actually, thanks for catching it! I'm surprised no one noticed it earlier 😅 I'm fixing it now
lol; happy to test if you have a commit somewhere 🙂
wouldn't happen to also manifest as possibly making collision events be "laggy" would it? sensor variant seemed to fire immediately 😄
Shouldn't affect collision events, there's just an incorrect condition that causes restitution to always be 0
But I know of some issues with collision events that should be fixed by #112 once I have time to finish it
cool; will follow along there; thanks so much for this library btw been great for the most part
The restitution issue should be fixed on main now
things are bouncing! now to see if i can do some work arounds on the sleepy colliders 🙂
Hello! Very neat library, I have a tiny, probably very stupid question but is there a way to see the collision normal in the CollisionStarted & CollisionEnded events? I'm trying to figure out if I need to look at the Collision events instead since they have contact points, but I'm not sure. Basically what I'm trying to do is to check if my player is standing "on the ground" like this:
fn collision_events(
mut movables: Query<&mut Movable>,
mut collisions: EventReader<Collision>,
) {
for collision in collisions.iter() {
if let Ok(mut movable) = movables.get_mut(collision.0.entity1) {
movable.on_ground |= collision.0.normal.y >= 0.9;
}
if let Ok(mut movable) = movables.get_mut(collision.0.entity2) {
movable.on_ground |= collision.0.normal.y >= 0.9;
}
}
}
But this is kind of messy and I will never detect if the collision ends like this. Is there a better way perhaps? 😅
(Trying to do the catlikecoding unity tutorials in bevy)
I tried to create my own joint, It seems I would need to add it to the solve_contraint and joint_damping systems.
But those are not exposed in the API.
How can I add my custom joint that its contraints are resolved.
solve_constraint is public so it should work as shown in custom_constraint.
joint_damping is currently private yeah, I can make it public in a sec
joint_damping is now public, but it requires a bit more manual scheduling than solve_constraint since there isn't a separate system set for user joint damping. To avoid conflicts, it's probably best to use .after(SubstepSet::SolveVelocities)
I think we could maybe add an extension trait to add methods like .add_xpbd_constraint::<Constraint>() and .add_xpbd_joint::<Joint>() to App so that you wouldn't have to manually schedule these things
Yeah CollisionStarted and CollisionEnded only give access to the entities, so you need to use Collision events. You could maybe do something like this, although it's not exactly optimal:
fn collision_events(
mut collisions: EventReader<Collision>,
mut started_collisions: EventReader<CollisionStarted>,
mut ended_collisions: EventReader<CollisionEnded>,
) {
for collision in collisions.iter() {
let entity1 = collision.0.entity1;
let entity2 = collision.0.entity2;
if started_collisions
.iter()
.any(|ev| ev.0 == entity1 && ev.1 == entity2)
{
// respond to started collision
} else if ended_collisions
.iter()
.any(|ev| ev.0 == entity1 && ev.1 == entity2)
{
// respond to ended collision
}
}
}
On the main branch there is also a new Collisions resource (name TBD since it's so close to the event name) which would allow you to iterate e.g. CollisionStarted events normally and get the collision data easily like collisions.get(entity1, entity2)
I currently face that issue where the application panics due to scheduling issues:
let substeps = app
.get_schedule_mut(SubstepSchedule)
.expect("add SubstepSchedule first");
substeps.add_systems(
(solve_constraint::<FixedJointWithRotation, 2>,).in_set(SubstepSet::SolveConstraints),
);
I also tried with before and after instead of in_set but that didn't help.
SubstepSet::SolveUserConstraints
Oh that's cool, I might pop over to the main branch then, it'd be very useful to just iterate over CollisionStarted and CollisionEnded and look up the contacts through the Collisions resource like you said! Appreciate the help! 🙂
Note: If I recall correctly, Collisions currently has an issue where the collisions are only available when the system accessing it is scheduled at a pretty specific spot; this PR should fix it (and some other issues) once I have time to finish it
I see! Good to know, I can probably just schedule my ground checking system to run in the PhysicsSchedule with a bit of luck 😄
I'll give it a go, thanks!
Not sure if this is optimal but it works:
fn collision_events(
mut movables: Query<(Entity, &mut Movable)>,
collisions: Res<Collisions>,
) {
for (entity, mut movable) in movables.iter_mut() {
let mut on_ground = false;
for collision in collisions.collisions_with_entity(entity) {
on_ground |= collision.manifolds.iter().any(|m| m.normal1.y >= 0.9 || m.normal2.y >= 0.9 );
}
movable.on_ground = on_ground;
}
}
Added it here:
.add_systems(SubstepSchedule, collision_events.after(SubstepSet::ApplyTranslation))
Well, it works until it starts sleeping, of course 😅
I'll go for the Started/Ended events.
It seems fixed joints can lead to some strange behaviors, is there a good way to prevent it to happen with adjusting some of the values?
Looks like maybe you put it into an impossible-to-satisfy setup?
I just spawn them and add a fixed joint with 1.5 on the anchor:
let box_gltf = asset_server.load("models/box-small.glb#Scene0");
let size = 0.25;
let cube_1_entity = commands
.spawn((
SpatialBundle {
transform: Transform::from_translation(SPAWN_POINT),
..Default::default()
},
// Collider::cuboid(size, size, size),
RigidBody::Kinematic,
Name::new("little_cube"),
Thing1,
))
.with_children(|commands| {
commands.spawn(SceneBundle {
scene: box_gltf.clone_weak(),
transform: Transform::from_xyz(0.0, -0.25, 0.0),
..default()
});
})
.id();
let cube_2_entity = commands
.spawn((
SpatialBundle {
transform: Transform::from_translation(Vec3::new(2.0, 2.0, 2.0)),
..Default::default()
},
Collider::cuboid(size, size, size),
RigidBody::Dynamic,
Name::new("little_cube"),
))
.with_children(|commands| {
commands.spawn(SceneBundle {
scene: box_gltf,
transform: Transform::from_xyz(0.0, -0.25, 0.0),
..default()
});
})
.id();
commands.spawn(
FixedJoint::new(cube_1_entity, cube_2_entity).with_local_anchor_1(Vec3::new(1.5, 0.0, 0.0)),
);
and there is a simple system that rotates the kinematic cube:
pub fn rotate_thing_1(mut thing1_query: Query<&mut Transform, With<Thing1>>, time: Res<Time>) {
for mut t in thing1_query.iter_mut() {
let position = SPAWN_POINT + Vec3::X * 1.0;
let rotation = Quat::from_rotation_y(time.delta_seconds() / 5.2);
t.rotate_around(position, rotation);
}
}
Copied most of the code (minus the gltf meshes), works correctly for me
I wouldn't expect that kind of problems to be possible in such simple cases, I've mostly seen it for very long chains of bodies where the masses are very small, which can cause numerical issues with f32
I can share the repo if that helps?
Yeah that'd be useful, thanks
its on the bevy_xpbd_test branch
(you can press L to lock the mouse, and editor_pls is available too.
You can also "equip" an object by pulling it towards you with the left mouse button, but when you rotate left and right, it sometimes deforms (like stretches)
Yeah this is really weird 🤔 I have the issue in your project as well, but when I do a one-to-one copy of spawn_experiment and rotate_thing_1 and the assets into a separate example, it works
@quartz heart it's this box 😅
// main.rs lines 94-97
spawn_blaster(Vec3::splat(3.0), &mut commands, asset_server.as_ref());
spawn_small_box(Vec3::splat(1.0), &mut commands, asset_server.as_ref());
// THIS
spawn_small_box(Vec3::splat(2.0), &mut commands, asset_server.as_ref());
Removing it fixes the joint issue. There's a box that goes flying so I think the box is clipping into the rotating dynamic box which causes it to get a massive angular velocity that takes a long time to converge
Doesn't solve the jitters/stretching when equipping objects though; it seems to happen at very specific angles only so it could be some numerical issue or something
I'm trying to solve a source of non-determinism. I printed the PreviousPosition in the integrate_pos system. In the picture, before I run the PhysicsSchedule I print the PreviousPosition. You can see though, while the frame 1s start at the same position, the first time it's printed in integrate_pos it's different. Is there a system that would change PreviousPosition that runs before integrate_pos?
I print PreviousPosition after it's set to Position so the issue would actually be with Position
It looks like the position is different even in update_aabb, is there anything that even runs before that?
According to bevy_mod_debugdump there isn't. I don't understand how the position is changing.
It's happening sometime between Prepare and the beginning of BroadPhase
oh, is it because of PreviousGlobalTransform. That isn't pub so I can't register it as a rollback component.
yeah, I tried that with a fork and now I don't get any desyncs!
done in #166
Ideally you wouldn't need to rollback it since it's mostly an implementation detail required for syncing Transform changes to physics positions, but it'll do for now
I also still can't tell if bevy_xpbd is truly deterministic or not 🤔
I was testing bevy_gaff with varying amounts of lag (even one full second), and it was still visually behaving perfectly deterministically when using keyboard controls for movement, but the logs say that it is desyncing every now and then. The logging seems to use a custom previous position component though, so maybe that's just not updated correctly or something
Also grabbing objects via mouse causes desyncs quite easily, but idk if it's caused by e.g. indeterministic input handling or spatial queries or something else
Have you tested with other inputs/scenarios? Like 3D physics?
There's a cross-platform determinism test that just spawns a 3D stack of cubes and records an insta snapshot that is checked to be the same across platforms and git pushes in the CI
But ideally it'd be more complex, maybe with pre-recorded inputs for movement, and maybe some joints and spatial queries
could maybe recreate the demo shown here in some way, although it's still a bit simple imo
Introduction Hi, I’m Glenn Fiedler and welcome to Networked Physics.
In the previous article we explored the physics simulation we’re going to network in this article series. In this article specifically, we’re going to network this physics simulation using deterministic lockstep.
Deterministic lockstep is a method of networking a system from on...
For me the videos on the site doen't load for some reason.
Yeah it's just a big cube that can be rolled on the ground, and there's a ton of smaller cubes that stick to the larger cube on contact
so it's kinda like a snowball becoming bigger, but with cubes, and the demo has deterministic rollback networking
But it doesn't really matter what the demo is, just something complex enough that it should be a reliable determinism test and ideally include as many features as possible
seems like LinearVelocity and AngularVelocity are "changing" (ie being mutably dereferenced) even though their values dont change, for static bodies that can't move. could that be possible?
hmm unless one of my systems is mutably referencing them heh
nope, not me afaik
debugging some netcode and it looks like my static walls' linvel and angvel are changing every tick, where bevy defines changing as having been mutably dereferenced
i wonder if it's possible to tell bevy to undo the mutably referenced marker if we know the component wasn't changed
Maybe fixed on main now?
there were systems that were setting the velocities of static bodies to 0 (since they don't have velocity) even if they were already zero
fixed, thanks 😄 static walls aren't replicating every tick now heh
I think that demo actually has some interesting edge cases, I think the article about interpolation mentions how hard it is to write accurate interpolation because there's so many things rotating and moving on arcs
Definitely a lot more complex than what you see in many networked games, where you usually try to supress motion on any axis that isn't useful for gameplay
I know there is another source of non-determinism in my game so I'll be tracking that down now
Is xpbd stateless?
Define stateless
Some things are stored for two or more frames like current and previous collisions (for collision started/ended events and in the future maybe persistent contact manifolds) but there's not much long term state. Mostly it's just components and small configuration resources
Also for the broad phase and spatial queries there are acceleration structures
Primarily for networking, Unity insisted that physix can’t be used for networking and only their new starless physics engine can be used for fully networked experiences.
As you need to predict and roll back constantly.
For example stacking cubes becomes really challenging with a starless engine, and often you end up with continua small movements which make the stack collapse after a few frames.
Yeah I guess bevy_xpbd is somewhat stateful, which enables some performance optimization and useful APIs
Can't say much about how it affects networking
I wonder how you would implement e.g. a broad phase with a stateless approach though, just rebuild acceleration structures from scratch every frame?
Yes that’s what Unity physics seems to do.
(And it is a big performance bottleneck)
The nice thing with bevy_xpbd is that you could just make a StatelessBroadPhasePlugin and replace the built-in one with that
With my current rollback code I don't think I roll any of the PreviousX components back, tho I do also avoid a bunch of them because my code acts directly on Position/Rotation, rather than using Transform/GlobalTransform. I wonder if that is why my simulation always drifts after a few seconds
I can't imagine the state of caching layers would matter all that much tho, if you apply updates before anything uses it it should act as if there was never any state to begin with
For determinism you'd probably want to roll back Position, Rotation, PreviousPosition and PreviousRotation, and maybe LinearVelocity and AngularVelocity. Maybe also TimeSleeping (and Sleeping?) but that's probably less important
And maybe Transform and PreviousGlobalTransform if you operate on transforms (which you don't)
ExternalForce and ExternalTorque too surely?
Yea if you use them then probably those as well
I don't set those manually at all but I desync if I don't roll them back
Interesting 🤔
Is CollidingEntities used internally anywhere or would it only need to be rollbacked if used?
I don't think it's used anywhere right now at least
Also, PreviousGlobalTransform needs to be rollbacked because of one of the systems in plugins::sync. I haven't checked which one specifically.
Yeah it's probably transform_to_position
It skips entities if the values of their global transforms haven't changed, so if PreviousGlobalTransform isn't correct, Position and Rotation are recomputed
I think
Out of curiosity, why is there a Position/Rotation component instead of using Transform?
What are PreviousPosition and PreviousRotation even for? 🤔
Also GlobalTransform has drifting issues due to the Affine4, which would require ugly workarounds like bevy_rapier's number rounding hack
or Affine3? idk
XPBD uses them in the solver in a few places:
- Computing contact positions at the current state (
Position) and before substep integration (PreviousPosition) to compute the relative tangential motion for handling static friction - Computing new velocities after constraints have been solved using
v = (x - x_prev) / delta_time. XPBD is position-based (hence the name), so velocity updates are derived from positional updates - Probably other things
Hmmm, wouldn't some of those require that it's set to Position before velocity is applied and constraints are solved? 🤔
PreviousPosition is set equal to Position right at the start of substep integration, before velocity is applied
unless I misunderstood the question
If PreviousPosition is set equal to Position at the start of physics, we don't need to roll it back right? 🤔
I don't seem to get desyncs turning it off. I'll leave it off and see if it causes desyncs.
The only reason I added it was because bevy_gaff does
Yeah I don't think you should need to roll back PreviousPosition and PreviousRotation in theory (and probably in practice) unless the engine does something dumb somewhere
And yeah bevy_gaff does roll it back, but I don't think it's actually needed, and it's probably there just in case it contributes to desyncs since bevy_gaff still has some desync issues when there's latency
Does the ShapeCaster component (I forget if that’s the actual name or not) cast from the position at the end of the frame, or is it from its position at the start of the frame? And/or is there a mode to have a cast run from the previous position to the current one?
Usecase is interpolated projectiles that e.g. fire off a particle system when they hit something, but at the point they hit them at, not where they ended up at the end of the physics frame.
I’m on my phone and it’s kinda tricky moving around GitHub on mobile, so please forgive me for asking something that’s probably really quick to see from the source code.
This was apparently a case of rtfm. Looks like I can set the origin of the shapecast to be the offset to the original position and then direction/max toi to whatever you land it in its end position. Easy-peasy!
I think a good middle ground will be at least to say that predicates alone can be sufficient for raycasting, provided that there's no meaningful loss in performance of doing group tests in the predicate. You can use predicates for both query filters and excluding entities, and I went ahead and wrote this as an iterator so that cast_ray can just get the first value of the iterator and ray_hits can collect from it.
pub struct RayHitIter<'w, 's, 'a, P: Fn(Entity) -> bool> {
spatial_query: &'a SpatialQuery<'w, 's>,
origin: V3,
direction: V3,
max_time_of_impact: Real,
solid: bool,
predicate: P
}
const OVERLAP_CHECK: Real = 0.99;
impl<'w, 's, 'a, P: Fn(Entity) -> bool> Iterator for RayHitIter<'w, 's, 'a, P> {
type Item = RayHitData;
fn next(&mut self) -> Option<Self::Item> {
let mut exclude_entity = None;
let mut cumulative_time_of_impact = 0.;
while let Some(RayHitData{entity, time_of_impact, normal}) = self.spatial_query.cast_ray(
self.origin + self.direction * cumulative_time_of_impact,
self.direction,
self.max_time_of_impact - cumulative_time_of_impact,
self.solid,
SpatialQueryFilter::new().without_entities(exclude_entity)
) {
if (self.predicate)(entity) {
return Some( RayHitData { entity, normal, time_of_impact: cumulative_time_of_impact + time_of_impact})
}
cumulative_time_of_impact += time_of_impact * OVERLAP_CHECK;
exclude_entity = Some(entity);
}
None
}
}
I will test the performance and if its good I'll replace the query filter with this and submit a pull request
As for whether a component based approach can replace groups entirely, an option might be to do something like have a component like CollidesWith<T: Component> and groups can be generated from this under-the-hood. But my ECS + dynamic programming knowledge is very limited, this seems like the sort of thing that might require all of these components to be reflected
Or perhaps CollidesWith<T: Bundle> if there's a way to iterate through component IDs in the bundle
I asked a somewhat similar thing in #ecs
#ecs message
I guess it might be possible to store the component IDs and somehow use those, but I couldn't easily find a way to do that without having to access World when adding the collision mask component
but my knowledge of this stuff is also quite limited so I'm not really sure what's possible
I see, well as I learn more I'll keep it in mind
Hello, I am having an issue with xpbd_2d that my entities get their Transform.translation.z position reset back to 0.
Is there a way to solve this in the main-branch of the plugin? I tried in 0.2.0 and then the z-order remains correct. But I would prefer to use the main-branch since the physics seems to work much better there with FixedUpdate.
Ah, I guess it got broken again :P I think I know where it's happening so I'll try to fix it
Hmm, for me the z component actually isn't getting reset on main 🤔
Do you have a code example?
I'll be away until later today/tomorrow. So I'll post an example when I get back. But I have a pretty simple setup where I'm spawning tiles and entities with xpbd colliders and rigidbodies using bevy_ecs_ldtk. I tried printing the values and first frame the z value returns as 1 but then gets set to 0 2nd frame onward. Manually trying to set the transform to something else resets the value after one frame again.
I was able to reproduce this, but only when the bodies/colliders are children of some entity. That bug should now be fixed on main.
If your bodies/colliders are not children, then it's probably something else
Tested and confirmed that it works now, thank you very much for the super quick response!
is there any quick way to make visible colliders?
In your Cargo.toml add the "debug-plugin" feature
e.g.
# I'm using the main git branch in this case
bevy_xpbd_2d = { git = "https://github.com/Jondolf/bevy_xpbd", branch = "main", features = [
"debug-plugin",
] }
You can enable or disable it during gameplay by modifying the PhysicsDebugConfig resource:
fn toggle_physics_debug_info(mut physics_debug_config: ResMut<PhysicsDebugConfig>) {
physics_debug_config.enabled = !physics_debug_config.enabled;
}
Yeah collider debug rendering is only on main currently
Do we have some way to make 1-way collisions?
You can utilize collision filtering to handle it pretty neatly. Datael added a PostProcessCollisions schedule for the filtering systems and a one_way_platform_2d example to show how it'd work
you could probably copy most of the one-way platform logic from the example and just adapt it to 3D (or it might actually work as-is in both dimensions?)
In my case I'm planning to make one-way doors so it'll be a bit different from one-way platforms, but that seems usable
Yeah that should work basically the same, just need to change the direction of the one-way behavior
i'm having trouble spawning bullets in relation to the positions of my ship. if i do my spawning before physics sets runs that frame, the bullet is always spawning effectively at the previous position, because the spawn happens and then physics runs, and then the player's ship is in their new location by the end of that frame.
if i spawn my bullets after the physics sets have run, i get the correct position of the player's ship for that frame, but then.. physics has already ran, so my bullet doesn't get integrated into the physics system until next frame - so it doesn't advance according to it's velocity etc. so it still appears one frame behind where it should be
Shouldn't the bullet also move if it spawns before physics? 🤔
when i spawn the bullet, it's origin is relative to the player. then physics runs, so the player moves, and the bullet moves too but you can see the bullet originated at the previous position of the player
I mean it doesn't really make sense to fire a bullet from the new position and also immediately move from there
You could make the bullet also gain the ship's velocity for the first tick, but it would still be slightly off I'd imagine
the bullet inherits the velocity of the player's ship and then some, but it still ends up originating at the old position, because i want the bullet to spawn based on the after-physics position of the ship, but if i spawn the bullet after physics, the bullet is a frame late appearing
at least i think that's the problem. wasn't expecting this to give me so much grief.
(especially noticable at higher movement speeds)
It just helps a lot if you decide on the order in which such events happen, in my case players use skills before moving (because skills can overwrite their movement), which means they would've always shot from their "previous position"
If you somehow had faster updates than frames/ticks you could possibly interpolate between positions and use that as the origin for the projectile
Where exactly in the schedule are you spawning the bullets? I would imagine .before(PhysicsSet::Prepare) to work
most of my game logic sets are in fixedupate before any of the xpbd sets runs, i was spawning there too. just experimenting with spawning after physics but it didn't really solve the problem
The only way to make it feel more responsive is something like the sub-tick timing you see in games like overwatch and CS2
i want to spawn a new bullet relative to the after-physics position of my player, but also have the bullet added to the physics system and simulated that frame i think. cake and eat it situation i suppose.
basically i want to spawn the bullet and instead of adding Position, add PositionFn(lookup player entity, calcualte bullet pos)
you could just do bullet_pos += (player_vel + bullet_vel) * delta_time to artificially simulate where the bullet should be when spawning it I guess
yeah that might be the way. feels a bit wrong
i thought about spawning before physics and then snapping the position after physics in the same frame, would that be less bad? 🤔
i don't know if the player is about to slam into something, so maybe snapping post-physics is safer than predicting the origin before physics
hmm i can use the players Position - PreviousPosition after physics to create a delta, and add to the bullet position
I don't think that works
PreviousPosition is the position before the current substep's integration step, not the position before the substep loop started
ah
also worried about collisions and things happening from when the bullet is spawned at the "wrong" position. could get messy
Oh right there's also another hack you can do
If the bullets aren't physics, you can just move them whenever
My projectiles do ray/shape casts then move to the new position, so I can run them after physics if I want
but they are physics bodies
my bullets are just dynamic bodies with circle colliders
what's the best way to disable collisions on bullets for the very first frame, until i snap the position? just manipulate collision groups before/after?
If you disable collisions for the first frame, can't they just jump trough anything that's directly in front of you?
if i set my collisionlayers in the post-physics hack when i snap the position, and set it to not collide before, that should mitigate some weirdness
kind of but it's not really advancing forward in that initial frame unless the player is
Wait so why would spawning it after physics not work?
Yeah I guess changing collision layers could work in your case; maybe we should add a ColliderDisabled component or something to make it more convenient though
it would also be neat to be able to make my own bullets not collide with my own player, which i don't think the collision layers is suitable for
could also add the collider after snapping the position, but this would make spawning them more annoying
hmm
technically you could make a collision filtering system that does this, and you could make a custom component like ExcludedCollisionEntities (bad name maybe)
in the future I'd like to have nicer per-entity collision filtering though, just not sure yet what the best approach is
do physics entities get simulated the first frame they are added? ie, if i spawn a fresh entity at a Position, with a non-zero LinearVelocity, at the end of the frame, will that entity still be at Position?
cool, i might do this. running into your own bullets is fairly janky atm
they get simulated normally, there's no logic that checks if the entity was spawned this frame
so the position will be different
ok thanks
if spawned before physics
the one_way_platform_2d example I mentioned here #1124043933886976171 message shows collision filtering, your use case should be much simpler to implement tho
the main caveat is that it needs to loop through collisions separately from the narrow phase (since it's a separate system and not a callback/hook) so it might add a bit of overhead
is it normal for camera jittering when not building in release mode?
(when a camera's copying player position)
now i'm just predicting the ship position by one timestep forward and spawning the bullet there, and it's working nicely. will ignore that and hope it doesn't become a problem later 🙂
// predict the position of the ship after physics runs later this frame,
// and spawn the bullet relative to the new location of the ship.
// this is so the bullet can still be simulated this frame.
let dt = 1.0 / FPS;
// see the xpbd integrator for this logic.
// abdridged. not supporting Locked Axes, normal gravity, etc.
let next_rot = *rot + Rotation::from_radians(ang_vel.0 * dt);
let next_linvel = lin_vel.0 + dt * ex_force.force() * inv_mass.0;
let next_pos = pos.0 + dt * next_linvel;
let bullet_origin = next_pos + next_rot.rotate(bp.bullet_spawn_offset);
let bullet_linvel = next_rot.rotate(Vec2::Y * bp.bullet_speed) + next_linvel;
No, this sounds like a system ordering issue. Might be something like copying the transform of the player after physics but sometimes GlobalTransform has already updated before that code runs
that sounds tough to fix, maybe I should just make the player its parent
and fix my hacky AnimationPlayer-finding code that breaks when I do that
use https://github.com/jakobhellermann/bevy_mod_debugdump to see your system ordering
@vestal minnow That example makes some assumptions about getting collisions when you stop touching, but that doesn't seem to actually be true and I end up being able to go back trough the one-way gate sometimes ... Is it still possible to figure out when collisions with something end when they get filtered? 🤔
Actually it's pretty obvious I guess, I can just increment a number each execution, update it if I skip the collision again, then remove things that aren't from the current iteration
well, now the camera's rotation is copying the player's...
I can multiply it by the player rotation's inverse to reset that, but now the rest of the world jitters
...so I guess I'm back to square one on the jitter problem?
If you want to reset the rotation wouldn't it make more sense to set Transform.rotation to default?
What exactly do you mean by "reset of the world jitters"?
the rotation respects the parent player's rotation, even if it's set to Quat::IDENTITY every frame it'll still rotate
the world jitter is hard to explain, some frames don't have the rotation fixed and some do, so the camera's direction has flashes of other directions?
I can take a video if you want
Oh this is with the camera being the child of the player?
yep!
I think it might be that the system that inverts the player's rotation has system ordering issues now
it's the same system, so yes
I essentially traded position-based jitter for rotation-based jitter... lol
😂
Should be as simple as adding a
.after(PhysicsSet::Sync)
.before(bevy::transform::TransformSystem::TransformPropagate)
I think ... At least if you have physics in PostUpdate and the camera update system in PostUpdate
that's definitely better, but still has issues
I'll try it without the camera parenting nonsense, brb
yeah that fixed it, thanks :)
.add_systems(
PostUpdate,
systems::camera_follows_player
.before(bevy::transform::systems::propagate_transforms)
.before(bevy::transform::systems::sync_simple_transforms),
);
that's how mine's scheduled. the system sets the camera's translation to the plauers without copying the rotation:
//..snip
camera_trans.translation.x = player_x.min(max_x).max(min_x);
camera_trans.translation.y = player_y.min(max_y).max(min_y);
it's nice and smooth
(well, 60fps like the physics..)
this looks like a better way though rather than referencing the system names!
hi! Trying to use bevy_ecs_ldtk to create tilemap collision, but all the colliders end up at the same place? I asked on the help channel for that plugin and they don't know why the transforms are wrong. Any help would be really appreciated
0.2
yeah a lot of issues have been fixed since 0.2 so you could test if the main branch works
the main branch of bevy_xpbd should work with bevy_ecs_ldtk since some people are already using them together #1124043933886976171 message
(although there was another issue, but that was just fixed)
yep that was it. Has the crate just not been updated in a while?
Yep, I just haven't made a new release yet. I still have a couple of things I'd really like to add for 0.3 (namely child colliders, which was planned to be one of the main additions but is still somewhat WIP) but I should've just made a release ages ago tbh
if I set the linear velocity of a kinematic body with an update function, will it be stopped at walls?
No, it would require a separate collision handling system. There's a very basic example here
at some point we'll probably add something like Godot's collide and slide and a built-in character controller
so for a player character, would you recommend a dynamic or kinematic body at the moment?
With a dynamic body you need to implement less things manually (but on the flip-side, you might have a bit less control)
so it might be a bit easier to get started at least
bevy_mod_wanderlust is also an existing dynamic body character controller, but bevy_xpbd support is WIP
I could put some more work in to getting it fully workin with xpbd