#Avian Physics
1 messages ยท Page 3 of 1
I'll just do it as soon as the clean up PRs I have are in, I'd like to more solidly separate concerns about the physics world and the controller's state anyways, which this should be useful for finding the stragglers
Btw are you aware of anything that is currently missing in bevy_xpbd but would be required in bevy_mod_wanderlust? A few days ago we added contact queries (like Parry's contact) since the character controller apparently needs it, and I was wondering if there's anything else that's been missing
I don't think so, the main one was just shapecasting/raycasting and then contact manifolds
I just have a shoddy implementation of penetration correction inside the controller which is why I need the contacts
the raycasting is mainly used for sampling of normals since shapecasting is a bit iffy on that
Tbf I think I could still make it work without raycasts or the contacts, it just makes it more robust to weird colliders
Cool, it'll be nice to have a proper character controller to suggest to people as an option since it's a pretty common request
No hurry though, we probably also need 0.3 to be released first :P
how ready is the child colliders pr? i have a bunch of code i'm standing by to remove once that lands. worth me giving it a try already?
i have dynamic rigidbodies that i want to additionally give large sensor colliders to, denoting how far their gravity field extends
I think that should work fine already. The main issues are with handling arbitrary nesting in a stable way (GlobalTransform causes issues...)
But yeah a RigidBody with direct children shouldn't have any issues
ok i'll give it a go, thanks
abstracting colliders is going to be difficult
abstracting? (in this context)
oh I thought you were talking about child colliders lmao
oxidized_navigation did it by just using parry colliders
https://github.com/TheGrimsey/oxidized_navigation/pull/14
which is probably enough for now since we don't really have other proper collision detection crates
although I kinda want to experiment with it eventually, could even try implementing Bevy's primitive shapes RFC and use it for some collider shapes
(not sure if that'd make sense but could try)
most of the code for this was the examples, it's a pretty simple change imo
though I think looking at it it might be better to make the xpbd and rapier features be separate crates
so that you can push out a release for the main crate without having to wait for both xpbd and bevy_rapier to release updates
Honestly I still think an interop crate for all these physics libraries would be a good idea
It isn't really any individual thing, but having to re-implement several things because each library has its own slightly different way (or just type) to do the same thing isn't really great
I'm already essentially writing one because controllers are a bit too deeply entwined with the physics engines guts
How would you implement an engine-agnostic collider type like you mentioned?
Probably just have an intermediary type that mirrors the shapes the libraries have
either that or just have 1 "source" collider type from one of the physics engines
I mean all the features come from parry, the biggest issue would be that they're both different component types, since parry obviously doesn't #[derive(Component)]
For now: I don't think all Bevy physics libraries will be parry based
Very true
it's parry
they both use parry primitives
sure for now
We really need bevy to get something to describe colliders, otherwise we can't import physics from gltf files either ๐ค
for now
the problem comes from migrating
which is why I think a mirror type would just be better long term
it seems like there's a couple closed source glam based ones, and one glam based one that might eventually get open sourced depending on if the dev feels like completing it
yeah that's why I have the idea of implementing the primitive shapes RFC (bevy_geometry) and creating a collision detection lib for it (uses bevy_geometry for some shapes but maybe engine agnostic?)
would be glam based ofc
well problem with that is not all shapes, even right now: https://docs.rs/bevy/0.11.3/bevy/prelude/shape/struct.Torus.html are convex
so theres a bit of a distinction here
we could precompute a decomposition of each basic shape I guess
just use sdfs for everything /s
but that's still not great because the decomposition might be too low or high resolution
Also there was a Jolt integration, and I'd expect to see Box2D eventually
SDF physics is so coool
with SDFs you could get robust collisions for e.g. cloth :P
https://mmacklin.com/sdfcontact.pdf
but requires some mesh representation for the other object iirc
and some spatial subdivision/voxelization stuff
I don't see this as a problem necessarily; the primitive shapes would be the normal convex colliders, and for the collision detection (and visual meshes) of other shapes there would just have to be separate types not included in bevy_geometry
also isn't this also a problem for normal visual meshes? you can't have just a primitive torus shape since you need to control the resolution
yes, but right now there is a distinct "this shape is what the collider will be"
because we have a separate Collider type
if you add a torus as a collider to an entity and it comes out being a pancake then it'll be a bit confusing for some
so mostly there does need to be some sort of "IntoCollider" thing
yeah what I was imagining is that the new Collider would basically be an enum (or store an enum) and then each variant would contain a shape like Collider(ColliderShape::Ball(Ball)) where Ball would be a primitive shape
gotcha, yeah, that was more my idea as well
I mean that's just parry's TypedShape I guess
just with shape primitives from e.g. bevy_geometry
I'm also a bit unsure how we can even generify calling methods like cast_ray between libraries
It feels like the interop crate itself would have to implement the integration rather than the other way around
because how do you query what you need from the ECS world?
yeah I'm not sure if stuff like that can be generalized nicely
the APIs + implementations can be so different
I guess again there could just be an official collision detection + spatial query plugin that everything uses
would still be physics-agnostic maybe
or idk
I wonder if I could plug in Rapier inside bevy_xpbd just for the solver ๐ค
very unnecessary ofc but just to test modularity and such
Could you just have a trait like RayCastWorld that can be implemented for system parameters? bevy_rapier has Res<RapierContext> and bevy_xpbd has SpatialQuery which both are system params, so maybe you could add a generic ray casting method
it still won't help with what I need to query in any given system
since you can't query for a trait resource
id have to know beforehand that I am using rapier or xpbd
which kind of defeats the point
yeah true
sounds great 
I didn't consider that oxidized_navigation only used the collider shapes and voxelized them so it was pretty simple to make generic
while a character controller needs way more integration
I mean hmm, this could work it'd just require a lot I think
I was thinking of having the RapierSystemParam just be a decomposed SystemParam in a way
where rapier sets the specific component ids and then constructing the final SystemParam out of that
but it seems a bit too dynamic
or maybe "deferred" system param initialization would be a better term?
I guess that is just what SystemParam::State is in the first place
eh, maybe this won't work
since SystemParam isn't object safe
yeah I don't really know what to do here, the only other option I can think of is having a "type override"
where for interop you have a file you use backend::*;
but that seems finnicky as all hell
yeah idk if it's possible to generalize functionality like cast_ray in a meaningful and robust way
I mean it should work the same given the same inputs to any physics engine
it's just the type/api level that is finnicky
yeah API level is mostly what I meant
but there's also query filters, weirder properties like "solid" and "stop at penetration"...
which aren't necessarily shared across engines
(although in our case most of them are because parry)
query filters I don't think should be hard to generify
they are effectively just |entity: Entity| -> bool {} closures
with possibly added state
so you could generify that with just a
pub trait Filter {
fn test(&self, entity: Entity) -> bool;
}
could maybe include ECS access in some implementations
- filtering by collision layers can be separate
I think the best bet for cast_ray is just setting a convention and a trait
as a physics library export a common type like SpatialQuery that is a SystemParam and implements SpatialQueryMethods
yeah that could work I guess
I just feel like you will pretty much always need some manual integration for each engine since the APIs can have different requirements and the data can be formatted differently (local or world-space normals?)
so I'm unsure how useful an interop crate that covers things other than basic data types would be
well the point is that the libraries themselves would deal with that to conform to the common apis
otherwise the alternative is every user that wants to switch physics engines has to do that themselves
which essentially means you are vendor locked to one
(unless you want to undergo a massive amount of work yourself to migrate your project)
I mean other engines already do this, dealing with stuff like local vs world space normals is just part of integration
yeah you're right, I forgot how interop crates are meant to work lmao
I need sleep
but yes at the very least common data types would be incredibly useful on their own
because they are the things being stored in components
glam for math types, Collider enum that is shared across bevy libraries would make interop/switching significantly easier
for something like Rapier, wouldn't a separate Collider add significant overhead? since it would internally need to convert it for parry
for heightfields/trimeshes it would double the memory overhead
or well for all colliders yes, but most are negligible
performance overhead not as much
but could always do some stuff to mitigate that on our end as well
but yeah interop generally will increase memory cost
@vestal minnow I'm considering implementing SDF collisions, but I have no clue how I would go about wiring that up to bevy_xpbd, seems like it wouldn't be as simple as making a new collider type in parry that's for sure ๐ค
it would probably require a separate collider component if it's not possible to make a custom collider type for parry
but if you had that SdfCollider working, you could then make a custom narrow phase (only for the SDFs, the normal narrow phase would remain) that computes the collisions, and then you'd insert the contacts into Collisions
the solver currently doesn't use Collider directly anywhere so it would work normally
same with the broad phase, if the entities have ColliderAabbs and other required components, it should work even without Collider
So basically, just find a way to somehow compute SDF contacts, and then add them to Collisions, and everything else should probably work
*with a reasonably sized grain of salt
Hmmm, that seems fairly doable ... And it would require custom SpatialQuery stuff I guess ๐ค
Also an interesting idea: a floating character controller could skip shapecasts and just use the SDFs
Might even be able to make something really fancy and apply a cone/cylinder beelow the player to the geometry so you always get correct distances, than some hacky best guess ... Maybe two or more different shapes if you want to have inverse kinematics that looks right? ๐ค
The thing with shapecasting is that we don't update spatial query stuff every substep
Which means you can't get a truly accurate float, and there's a bunch of weirdness with the shapecasts from parry that always ends up causes unexpected behavior if you throw it an edge case
(you could call .update_pipeline() every substep, just would be slow probably)
(especially without the incremental updates lmao)
It's still faster without the incremental updates tho ๐
If only they just worked
But it would just generally not be worth it. Especially when just shapecasting once per tick nets me a nice 60% server load :')
Before I fixed the incremental update my game wouldn't even run with these numbers tho
Ever since I updated bevy_xpbd so I could implement the one-way gates I've been able to walk trough my terrain ... Is this an intended feature from some improved contact stability stuff? 
If I have a plane/box and a 5m radius trimesh which is half above and half below the surface I can just walk straight trough it, and then sometimes get stuck on some non-existant geometry inside ... Very odd
@vestal minnow Is there anything I should keep in mind to make sure my collision logic can provide stable contacts? These sdf collision seem to all really just be point cloud-sdf collisions, except you can give the points radii and snap them to the surface cheaply (even repeat that procedure to get more stable contact points I guess?)
The most important thing is that the contact points and normals are valid, but if possible, it's also good to add collisions that are nearly penetrating but not quite, since the non-penetrating state can turn into a penetrating state mid-solve because of other constraints moving bodies around. If there's a way to get actual contact manifolds instead of a single contact, then that's a plus as well
I'm not familiar with the actual sdf contact logic though so idk what's possible
hi, I'm struggling to make a grounded check for my platformer character. Do shapecasts not inherently check that the entity is not itself?
Yeah they don't check that currently. You can add a SpatialQueryFilter and use collision layers or .with_excluded_entities([...]) to exclude the player entity
(it's actually .without_entities, oops)
I'm not able to get it to detect the ground. This is my code for making and testing the shapecast:
fn spawn_player(mut commands : Commands, assets : Res<AssetServer>){
commands.spawn((
SpriteBundle{
texture : assets.load("sprites/circle.png"),
transform : Transform::from_translation(Vec3::new(64.,128.,5.)),
..Default::default()
},
LockedAxes::new().lock_rotation(),
RigidBody::Dynamic,
Collider::ball(8.),
Restitution{coefficient : 0.0 , combine_rule : CoefficientCombine::Min},
Player{ max_speed: 64., accel : 6., decel : 10., jump_force : 100., grounded : false, ground_max_distance : 0.1},
ShapeCaster::new(Collider::ball(8.), Vec2::ZERO, 0, Vec2::NEG_Y)
));
}
fn player_ground_check(mut player_query : Query<(&mut Player, Entity, &ShapeHits)>){
if let Ok((mut player, ent, hits)) = player_query.get_single_mut(){
player.grounded = false;
for hit in hits.iter(){
if hit.entity == ent { continue;}
let dist : f32 = hit.point2.length();
println!("dist {}", dist);
if dist <= player.ground_max_distance{
player.grounded = true;
}
}
}
}
I get weird results. The distance only gets printed very sporadically, and also when I rub up against this one specific part of the level, which is on the player's left instead of below it
I think the default has max_hits of 1, so if it's detecting the player, it's not continuing to check for the ground
I think you need .with_ignore_origin_penetration(true)
And the shape caster seems to be the same size as the collider, so sometimes the very edge might hit the environment due to numerical precision
ShapeCaster::new(
Collider::cuboid(self.size.x - 0.5, self.size.y - 0.5),
Vector::NEG_Y * 0.05,
0.,
Vector::NEG_Y,
)
.with_ignore_origin_penetration(true) // Don't count player's collider
.with_max_time_of_impact(0.2)
.with_max_hits(1),
Here is what i'm using in my spawn player command
Should be easy to adjust for a ball collider
@vestal minnow would you expect this test to pass? it doesn't for me. not sure if i've overlooked anything.
#[test]
fn body_with_velocity_moves_on_first_frame() {
let mut app = create_app();
app.insert_resource(Gravity::ZERO);
app.add_systems(Startup, |mut commands: Commands| {
// move right at 1 unit per second
commands.spawn((
SpatialBundle::default(),
RigidBody::Dynamic,
LinearVelocity(Vector::X),
Position(Vector::ZERO),
));
});
// one tick only.
tick_60_fps(&mut app);
let mut app_query = app.world.query::<(&Position, &RigidBody)>();
let (pos, _body) = app_query.single(&app.world);
assert!(pos.x > 0.0);
}
(it passes if i call tick_60_fps twice)
So what it seems like you want to use your ground_max_dist when initializing your ShapeCaster and the grounded check is simply player.grounded = !hits.is_empty()
And initializing your ShapeCaster would go like this ShapeCaster::new(Collider::ball(8.), Vec2::NEG_Y * ground_max_distance, 0, Vector::NEG_Y)
well either that or I can control the distance using max_time_of_impact
and just cast from 0,0
I would expect it to pass... does app.update() run only startup systems on the first call, or also other schedules?
The Main schedule has this
i think it still runs them all on the first tick, i'll add a print statement to Update to check
so I tried creating the cast like this:
Player{ max_speed: 64., accel : 6., decel : 10., jump_force : 100., grounded : false, ground_max_distance : 8.0},
ShapeCaster::new(Collider::ball(7.), Vec2::NEG_Y * 8.0, 0., Vec2::NEG_Y).with_ignore_origin_penetration(false).with_max_hits(1)
but somehow the cast is still hitting the player? Those colliders should never overlap
ignore origin penetration should be true
yep it runs Update with just 1 tick
hmm
but if the cast starts below the player, if the player is on the ground, surely it needs to hit immediately?
my wild guess is that you do some sort of setup using commands and don't call apply_deferred before those components are needed to get into a query that does the simulation ๐คทโโ๏ธ
setting to true doesn't fix it
Oh now I see. Your ShapeCaster is still intersecting your player collider though right?
I do call apply_deferred I think
it seems to be. The distance is always the same when I print it
i found 1 instance of apply_deferred before setup
wait nvm
in prepare i think
(adding apply_deferred after clamp_restitution in prepare didn't help though)
even if I place the shapecast inside the player, with a radius of 4, and ignore_origin set to true, it still doesn't work
ShapeCaster::new(Collider::ball(4.), Vec2::ZERO, 0., Vec2::NEG_Y).with_ignore_origin_penetration(true).with_max_hits(1)
I have to go in a few minutes will look at it later if your issue is still not resolve but I still don't really get the distance check
You just want to check if your shape hits are not empty
Way simpler
Unless you want some more advanced logic
but shapecasts go forever don't they? Until they hit?
so I need to check that the cast isn't colliding with some ground that's ages away
You can just set the max_time_of_impact in your shapecaster initialization
is that not hard to get exact? Like why time and not max_distance?
it's basically a fancy term for distance
Yeah
so casts travel a set distance per second?
yep
so I have that ignore_origin thing set to true and it still hits immediately
or time of impact = how long until first hit when moving at 1 unit/s
So the way it all seems to work is by just sampling points against an SDF. If you want to calculate collisions between two sdfs you just pick points in space and snap them to the surface of the first sdf, then test them against the second sdf. There's probably a fair amount of optimization available with how you pick points. Getting near-contacts should be very easy tho, when checking a point against an sdf you just get positive numbers for non-penetrations, and negative numbers for penetration, could probably just set a threshold for what non-penetrations to pass on to xpbd ... Main challenge really becomes picking the points (and ofc optimizing when colliding with large compoud sdfs, which are very common)
yeah, picking the right points might be tricky
btw for the threshold you could use NarrowPhaseConfig property prediction_distance since it's what other contacts use
I noticed it was private so I made it public now
Yea especially since it impacts collision accuracy, collision stability and performance
the results are so inconsistent and I have no idea why
hard to say, but I think parry (the collision detection lib) handles the ignore_origin_penetration thing a bit weirdly in some cases
the most robust option might be to add the player entity to the shape caster's excluded entities
Hmmm, getting stable grounded results? My approach for this has been working quite well. Let me check all the hacks I added to it to make it work
Filtering the caster's entity definitely helps, and you'll also want a shapecaster that's slightly smaller than the player and have it start a bit above the ground. Then you want to discard every hit that says the toi is 0.0
i think i know why, will format it and push something to demonstrate
this worked, but I have a slight problem with that the filter has to include the entity it's being spawned inside, so I end up with this horrible mess of code. Is there any simpler way to do this?
fn spawn_player(mut commands : Commands, assets : Res<AssetServer>){
let pe : Entity = commands.spawn((
SpriteBundle{
texture : assets.load("sprites/circle.png"),
transform : Transform::from_translation(Vec3::new(64.,128.,5.)),
..Default::default()
},
LockedAxes::new().lock_rotation(),
RigidBody::Dynamic,
Collider::ball(8.),
Restitution{coefficient : 0.0 , combine_rule : CoefficientCombine::Min},
Player{ max_speed: 64., accel : 6., decel : 10., jump_force : 100., grounded : false, ground_max_distance : 8.0}
)).id();
let filter : SpatialQueryFilter = SpatialQueryFilter::new().without_entities([pe]);
commands.entity(pe).insert(ShapeCaster::new(Collider::ball(4.), Vec2::ZERO, 0., Vec2::NEG_Y).with_query_filter(filter).with_max_hits(1).with_max_time_of_impact(8.0));
}
@vestal minnow I see this // Todo: Reuse manifolds from previous frame to improve performance comment in the narrow phase code, do you have any plans on how to reuse the manifolds? Trying to make this collision code have as few (ideally none) allocs, but this one seems a bit harder ... I guess I just have it take a &mut Vec as input and assume that'll eventually be a reused one?
Parry's contact_manifolds takes a &mut Vec<ContactManifold> that will automatically be reused by exploiting spatial and temporal coherence if possible. The main issues with this when I last tried it were (1) it needs to use Parry's ContactManifold, so we'd need to do type conversions, and (2) it also seemed to cause collision instability
But if we did implement it, I'd probably add a contact_manifolds_persistent that takes a &mut Vec<ContactManifold> as well
or just make contact_manifolds take the vec instead of adding a separate function
I guess I'll implement it like that then ... I'm actually making some decent progress on this sdf collision stuff somehow ... It's just gonna need to have some restrictions you might not have with regular collision logic ... Tho I guess no one is gonna miss arbitrary sdf on arbitrary sdf collisions, just like how you don't trimesh-trimesh
For people who have had issues with collision events being missed or CollidingEntities not being updated correctly, it should be fixed on main now that I finally finished up #112
I also added methods for adding new contacts to Collisions in case that's useful
Hmmm, might be useful, wiring up my collisions to bevy_xpbd was actually the next step for my sdf collisions ... I should be able to have correct collisions for point or line based shapes like spheres, capsules and rounded cones (now that's a primitive you don't see often). Ofc no real contact stability work yet, but I can't really test that propperly if I don't see how the changes impact things
@vestal minnow The way the narrow_phase plugin is set up is a bit odd. I'd expect I'd need to disable it, and implement my own, but it also handles things like collision events and for some reason it's also responsible for checking sleeping entities and entities on non-overlapping collision layers. So I guess it's easier to just leave it enabled, and add my own system to add to Collisions?
Hmm, yeah it handles things that it probably shouldn't, I'll refactor it in a moment. The collision "validity" checks are unnecessary since they should be done during the broad phase, and wake_up_on_collision_ended should be in the SleepingPlugin.
I'm not sure where collision events and CollidingEntities stuff should be though; a new plugin like ContactReportingPlugin? Might make sense since not all projects require contact reporting
A ContactReportingPlugin makes sense yea
And yea I'd expect those validity checks to be done in the broad phase, especially since it already skips static-static, and sleeping-sleeping or sleeping-static is a similar optimization
Hey is there a Plugin or code sample equivalent of Rapier's DebugRenderer?
There's the debug-plugin feature
If you enable debug-plugin, it'll automatically add PhysicsDebugPlugin. It's very limited in 0.2, but on the main branch it can debug render colliders, AABBs, rigid body axes, contacts etc.
and can be configured globally with PhysicsDebugConfig or at an entity-level with the DebugRender component
I somehow missed it. Thanks, it works
But yeah I'll try to make PRs to fix these today, should be pretty quick
But you can also add new collisions during PostProcessCollisions and it should work probably maybe potentially
Hmmm, the structure of manifolds is more complex then I thought ... I imagined it would just be a list of points with local positions and normals for each. But it's a list of [normals and lists of normals and points]
Is the top layer the contacts made based on geometry, and the manifolds extra points sampled around it?
Yeah my rough understanding is that a ContactManifold is kinda like a face on an object, and it can contain many contact points for stability (like a cube could have 4 points in one manifold). Each point in a manifold has the same normal
Currently, I don't think the manifold itself is used for anything though, so you could maybe put all contacts in one manifold even if they had different normals. For semantic reasons and robustness I don't recommend it tho
The main issue with it afaict is the Vec<Vec<>> it ends up creating
It's interesting the structure shows something about how the manifolds work tho
Would it be good to use smallvec/tinyvec for the inner vector? Might reduce overhead a bit
Hmmm ... I guess it depends on how many manifolds you normally get for each point
If it's usually something like 4 it might be worth it, but if it's all over the place it would just be wasting some more memory
Yeah, might need to benchmark with different situations
@cinder summit wake_up_on_collision_ended is now in the SleepingPlugin, and I also have branches for the two other refactors. They ended up being slightly trickier than I expected, but might be working now. I'll properly test and finish them up tomorrow
hi! Just trying to check for collisions with the player and these exit sensors that I have in each level, but the collisions are never detected and I'm not sure why. Here's my code
fn check_exit_collision(mut collision_event_reader : EventReader<CollisionStarted>, mut level_selection : ResMut<LevelSelection>, exit_query : Query<(Entity, &ExitBlock), Without<Player>>, player_query : Query<Entity, With<Player>>){
if let Ok(player_ent) = player_query.get_single(){
//println!("collisions detected: {}" , collision_event_reader.iter().len());
for (exit_ent, exit_block) in exit_query.iter(){
for contact in collision_event_reader.iter(){
if (contact.0 == player_ent && contact.1 == exit_ent) || (contact.0 == exit_ent && contact.1 == player_ent){
println!("okay! Switching level to level {}!", exit_block.level_to_spawn);
*level_selection = LevelSelection::Index(exit_block.level_to_spawn as usize);
}
}
}
}
}
@cinder summit I managed to do the refactor finally, so NarrowPhasePlugin is only responsible for managing Collisions, and there's a ContactReportingPlugin that only sends collision events and updates CollidingEntities.
Some kinda confusing and arbitrary collision state handling with things like during_current_frame is still needed though... Collisions has to store collisions from the previous frame for the events (and in the future maybe persistent contact manifolds) and you also don't want to discard contacts between sleeping bodies
But overall, the structure is more modular and less coupled now
I think I'll also move the broad phase, narrow phase, contact reporting and contact queries under one collision module now. It's a bit weird to have the contact data structs and contact queries under narrow_phase, and having a shared module for collision things is also nice for high-level collision docs
Hmmm, guess it's finally time to test these collisions then ๐ค
Hmmm, wait that refactor of moving the checks to the broad phase is also an optimization isn't it? ๐ค
Most of the checks were already there, but yeah it might be a slight optimization
The checks were mostly just unnecessarily copied in the narrow phase
Guess I'll have to check the performance numbers again before I test the SDF collisions ... Probably also need a consistent test case ๐ค
It seems like the desync issues for my game and maybe bevy_gaff are not bevy_xpbd's fault. I found a bug with the way checksums for desync detection are being compared: https://github.com/gschup/bevy_ggrs/issues/71
Cool, thanks for looking into it. IIRC I also noticed that there didn't seem to be actual desyncs in bevy_gaff with keyboard movement, even with high lag, but it was still reporting desyncs.
With mouse input (grabbing) there definitely were desyncs though, but that could just be some input handling issue or maybe a joint determinism issue
Did not see this breaking change coming, good thing pattern matching saves the day ๐
- collisions.retain(|(entity1, entity2), contacts| {
+ collisions.retain(|Contacts { entity1, entity2, manifolds, .. }| {
@@ -54,7 +54,7 @@ pub(crate) fn one_way(
- if contacts.manifolds.iter().all(|manifold| {
+ if manifolds.iter().all(|manifold| {
yeah I thought it's unnecessary to duplicate the entities for args since they're accessible from the contacts
Oh that's your one-way wall thingy, I was confused and thought the one_way_platform_2d example was broken lmao
Yea I have basically a copy pasted and simplified version of it
With the ability to specify the direction rather than it always being up
Had to simplify it cause the other code caused desync
It's still pretty similar tho
QbvhUpdateWorkspace stack depth can be more than 255, so I changed u8 to u16.
After this change, I no longer received the error:
attempt to add with overflow
on the line:
workspace.stack.push((chil...
Haha, did someone else make the same workaround? ๐
Yea, the 255 shouldn't actually ever happen, you shouldn't get a qbvh with 255 levels of depth
This workaround just makes invalid behavior go from crashing to going on as if nothing is wrong
Eventually the performance of incremental update degrades so much it stops being usable in a game
Another potentially slightly breaking change incoming :)
I grouped collision detection stuff under a new collision module that makes docs nicer and the structure more logical. Just affects imports tho, and the same stuff is still in the prelude, so it's not really breaking
https://github.com/Jondolf/bevy_xpbd/pull/184
I'm unsure if I should also move collider components there... currently all components are just in components which is nice for seeing all components at once, but it'd also make sense to have colliders in collision
Grouping by components doesn't usually make a lot of sense
Yeah I agree in general, but where would e.g. RigidBody go? Or Mass?
I guess I could have a dynamics module or smth though
These aabbs are pretty close to the worst case possible, no wonder it runs so poorly ๐
Now I wonder what would happen if I just put both narrow phases in my app 
Should just work assuming you don't duplicate the collision state handling logic
I doubt it'd have a significant perf impact since they use different collider types
although it'd query a bit more ig
Put both collider types on an entity and get aabb race conditions 
I think it would still work probably
just duplicate contacts if the colliders overlap perfectly
Is ShapeHits even available for 2D? I tried to query it but I'm not getting any hits.
Nvm I'm dumb, have to spawn ShapeCaster first.
Hey dude, can you share the source code if you don't mind? Been trying to detect collisions with shape casting, but I just can't get it to work.
can do!
this code spawns the player:
let pe : Entity = commands.spawn((
SpriteBundle{
texture : assets.load("sprites/circle.png"),
transform : Transform::from_translation(spawn_trans.translation),
..Default::default()
},
CameraTarget(true),
LockedAxes::new().lock_rotation(),
Friction::new(0.0),
RigidBody::Dynamic,
GravityScale(2.0),
CollisionLayers::new([WorldLayers::PLAYER], [WorldLayers::WORLD]),
Collider::cuboid(15., 15.),
Restitution{coefficient : 0.0 , combine_rule : CoefficientCombine::Min},
Player{ max_speed: 64., accel : 6., decel : 10., jump_force : 130., grounded : false, ground_max_distance : 8.0}
)).id();
commands.entity(pe).insert(ShapeCaster::new(Collider::cuboid(14.,14.), Vec2::ZERO, 0., Vec2::NEG_Y).with_max_hits(1).with_max_time_of_impact(4.0).with_query_filter(SpatialQueryFilter::new().without_entities([pe])));
as you can see I have to spawn the player on its own without a shapecaster so that I can make a filter to exclude the player entity, then I add the shapecaster afterwards
and this code checks the hits, in my case it checks if the player is grounded:
fn player_ground_check(mut player_query : Query<(&mut Player, &ShapeHits)>){
if let Ok((mut player , hits)) = player_query.get_single_mut(){
player.grounded = !hits.is_empty();
}
}
It looks like adding this filter made it work...
Thank you!
no worries, glad I could help!
Question - I'm using bevy-xpbd to make a physics based game where you control a rope with two mice (each mouse controlling one end of the rope). It's working fantastically so far - way more stable than rapier was - except that maybe 20% of the time I get what seems to be a physics death spiral when starting the game.
When I don't get the death spiral, the rope jerks around rather energetically for the first fraction of a second, which makes me think I'm initializing it in an un-physical configuration. Are there any useful tricks to initializing a system of jointed bodies in a smoother way?
It actually seems to freeze every time when I'm recording a screen capture, which is interesting, otherwise I'd show you what it looks like in a normal startup
In any case here's a bit of gameplay so you can see how the rope is set up
I can't help, but just wanna say that that looks like a tremendous amount of fun
looks fun! is that a bunch of rectangle colliders with joints connecting them, set so they can;t collider with eachother? i wanted to try out a 2d rope / grappling hook at some point.
is it multiplayer, or do you have 2 mice plugged in?
the only time i've noticed huge energy spikes when spawning is when i've accidentally spawned something on top of something else it collides with, in which case it gets moved off at a high speed
i've not dealt with joints much though
Yeah this looks super fun!
You should just make sure the distances between the rope segments are correct at the start, and if you are specifying the attachment points/anchors, make sure they're the correct way around :P Also check if things are overlapping at the start, that could make things rather explosive
Other than that, I don't really have any specific tricks to make the initial state stable. One thing you could try is to start with a high compliance (low stiffness) and decrease it to the desired value over time, so that the joints wouldn't freak out and overshoot as much at the start. This feels a bit hacky though, so ideally it would be stable from the get go
Hmm, I'm trying to implement debug rendering for ray casts + shape casts, but I'm a bit torn on if I want the methods in SpatialQuery to also have debug rendering...
Gizmos require mutable access, so I would need to make all of the methods take a &mut self, which means you wouldn't be able to have multiple systems with SpatialQuery run in parallel. You also wouldn't be able to conveniently use your own gizmos in systems with SpatialQuery.
I think a decent compromise would be to only have debug rendering for RayCaster and ShapeCaster, and to add drawing utils to PhysicsDebugRenderer (or Gizmos) so that people could easily render the results of SpatialQuery methods, but only if they want to
Also, I wonder how I should render shape casts ๐ค
A ray, but with the shape + hit rendered at hit points? Or just a ray and hits, like how I'll probably render ray casts?
Debug rendering for RayCaster is working
Arrows and (default) colors, yay or nay?
I like the arrow!
And the default colors seem fine
Yay
Aww thanks y'all ๐
Yep exactly, with 2 mice plugged in controlling the ends. Had to get hardware events to differentiate the mice on mac but it works!
Hmm, great call on getting the anchors reversed! That's so plausible - I was confused as to which body was the 'first' and which the 'second'.
The compliance easing suggestion is a great idea as well.
For debugging, you could also pause the sim at startup before physics has run:
.add_systems(Startup, bevy_xpbd_2d::pause)
then later you can run resume or use PhysicsLoop::step in some system to step individual frames
the PhysicsDebugPlugin also renders joint things on the main branch with the debug-plugin feature enabled
3D works as well now, although I'd really like if we had solid gizmos for the arrowheads... I think someone was already working on it tho
Okay, I've figured out my issue, thanks for the assistance! Turns out the extra energy when spawning and the death spiral application freeze were more or less separate physics issues.
The extra energy came from a misalignment of joint anchors at each end of the rope, where I calculated link positions with a full gap at the start, but set up the link's anchor assuming a half-gap at the start. Now they're both half-gaps. Pausing and stepping the simulation made this very visible, I'm sure the debug view updates would've shown this as well but I didn't update.
The death spiral application freeze seems to just come from doing physics work and application setup work at the same time. A 0.1 second delay between app startup and starting physics solved this issue.
In Unity I'm used to using some kind of anchor auto-configuration to make it impossible to misalign joints during initialization like this; is there some way to do that in bevy_xpbd? At least for a 2d revolute joint, I would think the anchor points not coinciding would very often be unintentional. Like, set the anchor point on one body in its local space, and automatically set the anchor point on the other body to the corresponding location.
This isn't implemented yet, but we definitely could do this quite easily. After bevy_xpbd 0.3 is released, I'll probably work on joints (and joint motors), so I can implement it then
The auto config would probably be enabled by default like in Unity, but can be disabled
I'm glad you got it working! Your game looks super fun :)
@vestal minnow I remember there was some talk in the rendering-dev channel about aabbs for bevy, did they have any plans for what to use or to make one?
Since I'll be needing to use a non-parry bvh for shape/raycasting, I'm wondering if it makes more sense to just make a generics approach in bevy_xpbd, that can then be used for any future collision detection impl ... I guess we'd also need a bvh to speed up the broad phase too ... Ideally one that can actually update ๐
IIRC there wasn't a conclusion on what to use or whether to make one, but generally it was considered useful to have a (glam-based) BVH for Bevy, both for rendering and physics
I'm on mobile rn though so I can't look for the discussion
But if we do end up making a new collision detection lib for bevy_xpbd, we would eventually need a BVH for spatial queries and probably the broad phase, so it would definitely be useful to make one
Nvm, here #rendering-dev message
No crates were mentioned tho (other than Parry's Qbvh)
And bvh, which was the other nalgebra-based one I think
I think bvh initially used glam and switched to nalgebra actually ๐ค
it used to use nalgebra, then switched to glam, then switched back to nalgebra
That sounds great ๐
I think @thorn solstice mentioned that crate isn't as optimal as it could be. I might be able to implement something, but I don't really have any clue what type of bvh we should be aiming for, I guess using aabbs is the obvious choice here at least ๐ค
Yeah, it just uses basic binning for sorting which is both slower when generating the BVH and also doesn't generate as good of a BVH as doing something like the space filling radix sort. There's some good articles here about building performant BVHs: https://madmann91.github.io/ (part 1 talks about the radix sort stuff)
I haven't tried implementing it yet. But I've played with the one in An Introduction to BVHs and it produces something that's faster to traverse than the bvh crate by around 40% across a wide range of standard test scenes. I used:
fireplace_room (143165 tris)
sponza (3746636 tris)
bistro (3872303 tris)
hairball (2880000 tris)
san-miguel (9932385 tris)
cornell_box (3968 tris)
I implemented a super simple bvh for this https://github.com/DGriffin91/little_pt/blob/main/src/bvh.rs that's also faster. Though bvh build times are a lot longer.
Hmmm, guess I'll look at that approach then ... I wanted to see what parry's qbvh uses, but as usual the docs don't ell me anything ๐
Also I've fixed my aabbs but I realized bevy_xpbd still uses that angular velocity padding hack ... With things like rolling spheres it causes a lot of unnecessary aabb overlaps ... Not entirely sure what the right solution here would be, but if there's any ideas for solutions I could try to implement something for my sdf collisions at least ... Wouldn't be too hard to add extra info to limit how big certain aabbs get for most of the simple shapes at least ๐ค
Hmm, I could probably fix this by using compute_swept_aabb instead of compute_aabb to get what the AABB would be if we integrated for one frame using the current angular velocity. This would take the shape into account correctly
Might be a bit more expensive, but it's only run once per frame and not once per substep, and it would definitely be faster than having unnecessary overlaps
I think I got it working without the angular velocity hack for normal colliders, but realized that it of course won't work for you since you're not using normal Colliders :P
But it should be pretty simple to replicate for your case as well; shape.compute_swept_aabb(...) is just this:
/// Computes the swept Aabb of this shape, i.e., the space it would occupy by moving from
/// the given start position to the given end position.
fn compute_swept_aabb(&self, start_pos: &Isometry<Real>, end_pos: &Isometry<Real>) -> Aabb {
let aabb1 = self.compute_aabb(start_pos);
let aabb2 = self.compute_aabb(end_pos);
aabb1.merged(&aabb2)
}
and merged is this:
fn merged(&self, other: &Aabb) -> Aabb {
Aabb {
mins: self.mins.inf(&other.mins),
maxs: self.maxs.sup(&other.maxs),
}
}
(inf is component-wise min, sup is component-wise max)
So if you have a way to compute the AABB of an SDF with a given position and rotation, it should work
Hmm, the perf of move_marbles actually seems to be worse with these AABBs 
Eh, it's the same, ig I just had a random lag spike
Also here's an actual link to the fix I made
https://github.com/Jondolf/bevy_xpbd/pull/188/files#diff-1cd32c87ead2ee0e839b357e53c5f4f626cf6f7ef527224cd88c11f13728962f
I want to round my Transforms to prevent jitters (low-res pixely game), where should I schedule the system in so that they're done after the physics stuff?
Hmm, you probably want something like this:
.add_systems(
PostUpdate,
round_transforms
.after(PhysicsSet::Sync)
.before(bevy::transform::TransformSystem::TransformPropagate)
)
but we have to do some kinda weird processing on transforms to keep them in sync with the physics Position and Rotation, so I'm not 100% sure if this works
I think it should work though
(on the main branch)
Thanks! It looks like it's working to me, although I think I still need to tweak the camera movement.
Low-res games are a lot more finicky than I thought 
I do have a way to compute with rotation (and I just add the position after that) ... Using min/max of before and after the rotation kinda sounds wrong, but I guess things don't normally spin that quickly in 1/60th of a second anyway ๐ค
Yeah, it probably doesn't work perfectly for things spinning very fast, like if a body did a full rotation during a single frame, the AABB would treat it like nothing happened... I guess I could split the rotation into steps (pseudo-substepping) and get the lowest min and largest max of the AABB during those steps
I also feel like the correct thing for quickly spinning objects would be CCD once we have that
Wouldn't CCD still need AABB checks? Or does it work separately?
Hmm, probably does
let ltf = rot * Vec3::new(-half_bounds.x, half_bounds.y, half_bounds.z);
let rtf = rot * Vec3::new(half_bounds.x, half_bounds.y, half_bounds.z);
let lbf = rot * Vec3::new(-half_bounds.x, -half_bounds.y, half_bounds.z);
let rbf = rot * Vec3::new(half_bounds.x, -half_bounds.y, half_bounds.z);
(
ltf.min(rtf).min(lbf).min(rbf).min(-ltf).min(-rtf).min(-lbf).min(-rbf),
ltf.max(rtf).max(lbf).max(rbf).max(-ltf).max(-rtf).max(-lbf).max(-rbf),
)
I guess I need to optimize this aabb check tho, I think I can calculate the bounds of a box with a single rotation instead of 4 ๐ค
There we go, I also implemented the swept aabbs ... Seems to perform a fair bit better, and it's nice that my aabbs no longer become multiple meters because the spheres are spinning in place infinitely because there's no friction or angular damping ๐
I think you need to use bitmasks directly, like CollisionLayers::from_bits which is const
IIRC I tried making other methods const, but it was blocked by a Rust feature that hasn't stabilized yet
Make the bits?
yeah we could add const usage to the docs or examples probably, bitmasks are just generally more confusing imo so I prefer the non-const API
Ya that pattern should work
enum Layers{
Player = 1 << 0,
Enemy = 1 << 1,
Ground = 1 << 2,
// ...
}
We can definitely add it in the docs, not sure if we want 2 collision layer examples tho since there's already one with the non-const approach
I guess that example could show both ways
Hmm, good point, that might be a bit more annoying with the PhysicsLayer enum approach
I'm trying to get my kinematic body to not get stuck inside colliders but I'm kind of confused. I stole the kinematic collision code from this example here: https://github.com/Jondolf/bevy_xpbd/blob/a5987536790dc2a1057dd991c360fb7a21ca606a/crates/bevy_xpbd_3d/examples/basic_kinematic_character.rs#L130-L157
I used CollisionLayers so that the character doesn't collide with props sitting on top of the ground. It works, and the character can pass through it, but if you jump in the middle of it you get "stuck".
It's really weird, because even if exclude the props from the bodies queries in the kinematic function, the player still gets stuck inside it, which is weird since the prop is Static and the player is Kinematic
The movement code seems to reset the vertical velocity when the shape caster detects a ground hit
Could remove that and see what happens
No dice, it's still stuck. I can even walk on top of it, even though I can pass through it. I might make a minimal reproduction later.
Ok I'm feeling really stupid (again). Just to clarify are kinematic bodies supposed to collide with static ones?
No
Ok, I think I'm progressively narrowing down the problem. It seems that adding ShapeCaster to my kinematic body causes it to collide with static bodies. It explains why I can pass through static bodies horizontally while still being able to land on top of it, it's because my ShapeCaster was pointing down. Is this intended behavior?
No, the shape caster doesn't have anything to do with actual collisions. Are you sure you don't have movement logic that affects the vertical velocity when the shape caster detects hits?
Hmm, I think you're right...
I'm guessing that the caster isn't affected by physics layers?
Not unless you add a spatial query filter
Thanks for the guidance, I at least figured out the issue! Are there any plans to make the caster easier to use? For example, I needed to filter the entity it belongs to so that it behaves nicely. Though tbh, a general character controller would probably be the best solution.
Yeah a very common issue for people has been that they don't want the shape caster entity itself to be counted, so I'll probably make that a setting that's enabled by default. Eventually I'd like to have a built-in character controller as well, but bevy_mod_wanderlust is also going to support bevy_xpbd at some point (there's a WIP PR) so we'll have a 3rd party controller soon-ish at least
That looks like a really sweet plugin, I'll definitely keep an eye on that!
If only we had a crate for this and it was called bitmask 
I think in the end you still get memed because you can't const impl BitOr on stable iirc
Yep, I'll add this before 0.3 release
I usually do a docs improvement spree before every release
@vestal minnow Any idea if there's normally any tactics used to filter things (with CollisionLayers) early on the BVH level?
Parry has a bunch of visitors like (the things with the cursed names like RayCompositeShapeToiAndNormalBestFirstVisitor). They traverse the BVH with e.g. BFS or DFS, and you can give them callbacks that are run on the BVH leaves. These callbacks can handle the filtering
For reference, you can check the spatial query methods in pipeline.rs, Rapier also has a similar file
Idk if other BVHs handle it differently tho, I've only used Parry's Qbvh
But yeah I don't think the BVH itself handles any filtering, but the methods used for BVH traversal can
Hmmm ... Would it just filter against nodes it finds, or does the bvh actually hold some data about what is below it
Idk how the visitors work, but I think the callbacks you can give them just return true or false, and that determines if you continue the search
And for e.g. collision layers there's just an if that skips the leaf if it has incompatible layers
But this is done on the user-side so you can do any filtering
I'm considering if it makes sense to add something that propagates some filter information up the tree, so you can skip nodes that don't match your collision layer filter (or whatever other data, hopefully also a mask tho). I can't find a lot of info about how people use BVHs, mostly just about how they're made or very simple applications of them
Actually most BVH information also seems to just store triangles in them ... I guess that's what you'd do for raycasting or a trimesh narrow phase?
Also looks like there seems to be some interesting tradeoffs between the BVH2 approach and the SIMD-powered BVH4 approach. Supposedly the less wide your tree the less overhead you get with optimizing it, and the traversal isn't a huge part of the frame's cost. But if you have static data the BVH4 approach can still be a decent amount faster ... Might be an interesting optimization to experiment with at some point, there's a GDC talk about titanfall's SIMD BVH4 and it mentioned they split large static geometry into a separate tree ... It might also have some caching implications tho
wait for relations to drop and make an ECS-based BVH with the querying capabilities of the ECS ๐
Don't think using the ECS directly would be optimal, but it sure would be pretty fancy
I'm a bit stuck on how the order of operations would work for bevy_xpbd tho ...
Right now I'm thinking:
- Add/update all colliders with swept aabbs
- Run broad phase, narrow phase, integration, etc
- Update the aabbs to the normal aabbs at the new position/rotation
- Optimize the tree
Yeah it wouldn't be optimal of course and I'm not seriously recommending it, but having a way to do efficient traversal while somehow being able to interface with the ECS would be nice; I don't really like that our spatial query pipeline has to maintain a hash map with some collider data for the BVH
I'm pretty sure the broad phase and spatial queries generally use separate BVHs, but I'd have to check
I tend to just look at how Rapier does these things, but I'm not sure if that's good or not :P
Honestly having 2 different BVHs just sounds kinda inefficient, it does allow you to have to trees that are maximally optimized for their specific purposes, but now you also have to optimize both of them and have pretty much all data twice
I think the only thing spatial queries have that the broad phase doesn't need is colliders without rigid bodies, tho those are generally pretty rare
I also think we can exclude sensors from the BVH, since they can only detect collisions and not be detected. The broadphase could also just search things if it's a dynamic/kinetic rigid body or a sensor and is not sleeping ... Makes me wonder if we should slap some extra component on static bodies so we don't have to iterate over them
We could also just shove those in a separate BVH 
I don't think they do, at least from what I remember of checking myself a while back
However, I don't think they're actually using that broad phase anymore, but instead use their hierarchical SAP thing that doesn't use a BVH
Their hierarchical SAP is just a combination of sweep and prune and multi-layered spatial subdivision that has several grids with different sizes
But yeah this is for Rapier, idk if it's actually common to use separate BVHs for them. I don't see why it'd be necessary in general
Is there a way to define the origin of a collider?
I think most parry colliders are at local 0,0,0. But there are some exceptions, like capsule_endpoints ... I think you might also be able to give them a relative offset if it's something like a compound collider ... And I guess soon we'll have child colliders which could also be used (probably the least efficient option tho)
compound collider
Oh it looks like that might work, I'll try it out
How do you change the collider's mass? The docs says:
You should generally not create or modify this directly. Instead, you can generate this automatically using a given collider shape and density with the associated from_shape_and_density method.
But the from_shape_and_density method doesn't exist...
Oops, I guess the docs have the old name for that method :P
The current way is a bit inconvenient, but it's to add e.g. ColliderMassProperties::new_computed(&YOUR_COLLIDER, 2.0) where 2.0 is the density. However, my plan is to add a ColliderDensity component tomorrow which will allow you to change it way easier
You could do just ColliderDensity(2.0) with that
And you can also set mass properties for a body independently of the collider mass props with the individual components like Mass and Inertia; note that the collider mass props will be added on top, so you'd use a collider density of 0 if you don't want that
Thanks, I'll give that at try.
However, my plan is to add a ColliderDensity component tomorrow
Nice, you're doing god's work :D
Would anyone be free to do a quick test for the child-colliders branch btw? I think I'll merge that and the collider scale PR early tomorrow, but it'd be nice to have someone test it in an actual project to see if there are any immediately apparent issues that I haven't noticed in my own testing
I'm aware that at the moment they can be a bit more jittery and unstable than normal colliders in some cases, but otherwise I think everything should be working
Actually I think I might just merge them both in a few minutes and make follow-up issues for the remaining known problems. I've been testing quite a bit already and haven't really seen issues apart from the occasional instability with offset child colliders. I think I might know what's causing it as well, but the PR is already very large and delayed so I'll fix the issues in follow-up PRs
I see we need open source games that use xpbd so you can implement new features in them and see if it works
Your game ๐
My game doesn't have any usecases for child colliders tho ๐
I might technically have access to the repo still, haven't checked though lmao
Yea I think you do
I cleaned up some of the repo access for others, but I'd probably run into weird physics issues eventually so I kept yours ๐
Which I guess means you now also have access to SDF physics, maybe even a BVH soon ๐ค
The collider-scale branch might still cause breaking changes if you use transform scale for any physics bodies
I only scale 1 mesh in my game, and it doesn't have physics 
I guess so
don't worry tho, I won't look at or share any of it without explicit permission ofc
You can look at the SDF physics ... I'll opensource it eventually anyway
I also need to opensource the game, but considering I've pushed that back like 4 times now I think it's not gonna happen this year ๐
Could you still quickly test the branch just to make sure performance or overhead hasn't regressed in any meaningful way? I think it now has to do a bit of extra things even for non-child colliders
They're just standard Bevy events and the Collision event does have a basic code example in the docs so I kinda assumed it'd be relatively clear, but I agree it should definitely be documented better
CollisionStarted vs. CollisionEvent::Started
I don't have anything specific in mind
I'm not sure which one is better, separate event types or one enum, but originally I just kinda though it'd be useful to have them separate so that you need to iterate less if you need just one event type. I can see how the enum pattern could be nice as well though
For filtering events, you could just check if entity1 and entity2 match some query with query filters
I literally never use the collision events ... They feel kind of cursed to use, but I think it's the only way to get start/end without tracking it yourself
Seems to up the cpu usage from 25-34% to 26%-35% ... And only got 1 minor breaking change (get_shape -> scaled_shape) ... Tho I do have this odd issue where ... My SDF collisions are broken now 
Well at least perf isn't bad, but collisions breaking is a bit odd
Might be that ColliderParent in the broad phase
Actually it might happen later, cause I bypass update_aabb
you could also implement the child collider stuff for your sdfs but it's also a bit... cursed
in what way are collisions broken? just not detected?
Haven't checked the specifics but they just phase trough everything, which suggests that either the broad phase doesn't find them, or their collisions don't get handled
oh the solver also requires ColliderParent I think, I'll make it optional too
Does it work now?
I made it optional in both the broad phase and solver
It'll just default to using the entity itself if ColliderParent is None
Wait I think you also need ColliderTransform in the solver ๐คฆ
I probably need to make that optional as well
Yea can confirm, things still phase trough everything, but they do at least get to the narrow phase
I'll be back in a minute...
Now?
Seems to work now
Yessss
Thanks for testing that nothing broke horrendously
well... after fixing the stuff
I was thinking I was struggling with building things like SDF collisions and a BVH, but it sounds like these child collisions are much worse ๐
I think I'll hit merge on the 2 PRs and finally be free of child colliders for now, although they are sometimes a bit bouncy still which I need to fix
One thing I realized today is that for the broad phase I can't just expand their AABBs based on the rigid body velocity, because if the body is rotating and the collider is offset relative to it, the collider will of course rotate around the body and have speed from that. So I actually need to consider the linear velocity at an offset position
fixing this fixed some of the instability
but because it resembles uniform circular motion, the direction of the movement changes so I can't just use the offset velocity directly either
this I'll fix later
Are you saying making an AABB requires a sweep using all of thse?
- Position
- Rotation
- AngularVelocity
- LinearVelocity
- Parent Rotation
- Parent LinearVelocity
- Parent Angularvelocity
Yes except not AngularVelocity (it's the same as the parent's) and LinearVelocity would be computed (the offset velocity)
For computing the offset velocity I just need the position delta between the collider and parent and then I need the parent's linear and angular velocity
for 3D it's currently just offset_lin_vel = lin_vel + ang_vel.cross(offset), but ideally it'd consider the circular nature of the motion when the parent is rotating
I wouldn't say it's much worse, but there's a lot more work than you'd expect and a billion special cases, like you need to handle adding and despawning colliders while correctly updating their ColliderParents and the mass properties of bodies considering all the offsets and scaling in potentially infinitely nested hierarchies... oh and also you can't use GlobalTransform for numerical reasons, so you need to do custom transform propagation...
and then you need to support separate material properties, collision layers, events etc. for the different entities
and also ideally not break modularity and make everything super coupled
oh and also you can't access the data of colliders once they're removed of course, and we don't have hooks for that, so to handle mass property updates and other things correctly you need to manage another resource
I kinda want to see how Rapier handles child colliders, it's probably not as complex I'd imagine
I wonder if all this Iterator support I'm building would be useful for xpbd in any way ๐ค
You can construct a Bvh from an Iterator, and the traversal can be done with an Iterator:
fn test(query: Query<(Entity, &CollisionLayers, &ColliderAabb, &Position)>) {
let iter = query.iter();
let bvh = Bvh3d::new(iter.map(|(e, l, aabb, pos)| ((e, l), (Vec3::from(aabb.0.mins)-**pos, Vec3::from(aabb.0.maxs)-**pos), **pos)));
for (entity, layers) in bvh.cast_ray(Vec3::ZERO, -Vec3::Y, 10.) {
println!("{:?}: {:?}", entity, layers);
}
}
The traversal is mostly like this to avoid allocs, tho I still need to alloc a small VecDeque, shouldn't be too hard to reuse that tho
@vestal minnow do child colliders act as if they were a compound collider for you?
I'm a bit confused on the offset velocity
They can have different material properties and collision layers so I'm pretty sure they don't act like compound colliders
Ya I just mean do they act in terms on collision as the same rigidbody
one can be bouncy and the other not but both should move the same velocity
Yea I think they do function as one rigid body, otherwise they would just be two independant colliders with maybe some constraint between them
The offset velocity is specifically to create the AABBs for the child colliders I think
If those AABBs are wrong, they could miss some collisions
If that's somehow velocity or rotation related I'd imagine that would appear as unstable behavior
If you had a restitution of 0 on one collider and 1 on the other and dropped the body to the ground, only one of them should jump up. In a case like this, the velocity would clearly be different
The velocity of a body is the velocity at the body's Position, so if the collider is offset relative to that and the body is rotating, the collider at the offset will have a different velocity
Before child colliders, you can't really have had offset colliders properly, so this hasn't been an issue
that just sounds like 2 rigid bodies though
There's just one rigid body and one actual LinearVelocity component, but for expanding the AABB of the child collider the offset needs to be taken into account
Same thing if there's just one collider but it's offset
Because the uniform circular motion around the rigid body origin will make the collider have extra velocity independent of the origin's velocity
But again, this velocity is only used in the AABB expansion to avoid missed collisions
so in this restitution example the one with 0 will still get some angular velocity right?
because the bouncy part is up in the air
Yes
gotcha okay
ColliderDensity: https://github.com/Jondolf/bevy_xpbd/pull/194
Nice!!!
I am trying to convert my code from rapier3d, and everything seems great until I add joints. Can't seem to keep them from yeeting everything into the void at infinite velocity ๐
Hi!
I have just started learning xpbd and I'm not so sure that I'm doing the collision checks the right way.
Is there a better way to identify the two colliding objects?
I see, so there is no concrete way of doing this.
Alternatives:
- Use
CollidingEntitiescomponent to get all entities colliding with some entity, e.g. get a list of entities colliding with player
- Use methods in
Collisions(new resource on main branch/upcoming 0.3) likecollisions.get(entity1, entity2)(retrieves data for collision between two known entities) orcollisions.collisions_with_entity(entity)
- What .โงฒ. suggested
Something like this?
fn foo(collided_w_ground: Query<&CollidingEntities, With<Ground>>){ .. }
Yep
sounds exciting, I'll be sure to check it out!
Thanks!
Hey, quick question: I find the disconnect between parry shapes and bevy shapes to be ... I dunno the right word... annoying? Confusing? A little ugly? Something between all those. So, is there any downside to using convex_decomposition_from_bevy_mesh() everywhere?
There's several downsides to that:
- Creating colliders using convex decomposition is slow; the algorithm it uses, VHACD, can take several seconds or even minutes for complex meshes.
- Convex decomposition creates compound shapes that are made from several convex hulls. These are approximations of the shape and are less accurate than primitive shapes like
Collider::ball. A ball based on trimeshes or convex hulls would have vertices, so it wouldn't roll perfectly straight. - Computing collisions is much faster and simpler for primitive shapes like balls and cubes than for trimeshes and convex hulls. For a ball, it's mostly just a simple distance check.
My plan is at some point to maybe:
- Implement the primitive shapes RFC for Bevy to have a unified set of shapes that can be used for e.g. rendering, gizmos and collision detection
- Try to create an alternative for Parry using those shapes (although some custom shapes will still be needed for e.g. convex hulls)
This would make things more unified and hopefully less annoying.
Or we could add sdfs to bevy and then use my sdf collisions 
Mhmm
Hmmm ... bevy_sdf and bevy_raymarching ... That sure would be nice
can you make arbitrary lines/curves with sdfs?
I'd imagine it shouldn't be too hard, a capsule is just a line with width. And a curve is just a non-straight line defined by a formula ... So it's probably possible ๐ค
How is this different from https://docs.rs/bevy/latest/bevy/prelude/shape/?
Generation for some primitive shape meshes.
I don't think shape implements any trait nor are they one type, so you can't really do much with the
The other problem I'm having -- again, probably being silly because I'm new to this -- is that I can't position the collider relative to the shape. In rapier3d, the collider is or can be a child, so that can have a separate transform.
There's child colliders on main I think
The use-case being: I have a ground-plane, and I drew a box below that as the collider. (At least in rapier3d, that worked better than trying to make a thin collider.)
You can also do some other stuff, like with capsules you can use capsule_endpoints to have an offset collider, and compound colliders might work too
But I guess the other way is: how do I use the half-space collider? Like, if I just want it to be "can't go -y", is that... (0.0,-0.0,0.0)?
Yeah, nothing should be below the ground
So theoretically that's fine, right?
but the reason I used a box in rapier3d was there were weird problems where stuff got stuck
The parry docs about HalfSpace say it takes the normal, so I think it would be Vec3::Y?
wait is there a different way to just have ground?
I may have missed something very very obvious LOL
I think a box is the most standard way
The way I set up my plane-looking boxes is by having the mesh be offset relative to the collider
So going back to that... do I need to wait for child-colliders to land to do that?
I can also just use a very simple heightfield ๐
If you make the mesh the child you can do it on 0.2. But you can also just use bevy_xpbd main
All of these are also not "geometric primitives" but just shapes used for creating triangle meshes for rendering. A Sphere with a radius would be a geometric primitive, but a UVSphere with longitudinal and latitudinal subdivisions is not (infinite detail vs. some number of subdivisions). Same goes for Capsule, Plane, Torus and so on.
For them to be suitable for e.g. colliders, they would need to be simple and lightweight mathematical representations and not contain rendering-specific configuration.
Thanks, that makes sense.
Yep this would be Collider::halfspace(Vec3::Y), where Vec3::Y is the outward normal. Everything below the Y coordinate of the collider would be considered as ground
ah! I'll try that. thank you again!
While I'm here asking silly questions... what am I missing re: SphericalJoint? https://github.com/Jondolf/bevy_xpbd/discussions/183
I'm looking at https://docs.rs/bevy_xpbd_3d/latest/bevy_xpbd_3d/constraints/joints/struct.SphericalJoint.html, and have what is probably another silly question. I see that there is a swing_limi...
This isn't supported yet. The XPBD paper only describes handling spherical joint limits for two axes and mentions that twist needs to be decoupled from swing, and I'm not 100% sure if the third axis would also need to be handled separately or if we can just apply the same logic as with two axes. I'll revisit this when I do more work on joint things (after 0.3)
But yeah "swing" by default is the local X axis and "twist" is the Y axis
I'm not 100% sure if the third axis would also need to be handled separately or if we can just apply the same logic as with two axes.
And by this I mean that idk if it's as simple as replacing b1 and b2 (twist axes on body 1 and body 2) with c1 and c2 (the third axes on body 1 and body 2, in this case the Z axis)
What happens with the third axis now? It is it unlimited, or fixed?
shouldn't be limited in any way
thanks.
oooh, incidentally, from the next line in the paper: "All limits can be made soft by using ๐ผ > 0."
lol except not that character -- it is ๐ผ
yep, compliance (alpha) is just the inverse of stiffness, i.e. 0 is infinitely stiff (a hard constraint)
I'm still having some conceptional problems, I guess. Does that constraint apply to the limits applied to the otherwise allowed degrees of freedom for a joint or to the non-allowed degrees of freedom?
Like, for a PrismaticJoint, does it mean "how much the thing can be pushed off track" or does it mean "how much the thing can be pushed past the ends of the line"?
I'm not sure if I fully understood the question, but for a prismatic joint, the limit does "if the distance between the bodies is greater than the maximum distance, move the bodies towards each other until the distance is within the allowed extents (and the constraint is satisfied). Otherwise, do nothing."
Limits are "inequality constraints", i.e. they only apply when some criteria is met (like the distance is over max or below min)
A prismatic joint only allows 1 DOF that has configurable limits (the "free" axis). You can think of the other DOFs having a limit of [0, 0]; the distance or offset must always be the same value, i.e. relative movement isn't allowed. This would be an "equality constraint".
A joint with 6 DOF and no limits would do nothing
Let me try to illustrate my question with another example. Imagine a box with a hinged lid. The lid is a "revolute" joint, allowing rotational freedom on one axis. (Let's say X.) The limits in the Z and Y directions are effectively hard constraints (you can't twist the lid that way), as are the degrees of translation -- it doesn't slide. When you close the lid, collision with the box itself effectively enforces a limit. When you open the lid, with most hinges, it can't go all the way back and around. But that limit is usually kind of "springy". It's a soft limit.
Yeah we don't currently have compliance for individual limits. Instead it's a shared compliance for the entire joint, so if you increased the compliance of the hinge in this case, it'd be springy in all directions. Configuring this would be very easy to support though, so I'll add the option when I work on the joint stuff
Thanks! Would it be helpful to file an issue?
That'd be nice, thanks :)
Cool. Gotta go now, but will later
Found some strange behavior that happens when rigidbody type is changed after an object is initialized: I spawn two cubes at the same height, one is static and the other is dynamic. Beneath them are two platforms, the top is static and the bottom is kinematic. When I change the static cube to be dynamic, it does not collide with the static platform but does collide with the kinematic platform. If it is initialized as kinematic then later changed to dynamic it works as expected and collides with the static platform.
hello, what would be the way to add all the physics components like RigidBody to an already existing entity, without ruining it's position?
to be more specific the bevy_ecs_ldtk crate gives me spawned tiles that are already positioned correctly, but if I add the components, the position is reset
Is this in 0.2 or the main branch?
It has a lot of new features and fixes, so it can be useful. 0.3 should be released by the end of the week though
I think this issue was mentioned before and fixed, I'll see if I can find it
oh okay, yeah, then I might aswell start using that already if the update is so soon. got it!
Nevermind I wasn't on the main branch either, seems fine now ๐
Yep, found it #1124043933886976171 message
thanks!
Cool, although I wasn't aware of that issue and don't know when and how it got fixed ๐
I guess I semi-accidentally fixed it since quite a lot in the code related to that stuff has changed
By the way I tried testing the predicate-based raycasting, my implementation was 15%-200% slower though I believe this is due to unnecessarily cloning the spatial query filter every time it hits an entity that does not pass the filter. I have also experimented with an API to get around this: instead of adding the InteractsWith component with commands.insert(), it can be added with a custom command which can fetch the ComponentId when the command is applied. If you don't want to do it with a command you can also get ComponentId from the ComponentIdFor<T> system parameter
And it would be no more or less convenient to use an "InteractionId" that is analogous to component ID except would be friendlier for projects with too many components than would be reasonable for a bitflag type
The main problem I had was that I got lost with figuring out how change detection ticks work, in order to update the CollisionFlags groups you have to check every entities components every time they change. This involves a &World param so you can't mutate CollisionFlags, you must insert with commands, and I couldn't figure out how to only do this on entities whose components are added/removed.
But I don't think any of this is a no-go in principle, it just needs a better programmer than me to figure out (such as a future version of me, who I'm sure is a much better programmer)
Hmm yeah it sounds technically viable but quite tricky to do efficiently. Thanks for experimenting with it though, the insight is valuable
Do you have your code public somewhere? I could maybe try it myself at some point when I have time
Hmm I'm guessing this isn't intended... Is there a special parameter for reflecting on the surface normal?
The walls are RigidBody::Static
Went to make sure it works on the main branch before I send it to you and noticed this, it looks like there's a 3500% regression in raycast performance
Been hitting the attempt to add with overflow panic (https://github.com/dimforge/parry/issues/146), thought I was doing something wrong but I guess not? Are there any temporary workarounds for it or should I just ignore it for the time being
Hmm, this was supposed to be "fixed" / hacked around on the main branch already ๐ค
I wonder if the performance regression is related to the temporary "fix" me and @cinder summit made for the above problem ^
Incremental Qbvh updates were causing very frequent crashes so we switched to full updates until it's fixed. In our testing it didn't really seem slower though...
Oh I'm not on main branch, just on .2
Ah, yeah I'm not aware of it being an issue on the main branch anymore
so you can ignore it until 0.3 or try the main branch
Perfect thanks
If nothing moves it would definitely be fairly slow to rebuild ... But the raycast itself should get faster since rebuilding a BVH almost always gets you a better result than updating one, especially if it's built by splitting on an axis ๐ค
I've just switched to xpbd from just using normal transforms.
Couple questions.
How do I make it so I'm not on ice.
I put velocity to 0 at the start of the movement function and make velocity = to move speed but that seems to cause a minor jitter.
I tried velocity += movespeed,
I'm also not sure how to change my rotate enemies towards targets function.
How do I use rotation in xpbd?
How do I make it so I'm not on ice.
You could setFrictionhigher (edit: if it's top-down,LinearDampingmight be what you want, see messages below)
I put velocity to 0 at the start of the movement function and make velocity = to move speed but that seems to cause a minor jitter.
I tried velocity += movespeed,
I'm not sure what could be causing jitter in this case. Have you tried just setting a constant velocity in some direction and seeing if that also jitters?
I'm also not sure how to change my rotate enemies towards targets function.
How do I use rotation in xpbd?
On the main branch, you can use normalTransforms for most things, sotransform.look_at()could work. Otherwise, you would use theRotationcomponent (orAngularVelocityif you want it to be more gradual).
No, if it's top-down then you could use LinearDamping or just have a system that does e.g. lin_vel.0 *= 0.99
(note: LinearDamping(0.99) isn't equivalent to the above, the damping method is different)
Would physics work right if I make terrain that is a mesh (not a height field) and is split into chunks? It won't be a complete mesh, meaning the shape will have holes on the sides. But during normal gameplay, nothing should interact with it from the backface side of the mesh.
I don't see why it wouldn't work
Awesome
I want to do something similar to this eventually, but I've got a lot of other things first. I'd be curious to know if you learn anything interesting in experimenting
For what it's worth, heightfields in parry are just trimeshes
It's just a difference in how you construct it
hello, is there a big performance difference between having a RigidBody::Static + Sensor or using SpatialQueryPipeline::aabb_intersections_with_aabb every frame?
If the scene isn't massive, I would imagine that the AABB spatial query might be slightly faster since it just checks for AABB overlaps instead of doing actual collision detection like a sensor would
But I haven't actually compared the performance, so it's hard to say for sure
got it, thanks!
Should I be replacing Transform to Position?
setting position doesn't seem to be working
In 0.2?
ya using Transform wasn't supported in 0.2 yet but it does work on the main branch and 0.3 which will come in a couple of days
in 0.1 and 0.2 you need to use Position and Rotation
player_query: Query<&Position, With<Player>>,
mut objects_query: Query<
(&PlayerAttach, &mut Position),
(Without<Player>, Without<WeaponSlot>),
>,
) {
if let Ok(player_transform) = player_query.get_single() {
for (attach, mut transform) in objects_query.iter_mut() {
println!("before {:?}", transform);
transform.0 = player_transform.0 + attach.offset;
println!("after {:?}", transform.0);
}
}
}
TankTreads,
tank_treads_sprite,
Collider::cuboid(64., 48.),
PlayerAttach::default(),
Position::default(),
));
commands.spawn((
TankBody,
sprite_bundle,
Collider::cuboid(64., 64.),
Position::default(),
PlayerAttach::default(),
));
commands.spawn((weapon_slot, Position::default(), Collider::cuboid(32., 32.)));
commands.spawn((
PlayerBundle::default(),
Collider::cuboid(64., 64.),
Position::default(),
Transform::from_xyz(0., 0., 0.),
LinearDamping(5.),
));```
This doesnt actually update the position of the attached entities.
And I'm trying to figure out why
If I add a rigid body they just fly around the screen because they bump into eachother
Should I add them to sperate layers?
It looks like they're spawning at the same spot, so they will be heavily intersecting which causes a massive burst of velocity. You probably want to move them so that they're not overlapping at the start, or if you don't want them to collide against each other at all, you could use CollisionLayers
I'm pretty sure I've done it wrong but basically I want the tanktreads body and weapon to be sperate sprites
So I can swap them out rotate them and have seperate collisions
But they are the same entity
Well in this they are seperate entities but they are the same character
On the main branch, you could make a parent tank entity and have the tank parts as children of that entity. In 0.2 though, you can't have colliders on children, so there would need to be just a single collider on the tank
So should I just use Transform for all the other sprites
The player entity is basically just a position I use to make sure they all stick to the same xy
I have a player attach component so they just get their transform = to player position
You could do something like this
commands.spawn((
PlayerBundle::default(),
SpatialBundle::default(),
RigidBody::Dynamic,
Collider::cuboid(64.0, 64.0),
LinearDamping(5.0),
))
.with_children(|child_builder| {
// On main, these could also have colliders, but not in 0.2
child_builder.spawn((TankTreads, tank_treads_sprite));
child_builder.spawn((TankBody, sprite_bundle));
child_builder.spawn((weapon_slot));
});
Children are positioned relative to the parent with transforms, but you can't have colliders on them in 0.2, only on main/0.3
Cool I'll try with the child approach
I cant remember why I didn't go with it in the end lol
Works like normal
Still need to fix the enemies spawning and rotations
Also I notice a little jitter in the movement but I don't quite understand how thats happening
But thats a seperate issue
The default physics timestep is a fixed 60 Hz in case that matters for the jitter
nvm I see the jitter too and my screen is 60 Hz
Yeah I just realised my map size was too big.
I'm using a tiling crate
and 128x128 is too big causing a bit of a jitter
Thanks for all the help btw I prefer this crate to rapier after a referral from @sleek thicket
Whats the best way to choose a location for the spawn?
I used to rely on the transform
let min_spawn_distance = 100.0;
let spawning_distance = 300.0;
let distance_x = rng.gen_range(-spawning_distance..spawning_distance);
let distance_y = rng.gen_range(-spawning_distance..spawning_distance);
let adjusted_distance_x = adjust_spawn_distance(min_spawn_distance, distance_x);
let adjusted_distance_y = adjust_spawn_distance(min_spawn_distance, distance_y);
let spawn_location = Transform::from_translation(Vec3::new(
player_transform.0.x + adjusted_distance_x,
player_transform.0.y + adjusted_distance_y,
100.0,
));
let sprite_bundle = SpriteBundle {
sprite: Sprite {
custom_size: Some(Vec2::new(32.0, 32.0)),
..default()
},
transform: spawn_location,
texture,
..default()
};
commands.spawn(EnemyBundle::basic(
50.0,
50.0,
16.0,
AttackSpeed(Timer::from_seconds(0.2, TimerMode::Repeating)),
10.0,
sprite_bundle,
));
pub fn basic(
health: f32,
max_health: f32,
speed: f32,
attack_speed: AttackSpeed,
attack_damage: f32,
sprite_bundle: SpriteBundle,
) -> Self {
EnemyBundle {
enemy: Enemy,
stats_bundle: StatsBundle {
health: Health {
current: health,
max: max_health,
},
move_speed: MoveSpeed(speed),
attack_speed,
damage: Damage(attack_damage),
},
sprite_bundle,
reward: Reward::Experience(ExperienceEvent(10.0)),
enemy_type: EnemyType::Basic,
damageable: Damageable,
range: Range(48.0, false),
collider: Collider::ball(16.0),
rigid_body: RigidBody::Dynamic,
targetable: Targetable,
}
}
But I have to change the position now.
Transform can still be used for the initial position even in 0.2, but if you use Position then it'd be just Position(Vec2::new(...))
oh or did you mean specifically how to position them in a non-overlapping way?
Hmm ok, you can try Position(Vec2::new(...)) then
Will that conflict with the rigid body I init in the new
When I spawn new enemies
They always spawn 0,0
Even though I spawn them with a transform
Which is why I assume I need to use position
but if I add position doesn't it conflict with the defaul rigid body because that also adds a new position
ye
Ah cool
Ye that worked
ty
And sorry last question about rotation trying to figure out an ez way to do this
fn move_enemy_to_target(
mut enemies: Query<
(
&mut LinearVelocity,
&mut Position,
&mut Rotation,
&MoveSpeed,
&Range,
&MovingTarget,
),
With<Enemy>,
>,
) {
for (mut velocity, mut transform, mut rotation, speed, range, target) in enemies.iter_mut() {
if range.1 {
continue;
}
let player = target.1;
let difference = player - transform.0;
let movement = difference.normalize_or_zero() * speed.0;
velocity.0 += movement;
let angle = difference.y.atan2(difference.x).to_radians();
rotation = Rotation::from_radians(angle);
}
}
Easier to see
Yeah
Forgot that
Nah they aren't rotating
Looks funny though
I've adding damping though so they aren't insanely fast anymore
Tried using transform to rotate them but thats not working either
How it would have been before adding physics
Also whats the best way to add a max velocity because I'd like it to instantly stop when done moving but if I put damping to = movespeed it makes everything move at the same speed
And I realise if I add velocity = 0 then velocity = movespeed to reset it
Then anytime I hit something with velocity from something else it will set to 0 again
For whatever reason, if you do this in rapier, things "sproing" apart but not to the amusingly high velocities of xpbd's Oh No Is This Nuclear Fusion?! reaction.
Might there be some kind of quality of life option where objects which spawn inside other objects are teleported to a clear space nearby instead?
Yeah I think that should be possible
I think there was an easy way to implement that but I'll check
Basically it would still solve contacts when they're overlapping, but it would skip adding velocity caused by the contact if the body was just added
Not really
Right now, in a situation which might end up going either way, the object is not merely spawned on the wrong side of the wall but hurled at the speed of light into the abyss
It wouldn't change the direction in which the bodies move, it would just make the correction more controlled
(maybe also log a debug-level message when this happens?)
god help us all
When it goes ballistic, you know "huh, everything vanished", which is not a great debugging experience.
I don't think it's good to use explosive behavior as a way of indicating that you could position your bodies better
Idk in what situation you want bodies to go at the speed of sound at spawn rather than getting gently pushed into a non-penetrating state
I feel like the better alternate options might be: 1. leave it stuck, or 2. crash
right, hence crashing
crashing feels a bit harsh imo
My rationale: in many cases "went to infinite speed" is a effectively a crash, in that probably whatever you were trying to do is now completely impossible and your world is in an unexpected state. It's just a crash you might not notice right away.
But I agree it seems harsh as a default behavior, and a debug message probably is fine.
agreed on that.
If you had a game with some spawner and another entity happens to move into it when it's spawning an entity, and the developer hasn't taken this into account, you probably don't want to just crash the whole game because of potential unexpected behavior
I am now arguing about a hypothetical I do not strongly believe in, but, yeah, if this were implemented I would expect it to be a flag to the debug plugin or something.
Yeah I think I'll just keep the current behavior for now but add a log when a dynamic body is spawned overlapping a collider
Later on we could also add the option to do the non-explosive correction
On a different note, on some discussion I noticed above: what is the deal with Position, going forward with 0.3 and beyond?
It's still used internally for everything, but Transform feels more idiomatic and familiar for Bevy users so I'm transitioning to using it in the code examples more.
Position and Rotation are still usable by users, and they still need to be used when doing things in the SubstepSchedule (because the Transform syncing isn't run at every substep for performance)
I'll add stuff about this in the docs of Position/Rotation tomorrow
Oh I just noticed that we hit issue/PR number 200 on GitHub ๐
Oh wow, when 0.2 was released, we were at just 72... it's been a while since the last release I suppose :P
Thank you! From a practical point of view, if I'm doing something in a regular update system, is there any reason to use Position/Rotation?
I don't think so
Thank you again for your help (and responsiveness and etc!)
If you were using f64, you could have slightly more precision with Position/Rotation, but in normal systems I'd imagine it's negligible
Now, I'm going to go play Cities Skylines II until bevy 0.12 and xpbd 0.3 are released ๐
I went ahead and implemented the warning already https://github.com/Jondolf/bevy_xpbd/pull/202
It just logs "{:?} and {:?} are overlapping at spawn, which can result in explosive behavior." (where {:?} are replaced by the entities)
and now I'll go to sleep
I feel like this should be behind a #[cfg(debug_assetions)], so the check gets optimized out on release builds
Weird that I've not seen things behave explosive when the reprediction forces the client back inside an SDF collider that the server doesn't have ๐ค
A lot of people might be using release mode when developing tho
(including me pretty often)
I guess these warnings could be behind a feature though, whether that's debug-plugin or something else, but ideally something that is enabled by default
Yea I guess that's a good point ... I made my release mode unusable for developing ๐
[profile.release]
lto = "thin"
codegen-units = 1
strip = true
panic = "abort"
I instead have other crates set to opt-level=3 and my own to opt-level=1 with debug_assertions enabled ... Kinda wish we had a better check than "debug_assertions" tho, since that auto disabled with opt-level > 0
That feature is relatively recent so only on main atm
I added an ignore_self property for RayCaster and ShapeCaster now for ignoring hits against the own collider. It's true by default since it's such a common issue, but it can be changed to match the old behavior like .with_ignore_self(false)
Also you mentioned the same issue a while ago ^
Nice
I think every intended feature and bug fix is finally done for 0.3 ๐
now all I have left is docs improvements and 0.12 migration
do you have a changelog?
I'm already using the main branch, but I'm just curious what happened between 0.2 and 0.3
I will have a GitHub release and also a blog post on my website like the one for 0.2
Spatial queries, Bevy 0.11 support, improved scheduling, damping, gravity scale, better forces, locked axes, bug fixes...
that post might take a while to write...
That's awesome
I don't mean to disparage rapier because I'm sure it's quite good but all the stuff I tried with it surprised me or I just couldn't get it to work. And I haven't had that issue with xpbd.
Thanks, I try to make things as logical and ergonomic as I can
Also this aged well ๐
As I mentioned in the previous post, I will unfortunately have to take a long break from active development due to school. I am not abandoning the project, but I will not be able to add many new features or improvements until around the end of March next year when I should be free to work actively again.
says this, ends up making a release that's bigger than the previous one
yep, I do pretty well in school as well and the matriculation exams I had went fine, so I'm not too worried
I just originally wanted to put out a disclaimer that I might not have time so that I don't have pressure to work on bevy_xpbd when I should be studying
Yeah, that's smart
jondolf are you studying computer science, or something related? if so, hopefully you can get credit for bevy_xpbd in some way. in the UK if you were doing a comp sci degree you could probably make it your final year dissertation project.
I'm not in uni yet so no ๐ just the last year of high school
In a year I will be though
High school is just studying a bit of everything, not a specific degree
(although you can choose what courses you take to some extent)
Our school only has one or two courses with programming, and one of them was very introductory python programming related to math
ah right, ha. good stuff. well maybe bevy_xpbd 1.0 just in time for the final-year uni project ๐
official bevy_physics as final year project :P
my school didn't have any programming courses either fwiw.. although i was writing nonsense in visual basic 6, not physics engines
๐
Do you need rigid bodies to handle collision or are colliders able to do that seperately
In 0.2 I think colliders need to have rigid bodies to detect collisions, but on main colliders work on their own. But for collision response, you still need rigid bodies currently. A collider without RigidBody acts like a sensor
So if I want a projectile to detect its hit something
Can I just use a sensor to detect that its hit another collider?
And if so do I need to add them to the same collision layer or is there a default collision layer?
A collider without CollisionLayers interacts with all layers by default. You could make the projectile a sensor, but it needs to be a rigid body to be affected by velocity
Because of the rotation issue I had saved it in a seperate branch and I'm gunna wait for 0.3 ๐
Im assuming that 0.3 isn't ready yet?
No, but all I have left is docs improvements and some release prep
#1124043933886976171 message
should be released right after Bevy 0.12 releases
whenever that is
ty
in current bevy-xpbd master, are there small spheres ~0.05 in diameter automatically placed in the middle of each RigidBody?
where do these come from, and why are they there?
The yellow dot? It just marks the center of mass and is at the middle of the rigid body axes
probably a bit unnecessary though
ah nvm, I thought those were physical objects, since physics start behaving weirdly at that size
Just wanna verify: if I want to have a small object, e.g. Collider::cuboid(0.02, 0.02, 0.02), should it work out of the box? Or are there settings (like length tolerance in physx) that I have to change?
Ideally it should work but there are probably numerical precision issues at those smaller scales
I'll add something like Rapier's physics scale at some point, it should help
precision issues? why? I thought floating point mantissa has the same precision regardless of its exponent
to clarify: I thought that precision issues happen when you operate on floats of wildly different scales, but there are no issues if all numbers have the same scale (no matter large or small)
i'm wrong apparently, since small things start to jitter, but wanna understand why
float precision is the best near 1
I'm not that familiar with floating point error details, but that cuboid would have a mass of 0,000008 if the density is 1, and the solver has to deal with other small numbers like the substep delta time, so it could be that some numbers are very close to zero (or very large if the small number is the divisor) which could cause precision issues
and also this afaik
could test with f64 to verify that it's a precision issue tho
unfortunately, debug render doesn't work with f64:
bevy_xpbd_3d = { git = "https://github.com/Jondolf/bevy_xpbd", branch = "main", features = ["debug-plugin", "f64", "3d", "collider-from-mesh"], default-features = false }
--> C:\Users\user\.cargo\git\checkouts\bevy_xpbd-87d8ac3552aaa63b\da2ab00\crates\bevy_xpbd_3d\../../src\plugins\debug\renderer.rs:418:25
|
418 | .sphere(point.adjust_precision(), default(), 0.025, point_color);
| ------ ^^^^^^^^^^^^^^^^^^^^^^^^ expected `Vec3`, found `DVec3`
| |
| arguments to this method are incorrect
in 2 places, line 418, as well as line 470
should be fixed now
there's funny behaviour going on, even with f64:
https://www.youtube.com/watch?v=z_ke6jVr-BE
Hmm, that's a bit strange... would you mind making an issue? I can investigate further when I have time
(that's just a cube on a halfspace, friction=0.3, restitution=0.7, everything else default)
yeah I'll make an issue
I'm currently revamping and updating quite a lot of high-level docs, the table of contents is looking kinda fire
Makes me realize how big the engine is :P
Previously it was just an unstructured list of common tasks that was missing a lot of things (+ there was also a list of features)
now it's at least structured
You can just do lin_vel.0 += vector
But yeah some examples probably should multiply by delta time, I'll test tho
It looks like that RenderLayers no longer has any effect on colliders, on the latest commit. Previously the scale would be affected, but it doesn't seem to work anymore 
Uhh... it was previously affected?
How would RenderLayers affect anything physics related?
Hmm, previously the colliders would be affected by the scale of the camera's RenderTarget. So when you're rendering to an off-screen image and scale the image up, both the sprites and the colliders would be scaled accordingly. But it doesn't seem to be working anymore.
bevy_xpbd doesn't even use bevy_render other than for creating colliders from Meshes
I guess bevy_gizmos uses bevy_render but I only use the gizmos directly
Actually, I think the debug-plugin is just fooling me. It's not being rendered in the layer I want, so things are completely misaligned.
I think you can change render_layers in GizmoConfig
but I haven't used render layers so idk
Thanks, that did the trick! Also thanks for the caster update!
Also, about debug-plugin, is there a reason why it's behind a build flag?
It enables bevy_gizmos which in turn enables some other deps, and people might want to use bevy_xpbd in a headless context
However I could make it a default feature and allow people to enable PhysicsDebugPlugin by adding it manually instead of automatically adding it when the feature is enabled like we currently do
allow people to enable it by adding PhysicsDebugPlugin
Yeah, that would definitely be nice!
It would also make docs nicer since I currently can't link to the plugin when the feature is disabled... yeah I think I'll make it a default feature
just in time for 0.3 :P
it wouldn't even add dependencies other than bevy_gizmos because some other default features already enable bevy_render
I guess the main con with this approach is that you can't easily toggle the debug rendering through the command line because you now need to add the plugin manually, but I'd say it's about the same effort as commenting/uncommenting the plugin
- previously you would have needed to comment out any debug configuration if you disabled the feature, but now you can have the feature on without the plugin
Nice! I guess people who want the cli workflow can just add their own cfg in their code.
yep
Err, okay I think kinematic stuff is broken in the latest commit. Spent like 2 hours debugging my project. But turns out that cargo run --example basic_kinematic_character is broken too...
The character just falls through the floor
oh whoops, it's not broken, I just changed it to use Transform for positions and accidentally moved the ground up instead of the player ๐
so it's just spawning the player below the ground
That means my code is actually broken ๐ญ
oof
this example should be fixed on main now
Hi, I've been trying to update CollisionLayers on an entity after its been spawned. Currently my function runs on the update stage, I've tried a CollisonLayers mut query and inserting a new component, they both seem to change the groups and mask values but the entity still collides with the same things as before the function is run. Is this approach fundamentally wrong? I'm on the main branch. Thanks
It should be fixed on the main branch now
previously it wasn't updating the collision layers for the broad phase correctly
Great, thank you
I updated the examples to multiply by delta time where appropriate, among other fixes and improvements like refactoring the character controller examples to be slightly more complete with a CharacterControllerBundle
https://github.com/Jondolf/bevy_xpbd/pull/210
also I did this
for the character controllers? yeah I could add a MaxVelocity thing
eh, it's not strictly a character controller thing and might be unnecessary for the example so I might just leave it as is
ah yeah just clamping the input direction length to 1.0 but you can still have e.g. 0.6 if you're using a joystick or something
Bevy just doesn't have a nice input thing built-in that would support both keyboard and controller as far as I know
so currently it's just using keyboard input
yeah I'll probably add the clamping but in this case it just does nothing since the length is always 0 or >= 1 with keyboard input
alternatively I could add leafwing to the examples but idk if that's overkill
yes but that's the same as .normalize()/.normalize_or_zero() which it already does
or I guess not all of the examples do that actually
but the character controllers do
adding gamepad support is more than a few lines I'm pretty sure
or it might be just a few lines looking at the cheatbook ๐ค
I think I got it working with both keyboard and gamepad input, but I haven't actually tested with a gamepad yet (does a PS5 controller work? I know some games don't support it on PC)
I added a MovementInputEvent and split the movement system into three systems, one for keyboard input, another for gamepad input, and a third one for actually handling movement based on the movement events (Move or Jump)
It does add about 90 lines of code, but I think it's good practise to have the input handling be separate anyways and it's nice to have a semi-complete character controller example since we don't have an official one
wait I'm bad at math, 60 lines of code
I think a total of 230 LoC is still pretty good considering it has a functional (yet basic) character controller with keyboard and gamepad support and all of the setup stuff + some comments
Here's the new version https://github.com/Jondolf/bevy_xpbd/pull/212
tomorrow I'll test if gamepad input actually works
thanks
to not dampen y
could just increase gravity I guess
ah yeah keyboard input had it that way around because it needs to be negative for the movement to make sense, but I should do the negation in movement and not the input system
maybe LinearDamping and AngularDamping should be vectors so that it allows you to dampen different axes separately
idk, I'd have to check but I think Rapier has scalars at least
gravity compensation?
there's GravityScale
it'd be weird to special case gravity for damping imo
gravity is mostly just sugar for ExternalForce
modeling gravity as a force. shaking my head. did einstein teach us nothing?
||this is sarcasm btw||
#math-and-physics message
the input directions should be fixed now
or at least be the same across keyboard and gamepad
yep, just need to properly migrate to Bevy 0.12 and wait for it to release
and prepare release notes
wanderlust seems to have a friction coefficient that is the ground's friction coefficient when grounded and otherwise an air damping coefficient of 0.25
and then computes and applies forces
I should probably separate friction and air damping as well for the character controllers
and add a separate Grounded component to make the logic clearer
yep, just need to add autostepping, proper move_and_slide, jump decay, agnostic up vector, coyotee time jumping...
and slope handling
but it'd be nice to have a properly ECS-integrated character controller, I feel like Rapier's KCC is very weird and needs a ton of special casing
I feel like it could be implemented with just components and a bundle, and then maybe have a world query (or SystemParam) to allow move_and_collide type logic
And it would be nice if it allowed you to use input action mapping like what leafwing provides
yep
I've not looked in a huge amount of detail but that devlog looks fantastic
FYI, if using bevy_xpbd_2d and it appears like your starting translations are being ignored (everything is moving to the origin), switch from PhysicsPlugins::default() to PhysicsPlugins::new(FixedUpdate) head desks
FixedUpdate works for me for now, just porting some of my toy exercises from rapier and spent some time head scratching over that bit of oddness
I'm migrating from Rapier to XPBD (2D).
I'm using the rapier contact events to figure out the magnitude of the force of a collision.
I cannot seem to find an equivalent in XPBD?
Is there a way to get not only collisions, but also the magnitude of the impact of said collisions?
I am seeing some issues with my tiny game when converting to WASM. I am not saying it is XPBD. I am thinking it is not.
You have perhapsly seen me yapping in the WASM-channel. Any chance of getting someone to look at it, paid or otherwise? Happy to pay if I get this issue fixed. But it is out of pocket and I am an old alcoholic. So $100.
It seems to work perfectly on desktop, but something breaks down on WASM. I thought it had to do with my ordering of systems, but I am leaning towards getting multiple collision hits for the same object. See a discussion here: https://discord.com/channels/691052431525675048/1167625836791332865
Happy to pay people to tell me I am wrong, as usual. As long as I get a running Ponkatris.
And I don't want Godot. I want Bevy/XPBD. I came for the best physics engine. And by God. This is the hill.
OMG, I haven't updated this library in years. There is a 0.3?
Regarding cocporn's message above:
Is it expected for a Collision event to be generated more than once per frame for a collision? We are seeing up to 4 of these in a ball-cuboid collision (and this seems to show up more reliably at lower framerates). From the docs, it sort of sounds like this could be expected behavior. (one collision, multiple contact pairs if the overlap is just right?)
Should we be using CollisionStarted?
(as an aside, if so, Collision feels like a very unoptimal name for that event)
I'm guessing you're using 0.2, this shouldn't be an issue on main
Yeah, 0.2.
Also I agree Collision isn't great; on main there's a much more capable Collisions resource that you should be able to use instead, so I might even remove the Collision event
Or I guess it's not equivalent since events are consumed
And if you were using the resource, you could potentially miss collisions if you don't run your system every frame (since they wouldn't be in the resource anymore)
Idk, I'll probably leave the event be for now and reconsider its name/existence later
And no there is no 0.3 just yet but all the features are done, I'm just waiting for Bevy 0.12 and doing some release prep
Great! Huge fan.
To me it seems like the most stable physics engine I could get my hands on.
There's no nice user-facing way to access contact forces yet, but you can technically access them using the PenetrationConstraints resource in a system running in the SubstepSchedule and SubstepSet::SolveUserConstraints
I think I might eventually add something like SolverContacts that would give access to the forces, or somehow integrate it to the existing collision resources/events
You just can't compute the forces directly in the narrow phase collision detection, so you first need to run the solver to get them
Thanks for the insight! For my small project, this is beyond my scope.
How accurate of an approximation do you think one could get by comparing the positional change (i.e. velocity) up until the point of collision?
I'm using this for fall damage, so I just need a rough impression of the "severity" of the impact in general.
That could be fine, but you can also access the penetration depth of collisions with the Collision event or on the main branch also with the Collisions resource
(the API has changed from 0.2 tho)
I thought penetration depth was only applicable in situation where the collision actually causes one collider to overlap the other?
(but I suppose now I'm working on intuition rather than experience)
Collisions are only handled if there's penetration in XPBD, you can't resolve overlap if it doesn't exist
I see. My thinking probably stems from interpreting "penetration" as in the real world. I.e. something actually enters/breaches something else.
Which would be an unwanted case in a physics simulation.
Thanks for clearing it up!
Another thing if I can bug you with it:
I see no way to work with impulse forces in XPBD. Is this the case? I'm wanting add an external force to something regardless of its mass.
looks like 0.2 didn't have impulses either, but they do exist on the main branch
you can also just change velocity
also, impulses are still dependent on mass, in a way they're just forces that are applied in a single burst instead of over time
force = mass * acceleration (unit is Newtons)
impulse = force * delta_time = mass * velocity (unit is Newton-seconds)
I see!
to make it not dependent on mass, just add to velocity directly without a mass term
translating from rapier, "impulse" is just ExternalForce where with_persistence is false, right? Or is it something else?
On main there's also ExternalImpulse and ExternalAngularImpulse. The magnitude of the velocity change during a frame is different for forces and impulses. Impulses aren't multiplied by delta time while forces are.
The other difference between our forces and impulses are that forces have with_persistence = true by default (because they're "continuous") while impulses have with_persistence = false (because they're "instantaneous" / applied in a single burst)
I just checked what the auto-generated release notes for 0.3 would look like, so here's 0.3 at a glance :P
it's quite long but still missing a lot of detail since a lot of the PRs are pretty impactful fixes or improvements
now I technically have everything ready, just have to wait for Bevy 0.12
(well, the blog post is definitely not ready, but that can come afterwards too)
0.1 to 0.2: 4,432 additions and 606 deletions
0.2 to 0.3: 11,725 additions and 2,321 deletions
0.3 to 0.4: 33,000 additions and 9,200 deletions??
0.4 to 1.0: โ additions and โ deletions
Yep :p should probably aim for two releases per Bevy release
And yeah water could be a good example for sensors and forces, I just don't know what to call the example... water indicates fluid simulation which it is not
Yeah maybe something like that
Or maybe some gravity switching thing where some areas have inverted gravity
Just checked out the new kinematic character example, but why is there a CharacterController filter here
:
https://github.com/Jondolf/bevy_xpbd/blob/f2f11668e18c78132d879249a70bd1a2297de218/crates/bevy_xpbd_3d/examples/basic_kinematic_character.rs#L311-L314C4
I tested it on my own project, but collisions becomes really buggy after adding that.
Oops, yeah that doesn't do what I intended
I meant to have it handle collisions between character controllers and everything else, but that code requires both bodies to be character controllers
I'll fix it later today
Alright, cool!
Also, it looks like that the movement code now all happens in Update using deltas. Since the input and movement code is now separated, can't the movement code just stay in PhysicsSchedule?
Yeah, I think I'll do this since it's generally recommended to handle actual rigid body movement in a fixed update schedule of some kind (PhysicsSchedule in this case). Although it should be basically equivalent here since it's multiplying by the delta time.
The main two reasons I didn't do this are (1) PhysicsSchedule looks more like an internal thing, and (2) in the PhysicsSchedule you should currently use DeltaTime instead of the normal Time resource, which can be confusing
I wonder if I could replace DeltaTime and SubDeltaTime with custom clocks using the new time API though... I haven't looked into it much yet so idk
basically Time<Physics> and maybe Time<PhysicsSubstep>, and overwrite Time<()> with them based on the schedule (PhysicsSchedule or SubstepSchedule) similar to how Time<Virtual> and Time<Fixed> work
this way people could just use Time and it'd "just work"
also maybe we should change the default fixed timestep to 64 Hz to match Bevy's defaults
Ooh it works ๐
I can remove PhysicsTimestep completely and replace it with Time<Physics> where Physics is a custom clock that is an enum storing the same configuration as PhysicsTimestep
Before:
.insert_resource(PhysicsTimestep::Fixed(1.0 / 60.0))
After:
.insert_resource(Time::new_with(Physics::Fixed(1.0 / 60.0)))
And you can just use Time instead of DeltaTime or SubDeltaTime everywhere
Since it's updated based on the schedule
This way I can also make physics systems more schedule-agnostic since the time resource is unified
Nice! ๐
Is there some resource or something similar to 'physics_pipeline_active' from rapier3d? Basically I need a way to query if the physics pipeline is active
There is no separate "physics pipeline", it's all just systems that are run in the PhysicsSchedule. But the PhysicsLoop resource is used for controlling how/when the schedule is run, and it has a paused property that can be seen as the "activeness" of physics
Thanks 
@vestal minnow How can I escape the Collider dep for mass properties?
Do you mean how you can compute mass props for your bodies without Collider?
Yea, and without systems that calculate it using a Collider later
Isn't update_mass_properties the only system that does that
or are there others
If you take out the colliders, it's just this
fn update_mass_properties(mut bodies: Query<(Entity, &RigidBody, MassPropertiesQuery)>) {
for (entity, rb, mut mass_properties) in &mut bodies {
let is_mass_valid =
mass_properties.mass.is_finite() && mass_properties.mass.0 >= Scalar::EPSILON;
#[cfg(feature = "2d")]
let is_inertia_valid =
mass_properties.inertia.is_finite() && mass_properties.inertia.0 >= Scalar::EPSILON;
#[cfg(feature = "3d")]
let is_inertia_valid =
mass_properties.inertia.is_finite() && *mass_properties.inertia != Inertia::ZERO;
if mass_properties.mass.is_changed() && is_mass_valid {
mass_properties.inverse_mass.0 = 1.0 / mass_properties.mass.0;
}
if mass_properties.inertia.is_changed() && is_inertia_valid {
mass_properties.inverse_inertia.0 = mass_properties.inertia.inverse().0;
}
// Warn about dynamic bodies with no mass or inertia
if rb.is_dynamic() && !(is_mass_valid && is_inertia_valid) {
warn!(
"Dynamic rigid body {:?} has no mass or inertia. This can cause NaN values. Consider adding a `MassPropertiesBundle`.",
entity
);
}
}
}
(warning stuff optional)
Idk how mass properties are computed for SDFs though, probably some rough approximation
I think the easiest option would be if I could say "this collider is X kg, and the center of mass is here" (I can't know that for certain if it's not a simple SDF tho, but the user could always override it) ... Not sure if that's enough for what physics needs tho
The volume is easy to know for some SDFs, but when you do fancy operations with them, the whole SDF turns into a mysterious black box, tho I guess those also can't really be dynamic colliders, unless I sample the SDF at which point I can approximate the center of mass and density ๐ค
There's also fun SDFs that have infinite volume ๐
That should be just
commands.spawn((
RigidBody::Dynamic,
Mass(X),
CenterOfMass(Y),
));
but you also need some non-zero Inertia
If it has infinite volume and a non-zero density, the mass is infinite, and it's therefore a static body technically
(although we don't handle it like mass == 0 -> static)
Interia should be proportional to mass right? I wonder if a constructor that takes these two fields would work ... Tho maybe that would need a breaking change later with that weird angular interia parry seems to have logic for ๐ค
yeah angular inertia is proportional to mass
- of course how the mass is distributed relative to each rotational axis
a lot of shapes have known formulas, but idk how it'd work with SDF operations and whatnot
Most primitives should be easy, but yea figuring it out when any sort of operation is involved would be hard ... Especially any operations that result in bound SDFs, because those are just impossible to reason about, but I'll probably drop all operations that guarantee bound SDFs anyway ๐ค
Dynamic objects probably won't be non-primitive shapes anyway
approximate the shapes as their AABBs ๐
I actually considered doing that ๐
No clue how to make a Matrix3 out of it tho ๐ค
The parry code sure is a confusing web to navigate trough ...
Seems like I need this:
https://docs.rs/parry3d/latest/src/parry3d/mass_properties/mass_properties_cuboid.rs.html#19-24
and this:
https://docs.rs/parry3d/latest/src/parry3d/mass_properties/mass_properties.rs.html#173-181
bevy_xpbd has Inertia::shifted already in case that helps
nvm that's done internally I think so I'm pretty sure you don't need that
"just" the "angular inertia tensor of the rigid body from its principal inertia values and axes"
which is exactly what you linked now that I look more closely ๐
I implemented this now, unifies all of the time APIs really nicely
https://github.com/Jondolf/bevy_xpbd/pull/214
Just has a weird issue where objects get a random jitter roughly once a second when moving, almost like the simulation stops for one frame
Also it could be considered weird to have Time<Physics> contain configuration about the timestep, like implementing Time<Virtual> and Time<Fixed> in one type
there's a separate PhysicsTimescale resource already with a simple code example in docs, but that'd be a nice actual example as well yeah
you seem to be suggesting new examples every day haha, I like it though
I'll add it to my list
I mean in an ideal world it would make more sense for xpbd to just directly use Virtual or Fixed, since most engines just give you two loops: One for physics and one for frames
I mean it would be very easy to make that even without an xpbd example, you just set the timescale on virtual lower and done
Tho I guess if you want it to feel decent you want to up the frequency of updates too, otherwise it becomes a jittery mess ๐ค
I had caveats in mind but I can't come up with many right now
One is that substeps need to have the separate timer or somehow compute it
so some kind of Time<Substeps> would be needed
Main one I can think of is actually a pretty cursed one ... What is xpbd ... Runs slower than FixedUpdate ... Like you process server updates at 60FPS but physics at 20FPS ... It's a fairly common scheme
also FixedOnce needs to be enablable(?) somehow
Is xpbd runs in FixedUpdate there would only be FixedOnce and Variable, and the way to set FixedOnce in a server is to just overwrite Time<Virtual>'s delta somehow
Because whatever the delta was on the server, ti's actually just the fixed timestep
also also, it's nice to be able to advance physics independently of Time<Virtual>/Time<Fixed> when running physics manually for example
Yea the manual updates are useful ... Either way I think the physics schedule/time should probably stay at least until FixedUpdate becomes easy to use
After that it might be worth seeing what the general opinion is on how it should work if a bevy_physics existed ๐ค
Yeah that's kinda the mindset I have for developing bevy_xpbd in general
"What should bevy_physics look like"
(not that we're close to it yet, but in terms of the future)
Kinda hard to envision what bevy_physics would look like when there's a bunch of rough edges around that would make a bevy_physics unpractical to implement