#Avian Physics
1 messages Β· Page 28 of 1
Not really, other than toggling PhysicsPickingSettings::require_markers if you're not using PhysicsPickable for any entity (since for them, picking would be enabled regardless)
The picking backend was largely made to match Bevy's MeshPickingPlugin, which doesn't support toggling picking at runtime either. I would merge a PR adding an enabled property for PhysicsPickingSettings though
Got it, thanks for the info!
I'll look into this when I have time, though I am confused why this would be happening. The broad phase should already be filtering out collisions between static or sleeping entities
y'all, does anyone know how to use bevy 0.15 picking with avian? I'm looking for examples but can't find any. Just the docs saying to add a plugin, but no complete example https://docs.rs/avian2d/latest/avian2d/picking/index.html
well the bevy_picking is fairly straight forward just looking at the official docs and examples cover everything you'd probably need?
https://docs.rs/bevy_picking/latest/bevy_picking/
https://bevyengine.org/examples/picking/simple-picking/
https://bevyengine.org/examples/picking/mesh-picking/
app.add_observer(|trigger: Trigger<Pointer<Over>>| { println!("{}", trigger.entity()) });
There is an example here too, similar to Bevy's mesh picking example but for colliders
https://github.com/Jondolf/avian/blob/main/crates/avian3d/examples/picking.rs
It's 3D but 2D works the same
The main issue now is that if you're using picking with individual colliders, if they are packed tightly you end up with the collision issue
What do I need to do to enable Collider picking? I enabled the "bevy_picking" feature of bevy and added the PhysicsPickingPlugin, but it doesn't work out of the box. Then I tried setting require_markers and added PhysicsPickable to the camera (which isn't the main/default camera on the default RenderLayer) and added the same component to the entity I want to pick. I already checked the collider of the entity with the PhysicsDebugPlugin, which seems fitting.
I believe the issue stems from having two different scenes in the same world - one for the normal game world and one for the inventory. While the objects in both scenes have different CollisionLayers, the camera used for picking doesn't have a CollisionLayer assigned. This likely means when picking, I'm hitting other large objects (like hills or trees) instead of the intended pick target. Is there a way to filter during picking, similar to how CollisionLayers work?
Hey, say I want to generate a collider for a polygon defined by the lines (Vec2, Vec2) that form it's outershell, what would be the way ? Collider::polyline ?
When I insert an AngularVelocity to an mesh that is a child entity of another entity which has a non-identity rotation. The rotation applied to the mesh seems a bit off, i.e. it is applying the parent rotation as well. How can I apply an AngularVelocity to a child entity only at local level (excluding the parent transform impact)
What are the resources that are used to compute the position/rotation of Colliders? Any resources that might need to be rolled back in time (on top of the collider entities) in the case of a network rollback?
(sorry I think i asked this before already)
I realized that some resources that I was missing that might be important are Time<Physics> and Time<Substeps>
We both asked that on the xpbd -> avian change, there's an issue or something with a list. Iirc for resources it's just making sure it picks up Time<X> correctly and Collisions if you don't disable warm starting. In my rollback code I handle the Time<Physics> thing by swapping Time<()> to Time<Fixed> before rollback, since avian basically just copies the delta from Time<()>
I haven't actually been able to avoid mispredictions at all with sleeping enabled however, since the waking logic uses change detection, and rollback will always trigger change detection
I assume the whole sleeping issue should get fixed once we get simulation islands, tho I'm not 100% sure about that
So the problem is that if you roll back e.g. velocity, it triggers change detection and wakes the body up?
Yea, it's especially noticable if the rollback doesn't even bother checking if the value actually changed before rolling back, since at that point it creates a situation where things never sleep
Because Position, Rotation, LinearVelocity, AngularVelocity, etc all get "changed" every frame
Are rollbacks needed while the body is sleeping? Like can you just not roll back position and velocity etc. for sleeping bodies
In theory once it's sleeping it's fine if the sleep timer is longer than the window used for rollback, the issue is that the timer will get reset constantly and thus go to sleep/wake up at different times compared to the server
Which then manifests in slight differences in collision responses
Right
The delta should always be equal to the fixed-time-step delta anyway no?
However you don't reset in time the actual Time<Physics>.elapsed value, so the time keeps accumulating during rollback, but maybe that's not a problem and only the deltas matter?
Yea, I just had issues with my rollback where I didn't actually specify that time in Time<()>, because all my code pulled it from elsewhere and avian previously had a delta in Time<Physics> too
As for elapsed, I don't do anything with it, I'm not sure avian even uses it π€
I see, yes it's a good call to switch Time<()> to be equal to Time<Fixed> before the rollback
Oh i already did that actually
@vestal minnow Hello curious what is this massive number
That's just f32::MAX
ah i see tought i was doing something wrong
@cinder summit for the Sleeping issue, I guess the ideal solution would be to reset the component value AND its ComponentTicks value so that it gets reset to exactly the same state as it was n frames ago in terms of ChangeDetection. Then if the entity was sleeping n frames ago, sleeping is not triggered even with the rollback
That's not actually ideal tho, then things won't be able to detect that the value did in fact change
You mean in case the component had changed in our prediction, but when you rollback the component did not change at all?
I think that's what we want though, after rolling back the component fundamentally didn't change. The rollback itself shouldn't count as a change, we are just rewriting history
If there's a component or resource that only does something based on changed values, like say updating a spatial index with new Positions, we probably don't want to roll back that entire resource just so this hacky sleeping implementation works tho π€
hmm..
So we have this thing
I've been trying to figure out why the heck it's like that and not just this 
Also the old/current version is doing a lot of math like a + (b - a) like wut
is that bevy code?
My code from July 2023 lol
in Avian
I had some weird reason for doing this in a convoluted way but I don't remember why and it makes no sense at all now
(this also seems to be part of the cause for a lot of the rotation denormalization issues people keep having)
Fundamentally what this appears to be doing is
position.0 += transform.translation - previous_transform.translation;
rotation.0 = previous_transform.rotation.inverse() * transform.rotation * rotation.0;
but with a lot of extra steps lol
I don't understand why I wanted to add the change in transform though, rather than simply setting Position and Rotation to the actual new transform
I think I'll just test a bunch of scenarios with the simpler version and see if it has broken anything :P
If not, I'll make a PR
This commit implies it was for change detection reasons, but... why would it have helped
https://github.com/Jondolf/avian/pull/96/commits/c16a9de598c4330c2743b8af01a550b637c99a59
Sleeping and change detection work fine with the new simpler version π€·ββοΈ I legit have no clue why I originally made it like that, I'm confused
well, PR it is
Would a difference be that your simplification doesnβt retain previous βzβ for 2d? Still I applaud such simplification π
The vecs get truncated to 2D anyway so it shouldn't matter
the z isn't used for anything here in 2D since Position stores a Vec2
Still for graphics conserving Transform z might be useful I imagine ?
I mean yeah graphics should probably be a separate entity but eh
Yes it's still conserved for the visual Transform and GlobalTransform, but this is just updating the Position component used by physics, where the Z coordinate doesn't matter
for 2D
Position and Rotation are like Rapier's internal RigidBodyPosition::position, and are kept in sync with the GlobalTransform used for rendering
components for the physics position must be separate from GlobalTransform, for now at least
Is there something triggering change detection on Collisions every frame?
2025-01-10T23:51:48.392280Z INFO lightyear::client::prediction::resource_history: Resource "avian3d::collision::Collisions" changed, adding to history
2025-01-10T23:51:48.392294Z INFO avian_3d_character::shared: collisions tick=Tick(28) collisions=Some(Res(Collisions({})))
2025-01-10T23:51:48.400536Z INFO lightyear::client::prediction::resource_history: Resource "avian3d::collision::Collisions" changed, adding to history
2025-01-10T23:51:48.400535Z INFO avian_3d_character::shared: collisions tick=Tick(29) collisions=Some(Res(Collisions({})))
Doesn't Collisions just change every frame?
It recomputes collisions so it makes sense it would get triggered π€
I have a really nice solution for this in my rollback crate: I only store changes
What do you mean by "I only store changes"? You don't use change detection?
When I disable the SleepingPlugin, my colliders fall through the floor (RigidBody::Static) for some reason
Ok I managed to have no rollbacks for my player-controlled RigidBody, but for some reason when I add an extra non-controlled RigidBody I do have rollbacks on that one.
Whoops, that's a regression. Will be fixed by #624
Another mildly scuffed way to disable sleeping globally is to set the threshold(s) in the SleepingThreshold resource to be negative
Yes that's what I did
In my example https://github.com/cBournhonesque/lightyear/tree/main/examples%2Favian_3d_character, I don't have any rollbacks for the character controller but I have some for the inter boxes which are Cuboids.
If I just spawn a Cuboid I see constant rollbacks, and I see that it's Position/Velocities keep changing slightly. Is that expected? I would expect them to have 0 velocity, but they seem to twitch very slightly
If it's a dynamic cuboid and not sleeping then it's constantly applying gravity and contact impulses, so yes it's expected to change slightly
That's the second reason for sleeping (first reason is optimization), it allows objects to be properly resting instead of constantly moving slightly
but wouldn't a cube on a flat surface not move at all even with gravity? or is it because of slight numerical instabilities in the solving process
This doesn't explain why I keep getting constant rollback on that cube.. I don't know which component/resource I am missing. I just spawn a cube on client/server with no movement
A cube resting on a flat surface has 4 contact points. At each substep, the cube gets a downwards velocity from gravity, and then the contacts are solved sequentially to apply a corrective impulse at each of the 4 points (even the point order affects results).
Contact solving is iterative and not exact. Even with a "block solver" that solved all contact points simultaneously, I doubt you'd get contact impulses that perfectly cancel out gravity to reach exactly zero velocity, especially with floating point math. You could maybe have some minimum velocity threshold for object movement though, where e.g. velocities below 1e-3 units per second get clamped to zero
I see, so avian dynamics is deterministic but not contact solving?
I'm not sure what you mean by that. Avian uses an iterative impulse-based Gauss-Seidel style solver like pretty much every game physics engine out there. At a high level the implementation is basically the same as in Rapier, Box2D, Jolt, probably PhysX, and so on.
No engine for real-time applications has an exact solver, they're pretty much all iterative and approximate
There's also an Accuracy section for Avian's dynamics here
https://docs.rs/avian3d/latest/avian3d/dynamics/index.html#accuracy
Rigid body dynamics, handling the motion and physical interactions of non-deformable objects.
You have deterministic tests that check that run_cubes() gives the same result every ime. Does run_cubes() also include contacts?
I guess the tests are deterministic because the contacts are solved sequentially in the same order, but if I spawn the cubes in a different World maybe the contacts would be solved in a different order?
I'm not too familiar with avian internals, but do you think that I should try adding sorting here: https://github.com/Jondolf/avian/blob/v0.1.0/src/collision/contact_query.rs#L213 to see if it helps? (just to test if this can avoid the rollbacks, not to make a PR to avian)
The current cross-platform determinism test is here, it tests both contacts and joints. It's 2D but we also had a (much worse) 3D test before. A proper 3D test would be valuable though, we could probably just make a 3D version of the existing 2D test
(there's also a matching determinism_2d example you can run to see it visually)
I believe the main thing that is important is that the entities in contact data are in the same order across worlds, like in that PR you made a while ago
This could probably be tested by randomizing entity spawn order to make the IDs unstable across runs
Yes i probably have something similar happening again. ClientWorld has more entities than the ServerWorld which might cause some hashmap to be iterated in a different order or something
I'll try this in the determinism_2d example
Is it deterministic when you don't have collisions? For example if you just have a cube moving and spinning around in the air
I think it's deterministic even with collisions when I only have one contact point. If I only have the main player (which is a capsule that collides with the floor), it is deterministic
So it might just be the order of iteration of contact points
@dreamy viper It looks like it's definitely not deterministic if I shuffle the order of entity columns spawned in the determinism_2d example, which implies that entity ID order indeed affects things
Is it something that I missed in my past PR?
Not sure, I'm looking into it
haven't found the source of non-determinism yet, I tried changing some things but it still produces different results for different entity orders
(and now I've been nerd sniped into writing JS to embed some tags into Bevy docs xD)
If change detection triggers I then compare the value with the value before it in history before doing anything with it, tho I'll probably add an opt-out later because comparing Collisions isn't particularly beneficial most of the time
I guess I was just surprised that change detection was triggered on Collisions even though the collisions were all empty
Yea it's trivially easy for change detection to trigger on resources with collections, you just iter_mut because you might need to change stuff, and then it triggers change detection despite having 0 entries or not actually mutating anything
We could bypass change detection for it, count the number of changes, then mark it changed if there were any π€
related
The performance characteristics and easy of triggering when there is no change means I rarely use change detection in bevy, it's too brittle and slow. I'd much prefer it if I could opt-in to a slow path for certain components for granular detection that does equality checks and only iterates over the changed set.
@vestal minnow is my guess correct?
Question, when inserting a dynamic rigidbody does avian, insert a series of aditional components too?
is there a good way to deal with ejecting dynamic rigidbodies inside of another collider?
in the most recent version yes https://docs.rs/avian3d/latest/avian3d/dynamics/rigid_body/enum.RigidBody.html#impl-Component-for-RigidBody
A non-deformable body used for the simulation of most physics objects.
These are the required components that get inserted alongside rigidbody, as long as they aren't already decalred on that entity
Released a tiny 0.2.2 patch for avian_derive to replace an unmaintained dependency (see #627)
https://github.com/Jondolf/avian/pull/628
i'm super new to Bevy and was trying to just get a feel for stuff, play with some planets. Can't seem to understand why the collisions here aren't working though
Here's the full file
Thanks!
This could be related, yeah. There isn't a way to apply CollisionLayers to picking currently, but I would probably accept a PR that implements it. I guess the simplest approach would be to just have CollisionLayers on the camera entity and use that for the filter, but it's a bit weird since CollisionLayers has both "memberships" and "filters", but picking only cares about the filters to determine what layers it should consider π€
I tested exactly this, as camera component. But yeah, if we need only the half of the data of CollisionLayers, we probably should introduce a new dedicated component
I worked around this by using the MeshPickingPlugin, but that's awkward, because if the player wants to pick / select a rotating small worm in my game, he needs to hit it exactly, obviously. A bigger collider and picking by physics would be great. I also think thats a really important feature for real world applications/games.
I never looked into the implementation details of avian, but if you think that would be cool, I would give it a try.
In general, I'd recommend using smaller values if possible, especially for physics. Physics doesn't tend to like very large or very small values. I'm not sure if that's related to the problem though, I'd still expect collisions to be detected at least
Might want to add the PhysicsDebugPlugin to visualize the colliders and make sure they look like they're actually intersecting
hmm, i was trying to scale everything in terms of Meters with realistically sized planets, so it is pretty large,
it does complain here
WARN avian3d::dynamics::rigid_body::mass_properties: Dynamic rigid body 19v1#4294967315 has no mass or inertia. This can cause NaN values. Consider adding a `MassPropertiesBundle` or a `Collider` with mass.
but i did add a MassPropertiesBundle
i'll try to add the Debug plugin
This means that the dynamic body has non-finite mass properties, like NaN or Infinity
You could log ComputedMass and/or ComputedAngularInertia, they store the actual mass properties used by physics stuff
Yeah so your cuboid with a side length of 1,000,000 and a density of 2 would have a mass of 2,000,000,000,000,000,000 :P
@vestal minnow should I open an issue before starting with the implementation?
this sounds like a really hard problem btw. A realistically sized solar system will run into floating point precision issues quite early I think. There is bevy_big_space but I'm not sure how far the avian integration is. If you don't care about small scales though, you could try to rescale everything, e.g. using AUs instead of meters or something (or solar radii)
Yeah that'd be nice, I'm trying to think of what the ideal solution and API would be
got it, ill just scale it down since i'm just playing around right now
We could just add a PhysicsPickingLayers component or similar, but this sort of feels like there should be a more unified API between different picking backends
we could add a optional LayerMask to the PhysicsPickingSettings
but maybe its a bit to global
Yes I was considering that as an option, but I think it would be good to also allow having different layers for each camera if there are more than one
Something that I think could make sense is to change PhysicsPickingSettings from a resource to a component that you can put on cameras
But ideally it'd be consistent with other backends, like MeshPickingSettings should also be a component, so we'd need to change those too on the Bevy side
I might ask around about that in #1236111180624297984
I would prefer using a PhysicsPickingLayers, honestly, because it's more fine grained, and it feels more aligned with the MeshPickingPlugin - because it considers the RenderLayers, and the CollisionLayers feels like an equivalent. The only difference is, RenderLayers work on a camera. So maybe it would be a nice option.
I create an issue and start trying around until we have a final solution
how do i raytrace with avian3d and check for collisions? i would also like to know the entity it hit
alright thanks
ChangeDetection is triggered spuriously for avian components, right? i.e. even if the value doesn't change, LinearVelocity/Rotation/etc. are all updated every time the physics schedule runs?
I think avian does try to avoid this for position/rotation, and linearvelocity/angularvelocity are only changed under certain conditions I think π€
Interesting issue I discovered today (or well, I kinda knew about it, but it resurfaced now)
Edit: I was at least partially wrong about things here, added a clarifying comment
https://github.com/Jondolf/avian/issues/629
If I have a kinematic rigidbody, is there a way to make it push dynamic objects "gently"? For example, I want a pusher like in one of those coin game machines - but no matter how fast the pusher moves, I want it to only nudge the coins forward, instead of flinging them at high speed. Since this is very unphysical I imagine that it might be tricky to achieve this, but can I somehow approximate it?
maybe you could query for collisions around a larger radius and then manually apply damped spring forces?
(not literally a damped spring, would be a repulsive force based on the distance, but damping would still make sense)
if your collider shape is complex and the shape matters a lot, then the hardest part is probably figuring out the distances relevant for the repulsive force
the force could maybe look something like this:
// r is the vector between the colliders
// gamma is a parameter controlling how steep the repulsive profile is (between 0.5 and 3 maybe)
let force = strength*r.normalize_or_zero() * r.pow(-gamma)
If I understood it correctly, to apply a force or an impulse, you add an ExternalForce or impulse to the entity.
If you have multiple systems exercising forces, you would then always check if the component is already present and modify or add it based on its existence?
Or what is the best approach?
Is there any good way of debugging the spatial query pipeline? I cannot get picking with colliders to work and I'm kind of at my wit's end in terms of what could be going wrong
the ExternalForce has a setting to change whether forces will persist over updates, and all the methods to add forces are cumulative
Not really, other than logging and/or drawing results manually. We could theoretically support debug rendering for all of the spatial query methods, but it'd require making them take &mut self instead of &self, which may not be desirable in some cases
Picking should work if the relevant physics plugins are enabled, PhysicsPickingPlugin is enabled, and ofc the colliders are correct (if they're rendered correctly with the PhysicDebugPlugin then they should be)
Also I think RenderLayers for the camera and colliders must match, if you've configured them π€ though this seems strange for collider picking
It was like that in the original bevy_mod_picking's Avian backend, so I guess I copied it over
I'd probably remove it since colliders have no connection to RenderLayers at all, there should just be a way to filter by CollisionLayers
only reason for renderlayers is to ensure WYSIWYG for rendered objects
for colliders it probably doesn't make sense
yup
made an issue for this
https://github.com/Jondolf/avian/issues/631
Yeah, all of this is true, and the render layers are compatible, and yet I still see only the dreaded 0v1 being hit by pointer events
Thus the end of wits
Is anything other than a collider necessary to get something to appear in spatial queries?
Position, Rotation, and Collider are the only necessary components afaik. The physics position components are inserted automatically for colliders, and they're auto-synced with Transform (if present) so you shouldn't need to use or specify them anywhere
assuming the relevant plugins are enabled of course, if you have e.g. PhysicsPlugins::default() then they should be
Yeah, the relevant plugins in this case should literally just be PhysicsPlugins::default() and PhysicsPickingPlugin
Yeah I've looked at that. Basically I just don't see how our code is different from that in a way that matters
I guess I should mention that I'm using the settings that require PhysicsPickable components, but as far as I can tell those are also everywhere that matters
wait
oh that is cursed
but technically documented
@sullen lantern make sure your camera has PhysicsPickable too :P
It does π
(This is how the old bevy_mod_picking rapier backend used to work, so it's not a surprise, although it is weird)
yeah I was also confused why require_markers: true broke picking, but I remembered the marker is needed for both
with that it does work for me
Okay it turns out the problem is weirder than I expected
So, I can get pointer events to fire targeting my entities, but it seems fairly inconsistent
I'll have to test some more tomorrow morning, it's almost bedtime for me π΄
But if you have multiple systems which insert an external force, wouldnβt they overwrite each other?
As inserts would overwrite a previous existence of the component.
So when the commands play back only the last inserted one would apply its force.
You only spawn the component once in the beginning. To add a force you just query for the component and call the add_force method on it. Multiple systems will be cumulative that way.
Is there an easy way to get a SpatialQuery in an exclusive system (i.e. a system that just takes &mut World)?
Probably using SystemState
Holds on to persistent state required to drive SystemParam for a System.
TIL you can also use them like this https://bevy-cheatbook.github.io/programming/exclusive.html#exclusive-system-parameters
huh, that's pretty cool
Doh! It's right there on the on the exclusive systems pages
Thanks both! π
@vestal minnow Okay, I've concluded this likely has nothing to do with avian π Thanks, regardless
Okay cool π did you figure out what it is / how to fix it yet?
Nope! Basically, it turns out that picking events aren't being reported correctly unless the mouse button is held down
Next place to look is probably interactions with bevy_egui
(In other words, the reason I thought that the backend wasn't working correctly was that Pointer<Over> events were not being reported, but that lack of reporting is the shortfall, the backend is reporting hits correctly)
Huh, yeah that sounds strange π€
Do you have UI or something overlaid and blocking pointer hits? Or something else like that (I'm not too familiar with how the picking stuff works :p)
Unsure π For example, right now, a global observer of Pointer<Click> always reports 0v1 (the window) as the hit entity
Holding down the left mouse button and dragging over the actual collider entities will produce Pointer<Over> events though
But the main difference between the application and a simple picking example at this point is probably the use of egui, sooooo
Ah I thought I tried that, but the component was removed (I added a zero force to it).
Will try again, thank you!
Yeah it shouldn't be getting removed with the current way things work. I intend to rework the force and impulse API at some point though, probably to use commands or a ForceHelper system param for applying individual forces without having to deal with component shenanigans. Likely also a separate, optional ConstantForce component for "persistent forces" (e.g. custom gravity)
yeah, this sounds like egui
the egui picking back-end uses wants_input or something to tell if the stuff drawn with the painter is going to try and grab the pointer input.
Yeah, it was egui. Basically, the change in bevy_egui 0.32 to capture mouse pointer events essentially caused all our pointer events to die. I'm not sure if there's a very good way of addressing this in general, since it's not like we can control when the egui context wants_mouse_input. I think right now it just always thinks it wants it because the viewport that's being picked in is basically just composited in. Not sure if there's a better way of handling that...
In 0.32, bevy_egui captures mouse input in every Window by default (i.e. as a default field in EguiContextSettings)
as far as I can tell, there is no way of disabling this other than creating a system which manually overwrites the EguiContextSettings
so, for us, the bevy_egui 0.32 upgrade essentially quietly broke all picking interactions on the application
Maybe the way this works makes sense if your application is like, a game window with an egui::Window floating on top of it, but if it's primarily an egui application with camera views composited into it, then picking in all those views just... doesn't work
Again, I'm also kind of a novice with egui/bevy_egui, so it's possible that a more "natural" configuration avoids this problem
I'm seeing if we've run into this at work, give me a bit. if we haven't then we will, if we have then there's a fix.
On the other hand, this also just wasted like 8 entire hours of my life
Follow up: We hadn't run into this yet, you are on the bleeding edge. Should flag in https://discord.com/channels/691052431525675048/1098915028142403735
We're interested in getting this fixed too
Yeah, I'll ping them and/or write up an issue
@vestal minnow the pull request for the picking-layers stuff: https://github.com/Jondolf/avian/pull/632
Hello, I'm quite new to both Bevy and Avian so apologies if the following question makes little sense.
I was wondering why in the official examples the systems related to movement run in Update rather than in FixedUpdate for example. How do the schedules defined by the user (to update for example LinearVelocity) relate to the internal schedule of the PhysicsPlugin?
To avoid changing the LinearVelocity in Update I thought about following the custom_broad_phase example to overwrite the First step phase but there seems to be no FirstPlugin like BroadPhasePlugin.
Hey, say I want to generate a collider for a polygon defined by the lines (Vec2, Vec2) that form it's outershell, what would be the way ? Collider::polyline ?
Collider::polyline was the solution, it works perfectly
if i want to run something in FixedPostUpdate after all avian systems, is the best way to do it .after(PhysicsSet::Sync)?
Yes
probably just a leftover from old schedule, movement definitely should be in fixedupdate now
If I update Transform in PreUpdate, the first Physics update step-update will be ignored, right?
Since StepSimulation runs first, (which will update pos/rot), then Sync:TransformToPosition will run, and finally Sync::PositionToTransform.
I think TransformToPosition is supposed to run once before all the substeps π€
Ah i see there are some systems that are running outside of any SyncSet and before StepSimulation..
I was mostly looking at at the SystemSet order which implied that the TransformToPosition would happen after StepSimulation
This isn't really documented
Yea the whole SyncPlugin situation kinda sucks in general ... I've seen even @vestal minnow be frequently confused about why things are the way they are, and it's neither particularly efficient nor intuitive ... It's just a bit unfortunate that bevy_transform isn't really made for non-graphical purposes ... Not yet anyway
I think most of the examples handle input and movement in the same system to keep things minimal, and the fixed timestep schedules still don't like input afaik (unless you're using LWIM)
but yeah movement should be done in FixedUpdate generally
Yeah it's pretty confusing. I had a branch to reorganize some of the transform sync stuff, but it had some bug so it's still WIP. Should probably finish it soon
Is there an Issue about work can be done on Transform directly to help?
I'm not sure there's an issue but I've at the very least seen nth show up here to discuss Avian's needs for reworking bevy's Transform ... There might be some stuff that could be investigated head of time tho ... The main thing iirc is that Position is global while Transform is local, this difference could potentially be bridged if we propagate the inherited transform down π€
There's also some weirdness around non-uniform scales and shear, but I think avian already handles those somewhat so they might not be a major concern atm
Avian mainly just needs a global transform (or isometry) that is not in affine/matrix form, and also a 2D version of that
And an f64 version assuming we want to keep support for that
Afaict people just use it for cases that really just need big space
Just extract it from GlobalTransform and panic if it's not a perfect isometry, and then still get UX issues because GlobalTransform sucks π
I think eventually we might want something similar to Jolt, which can be optionally compiled with double precision for positions, but drops down to floats as soon as possible for most calculations
things like collision queries take a "base offset"
and yeah big_space support
Hmm the upcoming non-fragmenting relations could be nice for our ColliderParent stuff
Replace it with ColliderOf and RigidBodyColliders
Also I wonder if we could handle multiple physics worlds nicely with physics worlds as entities (resources like Collisions, SpatialQueryPipeline, etc. are components) and relations that support querying by value (each physics world has a different ID, systems can query for entities belonging to a specific world)
or something like that
Damn, my server-entity Transform gets slightly updated during the physics step, but not my client entity... I don't know what it could be. I'm running the same physics plugin in both, with no gravity and no sleeping
ah it's collision-related. Is there anything I can do to help debug the non-deterministic contacts?
If you give me a couple pointers to get started (how to modify/run the deterministic test, if that's what you're using) I can work on that.
I'll test:
- when entity orders are different
- when there's multiple points of contact
@vestal minnow How do CollisionLayers interact with picking? I noticed that entities with colliders become non-pickable when they have CollisionLayers::NONE
Did you also disable warm starting?
no, do i have to?
Easy way to check if you have issues with rolling back Collisions
Something is modifying my Kinematic's Transform during the physics-step but i don't know what:
2025-01-17T20:53:10.186746Z INFO shared::player: AfterInputsApplied is_rollback=false tick=Tick(5061) transform=Mut(Transform { translation: Vec3(0.0, 0.0, 0.0), rotation: Quat(0.00449998, -0.0014999844, -6.749975e-6, 0.99998885), scale: Vec3(1.0, 1.0, 1.0) })
2025-01-17T20:53:10.187295Z INFO shared::player: After Physics is_rollback=false tick=Tick(5061) entity=212v1#4294967508 transform=Transform { translation: Vec3(0.0, 0.0, 0.0), rotation: Quat(0.0044999802, -0.0014999846, -6.749976e-6, 0.9999888), scale: Vec3(1.0, 1.0, 1.0) }
it only happens on the server
could it be the transform->position->transform sync step?
The thing is that on the client the physics-step doesn't change anything:
2025-01-17T20:53:10.166628Z INFO shared::player: AfterInputsApplied is_rollback=false tick=Tick(5061) transform=Mut(Transform { translation: Vec3(0.0, 0.0, 0.0), rotation: Quat(0.00449998, -0.0014999844, -6.749975e-6, 0.99998885), scale: Vec3(1
.0, 1.0, 1.0) })
2025-01-17T20:53:10.167346Z INFO shared::player: After Physics is_rollback=false tick=Tick(5061) entity=399v1#4294967695 transform=Transform { translation: Vec3(0.0, 0.0, 0.0), rotation: Quat(0.00449998, -0.0014999844, -6.749975e-6, 0.99998885)
, scale: Vec3(1.0, 1.0, 1.0) }
For the determinism test I was just running crates/examples/determinism_2d.rs, but use rand to change the for col in 0..COLUMNS { ... } loop to shuffle the order in which the columns are spawned, resulting in a different entity order
let mut cols = (0..COLUMNS).collect::<Vec<u32>>();
cols.shuffle(&mut rand::thread_rng());
for col in cols {
// ...
}
ok thanks
nvm I discovered that it uses the default SpatialQueryFilter and can probably imagine it amounts to that
Oh i forgot to add RigidBody::Kinematic on the client, that's why it doesn't change there. Still i'm surprised that the Transform values are modified during the physics-step for a Kinematic object with no velocity
To eliminate any potential effects of Transform shenanigans while debugging, you could also use Position and Rotation directly for the physics entities and maybe debug render the entities with PhysicsDebugPlugin to still visualize what's happening
Change detection probably triggers but actual values shouldn't really change
My strategy was to just disable SyncPlugin, network Position and Rotation instead, and put a custom system after the fixed main loop to sync pos/rot to Transform π
Well they don't change much but still from 0.99998885 to 0.9999888
Yes I did that before, i was running the SyncPlugin in PostUpdate; but i wanted to try syncing Transform directly instead
BTW @vestal minnow any plans for https://github.com/Jondolf/avian/pull/527? Definitely going to need that if I'm gonna fix my SDF tree π€
Yeah spatial queries filter by layers, defaulting to LayerMask::ALL. Currently though, colliders that don't belong to any layer are ignored. Perhaps it could be better to make this filter an Option<LayerMask>, so that None ignores the whole filter and includes all entities regardless of layers
(also the layer filter can't currently be configured for picking but after I merge #632 it can)
I'm fine with it I think, though like I mentioned at some point, I don't want aabb or swept_aabb to have the entity or context in it since just getting the AABB of a collider is a useful operation in itself that shouldn't be tied to any other collision detection logic or the ECS. There should just be a separate method such as aabb_with_context, that defaults to calling aabb.
I'll leave a comment on the PR and can probably get it mergeable over the weekend myself as well
Or I guess that had the problem that then aabb might not work for some colliders that require the context
Yea, I'd have to panic on aabb
Being able to skip the argument when it's not necessary would be really nice tho, passing () all the time is kinda clunky
And if the default collider ever ends up needing it it would be possible to just wrap it in some kind of system param or something too π€
And you need to pass an entity which would make no sense in cases where you don't yet have an entity to begin with
Might be worth changing the API so that specific case can't happen
Right this idea
I guess make AnyCollider only have the _with_context versions, and implement the empty context version manually for Collider
ideally we'd implement Bounded2d/Bounded3d but at least for now we still need to support f64 bounding volumes :P
So I wasn't able to understand why this happens, but I have 0 rollbacks if I add
app.insert_resource(avian3d::sync::SyncConfig {
transform_to_position: false,
position_to_transform: true,
..default()
});
but i have constant rollbacks if I use transform_to_position=True.
So maybe the transform->position sync is causing some issue.
Note that I only have interpolation added on the client, so the sync_transform_to_position will always run before PhysicsSet::StepSimulation. (which shouldn't cause any issues because the Transform value is reset before that thanks to interpolation, but maybe the sync is causing some numerical instability? Or does someone have another hypothesis?)
I guess that makes some sense if a hierarchy is involved. Some floating point error would add up in transform -> position, then it would add up (possibly in the same direction again) in position -> transform
Iirc Jondolf had some awful hack to avoid it from detecting its own changes, but that wouldn't stop it from picking changes up changes caused by rollback or network updates π€
did anyone try the pickable functionality? I just took the picking example, added
.insert_resource(PhysicsPickingSettings { require_markers: true, })
to the main, added PhysicsPickable to the entities, and nothing is pickable.
is there an efficient way of only getting the collisions of entities with a component?
Can it be that Avian is just too inaccurate? This is a plane facing upwards, and I am shooting a capsule downwards. This should be just a Y vector, however it is not precisely that. I have never had any issue with this in other physics engines. I do not want to shit on Avian or anything, because all my respect to Jondolf and the other maintainers, however this is a real issue in my opinion.
Avian can't control how normals are computed from ray casts or shape casts, those are computed by Parry
I believe capsules in Parry use a form of GJK for shape casts, it is an iterative algorithm that produces approximate results
Regardless of the algorithm though, getting exact results for something like this is basically impossible with floating point math, it is extremely unlikely that you'd get a perfect Vec3::Y
i had exact same issue with unity though π§
I have not seen any engine use something other than GJK (or specifically a form of Minkowski ray casts) for general shape casts and it cannot return exact results
you could probably get more accurate results than Parry's implementation does though
Did you add it to the camera?
it's probably not even needed, ghost collisions are way more concerning
especially when they happen on a flat mesh collider
Depends on what exactly you need, but you could have a query like Query<(Entity, &CollidingEntities), With<MyComponent>>, and then for each pair of colliding entities you get their contacts from the Collisions resource
fn print_contacts(
query: Query<(Entity, &CollidingEntities), With<MyComponent>>,
collisions: Res<Collisions>,
) {
for (entity1, colliding_entities) in &query {
// Note: If you also want to make sure the second entity
// matches the query, use `query.iter_many(colliding_entities.iter())`.
for entity2 in colliding_entities.iter() {
let Some(contacts) = collisions.get(entity1, entity2) else {
continue;
};
// Do something
info!("{entity1} and {entity2} are colliding");
}
}
}
Make sure to add CollidingEntities to the entities, since it's not added automatically to avoid unnecessary overhead for entities that don't need it
You could also just iterate over all collisions and then check if they match a query but that can have more unnecessary iteration
i would also need to effiecntly know what the colldignentities contains, currently i have a bug because my projectiles colide with each other and then despawn
Are you trying to make projectiles not collide with each other? You could use CollisionLayers for that
yeah but im kinda trying to avoid that, i dont like using layers, i would rather rely on logic for that
@wispy lance #1124043933886976171 message layers are perfect for "x shouldn't hit y", this sorts out the rest. still haven't found anything better.
That will be much slower since it means that you're still running collision detection between the bullets, but if you do want to just detect what the colliding entities are then you can check if they match the query like I noted in my example
For example like this
fn bullet_hit(
mut commands: Commands,
bullet_query: Query<(Entity, &CollidingEntities), With<Bullet>>,
other_query: Query<Entity, Without<Bullet>>
) {
for (bullet_entity, colliding_entities) in &bullet_query {
for other_entity in other_query.iter_many(colliding_entities.iter()) {
// Despawn bullet since it hit a non-bullet
commands.entity(bullet_entity).desapwn();
// ...
}
}
}
But again this won't stop bullets from colliding with each other.
You just won't despawn them when that happens
You could use custom filters/hooks too but that would also be more expensive than just using layers
if there are bullets that can kill enemy bullets (e.g. shoot down a rocket), you'll want at least some of them to collide
okay i guess im gonna use layers
Yeah I'd like to try this to alleviate them #1124043933886976171 message
And maybe enable internal edge fixing for trimeshes by default
And maybe a tilemap collider at some point
grid collider
for tiles and voxels
unless you want to do the same thing as unity and just convert it to mesh so that it allows custom colliders on tiles
With this I think the main limitations are that the shapes must be a part of the same compound shape for internal edge removal to work, and it relies on approximately matching vertices so it doesn't work for "T-edges" where the vertex is on an edge or face but not on another vertex
I think theoretically it could be generalized to handle these cases too, but it might be much more expensive
i never had ghost collisions on edges of a flat mesh in unity though, so maybe there's something that can be fixed before doing that
I mean this should fix it
for meshes
just default to TrimeshFlags::FIX_INTERNAL_EDGES
my character has legs now: https://www.youtube.com/watch?v=_PKk0MWIlLU
(well sometimes the character has legs)
Whoa this is sick! Is this like 3D Fancy Pants?
(the stickman platformer game series)
Not sure what exactly this will be, but it's a family of ideas that I have basically been following since maybe 12-13 years or so, and playing fancy pants was probably a big inspiration
this one is also an attempt to do something mirror's edge like (but physics based)
how do i apply velocity for knockback? i want it to start slow, get faster and slow again
but I have opted not to show 1st person this time because I myself got sick playing in full screen for the first time π
π² thanks!
how did you make that jumping trajectory gizmo?
that's just a bunch of lines in a row
just a loop over simulated time, adding external forces to the velocity each loop and drawing a line between the old and new simulated position
that sounds like you're trying to implement motion matching, i thought it was just simple IK D;
not really, but I am doing shapecasts in the loop there to find where the player is going to land roughly, to orient the "feet" properly on landing depending on player input
but I am also doing some rough prediction of the player position into the future on the ground to estimate the next feet positions (which are determined just using ik)
and then I'm also procedurally updating hip, neck and head positions based on the vector between contact point and center of mass, which gives a lot of the emergent motion
knowing when to do steps is the most tricky part of the animation part I would say, and I will probably try something a bit more fancy soon
yeah you're probably halfway there to rediscovering motion matching xD
hmm not sure, I will probably never have a huge database of animations
i think most of it is just blending
yeah I mean the trajectory prediction part is probably shared with motion matching, but I would say the largest part of motion matching is still the lookup into the database based on the motion features and last animation clip
Currently, linear and angular velocity damping are handled with a PadΓ© approximation of exponential decay. This formulation is also used by engines such as Rapier and Box2D. Box2D has a brief deriv...
Guess we doing music in our physics now 
at least we're not writing Swift
It would've been so funny if this PR was on a physics engine written in Swift π
I have an issue with shapecasts, they keep detecting and not detecting at random, and the normals are going haywire (in the debug renderer)
What shape are you casting and what is it hitting?
sphere, rectangular prism
converting, one sec
The max distance was set to 0f32.next_up(), if I set it to 0.1 then it stops disappearing and reappearing but normals get... weird
getting vid
Yeah that's largely expected I think, the hit point and normal just moving around a bit, likely due to inaccuracies with Parry's shape cast algorithm
Same as #1124043933886976171 message
and here, why does it disappear? It says it's not hitting anything sometimes when it is
and that messes with my player controller
You need a larger max distance, even something like 1e-3 might be enough
What do you think might be good?
I'd say test what is large enough to not miss hits but not too large to cause other problems with your controller
also, do you think those normals will get more accurate once/if parry is removed as a dependency
If I figure out a more accurate shape cast algorithm then maybe. Could also try improving it in Parry in the meanwhile
Alrighty, cool
That works for me since slightly inaccurate normals and "weird" ground angle detection is fine for me while I'm still just learning gamedev with bevy. If I am ever in the position to sit down and make a real game for other people, it'll probably be in a long while. Maybe even after bevy is stable (or has a scene editor)
Thanks :)
No worries π
another question
When my player moved mid-air
how do I stop them from launching up when moving into a wall?
I'm using the capsule collider and the character is dynamic not kinematic
I think the physicsy solution would be for it to have friction so it doesn't slide past and redirects all velocity, but for character controllers I've more frequently seen code that just removes velocity when you touch things, and then only reapplies the velocity that should exist π€
- It has the default friction (0.5 static and dynamic)
- Knowing how to do this would solve many of my problems. Is there a way to access what the velocity would be if it were set to 0 and then computed one tick ahead?
I don't think there's actually a way to know, the code I've seen in other character controllers just tracks the current velocity it is applying so it can cancel any velocity it didn't create when you bump in to something that's supposed to stop you ... It's odd that it would happen with default friction tho, might be something else going on here too then π€
When in the air I'm using externalforce and not velocity for movement
since I like the floaty feel while airborn
wait no
I'm using velocity
lemme try using externalforce
bug still present
ExternalForce/Impulse would just end up modifying velocity anyway
Yeah
btw, for character rotation, should I just modify transform directly and use a spherical collider?
since that's what I'm doing rn
for snappiness
Iirc the main cause of flying up like that is usually just the result of inputing too much power from the character controller. Especially if the case is that forces are redirected up, you then see you're no longer moving in the desired direction and apply more force. If that repeats a few frames you end up pretty far in the sky
hmm
The think is, I don't want to player to move slowly
maybe I just need a cylinder collider?
that fixes it :)
But wait
do shapecasts have colliders?
as in
around the origin
Shapecasts cast shapes so yes
They don't interact with physics, they just find any collider matching the filters
lemme send a vid
ok so
I'll just show you actually yeah
Is it just because it's the center of the shape?
of the player collider
This seems to happen at the location of the shapecast even if I move it
and I'm not doing anything with that collision info (yet)
Both the shapecast and the cylinder start at 0,0,0 in the entity's local space
I tried moving the shapecast down and it happened at it's location too but I think I just found the problem
I am actually using it
when it collides it moves as if it's grounded
and I don't want that
hmm
how do I make it not collide on its sides...
You check the dot product between the normal of the shapecast hit and the up vector
ooh and this would work w/ ramps too
So you can specify some arbitrary range of angles that are acceptible as "grounded"
brilliant
thanks
https://docs.rs/avian3d/latest/avian3d/spatial_query/struct.ShapeHitData.html what is point1 vs point2?
Data related to a hit during a shapecast.
Bevy Swift would actually be a cool name for a physics engine, if it wouldn't compete in google searches with taylor and language
"it's not just a physics engine, it's a swift physics engine"
See the docs for the fields below, one of them is on the shape ths is being cast, and the other on the collider that is hit
It's easy to mix them up tho π
I feel like they should be the other way around but switching them is an annoying breaking change :P
cast_point, hit_point?
hit_point_self and hit_point_other
Maybe like
- Get rid of
normal2, and only havenormal, which is the normal on the shape that was hit. This is consistent with ray casts, and I think the normals are just opposites of each other anyway. - Store
pointas the hit point on the shape that was hit, andshape_point/cast_point/self_pointfor the other one.
Oh no, I have unleashed the bikeshed ... What have I done 
we really do need a bikeshedding channel
Time to create an Avian Bikeshed crate just to get an extra channel for bikeshedding π
Why get rid of normal2 instead of adding an equivalent for raycasts?
And storing normal2 is kinda pointless if normal1 == -normal2
Is it always like that tho?
yeah we need to verify that this is always the case, but I think so
if the surface is perpendicular to the cast location, sure, but what if it's slanted?
wait
nevermind
brainfart 2: electric boogaloo
wait no
The normal is the normalized vector between the two points
this sounds good to me then
Or it's also perpendicular to the surfaces, hence the name normal
if it's perpendicular to the surface then what if the surface is slanted
and it gets hit by a shapecast
its normal might not point towards the origin
Can you give an example? Like what the two involved shapes are
wait nvm
I thought it was the normal on the casting location (which doesn't even exist)
brainfart 3
looks more like adhd than brainfart
How'd you know...
Yeah it's the normal pointing from the surface of shape A to the surface of B at the point of contact. I'm saying surface kinda broadly here, of course if you have e.g. a ball that is cast towards the corner of a triangle, the "surface" of the triangle there is really just that single vertex
I get it now I think
and yeah I think normal1 and normal2 are just negative vers of each other
looks like unity doesn't have normal2 on spherecast
yeah looking at Parry it's just doing this
normal1: Unit::new_unchecked(normal1),
normal2: Unit::new_unchecked(pos12.inverse_transform_vector(&-normal1)),
looks like godot doesn't have it either
I'm still confused about how Parry's results here work
It looks like some things are in local space and some aren't
maybe it'll make more sense when you start rewriting it from scratch
lol yeah
I have a vec3 called movement that never has a y component. I want to rotate it so that it never points away from the surface you're on
so if you're on a plane, it would be the same
and if you're on a ramp, forward moves you up and forward at the angle of the ramp
and more importantly, backwards moves you with the ramp, and doesn't send you flying off of it
You say this like physics and collisions actually make sense 
project on plane
Physics:
how
A 3-dimensional vector.
How do I get RHS
as in, how do I get that vec3
for the plane that I wish to project onto
i just had leftover code from unity, that's what it was called there
it exists in bevy but I need a vector to project onto
RHS is plane normal
it is
A 3-dimensional vector.
it works :3
yippee
I now have a somewhat mostly functional player controller!
(as long as the environment is fully static but shhh)
@cinder summit hypothesized that it's because of the use of GlobalTransform and the switch between Quat -> Mat3 -> Quat. I'll try to open an issue an avian that explains all the possible things that prevent determinism
Yea that Transform -> GlobalTransform -> Position + Rotation -> Transform chain is going to be far too lossy, especially if we dare also use hierarchies
moving platforms are easy until they start rotating
For transform_to_position there is this check
// Skip entity if the global transform value hasn't changed
if *global_transform == previous_transform.0 {
continue;
}
which seemed to work when I tried it, but there could definitely be some problem(s) there
Hmmm ... Rolling back whatever previous transform is might have some effect
the problem is, to prevent sliding down ramps, the player's velocity is set to 0 when no movement keys are pressed...
I could just increase friction
when to movement keys are pressed and the player is grounded, I should say
check very very valet tutorial videos
π«‘ on it
Actually rotating is easy too as long as you don't expect to stay on there for too long π
It will
you off eventually
VisualInterpolation might be causing Transform/GlobalTransform to change
i had a working moving and rotating platform with anti-gravity. i celebrated for a short while before nausea hit.
@vestal minnow I think we discussed the idea of using Transform as the source of truth and getting an entity's local space by just propagating that info down instead ... Would that actually be viable, or would we need features from a Transform rework first? π€
when porting over to bevy i wondered if i even need that, every game i remember has like one rotating cog/turbine/car/train as a platform in the entire game and never uses it again
Hmm I don't think I remember this, what do you mean by using Transform as the source of truth?
Like don't use GlobalTransform at all and instead propagate manually to compute the global Transform?
Yea, except we might not necessarily want to compute the global transform and instead just up to the collider root or the parent
didn't help
Except for maybe the wall sliding bit
w/ friction
with hovering collider there's no sliding unless you apply it manually
Ohhh
Closed the Taylor PR for now btw
https://github.com/Jondolf/avian/pull/633#issuecomment-2600279615
I see
no Taylor nor Swift π
I'll look into that
caching makes a lot of sense with movement in fixedupdate, i guess i'll try copying that
I've found a solution for sphere shapecasts!
shrink them and increase max_distance
it's only a partial solution and extremely context dependent
but it works
if you're shrinking it anyway then why not raycast
I should probably think things through more before I send messages
especially if I ping people
sorgy Jondolf
no worries I didn't even get a ping for some reason :P
also I don't mind pings, I'm a madman who has all notifications enabled for #math-and-physics, #ecs-dev, #math-dev, this thread/topic and some other channels probably
@cunning gust
I should probably think things through more
that's probably not gonna happen with adhd unless you get it treated
I'm medicated
Probably not enough, but my psych advised against increasing the dose since I'm starting a new medication rn
I've been trying ways to make the API in the collider context PR less ugly, I managed to at least make wrappers like AabbContext and ContactManifoldContext to remove the entity arguments from the methods and make you not have to do &<Self::Context as SystemParam>::Item<'_, '_>
fn aabb_with_context(
&self,
position: Vector,
rotation: impl Into<Rotation>,
context: &AabbContext<Self::Context>,
) -> ColliderAabb;
well, considering that i can feel it through text it's not helping much, yeah π₯²
aabb has rotation?
that's the rotation of the shape whose AABB you're computing
This is a method on Collider (or the AnyCollider trait specifically)
is there a way to invert the collisionlayers? i want something to collide with everything except one, and adding each layer to collide with every time i add a new one is kinda messy.
If I use spacialquery's shape_cast with a max distance of 0, does that just check if the shape can fit in the space?
I've found something weird. When I set the velocity of an entity and it moves, it doesn't take it's children with it, but it does when I set it's transform π€
AYWGQUIFGUAIUAWIGFU
I JUST TRIED TO GO BACK TO AN OLD GIT VERSION
BUT I WASN'T TRACKING THE FILE FOR THE MODULE WITH THE PLUGIN FOR MY CHARACTER CONTROLLER
THAT
THAT WAS A DAYS WORK
ALL OF TODAY
i
i
oughhh
whelp, time to restart :/
and this is why you don't develop while tired π
if i wanted to generate something using physics in a loading screen do i put the physics step in a loop?
also is there a way to simulate radial gravity? i want fall towards a point rather than a direction vector.
I might have found something strange about the picking plugin. I was using the basics of the official example and found that after dragging for a while the shape would distort. After adding more and more from the example I isolated the problem to being caused by omitting the AngularVelocity.
Check this clip to see what happens
On the main branch or in 0.2? I can't repro this on the main branch, I suspect it was fixed by this
https://github.com/Jondolf/avian/pull/620
It seems that I can't reproduce it anymore using main, thanks!
Hi is there a way to a ray cast between a Point/Direction and a single entity? (i.e. I don't need the QBVH, etc.) because i'm only considering a single entity
Maybe I can just use cast_ray_and_get_normal from Parry directly?
Using parry methods directly is probably the way to go yea
anyone knows how to avoid having UI nodes subjected to picking functions in the example such as drag and rotate? I have a node with buttons that rotates. Adding With<PhysicsPickable> to the system makes it crash if I drag
@vestal minnow A while back I raised the issue of multiple physics worlds. This is the reason I'm compelled to use rapier (not bevy_rapier, but bare rapier) for my physics. Is there any likelyhood that this would be supported in, say, the next year?
can i add multiple colliders to 1 entity?
Yeah with Collider::compound or with child entities (which isn't strictly 1 entity but they still belong to 1 rigid body)
https://docs.rs/avian3d/latest/avian3d/collision/collider/struct.Collider.html#multiple-colliders
okay thanks :)
On the main branch, there are already some collision hooks (bevy_rapier has an equivalent too). These could be used to emulate at least a very basic form of "multiple worlds" with say a custom InteractionGroup(u16) component, since you could make a custom pair filter hook that skips broad phase collision pairs that don't belong to the same world/group. For spatial queries you can have similar filters with methods like cast_ray_predicate IIRC. Of course this isn't optimal, since the engine is still iterating over all of these entities, and you're simply filtering them without truly simulating each world separately.
I think the path forward for actual multi-world support might involve "physics worlds as entities", where a lot of the current resources like Collisions and SpatialQueryPipeline are turned into components on entities. You could then assign rigid bodies and colliders to these worlds using their Entity IDs. This naturally seems like something that could maybe be encoded with relationships. I think(?) relations could eventually make it efficient to iterate over entities belonging to a specific world, which would help make this faster and more powerful.
Again I can't give any real ETAs, but I'd certainly like to try to experiment with my current idea this year. The filter hooks on the main branch can also give a basic workaround just for "ignore interactions between different worlds".
assertion failed: b.min.cmple(b.max).all()
pub fn grow(&self, amount: Vector) -> Self {
let b = Self {
min: self.min - amount,
max: self.max + amount,
};
debug_assert!(b.min.cmple(b.max).all());
b
}```
im never calling this, this is somewhere in avians code
idk why its crashing
Presumably some value is invalid, like rotation or position having NaN or infinite values for some reason
causing AABBs to be wonky
okay im gonna look into the code causing it
that doesnt seem wrong, or can you find anything?
this is what i think caused it
yep this causes it, when i remove the transform.translation += it doesnt crash anymore
You shouldn't directly manipulate translation for player controllers, that teleports them (eg: into a wall when they walk into a wall) and doesn't change velocity (so a player can have velocity opposite to where they're walking using this method, and have no way to fix it)
hmm so i should implement my own velocity component?
And apply that on top of the default velocity component? probably not, you should probably just use ExternalForce with persistent set to false
ExternalForce also has the method apply_force() that takes a vec3 and applies that force
which is convenient
idk what that all is cuz i havent been using avian for anything except collision yet
An external force applied continuously to a dynamic rigid body.
here's the docs for the component
the description at the top explains pretty well
The engine never changed ExternalForce, so if you clear it or something, it's fine
is that also in 2d?
Probably
An external force applied continuously to a dynamic rigid body.
yeah
I've yet to use avian in 2d but it should be the same
@wispy lance if you're relatively new, just remember for future reference (this'll save you some time) USE .normalize_or_zero() WHEN THE VECTOR YOU'RE NORMALIZING CAN BE ZERO
otherwise you'll get NaN NaN or something
and it'll cause you a headache
alright, thanks i didnt know that xd
neither did I for a while lol
I had quite the bug: moving would slowly rotate you sometimes even with LockedAxes
just because the wrong normalize function?
using .normalize_or_zero() for my ExternalForce fixed it :)
yo how did you ever find out
yep. I was normalizing a vector and then passing it to ExternalForce::apply_force() and it was zero sometimes
Showed my code to some ppl in this very discord channel
they noticed it
oop gtg
before I go, https://docs.rs/bevy/latest/bevy/prelude/struct.Vec2.html#method.reject_from and https://docs.rs/bevy/latest/bevy/prelude/struct.Vec2.html#method.project_onto might be useful to you someday π
A 2-dimensional vector.
for that character controller
i just changed the code to normalize or zero (i didnt change it to externalforce yet) and it fixed the crash lol
are CollidingEntities cleared after each frame?
:D
Wdym?
and what's ColidingEntities (Capitalization makes it look like a struct/enum)
ooh
Looked at the dock, that's an interesting (and useful) component
I think it probably is
and you'd need https://docs.rs/avian3d/latest/avian3d/collision/contact_reporting/struct.ContactReportingPlugin.html
Sends collision events and updates CollidingEntities.
the plugin is in the basic physics plugin i think
or
oh
i found the error
A plugin group containing all of Avianβs plugins.
it was me
ah ok
i just checked and normalized_direction.reject_from_normalized(ground_normal) turned out to be exact same as my old code from unity, so now i can
a few lines of code π
i tested it and it seems like CollidingEntities doesnt clear after a frame?
is that correct behaviour?
It has the entities that are currently colliding with it, they are only removed once they stop colliding
hmm there is either a bug with my code or there is an issue with the component, so i have a sensor detecting players. but once the player leaves it still has 1 entity in the set which is the player?
im printing the length of the set
Once the player is no longer overlapping the sensor at all, that entity should be removed from the CollidingEntities of the sensor, if nothing is removed and you're sure the player is not intersecting it then it could be a bug, yeah
:D
should i record it?
Is there a way to get the equivalent of a ShapeCaster's point1 for a RayCaster?
the num 2 is printed which is the amount of entities in the set.
Show your code?
ok
You can get it as just ray_origin + ray_direction * hit.distance. We could technically store the point for convenience though
I'd say that's probably a good idea, that way I also don't have to recompute it every time I want it
Thanks tho
I'll use that code
i found the bug, its because the entities are being deleted in the collision, therefore never leave it which is why they stay
How do I create a collider from a gltf gahh
I can load the gltf but idk how to turn it into a mesh
The ColliderAABB is updated via an on_add hook, but otherwise if I mutate the Collider the ColliderAABB is not updated automatically?
There's an update_aabb system that updates it
See ColliderConstructorHierarchy and the collider_constructors example
I figured it out yeah
btw
why is distance for shapecaster from the surface and not the origin
it makes a lot of stuff w/ comparing it to raycasts annoying
and it makes doing stuff like checking how far you can go w/o clipping to teleport there damn near impossible for "weird" colliders (eg: capsule)
and another thing, how would I add multiple shapecasters to an entity? would I just have to give it a child entity w/ the second shapecaster?
Child entities, yeah
It's the distance the shape travelled before the initial impact. It was previously called time_of_impact, but people found it more confusing, and since the cast direction is normalized, the time is equivalent to distance
For ray casts it's the same, it's the distance the ray traveled before hitting the surface
The difference is that with ray casts you have a "point" moving along the ray, while with shape casts you have a shape moving along the ray
(ray casts and shape casts can actually use basically the same algorithm for most shapes)
Ahhh, ok, that makes sense
time of flight sort of deal
Out of curiosity, how come the init_transforms systems that adds Transform or Position/Rotation to a newly added RigidBody isn't implemented via observers? Is it because of some ordering constraint?
Also, if i have a collider C1 with P1/R1 (position/rotation), with a child C2 with P2/R2.
Would the child's GlobalTarnsform be based on P1 + P2 ? So P2 should just be relative w.r.t to the parent?
I saw this comment:
```/// Nested rigid bodies move independently of each other, so the Transforms of child entities are updated
/// based on their own and their parent's [Position] and [Rotation].
Mostly because transform propagation wouldn't have run before hooks/observers, though you could probably compute the global transforms manually too
Ah that's also why you're running your own TransformPropagation systems in Prepare?
There's so many tricky details to remember w.r.t to hierarchy, transformPropagation and Sync. Kudos to you to keeping that all in your head π
That's also because gameplay logic might move rigid bodies in FixedUpdate, which means that child collider positions need to be updated accordingly before collision detection
All the Position and Rotation components are global, the local Transform is used to determine the position relative to the parent like normal with Bevy's transforms
The on_add hook for Collider doesn't seem to add a correct ColliderAabb on the entity. Actually i'm not quite sure what it's doing:
let aabb = entity_ref
.get::<ColliderAabb>()
.copied()
.unwrap_or(collider.aabb(Vector::ZERO, Rotation::default()));
if let Some(mut collider_aabb) = entity_ref.get_mut::<ColliderAabb>() {
*collider_aabb = aabb;
}
Doesn't just this set the ColliderAabb value to itself?
@vestal minnow is there a way i can work around CollidingEntities?
Yea, this feels like a bad port for required components. Before required components this weird get or default dance was necessary to batch insert things
The ColliderAaabb is in local mesh coordinates right? not global?
I think I found a bug where:
- I create a RigidBody with Transform (but no Position/Rotation) in FixedUpdate
- I have SyncPlugin set to only do
position->transform - In
PhysicsSet::StepSimulation, I would expect Position to be added on my entity to match the Transform that I provided (-1, 4, 1); but it doesn't seem to be the case. APositionhas been added on my entity (in thePrepareset but its value is different from(-1, 4, 1)
The aabb function called on collider takes position/rotation so they might be global π€
Yes i think i just realized that, I opened a PR to mention this in the docs
Yeah it's global. Also note that it's not necessarily a tight-fitting AABB, it's a collision AABB that is (currently) expanded based on velocity, a contact tolerance, and a collision margin (if used) to account for speculative collision and other things
The details may change with the eventual broad phase rework
For now a tight AABB can be computed by just calling collider.aabb(...) if needed
Thanks that's helpful! My broad-phase check is pretty coarse so the existing aabb should fit my needs
https://github.com/Jondolf/avian/pull/364
will this be added in 0.3?
wondering how to clamp rotation
// Normalize the angle between 0 and 360
angle = (angle % 360.0 + 360.0) % 360.0;
// Clamp to the desired range
angle.clamp(min, max)
}```
chatgpt code
I ended up figuring it out
ok
and that wouldn't work
yeah idk what clamp is tbh
among other things, bevy uses radians
and please don't just ask chatgpt and give that as an answer
i usually use chatgpt for math and it provides the results i want
If I wanted chatgpt's answer, I would've asked chatgpt
but it isnt any different from a human answer most of the time
if someone asks here, it's because they either already asked chatgpt and didn't get the right answer or, like me, don't want to use chatgpt
What specific model are you using and what was the question? That seems wildly terrible for chatgpt standards lol
Is that what you're looking for?
I don't know if maxangularspeed clamps the rotational motion of an object, but if maxlinearspeed is clamoing linear velocity than maxangularspeed should clamp angular velocity
There you go
For sensors, the collision.collision_stopped() seems to never return true, is that possible?
for raycaster/shapecaster it makes sense, for cast_ray/cast_shape it could be a method just so that new people don't get lost
clamping angle is like when your camera looks up/down it stops instead of doing backflips, what does gpt say?
How can I force a certain velocity that ignores external forces ?
I have an infinite friction circle that should stay still on a slope, but instead slowly roles down due to gravity (despite setting the angular velocity in FixedUpdate)
I had a look at most SystemSets and didn't see any that seemed to be appropriate. I tried sandwiching it between StepSimulation and Sync, but it didn't work.
that depends on your end goal
"I have an infinite friction circle that should stay still on a slope, but instead slowly roles down due to gravity (despite setting the angular velocity to 0 in FixedUpdate)"
My end goal is for it not roll on the slope. (without extraneously bizarre methods)
disable gravity for the circle
you can lock its rotation with LockedAxes if you want to prevent rolling (and other rotation)
infinite friction doesn't help prevent rolling, friction is specifically what allows objects to roll instead of sliding
rolling resistance would be what slows down rolling, but it's not supported by Avian (or almost any other engine) outside of using e.g. AngularDamping or just fully locking rotation
I know. I made it infinite friction so that it would only roll.
That's why i said it's rolling down, not sliding
The issue as far as I can tell is that after the system that I run sets the angular velocity to 0, Avian's systems applies gravity and normal force on the circle, resulting in rolling
And there's not an obvious way for me to prevent that from happening (Im reluctant to use LockedAxes)
I thought putting it after WarmStart and before IntegrationSet::Position would work :/.
Tangential forces due to friction (from gravity) cause it to roll. I just want to negate those force (or really, just force a constant angular velocity), but still have gravity because that's what's giving it friction in order to be able to roll
Just triple-checking, are the docs in cast_ray_predicate correct? The ray stops and we return an answer when the predicate returns false?
that's not an end goal, that's an assumption for a step needed to reach the end goal
@vestal minnow are the docs correct here for cast_ray_predicate? https://docs.rs/avian2d/latest/avian2d/spatial_query/struct.SpatialQueryPipeline.html#method.cast_ray_predicate
In my project I have a situation where the predicate returns false, but the spatial_query.cast_ray_predicate doesn't return a hit
A resource for the spatial query pipeline.
Hello, is there any way to set an observer on a specific collider collisions without having to read all events and filter?
just found this, which doesn't seem to work though. Has an alternative been implemented since?
It's a goal + constraints i'm enforcing in order for it to be an acceptable solution.
@vestal minnow
I've looked further into the issue and I found out, that
2D
- The entity is not removed from CollidingEntities once it leaves, if the leaving entity is a Static RigidBody.
- ColldingEntities does not remove the entity, if the entity is deleted with commands during collision.
And I wanted to ask if there are still plans on adding this?
https://github.com/Jondolf/avian/pull/364
is there a nicer way to dynamically enable/disable the PhysicsDebugPlugin at runtime? i want to toggle it on occasionally during dev. looks like i'd have to set all the PhysicsGizmos fields to None or false myself to effectively turn it off atm.
afaik you can't use a run condition on an entire plugin
You can get ResMut<GizmoConfigStore> and use config_mut::<PhysicsGizmos> to get the underlying GizmoConfig, which has an enabled property
ah! thanks
in case anyone wants a quick way to toggle debug on/off: https://gist.github.com/RJ/b1853594ab4dabf6fff3e1d6ab2888df
Thanks that's useful info, I'll see if I can reproduce and fix this later today or tomorrow. I tried it earlier with just a sensor collider and couldn't reproduce the bug, but I'll try with a static rigid body too.
As for that PR, I'm probably not adding it; the way it is implemented in that PR is bad for performance and has overhead even for entities that don't have IgnoredCollisions, and the behavior of that component is something that I think would be better and more flexible to handle by the user with a custom pair filtering hook. A hook for this exists already on the main branch (see #610) and will be available in Avian 0.3
Okay, if there are still issues on replicating feel free to tell me, I can also provide the code to replicate the issue if you want to.
Hey,
I'm new to avian and I do this whole charade just to do something when two specific entities collide:
mut collision_event_reader: EventReader<Collision>,
mut ore_q: Query<(&Transform, &mut ExternalForce, &Ore)>,
mut ship_q: Query<(&Transform, &mut Inventory), With<Ship>>,
for Collision(contacts) in collision_event_reader.read() {
let e1 = contacts.entity1;
let e2 = contacts.entity2;
if ore_q.get(e1).is_ok() && ship_q.get(e2).is_ok() {
maybe_ore = Some(e1);
maybe_ship = Some(e2);
}
if ore_q.get(e2).is_ok() && ship_q.get(e1).is_ok() {
maybe_ore = Some(e2);
maybe_ship = Some(e1);
}
let Some(ore_entity) = maybe_ore else {
continue;
};
let Some(ship_entity) = maybe_ship else {
continue;
};
//do stuff with ore_entity and ship_entity
Is there a better way to do it or are there plans to make a better way to do these kinds of interactions, seems like one of the most common usecases ?
I had already asked that question but the answer was not as flexible as I wouldve liked
With the CollidingEntities component you can at least filter one side and then not have to do the whole e1 or e2 dance anymore π€
How would that look like ?
query.iter_many([e1, e2]) can be handy.
Also you may like https://github.com/rparrett/bevy_two_entities
Okay we need a bevy_two_entities + avian collab
iirc something along the lines of
fn some_system(
mut ship_q: Query<(&Transform, &CollidingEntities, &mut Inventory), With<Ship>>,
mut ore_q: Query<(&Transform, &mut ExternalForce, &Ore)>,
) {
for (ship_transform, ship_collisions, mut ship_inventory) in ship_q.iter_mut() {
for entity in ship_collisions {
let Ok(ore_transform, mut ore_force, ore) = ore_q.get_mut(entity) else {
continue;
};
// Do something with ship and ore properties
}
}
}
How would I use iter_many for this ?
For example #1124043933886976171 message
Something like
let maybe_ship = ship_q.iter_many([e1, e2]).next();
let maybe_ore = ore_q.iter_many([e1, e2]).next();
if let (Some(ship), Some(ore)) = (maybe_ship, maybe_ore) {}
That two_entities crate is pretty neat actually ... I think I might actually prefer that over CollidingEntities π
yeah this, tho you can use iter_many_mut instead of get_mut shenanigans
Oh right, I forgot we now have iter methods instead of just get_many π€
it'd be this I think
fn some_system(
mut ship_q: Query<(&Transform, &CollidingEntities, &mut Inventory), With<Ship>>,
mut ore_q: Query<(&Transform, &mut ExternalForce, &Ore)>,
) {
for (ship_transform, ship_collisions, mut ship_inventory) in ship_q.iter_mut() {
let mut iter = ore_q.iter_many_mut(ship_collisions.iter());
while let Ok((ore_transform, mut ore_force, ore)) = iter.next() {
// Do something with ship and ore properties
}
}
}
for iter_many you can just use a for loop
error[B0003]: src\combat\knock_back_system.rs:28:33: Could not insert a bundle (of type avian2d::dynamics::rigid_body::forces::ExternalForce) for entity 30v1#4294967326 because it doesn't exist in this World. See: https://bevyengine.org/learn/errors/b0003
stack backtrace:
force.persistent = false;
if let Some(mut entity_commands) = commands.get_entity(*entity) {
entity_commands.insert(force);
}```
im checking if it is there???
Yeah some code to reproduce this would be nice, I haven't managed to reproduce it with any collider setup where I despawn entities
okay, so code to reproduce with the entity deletion, the other one is something you could reproduce?
No I haven't reproduced this with any setup I've tried, to be clear
So code for anything that reproduces CollidingEntities not getting cleared correctly would be good
okay
i have a sort of spring system that applies a torque onto a player controller, but i need it to scale with player mass, and hence angular inertia, whats the best way to achieve this? (where the linear force solution is to multiply by the mass)
let upright_torque = (axis * (angle_radians * upright_s.upright_strength)) - (angular_v.0 * upright_s.upright_damper);
torque.apply_torque(upright_torque);
Just randoly hit this, looks like it's possible for the AABBs to be degenerate under specific circumstances? I'm using convex hull colliders
I fixed it by just tweaking the geometry, and it went away
Hmm, the constructors like Collider::convex_hull return an Option (should maybe be Result) so if it's degenerate then I think it should return None. If you're using ColliderConstructor or ColliderConstructorHierarchy, it should also skip these invalid colliders. Maybe it's not entirely reliable though π€
the convex hulls are computed by Parry
I think you'd need to just multiply by the total angular inertia tensor, which is stored in ComputedAngularInertia. However, this value is in local space in 3D. If you want the global version, you can use GlobalAngularInertia (updated once every physics step), or compute it manually with computed_angular_inertia.rotated(rotation).
Then you can just apply it like this
angular_inertia.tensor() * upright_torque
(If this is 2D, just using ComputedAngularInertia directly is enough)
We should probably have a way to just apply acceleration directly, without having to deal with mass properties
kinda like Unity's ForceMode
Hello, this is a feature I wish I would have in other game engines (Unity, Godot) but which is always lacking.
Is it possible to have subtracting collision shapes in Avian ?
The standard collision detection algorithms rely on convexity, and subtracting shapes tends to very easily introduce concavity. I think colliders for these shapes would need to be mesh colliders or use convex decomposition to break them into many smaller convex parts.
So no, subtracting collision shapes isn't supported, but if you can create a mesh for the resulting shape, you could make a collider for it. Subtracting shapes typically requires CSG (Constructive Solid Geometry) with boolean operators, which is not supported by Avian, but there are some other Rust crates for it.
(Side note: this is actually supported to some capacity by NiseVoid's SDF colliders as well, but that's currently only in their project and doesn't integrate with Avian's own Collider)
Actually planning to rework the SDF collisions to better support cases like this. Subtracting creates bound SDFs which can cause ghost collisions, there are some ways to fix them (at the cost of infinitely thin SDFs no longer being detected as collisions, which I'd argue is probably physically correct π
Also gotta try implementing those arbitrary SDF-SDF collisions, once I get to things like object placement, having only spheres and capsules against arbitrary SDFs isn't gonna cut it anymore
Could be a numeric stability/precision issue when applying transforms to an existing hull and then calculating the AABB?
@vestal minnow ive sent you the code examples to replicate the 2 bugs. I dont know if ur dms are open, i can send it in here too if you want.
thank you! i was just using the mass number before but ill use that now
well i just tried angular inertia, but something happened and now the forces are pretty much zero, but that's probably to do with my suspicious method of getting the torque, oh well mass worked fine anyways ill revist it later
How come the order of sets is BroadPhase, NarrowPhase, Solver, ReportContacts?
Wouldn't we want to compute contacts AFTER the physics have been updated in Solver?
i.e. Solver, BroadPhase, NarrowPhase, ReportContacts
How do you solve contacts if you haven't detected them yet?
Ah i see, I was only thinking about dynamics.
But that means that the ColliderAabb after Solver has run is 1-tick old compared to the actual collider position, right?
Yes I think so
But not from the POV of collision detection since the AABBs are updated before that
Also, can ColliderAabb be 'rotated'? or will their axes always match x/y/z
It's an AABB so no, an oriented bounding box would be an OBB
Should I make a PR to make Dir public? (the wrapper around Dir2/Dir3)
I need to create some for the SpatialQuery, but it doesn't seem exposed
I would approve a PR for that if there's a use case, yeah
the Dir name is a bit questionable though, sounds like a directory
My usecase is that I'm building a helper crate for Avian that makes use of SpatialQuery, so it would be convenient.
I can just stick to
#[cfg(all(feature = "2d", not(feature = "3d")))]
use {
bevy::math::Dir2 as Dir,
};
#[cfg(all(feature = "3d", not(feature = "2d")))]
use {
bevy::math::Dir3 as Dir,
};
that's fine too
yeah a PR would be good if you want to make one
Direction might be better for clarity and consistency with the other feature-dependent types like Vector, but I believe it conflicts with Bevy's Direction (text direction iirc) type
eh Dir is actually in Bevy too, just not in the prelude
Bevy's Direction should really be renamed to TextDirection
So Dir?
Also it would be nice if there was a cast_ray_predicate api where I could use the result of my computation inside the predicate.
Something like
cast_ray_predicate<D>(..., predicate: &dyn Fn(Entity, RayHitData) -> Option<D>) -> Option<D>)
where the predicate has the Entity + HitData and can return any arbitrary data D. If it does return D, then that gets propagated as the output of cast_ray_predicate
actually I can just modify some external variable inside my predicate
If I have line segment that's rotating quickly from one end, what would be the most effective way to find the first point it would contact within a frame? Would it be to just sweep a ray with small angle changes?
i'm stumped by something - does avian rely on some of the plugins in DefaultPlugins?
if i set my plugins like so:
.add_plugins(
DefaultPlugins
.set(AssetPlugin {
file_path: "../../assets/models".to_string(),
..default()
})
)
then it works as i expect. but if i replace the above w/ this:
.add_plugins(MinimalPlugins)
.add_plugins(StatesPlugin::default())
.add_plugins(AssetPlugin {
file_path: "../../assets/models".to_string(),
..default()
})
.add_plugins(ScenePlugin)
.add_plugins(MeshPlugin)
then it doesn't work. in both cases, i am adding avian like so:
app.add_plugins(
PhysicsPlugins::default()
.build()
.disable::<PhysicsInterpolationPlugin>(),
);
any ideas?
oh and i'm using a fixed timestep:
app.insert_resource(Time::<Fixed>::from_hz(SIM_HZ));
Does it give an error or is it just doing nothing? If you're using Transform then you might need TransformPlugin
We have a test that just uses this plugin setup currently, and it works
app.add_plugins((
MinimalPlugins,
TransformPlugin,
PhysicsPlugins::default()
.with_length_unit(0.5)
.build()
.disable::<ColliderHierarchyPlugin>(),
#[cfg(feature = "bevy_scene")]
AssetPlugin::default(),
#[cfg(feature = "bevy_scene")]
bevy::scene::ScenePlugin::default(),
))
(disabling ColliderHierarchyPlugin shouldn't be required, it's just unnecessary in that test and doesn't work if HierarchyPlugin is disabled)
This sounds like a "non-linear time of impact" query. Parry (Avian's current collision detection lib) has a cast_shapes_nonlinear method for this, but there is no corresponding spatial query that queries the world for hits since it's pretty expensive. We also don't currently have an abstraction around it for Avian, but it's possible to use Parry's version directly, passing in collider.shape_scaled().as_ref() for the shapes.
What you could technically do is to use e.g. SpatialQuery::aabb_intersections_with_aabb to get all of the entities inside the area taken by the line segment when it does a full rotation, and then call cast_shapes_nonlinear for each of those. The details depend on what exactly you're doing though, and how accurate/robust it needs to be
What you're doing actually seems very similar to the swept CCD stuff in Avian, but you're predicting future motion instead of sweeping from previous positions to current positions
Ah actually I can't do that because my FnMut gets coerced into a Fn...
Do you have thoughts about this?
I don't think that info is available since the filtering happens before the raycast is computed for a given shape IIRC
yeah
// src/spatial_query/pipeline.rs#L885
if self.query_filter.test(*entity, *layers) && (self.predicate)(*entity) {
f(Some(iso), &**shape.shape_scaled(), None);
}
Actually I just need whatever data i computed inside the predicate, I don't even need the RayHitData
I suppose I could use interior mutability? something like RefCell can still be mutated inside a dyn Fn maybe
Oh so you want the ray cast to return data computed inside the closure π€ This is more like ray_hits_callback which takes an FnMut
The callback is just called for hits in arbitrary order, it's not guaranteed to give the closest hits first
Yeah but ray_hits_callback doesn't have the order guaranteed
The other option is to just use ray_hits and sort by distance
I think that's fine too actually
Also I have an example where i add RigidBody + Transform to an entity, but Position/Rotation don't get added. Should I try adding unit tests for it in avian?
Actually it looks like you already have plenty..
Thanks, I'll take a look at those functions. From looking online, it looks like another solution is to do some raycasts and then look for the closest vertex to the collision point. Not perfect but maybe that's good enough for my use case. I guess to get the closest vertex, would it make sense to have some sort of ClosestVertex trait that the shapes the game will use can implement?
That sounds like point projection (project a point onto the surface of a shape to get the point closest to the input point). There's Collider::project_point for this
The resulting point is not necessarily a vertex, it could be on an edge or face too depending on the shape. But that may be preferable here anyway? ClosestVertex also wouldn't work for e.g. spheres or capsules since they have no vertices
I intended to do this earlier, but here's the 0.2.1 patch finally
@wispy lance This should also fix the bugs you had with CollidingEntities
thank you :)
Anyone know why this entity wouldn't move with Avian3D ?
commands.spawn((
RigidBody::Dynamic,
Mass(70.),
LinearVelocity(Vec3::ONE * 10000000.),
Collider::capsule(0.2, 1.8),
Transform::default(),
));
Just tested and it does move. Are you sure you have PhysicsPlugins? And of course that has no mesh so you won't see it unless you're rendering it with e.g. PhysicsDebugPlugin
I feel like an idiot, thanks
So I was thinking, for #632 (PhysicsPickingLayers) it would make sense to include a whole SpatialQueryFilter instead of just layers, right? So it would be PhysicsPickingFilter instead
Currently SpatialQueryFilter is just layers + excluded entities, but it'll likely have some more things like filtering by rigid body types and maybe custom predicates in the future, and I imagine it could be nice to have the full filtering options for picking too
cc @formal galleon, I can implement and push these changes to your PR if that sounds reasonable
sounds great! π
The LayerMask can only express OR? i.e. bit 1 | 2 means interact with an entity that has layers 1 OR 2?
Is it possible to express AND? (interact with entities that are part of layer 1 AND 2)
Also, it seems like in cast_ray_predicate my predicate is called on entities that should be excluded by the filter. Or are entities with no CollisionLayer considered to belong to all layers?
I see "Colliders without this component have all filters and can interact with any layer." in the docs; it's not clear if they also have all memberships
It's currently just OR. You could manually filter the results with a custom predicate to emulate AND behavior if you wanted to, but a default behavior of AND on the other hand wouldn't let you emulate OR behavior since AND is more restricting.
We could theoretically make this configurable though. I saw Rapier has an open PR with something very similar. I would be open to this if the perf impact is negligible
Colliders only belong to the default layer by default, which is the first bit in the layer mask
same as Box2D and Rapier now iirc
It's strange then; i'm doing filter.mask = LayerMask::from(31 as u32); and i'm still getting collisions with entities that don't have the CollisionLayers component
Isn't that 0b11111 in binary? Which includes the first bit, i.e. the default layer
If you want the 31st layer, that's 1 >> 31 I think
oh duh..
1 << 31
yeah, last one
1 << 30 is 31st
yep i wanted the 32nd layer; i'll do the AND logic in my predicate, thanks
wasn't layermask doc supposed to have it explained anyway
oh, it does have it
@vestal minnow now that first layer is default, i think it'd be a good idea to change FIRST_LAYER to DEFAULT_LAYER in docs
Hmm I'm not sure, it does already say in the comment that it's the default layer, and it's also good to emphasize that it's specifically the first layer, especially since that code snippet is kinda intended to teach how bitmasks and bitshifting work
you could just add SECOND_LAYER
i would like to generate colliders from meshes (meshes from .glb files) and then serialize them to disk (so i can load them in the future w/o needing access to the meshes). is this possible to do w/o starting a full blown bevy App?
i'm thinking i'll put this in a build.rs file. starting up an app and having it execute a single system and then exit should work fine but seems like a lot of machinery
tho i guess i'll have to ask this same question about bevy's mesh and gltf plugins
so maybe less work to just run it thru the whole rigamarole
There are methods like Collider::trimesh_from_mesh, and colliders should also be serializable, so maybe?
I haven't tried that sort of thing myself yet
i feel like i'm not the only person to want to have colliders w/o having meshes
like to run a headless simulation that is viewed by a remote client (that uses the meshes)
which is what i'm doing
colliders should also be serializable
i assume you mean meshes here
Collider should also support serde Serialize/Deserialize afaik, at least it implements the traits
#[derive(Clone, Component, Debug)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[require(ColliderMarker, ColliderAabb, ColliderDensity, ColliderMassProperties)]
pub struct Collider {
shape: SharedShape,
scaled_shape: SharedShape,
scale: Vector,
}
You might want to serialize just the Parry shape though I guess
yeah i'm fairly certain this'll all work fine just thinking about the most straightforward way to do it. i'll ask elsewhere about whether bevy's gltf loaders are useable outside of an App. if i can write a build.rs that loads a gltf, and extracts a mesh, i should be able to run that collider fn you mentioned (or a similar one) to make a collider, then save it to disk
@rocky seal it seems that @ethereumdegen has done this in some way btw #1278020494687338629 message
oh wow nice find, thanks
I vaguely remembered seeing that a while back, somehow still found it with Discord's search lol
discord's search function is unfairly maligned imo
Hello there, I want to add 6 ShapeCaster to a cube shape(entity) so it would shoot out of each side. When I try to add multiple ShapeCaster I get duplicate error. Example of current code:
commands.spawn((
Name::new("red_cube"),
RigidBody::Dynamic,
Collider::cuboid(1.0, 1.0, 1.0),
AngularVelocity(Vec3::new(2.5, 3.5, 1.5)),
Mesh3d(meshes.add(Cuboid::from_length(1.0))),
MeshMaterial3d(materials.add(Color::srgb_u8(255, 0, 0))),
Transform::from_xyz(0.0, 2.0, 0.0),
ShapeCaster::new(
Collider::cuboid(0.2, 0.2, 0.2),
Vec3::ZERO,
Quat::from_rotation_y(0.),
Dir3::Z,
).with_max_distance(2.),
));```
got my help from here: #general message
Ah yeah, in this case I think I actually want vertices because my use case is a stiff rope that wraps around the terrain (like Worms: Armageddon's ninja rope). So as it wraps around a collider I only want to create new hinge points at vertices.
Does Avian Physics provide cross platform determinism
Trough a feature to use libm instead of std I think
Yeah it should in theory be cross-platform deterministic with the enhanced-determinism feature enabled
There's also a test and example that verifies this for 2D, with a scene that has collisions and joints
There may still be some issues around determinism when used with networking though, or at least it's trickier to get fully working
I mean technically it is deterministic with networking, it's just that some of the stuff involved with networking like rollback or receiving things out of order can mess with things like warm starting and sleeping
Thanks for the info. Iβm doing some research to see which physics engine I should use for my bevy project and Iβm deciding between Rapier or Avian. And since it is a multiplayer physics game Iβd like to get consistent physics.
I believe some of the current issues may be related to the order in which entities are spawned (or the order of Entity IDs) affecting the simulation, and how that order may not be entirely stable across clients, or something like that. I don't really have experience with networking yet, though I should probably try making some test app to learn about it more
I think Bevy has a way where you can force entities to spawn in a certain order. I mean periwink is the maintainer of light year so he has experience with networking
Yeah periwink has been experimenting with these things with Avian and Lightyear, and has encountered these determinism issues causing rollbacks
I'm not sure if bevy_rapier is still entirely deterministic either, this PR has been open since 2022
https://github.com/dimforge/bevy_rapier/pull/233
and that's without networking and with a stable entity order
Avian should at least be deterministic without networking stuff (and if not, please make an issue!)
@grizzled depot may be more up to date about determinism on the bevy_rapier side though
I think that issue is still relevant, thatβs an interesting problem I look forward to dig into, but I didnβt yet.
Random thought but I don't love how this means that libm operations are now used over std everywhere. For things like rendering, you rarely care about bit-per-bit cross-platform determinism, and it can have a pretty significant cost. It would be good to use cross-platform deterministic math only where it is relevant, like in specific places in physics
I guess more specifically I think that enabling enhanced-determinism for Avian shouldn't mean you get slowdowns elsewhere
I think we should vet which Glam methods aren't cross-platform deterministic (this should be in the Glam docs!), and use software implementations only for those in Avian
And lint against using the non-deterministic methods maybe
Hello, the kinematic character controller has a collision solution that works pretty well but I think it says somewhere that it has some problems.
Right now it works fine except that when jumping when hugging a wall there is a high velocity loss even though I have Friction::ZERO.
Is there a work around or an alternate system someone knows about ?
something like collide and slide or smth
Can you "recalculate" a collider when a mesh changes vertex positions? I have a cylinder that slides over a terrain (a plane made of triangles). I added a collider with ColliderConstructor::ConvexHullFromMesh. It works well, but part of my game involves dynamic modification the terrain mesh - and so then the collider needs to be updated to match.
The only thing I can find that is similar is this open issue: https://github.com/Jondolf/avian/issues/455, which makes it sound like it's not possible ... is there any other way to do it? Thanks!
wouldn't you just generate and insert a new collider?
Yep, thanks! I just tried that and it works, but I'm guessing it will be pretty sub-optimal: I was kind of hoping I could modify the collider vertices the same way I modified the mesh vertices without recalculating everything. Though, I don't have much geometry so performance is not an issue. Thanks.
Slide-y question: I have a flat disc that slides along a low-friction plane3d that is subdivided into a bunch of triangles. Even if the plane is flat (all Y values are 0), the Collider::cylinder will collide and get stuck on the triangle edges - instead of smoothly gliding over the surface. I tried upping the CollisionMargin, but it doesn't help. I could model the colliders as spheres (like a roomba) but are there any easier tricks to stop hitting flat edges?
@vestal minnow I ended up implementing closest_vertex and had it just fall back to project_point (solid=false) for Ball/etc. Should work for my use case, though not sure how useful it would be to have in parry.
this is a classical issue with any collision engine. it's catching on the side of each of the ground's triangles. I think making the collider a sphere is a good workaround. if you really require the cylinder shape, you could look into modifying the Contact somehow to only allow collision normals which align to the triangle normals
Try using TrimeshFlags::FIX_INTERNAL_EDGES to see if that helps
there should be a _with_config version of whatever you're using to construct the mesh collider
another approach is to use raycasts and forces to float your collider above the ground
Im getting a bunch of conflicting implementations of trait errors trying to run the avian demos on both rust 1.83 and 1.84.
How do you run the demos?
Works for me with just cargo run --example INSERT_EXAMPLE_NAME
(on both Rust 1.83 and 1.84)
Does it say which trait?
if it's like Component or something like that then you most likely have conflicting Bevy versions somewhere
ah, I looked at my cargo run being ran when executing it via vscode's rust analyzer plugin run button and it was running:
Executing task: cargo run --package avian3d --example dynamic_character_3d --all-features --features 3d --features default-collider --features bevy_scene
im not sure why its running with all of these extra arguments though...
Figured it out.
In order to have cargo play nicely when running the demos for this project, you need to have --all-features set to false in cargo analyzer and you need all targets not enabled. so
// "rust-analyzer.cargo.features": "all",
"rust-analyzer.cargo.allTargets": false,
in the settings.json for rust-analyzer.
Still no real progress there on my side unfortunately, my current primary objective is to add proper timers and diagnostics to make profiling easier, add better benchmarks, and finish some collision detection optimizations and improvements I've been working on
aevyrie implemented spatial hashing for big_space though, which may help with a physics integration
Something in avian 0.2.1 is breaking the way my ColliderAABB is computed. My flow:
- after
Solverbut beforeSpatialQuery, I update thePosition/Rotation/Colliderof an entity that is a child of a parentCollider(the child entity is not a RigidBody, though) - in
PostUpdate, I use a gizmos to display the child'sColliderAABB(which is updated with one-frame delay inupdate_aabbswhich runs inBroadPhase(beforeSolver) - I use the normal sync plugin
It works fine in 0.2.0 but in 0.2.1 my ColliderAABB is in a different position than expected
The only PR which seems to be related is https://github.com/Jondolf/avian/pull/620
(Also do you use PreviousTransform to avoid change detection issues with interpolation?)
Avian physics feels soooo good⦠was so much fun to use for my little experiment project.
i'm looking up SpatialQuery but the example only deal with the returned collision shape.. how do i also get other bundled items along with that?
If you mean querying for components of entities returned by spatial queries, you can just have a separate Query and use get. I do have this prototype of an abstraction that would let you query for components directly with SpatialQuery though #1124043933886976171 message
so both Query and spacial query and find the query item that way
yeah
ok, i'll give it a go
Depends on the number of actual collisions and how complex the shapes are. There was a demo a long time ago with over 15 k colliders at over 60 fps, and I would expect performance to also have improved since then, but the colliders in that scene were flying around in space, so there weren't that many active collisions.
But yeah, Avian is not particularly optimized yet, and I would typically expect bevy_rapier to outperform it for collision-heavy scenes right now. It is something I am working on to improve though
do make sure you're running the app in release mode or with optimizations enabled for performance intensive things though, that can have a huge impact over debug mode
what does the path to increasing performance look like? Thinking if there's anything I can avoid doing that may help squeeze out a little more performance
On the user's side, probably stuff like
- try to keep triangle mesh colliders simple, or replace them with convex hulls or use convex decomposition if possible
- reduce
SubstepCountfrom 6 to 4, or whatever still gives good enough results - reduce
Time<Fixed>frequency from 64 Hz to something smaller like 50 Hz, and interpolate visuals to keep them smooth
On Avian's side
- add a contact graph and rework contact management (largely my current focus)
- simulation islands (half-implemented, blocked on the contact graph)
- rework broad phase to use BVHs, with separate trees for dynamic, kinematic, and static bodies, and for sensors probably
- rework solver to access body state more efficiently
- AoSoA SIMD constraints
- generally reduce allocations, branching, data fetching, etc. and increase parallelism
and a whole lot of other miscallaneous optimizations
yeah, I've been experimenting with substepcount 1 π
haha yeah that could maybe be alright for simple scenarios where you don't have any complex interactions (like chains, vertical stacks of objects, etc.)
Does reducing fixed update rate really help with perceived performance ? From my (limited real-cases) experience, it was leading to lag on every frame where itβs computing, so if youβre not combining that to a background execution itβs quickly limiting π€
It doesn't reduce the cost of running a step of physics, but it does leave more headroom so that you're not running several steps per frame, which can help avoid death spirals and lag spikes
Would simulation islands also let us efficiently do sleeping without archetype moves? π€
Also another optimization that might be worth it in some specific cases would be trying to deduplicate large colliders, which would require the assets thing ... Probably not a high priority tho, and some of the weird legacy things bevy_asset v2 inherited that might still backfire
I imagine we might want to keep the Sleeping marker still
could make it a SparseSet component, though that would impact query perf afaik
Collider already stores a SharedShape which stores an Arc, so it shouldn't clone shape data if you clone a collider
Might not apply to your SDF collider type tho
Yea the main issue there is that we can't really facillitate that in any way. If we had assets then it could be deduplicated at an asset level instead of generating duplicate colliders over and over
But again that is somewhat of a niche usecase probably
yeah
My new SDF stuff relies entirely on assets at least ... Or well, technically assets + a resource to contain an optimized version of the tree for calculations
Haven't even started on reworking the collision code tho 
@vestal minnow Master Jondi, I have a little bit of an issue with your crate, so I am building a dynamic scene that stores also the player. Player has physical components, since his body is dynamic, he has multiple components being inserted, I dont mind filtering them when building the scene but do you know where I can check which components are automatically inserted with a dynamic rigid body
Are avian joints mutually exclusive with transform propagation? I.E: can you have a joint thats a child of something, and still connect as a joint to something thats a fellow child of the parent or is outside of their parent child hierarchy?
im asking because Im trying to support gltf models for my physics sim but them being multi-primitive is causing issues with rapier
I think joints currently don't care about the hierarchy, so you can have them anywhere
These components are currently added via required components. I intend to make the force and impulse components optional pretty soon though, and a lot of the PreSolveX components will likely be removed after some changes to the solver in the future
Then there's also Position and Rotation which are automatically inserted by a system. They should really use required components too, but it caused some problems so I left it for the time being
anyone get bugs when they try to rotate something and it starts scaling and flipping like crazy?
is this because of interpolation settings?
How are you applying the rotation?
Scaling and flipping implies you're making the rotation denormalized, make sure you're not adding rotations with addition + and instead use multiplication * or associated methods
yeah i'm using rotate_local for rotation
hm I tried using ColliderConstructorHierarchy::new(ColliderConstructor::TrimeshFromMesh) and I was getting stuck on the geometry, like I would jump on my rock and couldn't move (using tnua)
commands.spawn((
SceneRoot(object_handles.0[&object.object_type].clone()),
transform,
RigidBody::Static,
ColliderConstructorHierarchy::new(ColliderConstructor::TrimeshFromMesh),
));
this is the gltf file I was using
it works fine if I load the mesh/standardmaterial separately and use just ColliderConstructor::TrimeshFromMesh
Not even remotely complete, but I have a very early prototype for multiple physics worlds using @surreal rune's new component indexes π
Here, the blue and red boxes are assigned to different PhysicsWorld entities. Each world has its own Collisions, SpatialQueryPipeline, and so on as components instead of resources. This lets people simulate groups of bodies separately, running in parallel where relevant/possible, keeping data structures localized to just the relevant entities. This could perhaps even be used for a big_space integration, with a separate world for each island.
Configuration is still shared (gravity, time step, solver parameters), and the vast majority of systems still operate on all entities across all worlds, but we could add more per-world options and flexibility as needed.
Some things I'd still like to try:
- Currently, all worlds are still run at the same time. It could be cool to support running specific worlds individually, possibly even at different time steps.
SpatialQuerycould either query all worlds, just the main world, or a given world. For querying specific worlds, we could also have aSpatialQueryByIndexto mirrorQueryByIndex.- It could be useful to be able to share static bodies across physics worlds.
I also need to profile to see if there's any meaningful performance impact compared to before. So far it looks fine
Fun side note: Just based on the description in Unity's docs, Unity Physics' implementation for multiple physics worlds sounds quite similar. Entities are assigned to worlds based on PhysicsWorldIndex.Value, and entities in different physics worlds are stored in separate ECS chunks, kinda like our archetype-level grouping by value. And the PhysicsStep is also shared across worlds
That's so cool! I have some more changes I need to make before I think the feature is fully complete, and I reckon there's a good amount of room for optimisation, but it's awesome you're able to use it already!
Yeah, I really like how straightforward the component index stuff is to use, it wasn't too bad to implement this (so far)
There's a few mildly annoying quirks I ran into, like how at changes the query filters for the Query signature, but nothing too bad
Yeah I wanted to make sure With<C> was always included (since you need to read that value I think that makes sense), but I didn't want users to have to type it every time
Tradeoff for sure
I pass the query returned by at to a helper method in one place and I need to add this extra () to make it work π
aabbs: Query<AabbIntervalQueryData, ((), With<PhysicsWorldId>)>,
Oh yeah that's ugly
fyi @reef owl, for multi-world support ^
hopefully I should have some version of this ready for Avian 0.3 / Bevy 0.16, assuming the component index PR gets merged
currently I'm mostly just prototyping though, and testing the PR with it
Hooray!
It's good to get this testing done before the PR is merged though! It may be the deciding factor on whether it's worth including at all
Are there any examples of setting up ragdoll on skeletal mesh?
Yeah, this is exactly what I was envisioning for big space. There is likely still some bookkeeping to do, but the gist of it is that entities in the same partition share the same physics world, and the same physics origin. Because partitions can split and merge, you would also need to be able to move the physics origin around independently of bevys transform, which is what worries me a bit.
Not to mention there would be a different physics transform for all these entities, in "partition space". That's why I was leaning toward a physics integration that is less tied to bevys built in transforms.
If I change the linear velocity of a RigidBody in Update, it wonβt take effect until the next FixedUpdate (when avian2d solves it), right? Also, Iβm new to Bevy/Rust, whatβs the best way to read the docs/source to find this kind of information on my own?
it'll keep adding up until fixed update, yeah
Still a bit WIP, but I have a working implementation for physics diagnostics (perf timers and counters)
the narrow phase and constraint solving are clearly pretty huge bottlenecks atm like expected
Heh, that looks familiar
Aesthetics may have been inspired π I've been meaning to add this for a while though, I need this for profiling + it's useful for more directly comparing performance to e.g. Box2D which has a very similar solver and similar timers
added some color
Sorry, but I've got a patent on using transparent rounded rectangles. That was a true innovation.
I'm afraid the patent isn't valid, I have a lot of translucent rounded rectangles on my old website from years ago
that website isn't even hosted on the internet anymore but we can ignore that, just trust me bro
ship.0.rotation = Quat::from_rotation_z(
Rotation::radians(ship.0.rotation.to_euler(EulerRot::XYZ).2)
.nlerp(Rotation::radians(angle), 0.25)
.as_radians(),
);
is there a way to simplify this? i want the ship rotation to also affect its children, if i understand correctly changing Rotation doesn't affect its children, no?
I've not found a built-in way to apply torque between two entities (e.g. applied to a RevoluteJoint from a motor). Am I right that's missing? Is it planned? And is the workaround to apply external torque to both but and reorient it every update to ensure it's aligned with the correct axis?
Yeah joint motors aren't implemented yet, but they are planned. Manually applying torque like that should be fine for now
Thanks. Are you thinking they'll be properties of the joints or separate entities?
Likely a property of the joint since the implementation is heavily tied to it, but it could also be a separate component like RevoluteJointMotor
but on the same entity as the joint either way
Rotation should have a From<Quat> impl which would shorten this to
ship.0.rotation = Quat::from_rotation_z(
Rotation::from(ship.0.rotation)
.nlerp(Rotation::radians(angle), 0.25)
.as_radians(),
);
Changing rotation does affect children if they also have transforms and are not rigid bodies themselves. Rigid bodies currently ignore hierarchies and transform propagation for the most part.
