#Avian Physics
1 messages ยท Page 9 of 1
It's your signature skill ... Unlimited Todo Works ๐
I used to be able to keep the number of issues below 10 pretty well, but now I have a bit of a backlog there as well
I'm trying to modify the one_way_platform example to use sensors and events, but I think I'm missing something?
for collision in events.read() {
let can_allow_collision = should_allow_collision(&collision.0);
println!("can allow: {}", can_allow_collision);
if !can_allow_collision {
res_collisions.remove_collision_pair(collision.0.entity1, collision.0.entity2);
}
}
I've changed a bit of logic for determining when a collision should be allowed, but I'm printing my results and it is what I'd expect.
As I understand it, I should be removing the collision from the collisions resource if I want the entities to pass through each other, is that right? Is there another mechanism I need to use to actually make the entities stop when they collide?
I believe you can't use collision events for this, because they're sent after collision response
Removing the collision pair is how you make them pass trough eachother yea. I think I also did the one-way thing differently ... I should check if my changes actually make sense, maybe I can improve the example ๐ค
And yes collision events don't work
If you remove the collision pairs, no events for it are generated
Yeah you need to use the Collisions resource here unfortunately
This is how my one-way collision stuff works ... It works in a subtly different way from how the example worked when I copied it, but idk if this is perfect either ... It has worked fine for me at least ๐ค
Looks cleaner and more capable than the current example based on a quick glance
I still don't quite like how it works however ... It probably needs some extra logic to check the point of the collision besides just the normal ... Otherwise a shape like this would behave weirdly:
_____
|__ __|
| |
|_|
Assuming the allowed normal is bottom to top, then hitting the T parts and going trough seems kind of wrong ...
Do you have many T colliders? ๐
No but I have arcs and they could have the same issue 
ah true
No built-in T colliders? Imma head out ๐
you could make it as a compound collider with two cuboid shapes
Luckily the only place I use these one way colliders is on cuboids, where it seems to work fine, allowing me to pass trough only one of the cuboid's faces
Yeah I'd imagine most one way colliders to be those 2D platforms or things like dungeon doors like in your case
I've gone through all these files in parry now to change types
still 436 errors
and waiting for the next wave of errors
I'm starting to wonder if it's called parry because it parried all the clippy warnings instead of solving them 
๐ค
bounding/
โโโ bounded2d.rs
โโโ bounded3d.rs
โโโ mod.rs
primitives/
โโโ dim2.rs
โโโ dim3.rs
โโโ mod.rs
hmm, I just realized that changing these to Glam is basically implementing bounding volumes for the Bevy primitives
Just use bevy_math and yeet the whole bounding volume module ๐
just switch traits
ye
I am using bevy_math, just not primitives yet
need to get it to compile first
I just need a better name than Size and then I think the bounding volume PR would be done ... Ofc it would still need intersection tests and implementations on the primitives so you can use them ๐ค
impls are for a separate PR but yeah
Unit
bang, no wrong assumptions
Having something called Unit be a radius of a sphere sounds kinda confusing tho tbh ๐
It almost sounds like it should be a constant where every size is of unit length
Worst part is that calling it HalfSize works now, but what if someone invents bounding cones and one of the axis is no longer a half size? ๐
That's a future problem ๐
imagine using bounding cones tho
maybe no one has just tried it and it's the most efficient bounding volume 
Everyone knows that the future of physics is based on bounding cones, CCD and sequential impulses
I mean CCD and sequential impulses are very standard
CCD isn't actually that standard tho. Some engines don't even support it ... Even engines without substepping ๐
I think Box2D has it on by default for everything, PhysX supports it, Rapier supports it, Bullet supports it...
I think Roblox supports it lol
don't remember
I mean obviously bigger physics engines would have it
If you want a realistic physics simulation with things that move fast you kinda need CCD
But in a game you can totally just work around it as long as you have some number of substeps
yeah
we really need Direction2d::new_and_get to get both the direction and the length of the original vector
it's painful to do manually
PR time I guess...
Future problem created succesfully ... Now it just needs to get merged so barry can also have this future problem once bounding cones take over the world
what about BoundingMonkey
It is a Blender primitive ๐ค

BoundingTrollFace
I really hope they optimize this to not take 6 gb per project eventually
like, use a global cache or something lol
I'm pretty sure there was a Rust blog post about how they're improving that
nice
oh hey I use nightly
maybe I should turn this on
for some reason I can't reproduce this anymore

time to make a PR and pray I'm not responsible for breaking XPBD 
also here's the new_and_length PR if anyone would like to review ๐
https://github.com/bevyengine/bevy/pull/11172
okay but seriously, why tf would you write this
let _1 = 1.0;
I...
why...

it's used once, and it's not even close to where the variable is declared
I don't know why anyone would do that, even if they were a beginner
tbh
I like how small my 65% keyboard is but the number of typos has also gone up 65% since I bought it
why is this at the bottom of the docs too
in addition to this
oh, it's references
The numbered list thing? They're added automatically because of footnotes
yeah
dunno if there's a way to get rid of them
sigh, PR templates
lol
imagine having to explain your change more than "Add thing"
I usually squash merge with PR description like what Bevy does
sigh
let _0: Real = 0.0;
Most of them are just let _ = smth to discard the return value of a function, but there's 97
I've removed quite a few already too
Thanks, I'll review when I lose motivation fixing these errors
lol
I've been doing this for like 6 or more hours probably
yikes
of course I forgot to edit this after CTRL+Ving it lol
ok I think there's still potentially an issue with dynamic rigidbodies
ill look into it
@vestal minnow Does change detection work as I'd expect on CollidingEntities?
I think it should
I'm pretty sure it's only modified on CollisionStarted and CollisionEnded
but those could have bugs ofc
As long as it's supposed to work it's fine I guess
I'm definitely not working on some really hacky code ... Surely I wouldn't do such a thing 
Luckily not ๐
Something without bounding monkeys at least 
lol
from afar it looks really good tbh
I like the cloud part
From afar I just don't know what I'm looking at
the resolution is bad, fog doesn't work, and wtf is that red thing
And then when I look closer I'm even more confused ๐
Pretty sure the red thing is a building
yea I need a better cubemap
I like the door that is like 10 meters off the ground
lol
what is an "orthonormal subspace basis"
Solid preparation for when you get 10m snow. Every building should have this 
the doc comment is even more confusing
Applies the given closure to each element of the orthonormal basis of the subspace orthogonal to free family of vectors
vs. Ifvsis not a free family, the result is unspecified.
An imaginary combination of words surely 
Glam doesn't have this ๐ญ
fun
At least wikipedia has info about what an orthonormal basis is, and I think it's the same thing because inner product space sounds a lot like subspace
I'll just assume it's basically like using Glam's any_orthonormal_vector and running the closure on the return type ๐
we'll see in the tests
oh
this might take a while longer
I've noticed when I set my gravity resource to too high of a number, I start to have my player entitiy clipping through object's its colliding with.
The effect I am going for is the player entity falling slowly under certain conditions.
Can anyone suggest a better approach because I think changing gravity is probably a pretty naive way to implement that lol
I imagine there has to be some feature of the engine I'm not aware of yet.
Edit: It's a race condition / system ordering issue
@vestal minnow I think I fixed it https://github.com/Jondolf/bevy_xpbd/pull/292
I need to make sure this still runs in the PhysicsSet, I don't know if you can do in_set inside configure_sets
looks like you can
ok should be ready for review
What has actually changed here from the example btw? It looks cleaner at a glance but I can't tell what is actually different or if it's just that there's no comments so it just looks shorter?
Oh, there's no "allowed to drop through soft collision" logic, that's probably what makes it look simpler
iirc I rewrote how things get added and removed from the list
And yea no dropping trough that doesn't exist in my game ... The doors need to keep you in, not be optional ๐
A separate cut-down example that really is just "one way" would probably be a decent addition to the examples
I think the old code used checks to see if you were already inside to allow you stay in. My code just says "You touched the right normal so you can pass"
How does the incrementing id in the Local come into it? I can't grok what that's doing
It does have the theoretical edge case where you can pass and immediately fall trough again tho ๐ค
It uses that to check if it is still passing, if not it gets removed
It's a workaround cause collision events for removed things aren't very accurate
Ah, yeah, that is what allows e.g. your T-shaped collider
Yea, would be easy enough to solve, if it wasn't the desired behavior ... I think it would also need some extra checks so that things spawned under a character are also added to the passing list
That's actually 90% of my overlapping entity warnings ๐
It's amazing just how complicated things become when you really start using them
In my case the one way collisions are literally a door problem ๐
I remember you talking about them a while back. Is it for something like a boss room or somehting?
Similar to what you'd see in boss rooms yea. In my case I have it on almost every room with monsters. It's a one way collision so your party can enter after you, but no one can leave (well until you abuse bugs in my character controller to fly over the door)
Hello, I'm trying to create pickups for my game that rotate and go up and down when they're on the ground before being picked up (similar to minecraft), however as soon as my little cube lands on the ground, rotating gets weird (probably due to the constant collisions). My code looks like this for the rotation
fn move_and_rotate(mut query: Query<(&mut Transform, &Pickup)>) {
for (mut transform, _) in query.iter_mut() {
transform.rotation.y += 0.5;
}
}```
The cube has a dynamic rigidbody and a 1x1x1 collider
any tips?
instead of mutating the transform you could try giving it an angular velocity instead
seems to work well, thank you!
For getting it to bob up and down, would it be recommended to use linearvelocity in a similar fashion then?
yeah using velocity is the way you're supposed to move things, you can modify the transform as well but velocity is meant to be the primary way of doing it
you could also do it so the rigid body/collider itself doesn't move at all and have the mesh be a child entity and just animate that, then you don't need to worry about someone missing a collectible because the collider is much larger than the visuals
Makes sense! Got it thanks again :D
Assuming it makes sense, personally I'd separate the bobbing animation/rotation from the physics entirely and instead make them a child object of the rigidbody. Figured it'd be worth throwing it out there in case it was something you'd not yet considered (Edit: I should read more carefully, that's what Scottlecrab suggested last)
appreciate it anyways :)
Sorry, I deleted my previous message. But if I run it like this:
.add_plugins(PhysicsPlugins::new(FixedUpdate))
.insert_resource(Time::new_with(Physics::fixed_hz(144.0)))
...would you not expect time.delta_seconds() in a system run on the physics schedule to be more or less constant? Because now I am getting this:
2024-01-02T19:52:11.015934Z INFO ponkatris_arcade::level_objects::player: Delta: 0.0180284
2024-01-02T19:52:11.032644Z INFO ponkatris_arcade::level_objects::player: Delta: 0.0155575
2024-01-02T19:52:11.032870Z INFO ponkatris_arcade::level_objects::player: Delta: 0.0155575
2024-01-02T19:52:11.033225Z INFO ponkatris_arcade::level_objects::player: Delta: 0.0155575
2024-01-02T19:52:11.049415Z INFO ponkatris_arcade::level_objects::player: Delta: 0.0167611
2024-01-02T19:52:11.049745Z INFO ponkatris_arcade::level_objects::player: Delta: 0.0167611
2024-01-02T19:52:11.065430Z INFO ponkatris_arcade::level_objects::player: Delta: 0.0166252
What is the best way of going about making this as stable as possible?
It should be consistent with that if you're running in PhysicsSchedule, don't know why it wouldn't be... Since you're running physics in FixedUpdate, you could try Physics::fixed_once_hz(144.0)
okay I can reproduce ๐ค
Ah, cool, thanks. I just tried that and it still varies quite a bit here.
I kinda found the issue, but have no clue why it's not doing what I'd expect 
The generic Time clock is set to use the physics clock for the PhysicsSchedule like this
*world.resource_mut::<Time>() = world.resource::<Time<Physics>>().as_generic();
But it doesn't seem to actually do it properly?
@merry tide If you replace Time with Time<Physics> in your system, does it work?
Let me check!
That turns it into this:
2024-01-02T20:20:07.951952Z INFO ponkatris_arcade::level_objects::player: Delta: 0.006944444
Which is a lot lower but consistent.
alright, I'll need to try and find why it's not working correctly with Time
Great, thanks!
Ohhhh I think I found why
If you run before PhysicsStepSet::Substeps, it probably returns a consistent delta time, but systems running after it don't. This is because the clock is set back to Time<Virtual> (basically real time) after the substepping loop
I just need to make it return to Time<Physics> instead, and it works
I'll push a fix tomorrow
Cool, thanks a lot!
Thanks for reporting the issue!
have you had a chance to review my PR
still fixing errors ๐
I'm decent at doing mechanical brainless activity for long periods of time
I did rewrite two entire libraries from Python to both TS and Dart, so I guess it just depends on how much I want the thing lol
I guess I really want glam collision detection
is it faster?
one of the blockers for official physics :P
we don't want nalgebra in the dependency tree
because duplicate math libs would be annoying and confusing
and we can also use Bevy's geometric primitives for the collider shapes
and APIs are just nicer
speed-wise, idk
Glam has some automatic SIMD stuff, not sure if Nalgebra has it... but it does have other SIMD stuff
ughhh third wave of errors
it was like 30 for a sec
getting smaller though
although I just commented out simd bvh stuff...
BTW, by adding FixedUpdate and that 144Hz-thing, it looks like gravity is very noticeably slower. That shouldn't be the case, right? Is it related to the time-stuff?
hi, sorry it's me again.
both cubes are just Dynamic Rigidbodies, and are spawned in like this:
commands
.spawn((
Name::new("Cube"),
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(Color::rgb_u8(124, 144, 255).into()),
transform: Transform::from_xyz(0.0, 5.0, 0.0),
..default()
},
RigidBody::Dynamic,
AsyncCollider(ComputedCollider::ConvexHull),
GravityScale(2.0),
));
the player is again just the dynamic character controller from the examples, with the difference that it's in first person.
im on the git main branch of XPBD, so up2date
any ideas what is happening here? :)
btw you should just be able to use Collider::cuboid(1.0, 1.0, 1.0)
yeah technically i'm aware of that, dunno why i went with the AsyncCollider.
but it shouldn't really make difference, no?
doubt it
funnily enough i could not reproduce it when the collider is just Collider::cuboid...
primitive shapes are typically more efficient and stable
should still work with a convex hull too though
with the convex hull i can quite reliabily reproduce the issue shown above :/
parry has this issue https://github.com/dimforge/parry/issues/166
but I've mainly seen it for very big faces
so I doubt it'd be the issue here...
i also noticed the objects to just randomly doing small little jumps when not doing anything, which seems a bit weird? xD
I generally avoid auto computed colliders and stick with loading in cube coliders from the gltf file at world load.
I've had similar issues with convex hull colliders when the two objects are moving and collide, just randomly explosive. Not sure what causes it so I also switched to primitive colliders
This I believe is a bug with how sleeping (deactivating physics for optimization) currently works
adding the SleepingDisabled component should fix it for now
It's basically trying to mark the bodies as sleeping, but for some reason it instantly wakes them up and causes a small jitter... but in other cases, sleeping works fine
@vestal minnow physics working as intended (aside from severe input lag) at extremely low FPS now - thanks
I'm afraid this is gonna be another one of those horribly obvious questions, but I'm having a little trouble changing a Collider's orientation with respect to its mesh. Given:
commands.spawn((
Collider::cuboid(20., 20.),
MaterialMesh2dBundle {
mesh: meshes.add(shape::RegularPolygon::new(20., 4).into()).into(),
material: materials.add(ColorMaterial::from(Color::WHITE)),
transform: Transform::from_xyz(0., 100., 0.)
.with_rotation(Quat::from_rotation_z(PI / 4.)),
..default()
},
Player,
RigidBody::Dynamic,
));
I'm getting:
I seem to be missing the magic for having the collider's edges match the mesh's edges here.
I do see https://docs.rs/bevy_xpbd_2d/latest/bevy_xpbd_2d/components/struct.ColliderTransform.html#structfield.rotation, but it cautions not to modify it manually...
ah. I think I see... as a child, with separate transform? let's try that here...
yep, that was it! Thanks for rubber duckying
are there plans to add interpolation for fixed timesteps in the future? Was working on my own solution and realized it was going to take a bit more grease than I thought
glad i could help
Is it possible to turn AngularVelocity off altogether for a mesh? I know I can set it to 0 during an Update system, but that does allow a slight rotation to happen in between updates.
You can use the LockedAxes component. https://docs.rs/bevy_xpbd_3d/latest/bevy_xpbd_3d/components/struct.LockedAxes.html
A component that specifies which translational and rotational axes of a rigid body are locked.
thanks! ๐
(for those in the 2d context, it's something like:
commands
.spawn((
LockedAxes::ROTATION_LOCKED,
MaterialMesh2dBundle {
...
Is there a way to spawn an entity inside another as a form of drop without causing explosive behaviors? I've tried keeping the original entity in a hash set the spawned entity maintains for collisions to ignore (much like the one-way platform example) but it doesn't seem to do anything.
loose pseudocode ```
struct Foo(HashSet<Entity>)
struct Bar
spawn Foo
spawn Bar(HashSet containing Foo.entity) at Foo.transform
// collision handler for Foo and Bar
if Bar.hashset contains Foo.entity {
if !penetrating
Bar.hashset.remove(Bar.entity)
remove collision
} else {
fire event!
}```
the idea is to spawn Bar inside Foo and have their collision ignored until they separate, then once they collide again, we can fire our event
If one of them doesn't interact with anything else until it separates it can be a sensor, otherwise they can have mutually exclusive collision flags and you make a duplicate collider attached to one as a child as a sensor which fixes their flags and deletes itself once it is no longer in contact
by mutually exclusive collision flags I mean that neither belongs to any group that the other interacts with
If you don't make a duplicate collider and their flags are mutually exclusive then I think there would be no way to detect when they are no longer overlapping. But now that I think of it, having this whole thing be a built-in feature would be very useful. I also run into this scenario right now but have a dumb solution of gradually scaling up the orphaned collider from a scale of 0.01
Thanks for the reply! That's pretty helpful. Hoevery, I don't think I can use a sensor since I can't guarantee the two entites would separate before interacting with another entity.
I feel like I don't know enough about the engine to conceptually figure this one out ๐ฌ
Any reason why a CollisionEnded event would fire when the left side of my entity exits the collision, but not when the right side exits the collision?
Bear in mind I have in no way even looked at how the normals of either entity are interacting
@vestal minnow Did you make any progress on the timing with FixedUpdate? I feel bad badgering people during the weekend, so let me add to this query: Happy weekend!
The issue with time being inconsistent with a fixed timestep?
Yes, where the time delta is jittery and it seems to also affect gravity.
It feels like what I want to do should be relative simple to do. I just want a bouncing ball somewhat deterministic.
I also had a playtester telling me that the physics were affected by which screen he was playing it on.
Yeah I meant to fix the time inconsistency but got invested in a big collision detection thing, my bad; I'll make a PR to hopefully fix it now
I'll also test this, that shouldn't be the case
I fully understand there are things that are way higher in priority, no worries. I just didn't want it to be forgotten, it is somewhat central to the experience I am trying to make. ๐
The Time inconsistency issue should get fixed by #294
As for gravity being faster, make sure your Time<Fixed> Hz and Time<Physics> Hz match
If Time<Fixed> is 144 Hz and you have e.g. Time::new_with(Physics::fixed_once_hz(60.0)), that means that you will advance the simulation by 1 / 60 seconds every 1 / 144 seconds, so the simulation will essentially be running at double speed
Let me try to repro it, I think I saw it in stranger circustances.
Perhaps I am mistunderstanding, but, would you expect these to perform similarly visually?
.add_plugins(PhysicsPlugins::default())
...and...
.add_plugins(PhysicsPlugins::new(FixedUpdate))
.insert_resource(Time::new_with(Physics::fixed_once_hz(144.0)))
?
Have you configured the timestep used by FixedUpdate?
It's 64 Hz by default iirc
Time<Physics> is separate
Making it 64hz does indeed make it run similarly (eyeballing it). Thanks!
yeah they should be the same; either both 64 Hz or both 144 Hz (or whatever value you want)
Perhaps that last code is enough to also fix the timing reporting into the system also?
this should fix it
or, explicitly specify Time<Physics> instead of Time in the system
Ah, OK. But should I, being a noob, just be running this from github as the dependency you think?
If you want the fix now, then yeah you could
Well, I feel I know you guys better than I know my parents now.
I will just do that, great!
(or I didn't merge yet but will soon)
just waiting for tests
oh they're done lol
I'll merge now
Great. And should I be using this: features = ["enhanced-determinism"]?
I read the docs, BTW. Haphazardly. ๐
The build system in Rust is actually pretty insane.
Yeah, it'd probably be good to have in your case. Note that proper cross-platform determinism isn't entirely working yet (not in bevy_rapier either), so you can't fully rely on it for e.g. games with networking
That's cool.
This is the reported delta time now:
2024-01-05T16:40:48.159156Z INFO ponkatris_arcade::level_objects::player: Time: 0.015625
2024-01-05T16:40:48.175372Z INFO ponkatris_arcade::level_objects::player: Time: 0.015625
2024-01-05T16:40:48.192755Z INFO ponkatris_arcade::level_objects::player: Time: 0.015625
[...]
Seems to just be stable, great!
Thanks so much!
No problem! This was a good bug to fix
or the bug wasn't good, but fixing it was ๐
Great! ๐
Hello ๐
In the process of moving from Rapier3D to XPBD I found an issue probably related to applying external forces to the car.
In my code I now use RayCaster and it's way cleaner ๐ However, as you can see in this vidรฉo, it seems that the external forces (that I set to non-persistent) are not applied correctly when the car is rotated. I multiply the car rotation to the force point but it didn't fixed the problem. Would you mind taking a look at the changes and help me fix the issue?
Ok, found the issue. It was related to the velocity at point functionality, don't forget to multiply the point by the rotation:
linear_velocity + angular_velocity.cross(transform.rotation * point)
How would distance constraints behave when I put them on two physics based character controllers? Would it make the controllers pull on eachother, or just prevent any further movement than the specified distance?
I'd assume pull on eachother, the constraints don't negate energy in the system
Yep
or at least try to not
Might lose or gain some mysteriously because integration is hard
There was also a bug where distance constraints forced the distance to always be equal to the rest distance regardless of the min/max distance limits, but that should be fixed on main (i.e. you can make it only have a max distance, not doing anything at a smaller distance)
I am seeing some strange stuff when changing the rotation of the level object, and I think I am doing it incorrectly. Can I share a video? I am not using the controller at all, it seems to be sticking to the wall.
I am changing the rotation through a Query<(&mut Rotation, &ObjectRotation)>.
And just setting it using ```rust
*rotation = Rotation::from_degrees(
object_rotation.original_rotation
+ (object_rotation.degrees_per_second * current_game_time.as_secs_f32()),
);
Which I think is probably wrong.
Hey bevy-physicians ๐
I would like to know if you have any idea why my car is juddering/jiggling. It seems maybe related to XPBD and more specifically the order in which I update the camera's target.
The strange thing is that my car is acting correctly on my laptop which runs the game at 60 fps (video #3), that's the only main difference as it doesn't work great at 140 fps.
The video #1 and #2 shows two cameras targeting the car, the first one is also following it.
I am using the bevy_dolly crate for the camera.
Do you have any clue on when I should trigger the camera's update? I already tried:
- Running both dolly camera update system and the camera position itself after
PhysicSet::Sync - Using
PositionandRotationinstead ofTransformwhen moving the camera - Using
bevy_framepaceto limit the fps to 60. - Configuring the time step to be fixed at 60hz (all above videos are using this setting already).
Aaaaaand... while writing this long message I understood that my laptop was running at 60 fps with a physics timestep of 60hz but my desktop was running at 140 fps also with a 60hz physics timestep.
I therefore fixed this bug by setting a physics timestep to a fixed 144hz. You can try this game by cloning my repo (press i to hide the debug tools).
.insert_resource(Time::new_with(Physics::fixed_hz(144.0)))
It behaves the same if I write it like this:
for (mut transform, object_rotation) in object_rotation_query.iter_mut() {
// convert the degrees per second to a rotation in radians
let rotation = object_rotation.original_rotation + (object_rotation.degrees_per_second * current_game_time.as_secs_f32());
let rotation_in_radians = rotation.to_radians();
transform.rotation = Quat::from_rotation_z(rotation_in_radians);
}
Is it because of the system ordering?
update_current_game_time
.after(PhysicsStepSet::SpatialQuery)
.run_if(in_state(GameState::Running)),
object_rotation
.after(PhysicsStepSet::SpatialQuery)
.after(update_current_game_time)
.run_if(in_state(GameState::Running)),
Yea I guess that's the logical thing for it to do ... I kind of need it to magically take energy out of the system tho. Players dragging around monsters or other players sounds like a recipe for disaster ๐
Could make a custom distance constraint that breaks the laws of physics
i.e. don't use apply_positional_constraint or whatever it's called in the constraint and handle it manually
Something is off with my raycasts, and I can't figure out if I'm doing something wrong, but my rays are always at the origin, this is confirmed both by the behaviour, and also by the debug rendering plugin. I know I've likely got something off with the systems, as I'm doing networking and I'm not currently running xpbd in my network schedules, but that shouldn't affect this. I've checked that global transforms are being propagated correctly, so it's likely not related to that either, do you know what might be up? I can send you the repo in case it's not obvious what's happening
They're attached to moving bullets and have the raycast origin as (0, 0) for the record
I think the RayCasters/ShapeCasters need to be on an entity with a RigidBody or Collider at the moment
Ahh, yeah I am missing that
I meant to fix this, but got a bit sidetracked; a workaround for now is to just add RigidBody::Static or RigidBody::Kinematic, shouldn't affect behavior in this case
That works! Thanks! It is a bit unexpected yeah, I was specifically using a raycaster for these bullets because I didn't want to have to deal with the ccd that would be required if they were normal colliders ๐
Hm, does anyone have any idea why adding a RigidBody to some tile entities would cause them to:
- No longer render (they have a
Spritecomponent) - Plummet performance (140fps -> 35fps)
There are about ~280 entities with rigid bodies. For reference, I get ~140fps in the many_shapes example and ~30fps in move_marbles. The rigid bodies are static, and are applied to the walls. I have the PhysicsPluginDebug enabled, but don't see the gizmo debug outline on the walls.
I've verified that the tiles aren't moving and that the collider size is non-zero - it's a (32,32) cuboid.
I've attached 3 screen recordings for context.
- No rigid bodies, just colliders. This runs smoothly and renders the wall tiles as expected at ~140fps.
- Rigid body with colliders. This doesn't render the wall tile sprites and is unperformant, rendering at ~30fps.
- Rigid body without colliders. This doesn't render the wall tile sprites but is performant, rendering at ~140fps.
I'm a bit stumped so would appreciate any insight.
let collider = Collider::cuboid(tile_size.x, tile_size.y);
let rigid_body = RigidBody::Static;
The relevant components ^
Maybe something with the sync plugin? On rigid bodies it tries to take the position/rotation and update the Transform wit them
If they somehow end up at 0, 0, and it also happens to at least one dynamic entity, the collisions there would probably explain the performance issue ๐ค
Just porting my code from using rapier to xpbd and very happy with xpbd so far.
However, I have a issue with a buoyancy simulation where I have a raft that is a rigid dynamic body with one collider attached as a joint in each of the four corners, acting as pontoons.
The raft spawns a bit over a ocean surface. It initially falls down nicely, but as soon as one of the corner pontoons comes in contact with the water surface and an external buoyancy force is applied to make the pontoon float, the raft starts spinning around much more than expected. (Note that the ocean is not directly handled by physics engine. By "contact" I mean that the water height is compared to the translation.y of the pontoons. Forces / damping are then applied manually.)
It calms down after a while and does not exhibit this spinning behavior anymore. At a first glance, it seems like the very first time a force is applied to the pontoons, the problem arises, even when testing with very small magnitudes.
Any idea what might be causing this problem?
I noticed that the documentation for ExternalForce set_force mentions that "... the torque caused by any force will not be reset.". Not sure if what is described there could be causing the initial exaggerated spinning(?)
For more details, the two relevant files would be as follows
https://github.com/claudijo/pirate-sea-jam/blob/origin/ocean_shader/src/plugins/buoy.rs
https://github.com/claudijo/pirate-sea-jam/blob/origin/ocean_shader/src/plugins/raft.rs
Cheers!
This would be a short clip showing the initial spinning as the raft hits the water. (The raft is a bit bouncy in general, but that is currently as expected.)
that water looks dope
Thanks @peak timber . If you want to check out the "playable" work in progress, you can find it here ๐ https://claudijo.itch.io/pirate-sea-jam
A little offtopic but does xpbd provide a way to render collision boxes or are you guys just using bevy gizmos for that
Add PhysicsDebugPlugin
it uses gizmos under the hood as well
i feel like i googled so much without finding this ๐
thank you though i appreciate it this will be useful
haha no worries
the table of contents here is decently comprehensive
https://docs.rs/bevy_xpbd_3d/latest/bevy_xpbd_3d/index.html#table-of-contents
yo my PR got merged
dope
I'll be waiting for the flood of issues to be opened about how it doesn't work and how I broke everything 
@vestal minnow Let me first congratulate you on a very nice lib.
Hope my question above kind of makes sense... Do you have any idea why I get a somewhat explosive behavior when initially applying an external force to my fixed joints, which act as floating pontoons?
Sorry for spamming the thread, but I've made a small code modification to exaggerate the issue and a short clip that shows the what's going on....
The minor code change is just to make sure a minimum none-zero force in the positive Y-direction is applied for each frame, which will slow down the falling of the raft.
As seen in the clip, the very first time any of the corner pontoons hit the water, the raft goes a bit haywire, but subsequent "bounces" in the water plays out as expected and are much less explosive.
have you tried changing the float system to run in FixedUpdate and also change the force so it isn't persistent, doubt it'll change much but there could be something funky going on just because of that
you could also change the center of mass so it's below the raft, which'll make it harder to tip over
Thanks for your suggestions. I did a quick try using the FixedUpdate schedule, but it didn't make any difference. I've also tried explicitly setting the persistence of the force to false, to no avail . The raft tipping over isn't really the problem, but rather the explosive and unpredictable reaction to hitting the water the very first time.
I've noticed something similar with a bunch of 2d squares
when they finally settle on top of each other, it's like a massive explosion goes off and they all launch apart
probably related
Yeah, maybe. I guess there are many things that can cause colliders to explode. Not so easy to know if it is related. I have a hard time figuring out what is going on here.
Seems like if the raft is falling without any angular velocity it will go haywire when an upward buoyancy force is applied at water level, start spinning and consequently gain some angular velocity, and after that when hitting the water, it will go into the water much more gently.
Also, it only seems to be a problem when having multiple colliders (pontoons) attached as fixed joints to single parent.
But it beats me what the root cause could be.
@noble pier Sorry for not responding, I've been kinda sidetracked working on collision detection stuff and Bevy's new primitives.
I'll try if I can figure out the issue
No worries. When you have time. Thanks.
im making a 2d game editor/playground and i spawn rigid bodies with different colliders, how can I edit existing colliders? I dont understand the data types that the colliders are built from.
im thinking adding a component to each entity with a struct that contains the fields that are used to make a new shape like cuboid(x,y), and then when I want to edit the collider shape, I will despawn it and spawn an updated collider (I need to define a different struct for each kind of shape).
is there an easier way?
I don't think you can edit individual properties of colliders nicely, but you can replace the old shape with a new one using collider.set_shape(new_shape)
alternatively, set the collider component like
*collider = new_collider;
what are these yellow circles being drawn on my rigidbodies with the debug renderer?
can't figure out how to turn them off
The colliders use Parry shapes which use Nalgebra (a different math lib than what Bevy uses, glam), so they're a bit of a pain to work with. I'm working on a fork of Parry that uses Bevy-native types though, which should make it nicer
It's the center of mass, see #260. The size was previously hard-coded so it looked weird at non-default scales, but it should be fixed on main
I think you can also disable it by disabling the axes
main as in the main branch of the repository?
I'd rather stick witha stable build. I can just turn the axes off though I guess, don't really need them either
like set axis_lengths: None in PhysicsDebugConfig
yep
is there a way to get a parry shape of the collider? or does the collider only use parry shapes to build the actual shape data?
collider.shape() or collider.shape_scaled() should get the SharedShape
And then that has methods to get the specific type of shape, but it's a bit painful since it's an Arc<dyn Shape> IIRC
Was this ignored? Can we not do rotation in 2D?
It seems like it is just broken that something next to something that is rotating is acting like that.
what's type of rigidbody is the rotating + thing?
Well, my friend. It is a RigidBody. ๐ Sorry, I am new.
Dynamic? Kinematic? Static?
No, it is an actual Static body. This is probably fixing my issue!
Yeah I'd try changing it to Kinematic
but even then I could see the issue continuing
you might have to manually set the rotational velocity too
Let me try it, but that makes a lot of sense.
I am in a broken branch, but I will test this as soon as I can. And I am sorry about being snooty.
haha didn't sound snooty to me
I was a little snooty. ๐ I've been up all night. This was never a dealbreaker to me, but it makes sense when you say it like that.
@vestal minnow, Hope your work with collision detection stuff is progressing well.
Sorry to bother you again, but I made some small progress getting a grip of my issue with initial explosive behavior when my joints are affected by external force for the first time.
I noticed that commenting the following lines in the function apply_angular_correction() from the file angular_constraint.rs will remove the symptoms.
*body1.rotation += Self::get_delta_rot(rot1, inv_inertia1, p);
https://github.com/Jondolf/bevy_xpbd/blob/main/src/constraints/angular_constraint.rs#L69
*body2.rotation -= Self::get_delta_rot(rot2, inv_inertia2, p);
https://github.com/Jondolf/bevy_xpbd/blob/main/src/constraints/angular_constraint.rs#L72
This makes the joined entities rotate freely in relation to each other, and prevent the initial tension that eventually snaps (in lack of better words) that is generated when the joints initially hits the water and are affected by an external force (buoyancy).
This is obviously not the correct fix, but does it tell you anything or give you an idea of what is going on?
(It seems like it would be less weird if the raft bounced dramatically each time the buoyancy force was applied, not just the first time the raft falls down without any angular velocity)
This could maybe be related
https://github.com/Jondolf/bevy_xpbd/pull/237
Could you try normalizing the rotation after those lines?
Thanks. Looked kind of promising, but unfortunately didn't help.
My guess is that there is an issue when applying an external force to one or more colliders/dynamic rigid bodies that are joined to a common collider/rigid body. When the force makes the angular velocity go from 0 to a none-zero value the explosive behavior occurs.
I've made a small example project that reproduces my issue. See https://github.com/claudijo/raft/blob/main/src/main.rs
I'm also attaching a short clip to show the example output
Hm, making it kinematic didn't seem to make much of a difference (regarding the rotating wall), but it was well worth trying, thanks!
I'd try adding a rotational velocity component and setting it to match the rotation that you're applying to the transform. The physics engine would hopefully use that additional data in solving the collision
Hm, that seems like it could help. I just decided to not use it for now, I might revisit it and try it. Thanks so much for the help.
Fair
I guess the "proper" way to do it would be too use a dynamic body and a motor joint to keep it in place and rotate it
Or i guess you could just not use joints, give it a higher dominance than the Pachinko ball and a gravity scale of 0 and then apply a rotational velocity to it
I'm pretty sure the rigid body type shouldn't really matter here
It feels like it should just work. I think it does in Box2D. But it is not a pressing issue.
You can rotate all rigid body types and apply angular velocity to kinematic and dynamic bodies
Yes, but is the problem that I am applying the force incorrectly?
Really, it isn't a pressing issue, but it would be fun if it worked.
Yeah I think a lot of other engines usually infer velocity from Delta rotation/position for kinematic bodies but it seems like bevy xpbd doesn't. The problem is the collision solver needs this velocity information to correctly resolve the collision I believe. Thats what it looks like to me at least in the video you're posting. Just a funky artifact from an improper collision resolution
If you're setting the rotation manually, that could potentially cause collision issues unless you run the system in a very specific part of the schedule, so it's generally better to use AngularVelocity. But the speed here is slow enough that I doubt it's the issue
Does this mean if I set the velocity of a kinematic body it will move? Or do I have to manually translate it also?
Setting the velocity will move it at that speed
But the engine won't touch the velocity (so e.g. collisions, joints and so on won't do anything)
Ooh nice. I did not know that ๐ that seems super useful
So it's still user-controlled
Is it simple to rewrite the code I already shared to make it apply angular velocity instead? If I want to rotate it at a specified degrees per second?
I think it's just this
ang_vel.0 = degrees_per_second.to_radians();
where ang_vel is the AngularVelocity component
it's in radians per second but you can just convert your degrees to that
Yeah, that doesn't really work for me either as I need to be able to deduce the current rotation from the game time, etc. But I am not going to worry about it right now.
I tried making it so that I set the rotation and the angular velocity, tho. Perhaps that is the correct thing to do?
It does something, I probably just did it all wrong. ๐
pub fn object_rotation(
mut object_rotation_query: Query<(&mut Transform, &mut AngularVelocity, &ObjectRotation)>,
current_game_time: Res<CurrentGameTime>,
) {
// Check that we have a current game time
if let Some(current_game_time) = current_game_time.0 {
for (mut transform, mut angular_velocity, object_rotation) in object_rotation_query.iter_mut() {
// convert the degrees per second to a rotation in radians
let rotation = object_rotation.original_rotation - (object_rotation.degrees_per_second * current_game_time.as_secs_f32());
let rotation_in_radians = rotation.to_radians();
transform.rotation = Quat::from_rotation_z(rotation_in_radians);
angular_velocity.0 = rotation_in_radians;
}
}
}
Am I just being a dumbass?
Setting the angular velocity probably isn't that helpful if you set the rotation anyway
Yeah, I am going to be a Gen Z'er and say that this "yeets" the ball into outer space. ๐
If the angular velocity is constant, you could compute the rotation like
let angle_radians = ang_vel.0 * elapsed_time;
or to be precise, that'd be the change in rotation after some delta time
pub fn object_rotation(
mut object_rotation_query: Query<(&mut Transform, &mut AngularVelocity, &ObjectRotation)>,
current_game_time: Res<CurrentGameTime>,
time: Res<Time>,
) {
// Check that we have a current game time
if let Some(current_game_time) = current_game_time.0 {
for (mut transform, mut angular_velocity, object_rotation) in object_rotation_query.iter_mut() {
// convert the degrees per second to a rotation in radians
let rotation = object_rotation.original_rotation - (object_rotation.degrees_per_second * current_game_time.as_secs_f32());
let rotation_in_radians = rotation.to_radians();
transform.rotation = Quat::from_rotation_z(rotation_in_radians);
angular_velocity.0 = rotation_in_radians * time.delta_seconds();
}
}
}
This actually works a little. It seems to almost do it. But the walls get jittery, and it still snuggles up to the wall every once in a while. Not using the absolute transform.rotation makes it not work the way I want, because I need the current rotation to be a function of time to make the level somewhat deterministic.
Would it be strange to deduce the angular velocity based off the delta in frames that follow each other, perhaps as an option?
I think that might be similar to Rapier's RigidBody::KinematicPositionBased but I don't remember exactly how it works
Yeah, cool. So it isn't an insane idea, I guess. Thanks for the help, I will do this next episode. ๐
Do you think implementing something like that would be a thing for an absolute noob like me? Is it something you would want in the codebase?
I'm not sure if I want it in the codebase at the moment, but maybe? I just haven't seen it in engines other than Rapier before
It might also be more of a character controller thing than a physics feature
I don't really want the split into RigidBody::KinematicVelocityBased and RigidBody::KinematicPositionBased since I find it to be a bit weird, but a separate component could maybe be alright
Sure, cool. ๐
The way this would probably be implemented though is to just set the velocity in IntegratorPlugin based on the difference in Position and PreviousPosition, divided by the delta time
That would make sense. Perhaps you could just add it is another system in the pipeline that makes some other values available.
what's the units for collider density? kg/m^3?
I think so
or I guess it technically doesn't have a specified unit, but if you treat distance units as meters and mass as kilograms then yeah
Parry doesn't give them explicit units iirc
cool. if you don't have established units then it makes sense to set the default to 1.0
Would you recommend working at a scale where 1 unit = 1 meter for the physics engine? It's what I'm doing rn but it feels a bit weird to be setting the camera projection scale to 0.01 ๐
or would it be better to just scale up my forces and gravity and keep 1 pixel in bevy as 1 pixel on the screen
Yeah it's generally recommended to keep values reasonable like 1 unit = 1 meter, since having bodies be e.g. thousands of units in size could potentially cause stability issues
but I haven't really noticed it myself so I'm not sure if it's a common issue in practise
Ideally we'd probably have a physics scale like Rapier so that you could use pixels but they get internally converted for the physics engine
honestly the physics scale in rapier confused me when I used it
it seems like sometimes units get converted and sometimes they did not
yeah it's confusing, especially the way it's documented
seb told me it doesn't do anything from the user's view point, only internally
I'll try to find the message
Sรฉbastien Crozet, dev (owner?) at Dimforge, main author of Rapier, Parry, Nalgebra and their predecessors NPhysics, NCollide, etc.
Here's the physics scale convo #math-and-physics message
sweet thanks
Do CollidingEntities online retain collisions for a few frames? I'm looking for a way to find all active collisions when a player is standing on top of a Sensor / Collider, rather than the discrete moment when the collision starts / ends.
Ideally I don't have to write something to track this state myself, though I can if needed. Assuming a solution exists in the crate that I'm missing.
iirc it's all entities that were colliding whenever the physics last did its thing
Not 100% sure how it behaves if a collision started that physics update and ended before the last substep tho
https://github.com/Jondolf/bevy_xpbd/blob/main/src/plugins/setup/mod.rs#L144-L145
Unless I'm misunderstanding, it looks as though ReportContacts (which is when report_contacts runs and updates CollidingEntities) happens after all sub-steps, so it seems as though it could be skipping over collisions in the situaion NiseVoid describes entirely?
https://github.com/Jondolf/bevy_xpbd/blob/main/src/plugins/collision/contact_reporting.rs#L152-L188
CollidingEntities appears to hold the entities for the entire time they're in contact instead of only being present for a single frame
It may be doing something inside the substeps to make sure that a momentary collision is included, though. I've not read it close enough but Jondolf can probably answer to that for sure
I couldn't resist so I read some more ๐
https://github.com/Jondolf/bevy_xpbd/blob/main/src/plugins/collision/narrow_phase.rs#L34-L37
It looks as though the collisions are added as part of each substep, but only ever removed after collisions have been reported, so even if it's only a momentary contact in a single substep, it won't get skipped over.
That's helpful context, thanks both ๐ I'm seeing a handful of updates where the collision is persisted, then I get a CollisionEnded event and CollidingEntities is empty. Probably some bespoke issue with my setup ๐
I was wondering if colliders sleeping may be involved, but after adding SleepingDisabled I'm seeing the same behavior.
Going to test a bit more.
CollisionEnded is triggered on the same conditions as the other entity being removed from CollidingEntities, so that condition sounds expected
(it's the code in the bottom half of the second link I posted)
Looking at the sensor example in the xpbd 2d crate, it looks like the collision start / end events happen at the "point of collision". CollisionEnd fires while the pill is overlapping the pressure plate. Let me know if I'm misunderstanding.
Based on the code you linked, if CollisionEnd fires, then it was also removed from CollidingEntities. This would track with what I'm seeing in my game, but isn't the behavior I'd expect.
See recording ^
That sure looks incorrect!
I think I remember seeing someone talking about when a collider is perfectly overlapped it stops detecting it
perfectly overlapped + not moving*
Ah, that could be it. If so, I'll need to write a work-around...
Trying to see if I can see where that info went. I'm pretty sure I saw someone talking about it.
I assume you're using the released version and not the main branch from github? (Asking this because it'll help me figure out where I need to look for it)
Ah. Found it. This is your exact bug from the looks of things: https://github.com/Jondolf/bevy_xpbd/issues/264
It was fixed with this: https://github.com/Jondolf/bevy_xpbd/pull/266
The recording of the sensor example I sent is using the main branch of bevy_xpbd, just a local clone of the repo.
My game where I'm seeing the same thing is on bevy_xpbd_2d = "0.3.2". Looks like 0.3.3 is the most recent, I can test it there rq too
Looking at your link ๐
But if you're using the main branch.............
Looks good, actually ๐ I had a stale clone, just pulled. The example is good now ๐
Going to check if this was included in the 0.3.3 release or if I should point my game towards the main branch
Thanks for your help โฅ๏ธ
Glad to be of service!
It wasn't included there, it just mainly has serde support since that was requested, and a few fixes from before that commit
Idk what's a good way to pull specific changes from the commit history without including any breaking changes so I made the release pretty small since I did it semi-manually
one thing on the main branch I'm noticing is that I need a rigidbody and a sensor for collisions to be picked up. on 0.3.2 i believe just a sensor was sufficient. do rigidbody's have a purpose if you don't need physics?
same deal w/ the sensor example https://github.com/Jondolf/bevy_xpbd/blob/7e7e14d210efb27177d975367bc47090cfa3652d/crates/bevy_xpbd_2d/examples/sensor.rs#L77. maybe it makes sense, just checking
Curious if there are any showcase projects that successfully combine bevy xpbd 3d together with rollback networking, eg bevy ggrs? What's happening in that space?
bevy_gaff is a WIP demo that uses bevy_xpbd, bevy_ggrs and bevy_matchbox for p2p networked physics using rollback. It only syncs inputs and relies purely on determinism, which can currently cause desync issues since we don't seem to have perfect determinism yet (in bevy_xpbd or bevy_rapier)
There are also other larger projects that have networking working with bevy_xpbd (syncing more than just inputs), but I don't think they're open source
I have a bunch of bricks that I'm trying to connect with fixed joints. I've checked the colliders and they're correct. if I set them to dynamic bodies and don't add the fixed joints, they tumble like I'd expect and I don't get any warnings. when I add the joints, they explode on the first frame and give me a ton of intersection-on-spawn warnings. the second image is of the joints, with anchor color in red and separation color in blue. I'm adding the joints with just FixedJoint::new(entity_a, entity_b). should I be setting the joint anchors differently?
it looks like a really really bad idea to do that in the first place
I'm confused about the PhysicsSet System Set. I assume that if I want to run a system after the physics engine does its thing I can specify my_sys.after(PhysicsSet) but it's unclear what schedule I should be putting it in?
would it just be the PhysicsSchedule?
like I want it to run after PhysicsSet::Sync
after a bit more digging in the source it looks like maybe I should put it in PostUpdate?
It depends on what schedule you added the plugin to. The default would be PostUpdate
oo
i just used default
didn't realize you could add it to different schedules
is that how you would get it to update at a fixed interval?
You can also configure the physics time to give you a fixed interval, but using FixedUpdate can be a lot simpler if you also have other things running at a fixed rate
Why am I getting contacts even when objects are not actually touching? In this video the contact points are rendered in blue. As you can see they are appearing long before the collisions between the colliders (which are rendererd in orange)
it's problematic because when I check for collisions in Res<Collisions> the contacts are showing up there too, when objects aren't actually colliding
there are contact manifolds in the collisions too, not just empty collisions
I wonder how far down one needs to go for float determinism!
For example this blogpost says that calls to external libraries (like sound libs, etc) can change the float precision, so one needs to change it back
https://gafferongames.com/post/floating_point_determinism/
Introduction Hi, Iโm Glenn Fiedler and welcome to Networking for Game Programmers.
Lately Iโve been doing some research into networking game physics simulations via deterministic lockstep methods.
The basic idea is that instead of synchronizing the state of physics objects directly by sending the positions, orientations, velocities etc. over the...
On several reads of blogposts from that linked one, take it with a grain of salt. It comes from a person with a vested interest on complicating game networking, removing net neutrality and bidding for sections of low latency connections..
Not being well informed about the subject... but why not in general assume you will have drift due to floating point inaccuracy and compensate on regular intervals, instead of fighting it? Or will that have significant impact on performance and/or graphics?
Well, compensating means extrapolating or predicting client side (quite typical). Thing is if you have determinism you don't need to send state, you can send only inputs of the system which reduces networking for example. It's all tradeoffs
But how often do you think that you need to send "keyframes" / state in worst case scenarios?
It depends on the type of game. RTS with thousands of units? Prohibitive
(E.g age of empires, total annihilation)
Right.
(I just read all blogposts from the linked page I posted, he describes several strategies and their tradeoffs, quite a good read)
Will add it to my read list. Thanks. Just looking into implementing multiplayer into my hobby game project.
With Rust, I'm pretty sure fp determinism should be possible by just using libm math for operations that are platform-specific (e.g. especially transcendental functions like sin, cos, atan...).
Glam has a libm feature for this, and bevy_xpbd uses it through the enhanced-determinism feature. This does make things a bit slower though since it doesn't use intrinsics and instead uses the same implementations for each platform
I wonder what performance penalty there is if any
But I think there's currently at least one sin that doesn't use libm in 2D so it's probably not working perfectly in bevy_xpbd atm
that one is easy to fix though of course, just libm::sin
I struggle a bit coming up with things that would need deterministic physics apart from debugging. The best I can think of is being able to do p2p and delegate object calculations to clients in a round robin manner, as an anticheat
speedrunner games that rely on physics. i did a test with @merry tide's game where i just hold diagonal movement and reset, and it's 50/50 about where you'd end up after first collision
p2p games with rollback networking need deterministic physics ... And having enough determinism issues can also add up to an unstable physics engine, where an interaction doesn't always product similar-enough results
Things like Linerider too, you don't want the track to just not work on some platforms
Same with delay-based netcode ofc. And even on client-server games having perfect determinism is still beneficial
Keep in mind, this is in 2D: Well, look at it from this point of view. I want a game to be tracked and competitive. And having a determined step with determined input end up different places seems like "it cannot be done". And I see this all the time with bevy_xpbd. I don't think I can do it, to be honest. I cannot make a ball-collider behave sensibly with two cuboid colliders.
This is before anything I was yapping about regarding to rotation. I just cannot make this work:
It should have a ball be able to bounce straight up, but it doesn't. And changing the angles on the walls flips which way the ball is going. But. If you do this:
If I do this, it bounces perfectly up.
So I don't even know, it seems to work with 45 degrees but not with another set of degrees.
Is this one collider instead of two?
They are both two colliders, I never merge colliders here.
I can show you how this crumbles so early, the same level with having something that is not 45 degrees seems to be solved in a way that always makes the ball bounce off to a random side.
You would expect this to behave the same without touching the controls.
But it doesn't.
These are static wall-objects, BTW.
It seems like it solves the correct bounce up by accident. It just feels a little arbitrary.
And if you all know a game like TrackMania, you should be on board with the idea of having something deterministic and timeable.
This was discussed some time ago already, but the issue here is basically that the ball first bounces from one wall and then the other instead of accumulating the forces into a single impulse where the X coordinates would cancel out.
I think the reason it works with 45 degrees is that the initial bounce goes perfectly sideways, so the second bounce will go perfectly upwards (assuming there is enough restitution). With other angles, it's probably more likely to initially bounce in a slightly different direction, which also affects the second bounce
(here's a lil picture showing the situation)
That makes sense. ๐ And that is what you see in the world.
But if it is 35 degrees it makes no sense, and it is not what you see in the world.
And that is arbitrary.
I believe this could be solved with either
- Using a Jacobi solve instead of a Gauss-Seidel solve, i.e. accumulating the "impulse" instead of applying two separate impulses in succession
- Using impulse-based methods instead of PBD/XPBD
We'll probably make (1) an option at some point, and I have plans to hopefully support alternative solvers to some capacity, which would solve (2).
But yes, determinism is an issue here too
I think I was wanting 1, but that was just because it seemed like what I could want intuitively.
Full disclosure, as much as I am getting to work here, most of the things I am a total noob at.
But my guess would be that "it's 2023" (when I started) and a ball bouncing on walls wouldn't be that much of an issue.
Have you tried with the enhanced-determinism feature by the way?
Yes, it is turned on.
This is my Cargo.toml-file for that part.
It just irks me to no end. We have the coolest physics engines, but we really cannot do Breakout.
I might try some things with your project if that's fine, I believe I should still have access
Hold on. If you're going to do that, and I welcome you. I am on that different branch now.
It's on this branch: https://github.com/COCPORN/ponkatris_arcade/tree/feature/egui
alright, thanks
I have sort of merged them into a single thing, but you need to start it as the editor if you're going to test it.
It's all in the README.
Again, it is no real biggie. But I just want my balls to bounce. ๐
I can also just make a WASM-version of it that shows it and push it to the site.
You will find a lot of nasty code in there. But I am trying to make it better. Day by day. ๐
I have messed around a lot with the physics settings also, so if they're not particularly correct now, sorry about that.
@merry tide Do you have an example of non-deterministic behavior? For me it's always bouncing the same way on restart (but not directly upwards like you said)
I feel like I have used the word "deterministic" incorrectly here. I think, tho, that I wrote that it "always bounces off to a random side". What I meant was that the side that it bounces off to seems random, but it is always the same side. So it is very in line with your sketch.
Ah, makes sense
Yeah, I was unclear in how I worded myself.
So the "not bouncing directly upwards" thing is the only issue here?
Well, I think that isn't the only issue I am looking at. I think what you are talking about with the 1) solver is what I am looking for.
Because it fails like this in so many ways.
But that would be me rehashing the stuff we've been talking about before.
I'll see if I can implement the Jacobi solver as an option in a reasonable way
It would require some refactors to how constraints are handled though
Keep in mind this isn't a huge issue. It is "just me" and my needs. And I think a lot of people don't really need this. But I just find it odd that you cannot really do a predictable breakout-clone. But now I am just saying the same things again. So look at this a couple of times before deciding to realizing it.
I think "unpredictable" is a more common term here
But, that being said, I am pretty sure I cannot realize what I am trying to do if it works the way it currently does. And that seems also a little strange.
Yes, that is probably correct.
Physics behave in a certain way in reality, and users will expect it to be the same in a game, unless the physics are very clearly weird
You cannot predict the behavior from the physics setup. But you can predict it if you're seen it before in the exact same configuration, which makes it deterministic.
Yes. For me they are clearly weird, but again, I think I am strangely representing somewhat of an edge case, I think.
Tbf real life physics isn't necessarily perfectly deterministic either, so perhaps being indeterministic is more realistic 
Pretty sure real life is deterministic, but good luck putting everything back in the exact same state down to a quantum mechanics level 
Yeah, but can I redescribe the breakout-case? Where that doesn't really work? Which makes tesselation not really work either.
Yeah for Newtonian physics it might be deterministic but at the quantum level I'm not so sure
(to be clear this was sarcastic)
A better sarcastic comment would've been "If unity can get away with not being deterministic, maybe that's the more normal approach" ๐
and Unreal I believe
I think we can agree that for my game there is a lot of CPU power for solving this specific thing. And I would just like to have that as an option.
Unity doesn't have this issue as far as I can tell.
Yeah it uses Box2D for 2D which uses sequential impulses
OKok.
Which doesn't have the issue of positional corrections mid-solve
Yeah, exactly, that makes sense. That describes it perfectly.
Didn't you experiment with that for xpbd too?
yeah
I have no clue what "sequential impulses" actually are tho ๐
it's weird saying "sequential impulses for xpbd" lol
I have this mental model where it is the difference between accumulating the impulses and averaging them before applying them, versus applying them in sequence.
it's mostly just accumulating impulses iteratively until you converge on a solution
Because xpbd solves using positions rather than impulses?
Because XPBD is a separate, position-based simulation method, so it's like saying "Use ham for juice"; both are edible but very different and rather incompatible
okay that was a horrible analogy lol
eXtended Sequential Impulse Based Dynamics, XSIBD. No more NVIDIA patent trolling 
hold A+W or W+D entire time
R to restart
Yes, but this level is running on the old WASM.
This is before I made it run with fixed physics.
what's the new one?
I haven't really made a version of this yet. I can make it quickly, I think. But honestly, I am shooting a lot from the hip here. Because it didn't run deterministically before (even running differently on different Hz on different monitors), I have been messing around a lot with different settings. But I think there is a version that is running on the fixed schedule now, but I haven't pushed it there yet.
Ah yes, variable deltas, the true nemesis of determinism
This certainly isn't deterministic at all. But let me try to push a version of it where I learned a lot with the fixed update stuff.
I think we already had a round about this where the timestep was shared and made consistent. But I don't think I updated that URL in particular.
a lil.
Restitution and dynamic friction are tricky here, since the way it's currently calculated depends on the current velocity, and if we accumulate the impulses caused by restitution, it'll just apply a huge impulse
either way it was kind of an edge case, the bigger problem is ghost collisions that probably can't even be resolved, and the hopefully resolved problem with A+W/W+D level
Yeah this is this issue: https://github.com/Jondolf/bevy_xpbd/issues/224
ah right. sorry, should probably check the issues before posting here
what does prediction distance do anyway? is it some sort of narrow phase optomization?
Currently, the solver applies positional corrections one by one instead of accumulating them and applying them all at once at the end. This means that the bodies can move relative to each other mid-solve, sometimes going into newly penetrating states.
If the collider sizes were exact, this could lead to missed collisions since collision detection is run before the solver (and therefore can't detect the mid-solve penetrations). To account for this, we use the prediction distance to accept collisions that are not necessarily penetrating yet, but close. If they end up penetrating during the solver, the collision is handled, otherwise it's skipped
ah ok I see
The issue here is that collision events and similar APIs currently also count the non-penetrating collisions, which is weird and unexpected from the user's point of view
In your case your game's scale isn't the default scale, so the prediction distance is way too big
You can probably make it like a tenth of what it is by default
or even less
but yeah collision events firing for non-penetrating collisions is a bug that I'd like to fix at some point when I have time
I'm just curious, is there plans to get rid of prediction distance by accumulating positional corrections and applying them at the same time? or is it better that it works the way it does now?
With XPBD, the current approach (Gauss-Seidel solver) has better convergence than accumulating (Jacobi solver), so things are more stable with less iterations required
but Jacobi has some benefits too
like potentially nicer parallelism and constraint order independence
ah okay
didn't realize there were such pre existing algorithms to collision solving
If we used impulse-based dynamics, which is much more common than XPBD, I don't think this would be an issue to begin with since the solver operates on velocities instead of positions
but everything has tradeoffs
right right. I don't know much about how xpbd works but from the limited knowledge I have it seems kind of like it's a similar difference between euler integration vs vertlet integration for motion, just taken to a whole new level
Kinda yeah
(if we're going to integrators though, Euler splits into three core types: explicit, semi-implicit/symplectic, and implicit. Explicit has issues with systems just gaining energy, and implicit is too expensive, so almost all engines, including bevy_xpbd, use semi-implicit)
I'm seeing a pretty significant performance hit (~90fps difference) when I chunk a large terrain made up of polyline colliders. Is there a way to optimize this further? I'm chunking so re-computing the polylines on the fly isn't too costly.
As in less performance with chunks, or less performance when it's one big chunk?
It's less performant with more chunks -- so it goes from 2 polylines to probably around 50.
If they're not static rigid bodies they could collide with eachother ... And maybe collisions at the edges could makes sense ... Other than that it sounds kind of weird tho ๐ค
Each chunk is a child of one static rigidbody
Well it's two levels deep: Map -> MapChunk -> PolylineCollider
Oh very interesting -- I just made each PolylineCollider it's own static rigidbody instead and we're back at 120fps.
So it looks like the slowdown comes from the hierarchy.
Hmmm ... Maybe it doesn't consider them child colliders properly, or maybe the check in the broadphase doesn't account for this edge case ๐ค
I'm just trying out different parts of the bevy ecosystem, and I'm seeing a lot of instability with a simple chain pendulum of capsules connected by spherical joints. They aren't clipping at all on spawn, and there is space between the colliders, so I'm not sure what is giving the system so much trouble. Attached is a video of the one time it didn't immediately explode on load, and it is still acting quite odd.
Mine isn't quite a pendulum, but I'm not seeing any stability issues
How are your joint anchors set up?
Let me copy out the relevant parts to recreate this; it's a bunch of kitbashed tutorials together just trying stuff out so most of the code is irrelevant.
creating the chain: ```rust
fn spawn_capsule(
commands: &mut Commands,
transform: Transform,
radius: f32,
depth: f32,
meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
) -> Entity {
commands
.spawn(PbrBundle {
mesh: meshes.add(
shape::Capsule {
radius,
depth,
..default()
}
.into(),
),
material: materials.add(Color::rgb_u8(124, 144, 255).into()),
..default()
})
.insert(TransformBundle::from_transform(transform))
.insert(RigidBody::Dynamic)
.insert(Collider::capsule(depth, radius))
.insert(Restitution::new(0.2))
.id()
}
fn spawn_capsule_chain(
commands: &mut Commands,
transform: Transform,
links: i32,
radius: f32,
depth: f32,
gap: f32,
meshes: &mut ResMut<Assets<Mesh>>,
materials: &mut ResMut<Assets<StandardMaterial>>,
) -> Entity {
let length = radius * 2.0 + depth + gap;
let first = spawn_capsule(commands, transform, radius, depth, meshes, materials);
let mut last = first;
for i in 1..links {
let offset = transform.translation + Vec3::new(0.0, -length * i as f32, 0.0);
let new = spawn_capsule(
commands,
transform.with_translation(offset),
radius,
depth,
meshes,
materials,
);
let anchor = Vec3::new(0., length / 2., 0.);
let joint = SphericalJoint::new(last, new)
.with_local_anchor_1(-anchor)
.with_local_anchor_2(anchor);
commands.spawn(joint);
last = new;
}
first
}```
setting up the swing point / chain: ```rust
let swing_point_height = 5.;
let swing_point_loc = Transform::from_xyz(0.0, swing_point_height, 0.0);
let swing_arm_length = 2.0;
let swing_point = commands
.spawn(RigidBody::Kinematic)
.insert(Collider::ball(0.2))
.insert(Swing)
.insert(TransformBundle::from(swing_point_loc))
.id();
let depth = 0.7;
let radius = 0.15;
let gap = 0.2;
let chain_height = radius * 2. + depth + gap;
let chain = spawn_capsule_chain(
&mut commands,
Transform::from_xyz(
0.0,
swing_point_height - swing_arm_length - chain_height / 2.0,
0.0,
),
2,
radius,
depth,
gap,
&mut meshes,
&mut materials,
);
let joint = SphericalJoint::new(swing_point, chain)
.with_local_anchor_1(Vec3::new(0., -swing_arm_length, 0.))
.with_local_anchor_2(Vec3::new(0., chain_height / 2., 0.));
commands.spawn(joint);```
swing system: rust fn swing(time: Res<Time>, mut query: Query<&mut Transform, With<Swing>>) { for mut sw in query.iter_mut() { *sw = sw.with_rotation(Quat::from_rotation_x( f32::sin(time.elapsed_seconds() * 2.) * 1.3, )); } }
It's not the exact same setup as the video (that was lost to me just experimenting with other stuff), but it has the same issues.
Thanks, I'll try to see what the issue is tomorrow if that's fine, it's quite late for me here
There's no rush, I'm just messing around at the moment seeing what's available.
looks like a really cool project. are you using a noise filed and marching cubes to generate terrain?
Thanks! I haven't got to map generation yet, that's just an uploaded image. But I do plan on doing some sort of noise-based generation. The main issue I'm trying to solve right now is performant destructible terrain. I want the contour to be perfectly aligned to the outside of the pixels, which means I can't use a lot of the existing contour algorithms since they all use the center of pixels.
can someone help me figure out how to rotate the player towards the direction they're moving in ? ๐
im using the code example in kinematic_character_3d
@vestal minnow It's kind of hard to keep up with all the changes I need to make to keep my sdf collisions working (gizmos are broken, I never fixed child colliders, I'm missing a few fixes from the narrow phase, etc) ... Could we create something like a collider trait, and a plugin that adds all systems to make that trait work? Maybe also some example of a custom collider type, something simple like the OnlySpheresCollider ๐
Using Bevy XPBD 2D:
I am struggling to find out how to make 2 bodies have a limited angle of rotation around their revolute joint axis,
angle_limit with angle_limit_lagrange set to non nil doesn't seem to have an effect
Maybe the unit of the angle is wrong? Doesn't look like the docs say what unit the angle should be tho ๐ค
Radians sounds the most likely at least
I tried with them and it didn't seem like I had a result
I am quite confused, does it have yet to be implemented?
I didn't get translation lock to work neither ๐ญ
I think something like that might be doable... We could add a collider trait and make the systems and plugins generic, and add some higher level plugin for collision detection
It could be something like a CollisionPlugin that takes a generic collider and adds the sub-plugins like BroadPhasePlugin, NarrowPhasePlugin and ContactReportingPlugin for that collider type. It would also make things clearer for users, since e.g. "broad phase" and "narrow phase" might be unfamiliar for many
Custom colliders are a rather niche use case, but I think it's still a cool thing to support, and it'd also be useful for the potential "dimension unification" if we added e.g. separate Collider2d/Collider3d components
(also can we nest plugin groups?)
found a solution for this, for anyone facing the same problem:
let rotation_angle = if direction.length() > 0.0 {
direction.x.atan2(direction.y)
} else {
0.0
};
transform.rotation = Quat::from_rotation_y(-rotation_angle as f32);
Separate dimension colliders sounds like it could offer some nice UX. I also think it could be very useful for benchmarks (especially that OnlySpheresCollider example). And ofc there's always the possibility you'll work on bevy_peck later, after you inevitably hit the limits of barry ๐
We're silently just building bevy_peck in Bevy... shapes and bounding volumes added already, and who knows, maybe support maps soon
all that would be left for basic collisions is GJK and EPA, and some mass property stuff lol
Having mass properties for primitives would be nice ... Then I don't have to hack around not having them for my SDFs ๐
Maybe from_primitive should be a part of the collider trait ๐
Then it'd force you to implement all the primitives for your collider type
Or just panic with unimplemented! lol
Can't wait for the
match primitive {
Primitive::Sphere(v) => Sphere(v),
_ => todo!()
}
I think I will still work on bevy_peck too... Barry is very nice to get a more "native" alternative quickly, but a separate and more custom-built solution could be very valuable as well
Main benefit to working on barry first is you can fix some of the low hanging fruit while also seeing how things currently work under the hood
At that point having it as a fallback for all the missing stuff of bevy_peck wouldn't have as many flaws anymore
Yep
Anyway if you want I could try to implement this collision trait, I'd just need to know what kind of interface it would need ... I think some stuff in bevy_xpbd's collision module isn't even used anymore either after some changes to the narrow phase ๐ค
Making the colliders generic in bevy_xpbd could also ease the transition 
If people had issues with e.g. bevy_peck, they could swap the colliders out with the old ones
It could even help with the transition from parry to barry 
Especially if we added a feature to make parry/barry optional (you'd probably like that)
And then hide both of them behind a feature flag so you can save 10s compile time for the ultimate sphere game
I started early testing for this already
I think just this might be almost enough for collisions specifically
pub trait AnyCollider: Component {
type Position;
type Rotation;
fn mass_properties(&self, density: f32) -> ColliderMassProperties;
fn contact_manifolds(
other: Self,
position1: Self::Position,
rotation1: Self::Rotation,
position2: Self::Position,
rotation2: Self::Rotation,
) -> Vec<ContactManifold>;
}
WIP tho, haven't checked everything yet
You also need a method to get the aabbs
yeah that too ofc
But yea, mass, contacts and aabbs are about all I have right now, so I'd imagine that alone should be enough
There used to be a check for collisions and then getting the manifolds but that seems to have changed already
What check?
I think the code went something like "Did they collide? Oh great, what are the manifolds"
Even if it was necessary for a specific implementation it could still just pass Vec::new() as result tho ๐
I don't think I remember a separate check like that tbh
It was quite a while back at least ... I was looking at main earlier because it didn't work correctly with my sdf collisions and the narrow phase looks a lot different now ... Collision pair reuse also wasn't commented anymore iirc
Still no solution for the Vec of Vec nightmare that is ContactManifolds and ContactData tho 
yeah there was a PR that fixed a bug in a kinda hacky way and refactored stuff a bit... I should probably make a follow-up to find a better approach for the hack
I should probably just add a collision.contacts() iterator to make the API nicer at least
by making a flattened iterator
I like how I just create it like this too
ContactManifold {
normal1: m.normal1,
normal2: m.normal2,
contacts: vec![ContactData {
point1: m.point1,
point2: m.point2,
normal1: m.normal1,
normal2: m.normal2,
penetration: m.penetration,
}],
}
I still don't get how things don't explode with my sdf collisions ๐
Tho I do have this cool bug that has been popping up more often recently where I get stuck in walls ... Pretty sure some code somewhere is multiplying normals by the distance's sign, which it should not (unless it wants to kno where the surface is)
Well at least my floating code causes explosions ... I really should convert that to be some kind of constraint, that way I can apply a smaller force 6 times instead of messing with something that has so much force it can throw the player 1000 meters into the air ๐
I think generic colliders for spatial queries might require changes to Parry
Time for Barry :)
I think we could make a separate trait for that too
That way we can create a bevy_xpbd_plocbvh crate ๐
Maybe it doesn't even really need a trait ... Having different APIs for different spatial query pipelines might be reasonable ๐ค
Raycasting we can do, but shapecasting and some other queries take composite shapes that we can't nicely abstract away with traits
with Parry at least
There are no shapecasts, only spherecasts ๐
I guess in parry it doesn't make as much of a performance difference to use a sphere vs another shape
Okay I think I have the basics for generic colliders through a CollisionPlugin working now...
Next I need to do stuff like child colliders and make the OnlySpheresCollider example
I might have a PR ready tomorrow maybe
Damn that's some high level collision trait speedrunning right there ๐
There's other things I should probably be doing but this is more fun lol
Gizmos might not be very doable via traits... could probably use primitives tho
Like have some .to_primitive() method that returns and enum, and pattern match that
although we don't have primitives for all shapes... could still add them to the enum separately
Yea I think that would be fine
Atm I don't have gizmos either
I used to have AABBs working at least but they broke for some reason 
@cinder summit Do your colliders support scaling?
I'll probably add scale and set_scale methods to the trait to support scaling via Transform, but I'm not sure if it should be on the same trait or on a separate trait like ScalableCollider
I made a draft PR for the generic collider stuff already in case you want to try it; it's WIP though, and I'll probably end up splitting the CollisionPlugin and generic colliders into separate PRs
https://github.com/Jondolf/bevy_xpbd/pull/302
You'd just need to implement AnyCollider for your collider and replace CollisionPlugin<Collider> and PreparePlugin<Collider> with your collider's versions
though I think ideally the PreparePlugin wouldn't handle colliders and it'd be done by something else
No, but I might add that later if it's relevant ... Tho with sdf colliders you do have the small detail that you can't do non-uniform scaling ๐ค
I have some questions regarding Bevy's physics:
-
How do you effectively limit the angle of rotation with a revolute joint, I tried setting
angle_limitbut no effect -
How do you lock the translation of an entity run-time, I tried changing the
LockedAxescomponent but no effect
Am I getting something wrong ๐ญ
I think LockedAxes should work, are you working with dynamic rigid bodies and just looking at physics interactions? (rather than direct mutations to transform/position/rotation)
Yes I am
I am working with dynamic rigid bodies specifically
I never touch the translation / rotation directly
I know it can cause unexpected behavoiur
Why not? It seems like applying a linear transformation to an SDF should be straightforward.
With polyhedra, it's just applying the transform to each vertex and the inverse transpose to each face normal.
If you do a non-uniform scale, the distances won't be correct anymore. The distance could measure geometry that is no longer the closest
In many cases you could make a new non-uniformly scaled SDF, but an ellipsoid for example is 30x more code than a sphere
You can probably transform the other direction, e.g. converting a ray into the SDF's local space. That's what I do in some cases.
That way a sphere remains a sphere.
There would be no way around it for two (relatively) sheared SDFs, though.
Yea, it would be doable for raycasts, but not any type of collision
- Angle limits should work, e.g. see the
revolute_joint_{2d/3d}example. The angles are in radians, and should be in the [-pi, pi] range. How are you setting the angle limits? LockedAxesshould also work (I tested). Are you adding it at spawn or just trying to change it in a system? It's not added automatically, so make sure you add it somewhere
Thank you for the reply, I'll try to answer asap (currently busy)
Currently in the middle of migrating from rapier2d to xbpd2d and I've come across this issue that my KinematicBody does not move smoothly. Is this a common issue? I cannot find why this happens for me
nevermind, I just implemented my camera follow system incorrectly ๐
Can you say more? I'm playing with a few approaches to follow cam and definitely have one or two that stutter so obviously won't work but nothing I love yet
Idk if this is what they used, but here's the general solution to camera jitter
https://github.com/Jondolf/bevy_xpbd/issues/211#issuecomment-1789342920
Ah, much better
- So I figure this was radiant for the angle limit, do I need to set something for it to effectively work? I can't find the example (unless you meant the doc ?)
- I did add a LockedAxis on spawn, that was mandatory too for it to compile, but I am still not getting any result :/
Is there some VHACD settings that will always create the closest possible convex decomposition? With the config I'm using I keep getting results like this. (white is the original shape, orange is the decomposed hulls). I tried doubling the resolution and it doesn't seemed to have helped at all
I really just want an exact convex decomposition. maybe implementing my own algorithm might be better? it seems like VHACD is slow for calculating exact decompositions
Maybe set convex_hull_approximation to false? Or increase downsampling values? I'm not familiar with how VHACD works, it's a Parry feature
I don't think it can give exact decompositions in all cases though
I think the ACD even stands for "Approximate Convex Decomposition"
Yeah it definitely seems like it's designed specifically for approximating high detail concave polygons into approximations of convex polygons. What I want is the opposite lol, just decompose relatively low detail concave polygons into exact convex hulls. It's being used as terrain collision data for levels
I think you might want polygon triangulation; you could then make a convex hull for each triangle
some approaches include earcutting and Delauney triangulation, there are some crates for those
I think Parry might also have them implemented to some extent
collider::trimesh?
it looks like I have to calculate the tris myself for that ๐ฆ
probably still easier than convex decomposition lol
yeah, with polygon triangulation
ya
it's not built-in atm
ohh
earcutr is decent although the API is a bit weird
https://github.com/frewsxcv/earcutr
well, I'm not sure if this is a you, or a parry2d question, but if I decide to go that route, would the physics engine have any issues with long thin triangles for collision detection or collision resolution? It looks like there are a few different algorithms where some more complex ones avoid such thin long tris
I'm not sure, but I think long thin triangles should be fine assuming they're not unreasonably long
like thousands / tens of thousands of units long
probably
you could maybe also make a compound collider that consists of many convex hulls instead of having a single trimesh
I think that might be what the result of convex decomposition is
just checked, yes it is
https://docs.rs/parry2d/latest/src/parry2d/shape/shared_shape.rs.html#224
Source of the Rust file src/shape/shared_shape.rs.
it decomposes the polygon with VHACD, adds the parts to a vec, and makes a compound shape from that
Sweet, thanks for all the info man! I'll probably use ear clipping and a compound shape like that
Quick question regarding collisions, does Kinematic not interact with Static bodies? That's what I'm observing, and the docs seem to point to it, but the wording confused me a bit. Also it's not what I expected, hence my doubts. If so, are you meant to handle Kinematic - Static collisions on your own?
Edit: the actual question I guess is, are collisions reported but the kinematic body retains its velocities, you need to change them yourself?
I think the collisions get detected, but kinematic bodies don't get affected by outside forces, so they can move trough static bodies. If you want it to have normal physics behavior you'd need dynamic rigid bodies
Hello
yo
So Translation Locked also works when it's constrained by a joint?
Does anyone know if there is a way to do a one-off raycast? I get a Ray returned from Camera.raycast_to_world, and I'm wondering if I need an entity with a RayCaster, and to set its origin/direction to the same as the ray, or if I can just do a one-off raycast via bevy_xpbd : O
You can use the SpatialQuery system param and call cast_ray (closest hit) or ray_hits (many hits)
https://docs.rs/bevy_xpbd_3d/0.3.3/bevy_xpbd_3d/plugins/spatial_query/struct.SpatialQuery.html#method.cast_ray
A system parameter for performing spatial queries.
It should work, yeah
Great :)
working for me at least
If I wanted to get the point on a collider which is closest to the specified target point, I would want to use collider.shape.project_point, right?
Yep
sweet now I gotta figure out how to work with nalgebra ๐จ ๐คฃ
I should really add a method to Collider
I guess probably project_point_local will be easier then I can at least use bevy transforms
FYI I made a PR to add this and other similar methods to Collider, thanks for reminding me I needed to do this :P
https://github.com/Jondolf/bevy_xpbd/pull/307
dang that was fast
wait is that repo for both 2d and 3d crates?
I thought they each had their own repo for some raisin
2D and 3D are under the same repo and source code, they just use different feature flags
same as Rapier
most code can be shared between dimensions
the dimension-specific code is just behind clauses like #[cfg(feature = "2d")]
makes sense
is the CenterOfMass component automatically calculated/added to rigid bodies?
yes
probably only for dynamic ones though, right?
Currently for all types of rigid bodies, but I might change it so that kinematic and static bodies don't have mass props since they don't really need them
well currently it works to my benefit ๐ I need to know center of mass for large static bodies because for calculating dynamic gravity attraction
If I removed mass props from static and kinematic bodies, you could probably still get them with collider.mass_properties()
it just wouldn't take child colliders into account
(since it's for a single collider)
Hmm, in theory I could maybe add some system param that queries the hierarchy and gets the "true" mass props for an entity
I actually don't need mass properties, since I'm just using a simplified dynamic gravity attractor component which allows you to just manually set the gravity pull and falloff and other such properties. It's not realistic but I imagine it will make it easier for level editing
still need the center of mass though to know where the attraction should pull toward
well I just realized I don't even need the center of mass either actually ๐คฆ
since it's more like super mario galaxy physics I'm not actually attracting toward the center of mass, I'm attracting toward the nearest point on the collider
but you'll still need a bigger trigger zone
could also iterate through all attractors in range but i have a hunch that in this case it'll be a bug attractor too
and sending ray down to get surface normal is probably too rigid for SMG physics
i had the ray down gravity system in unity but it didn't feel ideal. either way @ me if you come up with something interesting, i still want to add it in bevy eventually
I've got most of the dynamic gravity module functionality in already, check it here if you're interested
https://gitlab.com/Technostalgic/bevy_platshooter/-/blob/master/src/core/physics/dynamic_gravity.rs?ref_type=heads#L52
none of it involves raycasting at all, but that might be because my case is simpler than most people's probably, since it's in 2d rather than 3d
ah. yeah, i'm doing it in 3d
what i wanted is closer to psychonauts milkman conspiracy level than SMG anyway
i think in 2d SDF could work better
@cinder summit
basically I iterate over every "gravitational body" and do a spatial query against all the "dynamic gravity entities". the gravitational bodies have 3 simple properties, the max_gravity, falloff, and falloff extension, so I can calculate an aabb around the gravitational body's center of mass pretty easily with just that
I thought about sdfs, but then I decided against it because I didn't want to implement that functionality into my level editor ๐
why?
probably a dumb reason but I'm super tired of working on my level editor
it seems like the perfect use case for it though
I just got it to a usable state a couple weeks ago and I'm not looking forward to working on it again
sdfs? not for mine. the basis of my level editor works on polygonal geometry
so it doesn't seem like sdfs would fit in very well
doing geometric calculations on 2d sdfs is way different then doing them on 2d polygon meshes
integration with the physics engine I imagine would be a nightmare (for spatial querying)
nise is working on that from what i understand
interesting, might have to check that out
#showcase message
but the core of the gravity vector calculation works pretty simply and I think it could be translated to 3d fairly easily too. Basically you just get the closest point (to the player, or whatever other physics object) on the collider of the gravitational body (i call this the attraction_target). then you just find the difference between the player and the attraction_target and that vector points in the direction that you want gravity to be. and the magnitude of that difference vector is basically the distance from the gravity body, which you can calculate the strength of the gravity from pretty easily. I'm just using linear falloff for simplicity, so it's basically (difference.distance / max_distance) * max_gravity
you're not doing anything to allow one-sided gravity?
no, not right now. probably will need it in the future though
that's the main reason i went with ray in the first place
i figured i can just use dash to slam into another gravity surface
hadn't considered that before ๐ค I'm not sure how one sided gravity might become an issue though. Hopefully I can cross that bridge when I get to it ๐
e.g. you're making a hole in the planet, you need to make sure that you don't get attracted to the planet from below/inside, or to the walls
ah I see. so like you'd probably want to keep the same gravity all the way throughout the hole?
until you come out the other end
if you use center of planet then it's not an issue, but then there's an issue with anything that isn't just a basic shape
off the top of my head, I'd probably implement a trigger collider that the main gravitational body references. When you touch the trigger the current player gravity does not change until it stops touching the trigger. probably would have some implementation issues though
yeah, it screams bugs later on
what i did is just separate collider meshes into layers that make sense
there are bugs either way though
Collider meshes into layers? not sure I get what you mean
separate collision layers?
e.g. when you're on convex slope that changes gravity, if you stop then you start jittering because switching to new gravity changes ray enough to fall on previous face
can also be on the edge
you jitter between falling and on slope
it's fixed fairly easily by storing previous value though
ahh I see what you mean
you know what's really stupid is I've never even played super mario galaxy
me neither
lol
there was just 1 video that took apart its' gravity
i think this one?
https://youtu.be/QLH_0T_xv3I
Let's find out how Super Mario Galaxy's gravity and physics engine broke all the rules, and changed the Mario series forever.
๐ฆ https://twitter.com/JasperRLZ
๐ฐ https://patreon.com/JasperRLZ
๐คผ https://discord.gg/bkJmKKv
๐ https://noclip.website
๐ฐ Thomas Grip - Planning: The Core Reason why Gameplay Feels Good ( https://frictionalgames.com/2017-...
haha yeah I just searched for that and found it when you said that
tbh it looks like they used a bunch of different methods
so i guess thinking about it as fields could work too
but tbh it looks like SDF to me ๐
yeah I wouldn't be surprised if they did
oh yeah there we go...
this one is the case where just using ray makes sense though, just make inside mesh as gravity-changing...
i really need to play this thing...
lol same
so whan you say sdfs you really mean a vector field right?
cuz I don't really understand how you could infer direction from an sdf unless you sampled multiple points
oh okay they explain how it works at 12 min
Yea that's one major limitation to using sdfs. For many primitives you can instead calculate the gradient at most arbitrary points. That's how I get the normals for my sdf collisions
You can also sample a few points to estimate a gradient, that's slower and less precise tho
is it generally recommended to put the PhysicsPlugin in to FixedUpdate (PhysicsPlugins::new(FixedUpdate)) and all of my systems too?
for example my character movement that is physics based?
currently i just added the physics plugin in with its default, which is PostUpdate. and all my systems run in Update.
For anything more serious than a jam game it's probably the best option ... FixedUpdate is a bit annoying to work with atm, but I think some more improvements are coming in 0.13 ... At some point I'd imagine having it in FixedUpdate would become the default (with some games overwriting that with for example a game server)
great, thank you!
as both the plugin and my systems will run in FixedUpdate, do i need to make sure that my systems run in a specific order? before/after some xpbd systems? (i'm not asking about my own system ordering, but relative to other xpbd systems... if that makes sense)
Yea, before PhysicsSet::Prepare or after PhysicsSet::Sync, depending on if you want it to run before or after physics
me adding to the linear velocity so that the character moves makes probably sense to run before physics?
Yea, most things that actually affect physics would go before physics
great, thank you!
@vestal minnow https://github.com/Jondolf/bevy_xpbd/blob/main/src/plugins/debug/mod.rs#L280
This line probably shouldn't have the With<Collider>, and also is there any way to see the normals of the contacts?
I'll remove the With<Collider>. The contact rendering is a bit scuffed currently and only renders contact points, but you could make a copy of that system that also renders normals
I might just do that now actually
although I'm not sure if it should also show the penetration depth by changing e.g. the normal arrow length
A penetration depth of 0 isn't too uncommon tho ๐ค
yeah, could have a minimum length or something
Also I'm trying to debug some issues where I get stuck in colliders, but now I'm just realizing I don't even know what expected manifolds on the inside of solid colliders would be ๐
This sure doesn't look correct at least ๐ค
my arrow gizmo code is disgusting
let back = Vector::NEG_Z;
let up = dir.try_normalize().unwrap_or(Vector::Y);
let right = up
.cross(back)
.try_normalize()
.unwrap_or_else(|| up.any_orthonormal_vector());
let up = back.cross(right);
let q = Quaternion::from_mat3(&Matrix3::from_cols(right, up, back));
self.draw_collider(
&Collider::cone(head_length, head_width * 0.5),
&Position(b - dir * head_length * 0.5),
&Rotation(q),
color,
);
renders a cone collider for the tip ๐ also doesn't use Quat::from_rotation_arc
it's also just wrong in some cases
luckily 0.13 has arrow gizmos
and support for multiple gizmo configs... I can finally do physics gizmo configuration nicely
I guess the correct point would be the one with the highest penetration depth, so in this case the opposite side?
Maybe? Not sure what the expected result is for this kind of edge case
would make sense tho
I don't think this by itself is the main problem tho, this only goes wrong after you're already halfway into the wall ๐
Should it render the contact normal both ways or just one of them?
since they're just opposites
in global space
If I render just one normal, it might look weird/inconsistent in some cases
like is the normal pointing towards the wall or the player
it depends on the order of the entities in the contact (which currently depends on the position along the X axis because sweep and prune)
also ignore the box jittering
Both, because it helps with debugging when they aren't opposites
Like in my example ... Where they do this
Well even if it worked correctly they wouldn't overlap, like this
Whats up with that anyway?
Nice, it works ... And now I can see that my guess on what was going wrong was correct
merged and deleted branch so you probably want to switch back to main if you were using the PR branch
I use a local repo because something after 0.3.2 broke my sdf collisions ๐
I need to finish that generic collider thing
my main issues are that I don't really want to add collider generics to the PreparePlugin or SyncPlugin, so I might want some ColliderBackendPlugin or similar that handles that stuff
and adding a high-level CollisionPlugin also isn't ideal because then disabling e.g. the BroadPhasePlugin would be more annoying
it'd require nested plugin groups which aren't a thing
I'd basically like to have this
PhysicsPlugins (plugin group)
CollisionPlugins (plugin group)
BroadPhasePlugin (plugin)
NarrowPhasePlugin (plugin)
ContactReportingPlugin (plugin)
...other physics plugins
but keep the ability to disable individual collision plugins without needing to disable the entire CollisionPlugin and add the desired sub-plugins manually
but also support disabling all collision plugins at once by just removing CollisionPlugins/CollisionPlugin
For now I'll probably just ignore the idea of a high-level collision plugin and have a generic BroadPhasePlugin, NarrowPhasePlugin and ColliderBackendPlugin
That should be good enough for the generic collider use case until there's a nicer way of managing plugin hierarchies or dependencies
Isn't the broadphase plugin already kind of generic besides updating the AABBs?
yes, updating the AABBs is the only thing IIRC
I could probably move that to the ColliderBackendPlugin
I'm working on it rn
*or in a few minutes
I like the ColliderBackendPlugin idea in that the PreparePlugin and SyncPlugin will no longer need to be aware of colliders
so "rigid body logic" and "collider logic" will be more separate and work independently
@cinder summit The collider backend plugin file is 790 lines lol, I can see why that could be a pain to maintain as 3rd party
not even counting the narrow phase stuff you probably needed to copy
this yeets like half of the prepare plugin file which is nice
and a large chunk of the sync plugin
I'll make the sphere collision backend example thingy and then make a new PR
We could add support for Rapier's colliders ๐
although it'd be basically the same as our current colliders
Has anyone else been flooded with buffer-related log output when they enable PhysicsDebugPlugin::default()? Seeing tons of:
INFO Created buffer Valid((13, 599, Metal)) with BufferDescriptor { label: Some("LineGizmo Color Buffer"), size: 143280, usage: BufferUsages(VERTEX), mapped_at_creation: true }
INFO Created buffer Valid((14, 599, Metal)) with BufferDescriptor { label: Some("LineGizmo Position Buffer"), size: 23880, usage: BufferUsages(VERTEX), mapped_at_creation: true }
Likely a misconfiguration on my end since it's only happening in one of my projects, but if anyone's encountered this I wouldn't mind a lead ๐
Hmmm, it might be one of those things that gets filtered in my app ... What crate is the message from?
@cinder summit I seem to have all of the generic collider stuff working reliably now (haven't tested child colliders yet tho)
Adding a custom backend is very straightforward, just add a couple of plugins:
.add_plugins((
DefaultPlugins,
PhysicsPlugins::default(),
ColliderBackendPlugin::<CircleCollider>::default(),
NarrowPhasePlugin::<CircleCollider>::default(),
))
I believe you can have any number of different collider types at the same time without significant overhead, so you don't even have to disable the existing Collider-based plugins
I'll finish up the example and then finally make a PR
haven't tested child colliders yet tho
Time to create a hierarchy of spheres
I probably will lol
the orbit thing isn't an ideal example, but I'm not sure how else I should make circles collide more than once...
can't really have a ground plane unless I implement collisions against that too
I could make the ground a massive sphere ๐ค
that's what my current example is
this but with collisions
#off-topic message
the center is an attractor
I could make the attractor follow the mouse ๐ค that could be cool
could also hit the particles with it
Hey, I don't know much about bevy reflection but am getting this error when adding colliders / rigid bodies within an asset loader. Is this something that can be fixed either in my code or the library?
scene contains the unregistered type `bevy_xpbd_3d::components::collider::Collider`. consider reflecting it with `#[derive(Reflect)]` and registering the type using `app.register_type::<T>()`
I don't think we can reflect colliders yet because they could have recursion if they are compound colliders (a collider shape that contains other collider shapes). Reflection doesn't support it iirc
hmm... after this generic collider thing, maybe we could technically split it into separate Collider and CompoundCollider components without significant overhead
then at least Collider could be reflected
but might not be as nice API-wise I guess, not sure
you can create compound colliders through parenting right? I didnt realize there was an additional compound collider type
Yes parenting works, but compound colliders are also a thing. I believe it's required for colliders created using convex decomposition since they consist of several convex hulls
creating a separate entity for each convex hull would probably be unnecessarily expensive and a pain to deal with
I was thinking more like everything collides into one large center sphere, and a few things are made up of multiple spheres
yeah that could work
right now I have this
which is fine, could add some particles that are clusters though
this feels like a separate orbit example and not custom_collider though
It would be interesting if you could switch between regular and custom colliders
Ideally see if it has any FPS impact too (it should probably be a lot faster than parry)
The biggest problem I see with this (in my case, where a shape can have thousands of convex hulls) is that an entity per hull would prevent any parallel algorithm over those hulls.
This is a problem I also have with my physics solver (which does use Bevy ECS), preventing the solver from running each island in parallel.
It can't be worked around by using Query::get_unchecked, because I need multiple parallel queries. Maybe an exclusive system using UnsafeWorldCells would work.
Not exactly that, but I have something like this now
The red things are child colliders of the center thing
And use transform scale to make sure that works
There's just another determinism issue where the initial touch is explosive on some runs but not on others ๐ฅฒ
That's a pretty cool example ๐
