#Avian Physics
1 messages Β· Page 41 of 1
Subject to change, but yeah it's the maximum linear or angular velocity allowed for the body to start sleeping
If it is above that for even a single tick, the sleep timer resets
The heuristics for this differ a lot across engines https://discordapp.com/channels/691052431525675048/1400290477562921092
I guess I should make a minimum reproduction example because this is some really janky behaviour
If the RigidBody is on a child entity, then that is (currently) subject to wonkiness, bodies should typically be at the root of the hierarchy
The behavior of child bodies is not very well defined or tested atm
Worth noting that it works entirely as expected when the rigid bodies are child entities of something that has an identity transform
My usecase is a hitbox that moves with the player
Not sure if I even need a Rigidbody component on that
The player should have a RigidBody, but the child collider should not
I see, in that case I need to figure out why the child collider without the Rigidbody is causing massive lagspikes on collision (it has a sensor component on it if that matters)
Adding the PhysicsDiagnosticsPlugin and PhysicsDiagnosticsUiPlugin (requires diagnostic_ui feature) may be useful so that you can see where the time is being spent on Avian's side
Thanks! Will see what I can find with it
If you haven't already, it's also a good idea to also enable some optimizations for debug mode, at least for external dependencies
# Enable a small amount of optimization in the dev profile.
[profile.dev]
opt-level = 1
# Enable a large amount of optimization in the dev profile for dependencies.
[profile.dev.package."*"]
opt-level = 3
or alternatively run in release mode
optimizations can improve perf like over 100x in a lot of cases
Already did that, I am also on a fairly powerful machine so that should also not be the issue
was this in the simulation island branch?
Yup, just for the dev profile
It mostly slowed down the narrow phase since it ran island validation whenever contacts were created or destroyed
Is there an API for "give me the closest distance of this collider to any other collider"? distance only takes in two colliders
Computes the minimum distance separating two Colliders.
I think I can emulate what I need by doing a sphere cast around the collider and then sorting the hit distances so I get the smallest
but is there a more direct way?
Also, there is nothing like aabb_intersections_with_aabb for spheres, right?
ideally I would use aabb_intersections_with_sphere
But looks like parry doesn't support that as far as I can tell
oh I just saw that aabb_intersections_with_aabb doesn't accept a filter, so I'd have to manually go through the collision layers to filter them by hand 
there's project_point if you want the point on each collider that is closest to the given point, but there's no dedicated spatial query for the distance between shapes
Oooh that looks relevant. So can I get the distance to the closest collider by taking the distance of the projected point to the one returned by that method?
You can use it to get the distance to the closest collider from a given point, but it doesn't necessarily help you get the distance from a shape to every other shape
(unless that input shape is a sphere, then you can just treat it as a point and subtract the radius)
Oh I see
hmm
I wonder how important that fact is
If you specifically want the distance from a collider to any other collider, I'd probably just get the entities within some AABB or sphere using aabb_intersections_with_aabb or shape_intersections, and then manually calling contact_query::distance for each of those colliders
The specific application is for calculating an object's exposure
with the rationale that the closer something is to the wall, the harder it is to spot
again, copying the design from Thief
since relevant objects are either humanoid capsules or small grabbable objects, approximating them with a sphere could be alright
I consulted the original C++ implementation again, and they do something much simpler than what I was considering haha.
They just do 8 raycasts in 45 degree increments on the horizontal plane of the object and then sort the distances that they hit stuff at
Oh hey I just saw we have shape_hits
that also looks relevant
nvm that requires a direction 
are intersection callbacks ordered by distance? It says in the docs for hits that they're ordered, but I can't spot such a remark for intersections
How do you integrate layermasks/collisionlayers with spatialqueryfilter?
does the field with a LayerMask in it not work?
wowee 40k messages
mm can we change that bevy_xpbd link in James's original message lol, it has always bothered me after the avian rebrand
Hey @chilly wadi could you edit your original message here #1124043933886976171 message to something like:
An ECS-driven 2D and 3D physics engine by @vestal minnow.
https://github.com/Jondolf/avian
So that it looks correct in this preview ^ and is more up-to-date
done
Thank you!
Is it expected that the debug physics are lagging one frame behind or am I holding it wrong somehow? I played around with the schedule for PhysicsDebugPlugin but that didn't help.
yes the colliders are child entities
I guess this is a case where the global transform has not been updated yet?
I think it might be because the global physics position and rotation of child colliders is only updated before physics, not after
This should be fine for the actual physics, but makes them visually lag behind in debug rendering
Although I suppose for spatial queries it'd also be good to update the global position after physics, so that colliders aren't at an outdated position for things like ray casts π€ hmm
outdated GlobalTransforms are a major footgun in my experience
earlier today I was debugging an issue where forces were applied incorrectly when the framerate was low and more than one physics update ran per frame. turned out I was calculating them based on GlobalTransforms which are outdated by the time the physics schedule runs a second time
The debug rendering is (currently) not using GlobalTransform, it's using Avian's own Position and Rotation components that are used internally for physics
This has the downside that if you're using transform interpolation, you'll also see the debug rendering not always match the visual position, because it's rendering the physics position, not the interpolated rendering position
Which may or may not be what you want, I haven't quite decided which one it should render
This is a bit of a tangent, but @Jondolf could you update the main and bevy-0.17 branches to publish the next expected version, rather than the old version 0.3.0 for the avian crates? As it stands, cargo refuses to honor the [patch.crates.io] section (to use the git version) since other projects I'm using reference the last Avian version 0.3.1 due to semantic versioning being a thing. π
Do you mean changing it to 0.3.1 or the upcoming 0.4.0?
I find the jitter this shows to be super distracting, personally
Whichever you prefer (I suppose 0.4.0 given the amount of changes).
We could schedule the gizmo systems to run after transform propagation in PostUpdate and then read the newest GlobalTransform
Fair, yeah might be better to just render the interpolated version even if it's not technically accurate to the actual physics position
I guess one caveat is that then you can't do debug rendering for entities without GlobalTransform
I'm not sure what the naming convention for in-development crate versions is, but I did what Bevy does and named the crate versions in the repo 0.4.0-dev for now
https://github.com/Jondolf/avian/pull/827
Objective
We should bump crate versions in anticipation for the 0.4 release.
Solution
Bump 'em!
Thanks! I'll try it out.
I think if someone needs it, it should be trivial to add
We could even have the current system behind a toggle
I suppose we could also have some GlobalOrPhysicsTransform helper query data
Also updated the bevy-0.17 branch now
Would you accept a PR for this later?
I think I would, yeah
mm I'm wondering what bevy_rapier does here, I don't think it uses transforms but also I haven't seen people complain
I would suggest replacing the old behavior and if someone still needs it we can add it back behind a toggle
Is that alright?
maybe because the default isn't a fixed time step lol
That's fine
Which branch do you currently prefer PRs against?
Hmm I suppose I need to PR 0.17 anyways
Since that is what I use
Hmm it's possible to retarget to another branch later right? Targetting bevy-0.17 is fine for now but I'd prefer to merge it without a lot of unrelated changes like that
I think I'll merge it tomorrow anyway
Probably. If not I can open a new PR π
Or
I PR against main
And just depend on my own 0.17 fork
That way you donβt have to pollute your 0.17 branch
But I still get to use it
yeah that works too
crawls back to drawing a million fricking ER diagrams for an SQL course
@vestal minnow sorry to pull you out of your SQL hole, but it seems like there are some leaking dependencies from main (bevy 0.16) into bevy-0.17.rc.2 via bevy_heavy: ```
$ cargo tree -i [email protected]
bevy_reflect v0.17.0-rc.2
βββ bevy_heavy v0.2.0 (https://github.com/Jondolf/bevy_heavy.git#7331b214)
β βββ avian3d v0.4.0-dev (https://github.com/Jondolf/avian.git?rev=e05eec460b5e53af18ca46d4f2bc18e49b05c0d7#e05eec46)
βββ bevy_math v0.17.0-rc.2
β βββ bevy_heavy v0.2.0 (https://github.com/Jondolf/
βββ glam_matrix_extensions v0.1.0 (https://github.com/Jondolf/glam_matrix_extensions#c57bc2eb)
βββ avian3d v0.4.0-dev (https://github.com/Jondolf/avian.git?rev=e05eec460b5e53af18ca46d4f2bc18e49b05c0d7#e05eec46) ()
βββ bevy_heavy v0.2.0 (https://github.com/Jondolf/bevy_heavy.git#7331b214) ()
(this is making my build fail with messages like ```490 | fn unit_principal_angular_inertia(&self) -> Vec3 {
| ^^^^ expected `glam::f32::vec3::Vec3`, found `bevy_math::Vec3`
|
= note: expected signature `fn(&collision::collider::parry::Collider) -> glam::f32::vec3::Vec3`
found signature `fn(&collision::collider::parry::Collider) -> bevy_math::Vec3````
(This seems to have been a problem even before the version bump)
While I'm on it, Chris and I both would appreciate an event that is triggered when collider constructors are done
I'll do a PR for that
I think SceneInstanceReady is only triggered when the scene was successfully initialized, right @knotty thicket ?
Is there a reason to have a separate event and not just do On<Remove, ColliderConstructorHierarchy>?
(and check that a collider exists)
How do I use collisionlayers to set something to a certain layer?
I'm not against it, just curious if there's a difference
Yeah hmm main seems to be broken right now, I hadn't run cargo update in a while so I had the old deps cached and didn't notice
I'll see if I can fix that somehow later
Itβs a bit roundabout and not obvious. Plus, I can envision us one wanting to keep the hierarchy component there without removing it so that it has nicer editor/inspector integration
fair
Could you clarify your question? Do you mean where to put the CollisionLayers component (it's on the same entity as the Collider) or how to define layers (use an enum with #[derive(PhysicsLayer, Clone, Copy, Debug, Default)]?
ah heck
Since there is no published RC of avian, every dependency of mine points to the git source
which means that I cannot patch it
which means I have no good way of testing my Avian changes in production
;-;
is chain_3d supposed to have like 3 FPS in debug mode and crash when enabling the debug plugin 
wasn't it on the same entity as the collider?
Or was that changed?
Or did I always get it wrong lol
Also, am I reading it wrong that I'm supposed to enable use-debug-pluginon an example and it should just enable the debug visualization? Because that's not happening for me
You're right, that's a more direct relation. I tend to have them all together anyway. But I'll edit the original post if the OP replies.
Yes it is! I sometimes post about it π https://bsky.app/profile/embersarc.bsky.social
Having the plugin just allows for the possibility. In my experience, you need two steps. My app does this: ```
app.add_plugins(avian3d::debug_render::PhysicsDebugPlugin::default())
.insert_gizmo_config(PhysicsGizmos::default(), GizmoConfig {
enabled: false,
..default()
})
and I change that `enabled: false` -> `enabled: true` (or do it in code) to get results.
The code in the examples only adds the plugin, it seems.
CollisionLayers::new(LayerMask(2), CollisionLayers::ALL_FILTERS.filters),
Oh, that ALL_FILTERS is meant to be an entire CollisionLayers instance. Maybe you mean CollisionLayers::new(LayerMask(2), LayerMask::ALL)?
In any case, I'd recommend making your own enum and relying on the Into<LayerMask magic to help. e.g.:
#[derive(PhysicsLayer, Clone, Copy, Debug, Default)]
pub enum GameLayer {
#[default]
Default,
Player,
World,
Projectiles,
}
``` (or whatever)
and then you can use arrays like so: ```
CollisionLayers::new(GameLayer::Player, [GameLayer::World]),
``` or ```
CollisionLayers::new(GameLayer::World, [GameLayer::World, GameLayer::Projectiles]),
``` -- then you don't need to bring any unrelated constants into your code.
yep
@vestal minnow since I cannot use my Avian fork anyways because it cannot be patched downstream (no RC release on crates io) I submitted some PRs on the 0.17 branch anyways π
ColliderConstructorHierarchy isn't used if you're using a visual editor and have regular ColliderConstructor on reusable assets, etc.
check my third PR π
Sorry π just waking/catching up
Oh no need, I was just mentioning that I implemented the feature you requested π
Also, for PR 2, here's the before:
And here's after:
@tough zealot this solves your issue π
π₯³ thanks so much!
Is the filter for what I should or shouldn't be colliding the object with?
It's for what it should collide with
Yeah, the naming always stumps me the first time. The filter "filters in", not filters out. So in my examples, the player interacts with the world, but the world interacts with other elements of the world and projectiles. The player and projectile never interact.
Is the migration guide on the 0.17 PR up-to-date? I seem to recall that the SyncPlugin was changed
it filters for
It only includes changes that were made in that PR. The sync plugin refactoring was here
https://github.com/Jondolf/avian/pull/785
This should hopefully get fixed by #832
Thanks! I'll need to do an errand but can check back when it's merged.
Seems to work so far. After a test build I see only porting issues on my side of the code. Thanks!
Nice!
@visual sparrow I think I'm going to merge the bevy-0.17 branch in a sec, as soon as CI passes
I'll then test your remaining PRs properly and get them merged, hopefully I can change the base branch to main without messing things up too badly
Right now CI on the bevy-0.17 branch is failing on this, but only on some platforms 
Ubuntu passed, MacOS did not
It's happening consistently too
Hmm, I'm not having a smooth time updating to 0.4. This one is a bit confusing, as I'll show. Err, dunno how to make a thread...
I'm getting a mysteriously unsatisfiable Query after migrating to Avian 0.4.0-dev. In this query: ```
player_q: Query<(Forces, &mut Transform, &ColliderAabb), With<Player>>,
I always get `QueryDoesNotMatch`, even though it does (see pic).
`# invalid player entity 103v2: QueryDoesNotMatch(103v2#8589934695, ArchetypeId(74))`
Actually, I reduced the query down to _only_ `Forces` and it still fails. Wut?
mut player_q: Query<Forces, With<Player>>,
BTW there is no `Debug` impl on `Forces` so it's quite difficult to use `expect()` or `unwrap()` on the result since `Result` wants `T: Debug`. I needed to use ```
let res = player_q.get_mut(input.player_entity());
let Ok(mut forces) = res
else {
let e = unsafe { res.unwrap_err_unchecked() };
warn!("invalid player entity {}: {:?}", input.player_entity(), e);
continue;
};
``` to even print the error π
Hmm π€ yeah if it's a dynamic body then it should work
I think one caveat is that it might not work in an observer right after spawn since some components may not be fully set up yet, not sure
Oh, it's continuously occurring, not just at spawn. But this may be related to another thing I did and had to work around. I used to have a situation where I'd spawn things using RigidBody::Static because otherwise they'd fall through the floor, which was being loaded asynchronously. So I'd change to RigidBody::Dynamic later using Query<&mut RigidBody, ...>.
But that's not legal now, so I was EntityCommands.insert()'ing the changed RigidBody. I suppose that's not kosher?
Reinserting RigidBody should be fine, but I haven't tested it specifically for the force APIs
Well, I just tried not doing RigidBody changes (leaving at Dynamic the whole time) and still no go.
(BTW this is all bevy 0.16.1)
Hmm, maybe try a simpler rigid body setup first to verify that it's working for at least a basic case, and then work from there to try and locate what's causing the problem?
We do have some unit tests in the repo for forces so in theory it should work
OK. My player has two Colliders in a combined collider, as well as child colliders. But I changed all of that to a simple capsule Collider, and same issue. π
(IIRC, I did try this migration a month or two ago and it did work. But things have changed on both sides, Avian and my project, so....)
βΆοΈ OK, uh, it seems that the responsible component is Sleeping, which I add at init time. Heh. I can remove that... but I suppose I was relying on the 0.3.1 behavior where applying forces woke it up.
The heck
Secret form on non-determinism unlocked?
Also, as I've seen reported here before, I am also seeing avian3d::dynamics::rigid_body::mass_properties: Dynamic rigid body 95v2#8589934687 has no mass or inertia. This can cause NaN values. Consider adding a 'MassPropertiesBundle' or a 'Collider' with mass. even though I do just that -- i.e. in this case I was adding Mass(8.0) and Collider::from_sphere(0.1) (for example).
MassPropertiesBundle{ mass: Mass(8.0), ..default() } results in the same warning, presumably because the defaults for other fields aren't sane?
I can use MassPropertiesBundle::from_shape() but then I have to reverse-engineer the Mass I want π
Oh π€¦ It works on linux because it doesn't run on linux lol
#[test]
#[cfg_attr(
target_os = "linux",
ignore = "The plugin setup requires access to the GPU, which is not available in the linux test environment"
)]
fn collider_constructor_hierarchy_inserts_correct_configs_on_scene() {
The problem seems to be just that Name for glTF mesh primitives is now in the form of MeshName.MaterialName instead of just the mesh name, which the test was not expecting
needs to instead use GltfMeshName afaik
Mm this one is sneaky, right now you can't manually insert Sleeping, you're instead expected to use the SleepBody command. I might be able to make inserting/removing Sleeping work too though π€
I see that now in the docs. I'm not sure if that changed from 0.3.1 but the references to SleepBody/WakeBody are a bit far down in the Sleeping docs. Maybe it should be mentioned a little higher up not to manually use this component?
It's new in 0.4 because of the simulation island stuff that overhauled all the sleeping logic, but yeah they could be made more prevalent in the docs. I'll first try if I can just make the old way of simply adding/removing Sleeping work
I should be able to make it run on linux now
ping me when you made it work on macos
I noticed I wasn't able to observe you on Discord later in the evening anymore. Is that also part of the overhauled sleeping logic?
oh heck I believe this also affects APIs like ColliderConstructorHierarchy::with_constructor_for_name
i.e. the name you're meant to provide is in the form of MeshName.MaterialName, which feels very unexpected to me
I would expect "name an object in Blender -> load glTF -> refer to the mesh with the name used in Blender"
yeah agreed 
-# good thing I've never used that feature
IIRC there's a migration note about this explaining the reasoning.
yeah it's this
So we need GltfMeshName?
I guess I'd need to use GltfMeshName here too, but the system shouldn't necessarily be glTF specific I think?
Is there some comprehensive changelog for migrating to the new avian version
Not yet, but there will be later
I think mainly these PRs have breaking changes this cycle
From a networking POV I think the biggest things are that you may need to also roll back the ConstraintGraph resource, and also simulation islands might cause some problems (at least when I was trying them with Nise's stuff) but you can disable them by disabling the IslandPlugin
Don't forget the BreadPhase
:/ Avian doesn't even have bevy_gltf as a dependency
just as a dev dependency
huh
that's crappy design on Bevy's part 
you shouldn't have to know the scene origin asset to get the scene-authored name
yeah
this will also break bevy_rapier's AsyncSceneCollider which has a similar thing
mm perhaps for now we just roll with it, it's a change on Bevy's part, and the MeshName.MaterialName version is the canonical Name for glTF meshes now, even if I dislike it
one could argue that using something other than Name would be unexpected here
welp
BTW aside from the small issues I mentioned (and some I didn't) the update to 0.4.0 went smoothly!
dang, I didn't realize the release was so soon
@visual sparrow ping
(I just updated the tests and stuff to include the material in the name for now)
Neat
I'll try to fix it in a few minutes
Let's see what CI says: https://github.com/Jondolf/avian/pull/833
also, I left my pre-existing PRs targetting 0.17 because I saw that main is still on 0.16
let me know if you want me to retarget them
Merged the bevy-0.17 branch π
Hmm @visual sparrow do you know any git-fu to neatly retarget your two PRs, I tried with GitHub's button but it exploded the diff
I guess worst case just open another PR? There's probably a proper way tho
can do
uhhh wut, the collider_constructors example hangs with the PhysicsDebugPlugin enabled (on main too, not just with your PR)
oh there's an infinite loop sometimes, that's why
updated the PRs to point to main
Can i add an extra component ApplyPosToTransform which would make an entity apply the PosToTransform sync even if it does not have a RigidBody?
Another thing I would need is control to be able to add PhysicsTransformPlugin in multiple schedules, with different controls for each of them.
Would that be ok with you? Something like HashMap<ScheduleLabel, PhysicsTransformConfig>
If config.propagate_before_physics is enabled,then TransformPropagation runs twice per frame?
Yes, so that if you move things near the start of the frame, the global transforms are correct for physics
Should this initial TransformPropagate only run for entities with RigidBody? or Position/Rotation?
No, it also applies if for example you have sensors that are not attached to a rigid body, but are a part of some hierarchy, and some ancestor is moved
In that case you need to propagate down that hierarchy or otherwise the sensor will be at an outdated position from the POV of collision detection
I would tentatively say yes if this would be useful for networking, with the caveat that it feels somewhat weird to me / I may rework this later
What is this needed for? π€
I replicate Position and that's what I used to run prediction and interpolation
PostFixedUpdate:
- TransformToPos
- StepSimulation
- UpdatePredictionHistory (using Position)
PostUpdate:
- VisualInterpolation (on Position)
- ApplyPredictionSmoothing (on Position)
- PositionToTransform
- TransformPropagate
I want to run only TransformToPos in PostFixedUpdate and only PositionToTransform in PostUpdate
I feel like instead of generalizing PhysicsTransformPlugin to work across multiple schedules and with multiple configs, it may be simpler to just make a custom plugin for your networking use case, adding the systems and system sets exactly where needed
I might be able to sync Pos to Transform after StepSimulation in PostFixedUpdate and do the interpolation/correction using Transform
hm yes I could do that since the PhysicsTransformPlugin is fairly small.
The ApplyPosToTransform marker component is definitely useful, though
Yeah, queued that PR for merge now
Thanks! Merged the debug rendering one, and queued the other one for merge
great!
tangential: we don't have any builtin way to create a sphere sector collider, right?
bingo
I should be able to just throw a bunch of points at convex_hull for that, right?
oh heck
sleep well π
Has there been any progress on an off-the-shelf avian 3d kinematic character controller?
What's the standard way to offset a collider's position?
Edit: Collider::compound does what I wanted
Yesn't, the KCC working group did some work on a KCC a while ago, but there hasn't been as much progress recently, partially because people are busy with other things and partially because people want some better collision detection stuff (Peck, which I intend to work on more next cycle)
https://discord.gg/KDSvhq9M
first I need to get the Avian 0.4 release done
i've got two bodies i apply a relative force to (ie, one goes down, other goes up), and i'm migrating to Forces, which i've just noticed has a private global_center_of_mass() which would be perfect for using as the apply_force_at_point world_point on the other body
is that worth giving a public interface or should i have an entire extra query on position, rotation, and center of mass for this one operation
(don't want one of them to spin as much, so it uses regular apply_force; want to make that consistent between them, so i pretend it's an at_point at the CoM)
@vestal minnow does collider-from-mesh make sense without default-collider?
I just ran into an issue without default because the collider cache requires both, but the code that uses the collider cache only checks collider-from-mesh
from a glance, it seems to me like collider-from-mesh should imply default-collider
Hmm although there are some collider constructors that work without default-collider
I'll try gating the collider cache only on nopecollider-from-mesh instead
I'll fix the feature gate instead
There ya go, trivial fix: https://github.com/Jondolf/avian/pull/840
Hello, anyone know the status of a release for avian that would be easier to manage than pointing to git main ?
Also curious if there is a migration guide kinda deal already for things like ExternalForce and others, maybe a little write up or something because idk where to start with the new force api.
Edit: I think applying forces might be rebranded under the forces component now.
check the individual PRs that are tagged for the 0.4 milestone, they contain their respective migration guides for now
I'll try to get the 0.4 release out this weekend or early next week, in the meanwhile you need to use the main branch yeah
yeah it was a classic cargo update 
but this is still good π
Merged
thx!
Hey, I have recently replaced rapier with avian (rapier has some panic bugs) and I have noticed the big decrease in precision of very basic collision detection. Basically the case is like this - a projectile (kinematic circle collder, size 1) hits the rock (dynamic, circle collider, size 30), destroys itself and spawns effect where it did so. Rapier would cause effect to appear roughly about the edge of rock collider as expected. Avian does it it some other places, which appear to be somewhat random, close to truth but not quite as good as rapier. I managed to find configs that help with it slightly - I have disabled entirely speculative margin (SpeculativeMargin::ZERO) on projectile and I am also using observer instead of event reader (i.e Trigger<OnCollisionStart> instead of EventReader<CollisionStarted>). Now those two things made stuff better to some effect, but still far from rapier precision, at least to my eye (I can probably collect precise data.. if needed).
Anyone knows any other tricks to make avian more accurate?
could use a shapecaster instead of a collider
could make the projectile dynamic, so it stops when it hits something
could try turning speculative collision back on and reading the ContactPair off the graph
could make the projectile dynamic, so it stops when it hits something
huh, this is interesting take. I have been thinking of collisions as kinetic, because I wanted not to apply to any forces to them, so they just remove themselves on same frame as when collision detected. Was I missing something?
could use a shapecaster instead of a collider
I will see what it is.. never heard of this before
could try turning speculative collision back on and reading the ContactPair off the graph
I actually thought that speculative collision also applies to results of what is stored on the graph, but I did not really read the respective PR that deeply
you could also just increase the physics tickrate
or put a system in the substepping loop
Regarding speculative collision, there is this bit:
Speculative CCD: Contact points are predicted by the narrow phase for fast-moving objects before they actually touch. Speculative collision response is handled by pushing back the part of velocity that would cause penetration.
in here ,which made me think that I should not be able receive from contact graph anything different from what was "speculated", because speculation sounds like something that works on narrow phase. But it is possible that I misunderstand something in this..
or put a system in the substepping loop
you mean my system that looks at collisions? I use observer, it seemed to work better
The weirdest bit is that result somehow depend on the angle at which one circle moves to another
somehow from the bottom left it looks the worst π
my approach for projectiles is to just have them as dynamic bodies i delete after they hit something, i don't even have effects yet (damage is applied by the force it exerts)
if you want something with minimum unpredictability though, just don't give it a collider at all
can handle its collision manually
Looks like this for me now, somewhat random..
... that looks like just a kinematic-kinematic collision
are you manually keeping the rocks in place
... that looks like just a kinematic-kinematic collision
pretty sure only one of them kinematic, lemme check
also speculative collision helps prevent that
it just can't do anything if the bodies aren't free
Rock has this:
avian2d::prelude::RigidBody::Dynamic,
projectile this:
avian2d::prelude::RigidBody::Kinematic,
are you manually keeping the rocks in place
no, they spawn with 0 velocity and then have no reason to move, no forces are applied, cause projectile is kinematic
Oh, projectile is also Sensor
that's not how that works
yeah there's the reason
the projectile steps forward, records a collision, and does nothing else
if you want it to not penetrate either make it solid (and dynamic) or add a way to find out when it collided, ie a shapecast
For dynamic projectile not so different:
find out when it collided, ie a shapecast
ooh, sounds cool , sort of like rollback?
Though I still do not have speculative margin on, lemme try dynamic projectile with speculative margin
hm, no, this is worse
It is not cool to hit rock not on its edge, but liveable, hitting it outside of hitbox is definitely no go
get the data off the graph and make sure it's actually collided
But, say what I do if the answer is no (they do not yet collide)? Do I ignore that event? Then when I would know when it actually does collide?
oh right observer
I guess I can still capture OnCollisionEnded, then interpolate, but it sounds like an awful lot of workarounds π
i just read the graph in a schedule system
OnCollisionStart says "when two colliders start touching"...
where are you reading the objects' positions from?
I honestly thought that collision_events: EventReader<avian2d::prelude::CollisionStarted> also only tells me which collisions have started on this frame
a reader gives all events that have happened since either last time it was read or two Updates ago, whichever is more recent
Hm, still sort of not quite consistent
This is the system:
fn projectile_hits_by_avian(
mut commands: Commands,
// avian stuff:
mut collision_events: EventReader<avian2d::prelude::CollisionStarted>,
contact_graph: Res<avian2d::prelude::ContactGraph>,
// some other stuff:
projectile: Query<(&Transform, Entity), With<Projectile>>,
damageable_targets: Query<Entity, With<DamageableTarget>>,
bullet_hit_effect: Res<BulletHitEffect>,
projectile_assets: Option<Res<ProjectileAssets>>,
mut damage_event_writer: EventWriter<damage::ApplyDamageEvent>,
) {
for collision_event in collision_events.read() {
let e1 = collision_event.0;
let e2 = collision_event.1;
let actually_colliding = contact_graph.entities_colliding_with(e1).any(|e| e == e2);
if !actually_colliding {
continue;
}
if let Some(((projectile_transform, projectile_entity), damageable_target_entity)) =
(&projectile, &damageable_targets).get_both(e1, e2)
{
process_hit(
&mut commands,
&bullet_hit_effect,
&projectile_assets,
&mut damage_event_writer,
projectile_transform,
projectile_entity,
damageable_target_entity,
);
}
}
}
Projectile is this (from avian related stuff):
avian2d::prelude::RigidBody::Dynamic,
avian2d::prelude::Collider::circle(1.0),
avian2d::prelude::LinearVelocity(direction * speed), // Set initial velocity
avian2d::prelude::Sensor,
avian2d::prelude::CollisionEventsEnabled,
avian2d::prelude::GravityScale(0.0), // No gravity effect
Rock is this
avian2d::prelude::LinearVelocity(velocity),
avian2d::prelude::Collider::circle(27.0),
avian2d::prelude::Friction::new(0.7),
avian2d::prelude::Restitution::new(0.3),
avian2d::prelude::GravityScale(0.0),
avian2d::prelude::RigidBody::Dynamic,
(rock velocity is zero, which is not obvious from this here..)
Projectile used to be kinematic, I haven't tried kinematic without observer yet
if it's a sensor you can't prevent penetration unless you start before the objects overlap
at most you can have less penetration
I don't really mind a bit of penetration, just not half the object
haha, nice, yes dynamic non sensor projectile gives kind of best final pic
But it has another issue.. now projectile has knockback
So rock actually moves π
The weirdest result I got one shot that rickosheted π
It is addmitedly more fun looking actually
yeah, imo the physics should dictate the behavior entirely for this kind of thing
I need to test how often they ricochet like this, but I might actually just keep this like it is! Thanks for all your help!
Ok, the only issue is that after ricochet, projectile (which is long yellow line to imitate bullet) starts rotating (get angular velocity), which looks weird for a "bullet". I suppose I can make it a small circle and add particle system instead for trail, but maybe there is cheaper way of fixing rotation in the velocity direction or smth?
Ah, I remember now why I wanted projectiles to be Sensor, there is another weird effect if projectiles are dynamic bodies - they can hit another projectile, which looks kind of weird from gameplay perspective. They also then start rotating wildly not in a way that bullet with trail should
https://docs.rs/avian2d/latest/avian2d/dynamics/rigid_body/struct.LockedAxes.html#associatedconstant.ROTATION_LOCKED and some manual rotation setter
can use collision layers to prevent bullet-bullet collisions
Yeah, that sounded like it should help, but I must be missing some context, cause I thought I put bullet in same layer with target, which makes all bullets in same layer as other bullets
Oh, I see, I make them members of same layer, but then use different filters
CollisionLayers::new(0b11u32, !0b10u32)
I tried to do something like this:
pub(crate) const PROJECTILE_MASK: u32 = 0b0001;
pub(crate) const DAMAGEABLE_TARGET_MASK: u32 = 0b0010;
#[derive(Component)]
#[require(Health)]
// damageable targets can be hit by projectiles and other targets
#[require(avian2d::prelude::CollisionLayers::new(DAMAGEABLE_TARGET_MASK, PROJECTILE_MASK & DAMAGEABLE_TARGET_MASK))]
pub(crate) struct DamageableTarget {
#[derive(Component)]
// projectiles collide with damageable targets, but not with other projectiles
#[require(avian2d::prelude::CollisionLayers::new(PROJECTILE_MASK, DAMAGEABLE_TARGET_MASK),)]
pub(crate) struct Projectile;
But I think I missed something somewhere, this causes projectiles not to hit targets
default is already 0b1
I might have done & instead of |, but doing | also makes projectiles not to hit damageable targets..
don't have to give targets a specific mask, ... but i also made a mistake
CollisionLayers::new(0b10u32, !0b10u32)*
got it, this is simpler - projectiles do not hit each other and that is all this is saying. Looks nice, thanks!
I think I fonud a bug in the new implementation of JointDamping. Both bodies need to have the same RigidBody component, otherwise the damping does not occur. This is because, in src/dynamics/solver/plugin.rs on line 768, the call to get_many_mut requires that both bodies have the same components. Otherwise, it returns Err::QueryDoesNotMatch. I'm not sure what the right way to get both bodies would be as I'm still fairly new to bevy. I can create a github issue if needed.
I've attached a minimal example showing this in action.
doesn't that just mean they both have to match the query? they shouldn't need to be in the same archetype
And yet get_many_mut fails if they arent in the same archetype
If you dig into the function, you eventually get to this
pub fn get_inner(self, entity: Entity) -> Result<D::Item<'w, 's>, QueryEntityError> {
// SAFETY: system runs without conflicts with other systems.
// same-system queries have runtime borrow checks when they conflict
unsafe {
let location = self
.world
.entities()
.get(entity)
.ok_or(EntityDoesNotExistError::new(entity, self.world.entities()))?;
if !self
.state
.matched_archetypes
.contains(location.archetype_id.index())
{
return Err(QueryEntityError::QueryDoesNotMatch(
entity,
location.archetype_id,
));
}
Or at least, the archetype of the second body isn't in the matched archetypes of the query. Again, new to bevy so I could be misunderstanding, but the only difference between the left and right cubes is whether or not one has a Static or Dynamic RigidBody. I was able to trace it down to that method returning an Err and that being where the Err was returned
are you on avian main? because different body types aren't different components yet there
I am on main
does it work with kinematic instead of static bodies?
Well, I used dynamic bodies and yes. In my example code, I have 2 cubes on the left where both are RigidBody::Dynamic and they work as expected. The two cubes on the right, one is RigidBody::Static and the other is RigidBody::Dynamic and it does not call inside of the joint_damping function past the get_many_mut.
pub fn joint_damping<T: Component + EntityConstraint<2>>(
mut bodies: Query<(&RigidBody, &mut SolverBody, &SolverBodyInertia)>,
joints: Query<(&T, &JointDamping)>,
time: Res<Time>,
) {
let delta_secs = time.delta_seconds_adjusted();
for (joint, damping) in &joints {
if let Ok([(rb1, mut body1, inertia1), (rb2, mut body2, inertia2)]) =
bodies.get_many_mut(joint.entities())
{
...
}
}
}
not an expert on the internals but static rigidbodies probably don't get SolverBodys inserted
Ah, I think you're right. Just tried with one Kinematic and the other Dynamic and it works as expected. That makes sense
It just wasn't a thing in the previous version of avian where the damping was part of the joint instead of a separate component
this might still be a bug, if you want to file an issue about it
Will do. At the very least, it's a regression in features
Ah yup that's a bug, it should use a "dummy" SolverBody for static bodies like some of the other solver systems
I'll fix that later today
Should I still throw together an issue?
Sure, good to have an issue for it in case I forget
Just some short description of the problem is enough
Alright. Will do
Filed. Thanks! Really like the library in general btw. Really fun to code with
@vestal minnow
https://www.youtube.com/watch?v=vKuHEdC2hf0
I seem to have this bug where I collide with the middle part of a mesh, no trimeshflags seems to fix it really, do you have any tips for dealing with it?
In the video you can see that i slide down the slope well, but then when it hits that cross section, it collides with it, and the player is able to climb all the way back up on it (on 16.1 btw)
I have a ball collider defined with
collider: Collider::circle(BALL_SIZE),
collider_density: ColliderDensity(0.05),
rigid_body: RigidBody::Dynamic,
restitution: Restitution::new(0.5),
On collision it used to move away, but not anymore. Do i need to change anything?
Also I got this panic:
thread 'main' panicked at /Users/charles/.cargo/git/checkouts/avian-5a22c167119f3550/465b513/crates/avian2d/../../src/dynamics/solver/islands/mod.rs:650:9:
assertion failed: island.contact_count > 0
Is this with networking
If yes, you may want to disable the IslandPlugin (or help me figure out how to make it play nice with networking)
If not, it's most likely a bug
Just ran into the same issue as ChaosCat did yesterday with version of slab in updating to Bevy 0.17 and avian main - I think the version of slab named in avian's dependency lists needs updating from just 0.4 to 0.4.11 (the earliest non-yanked version with the get_disjoint_mut method), which should fix that without requiring downstream users to cargo update first
It's with deterministic replication; so it should work fine as long as everything that needs to be rolled back is.
Is there some sleeping/island specific resource to rollback?
The PhysicsIslands resource, and possibly the BodyIslandNode component
I believe also the ConstraintGraph resource which I mentioned earlier iirc
Note that I couldn't get Nise's networking stuff properly working with islands yet, which is why I added the option to disable them, but maybe your networking setup is different and it works there
Hm yeah that seems weird if you have TrimeshFlags::FIX_INTERNAL_EDGES
It should (in theory) fix ghost collisions with internal edges like that, at least for the edges of a given mesh, not necessarily at mesh boundaries where two different meshes meet
Thanks! Should be fixed by #842 once it merges
I tried it again just in case, still doesn't work
It is just one mesh, in blender its just a single thing
This is the repo just in case you want to take a look, the scene spawning code is inside examples/lol.rs and the character collision sutff is all in src/character_controller.rs
Could the Prepare step run in RunFixedMainLoop instead of FixedPostUpdate? or it is dangerous because other things in FixedUpdate might update Transform?
I tried applying TransformToPosition in FixedPostUpdate::Prepare, and PositionToTransform in PostUpdate
But it seems to break stuff and I don't really understand why.
My guess is that something might be modifying Transform in FixedPostUpdate, which means that TransformToPosition is getting re-applied if multiple FixedPostUpdate are running in a frame
finally finished updating to 0.17 with avian and no bugs so far 
There is a relatively simple way to implement a TPS camera interacting with physics to prevent clipping trough RigidBody ? Something like SpringArm3D in godot ? https://youtu.be/ZCb12AHKMfE?si=W7GNy7lggEN2cC0d
I have tried playing with joints but without any success for now
To try everything Brilliant has to offerβfreeβfor a full 30 days, visit https://brilliant.org/Octodemy . Youβll also get 20% off an annual premium subscription.
How to make a good third person camera in Godot 4 from scratch that you can use with your character controller.
Here is how to make a camera that has collisions and smooth movemen...
weird name for just a raycast?
you can use springs to make the camera zoom in and out smoothly to avoid collisions
in the video it's instant
It's simple to have it follow a raycast distance, but it will be fairly disorienting in practice unless you smooth the movement
I skipped towards the end it definitely is smoothed 
that's specifically added halfway through
the "springarm component" was just a raycast
lol
pretty sure the state of the art is unsmoothed anyway, unless the entire camera assembly is smoothed
for controller-targeted games there's usually systems to move the camera away from obstacles (there was a talk about Journey's impl of that) that relax the load on the distance-slider line-of-sight preservation
What do you mean by "the entire camera assembly"?
last thing that comes to mind for me was Super Mario Odyssey, which is smoothed as fuck, but that might be exactly what you mean by "camera assembly"
smoothed even when moving/rotating the camera in an empty void
oooooh got it
meanwhile my game's camera controller is literally as rigid as i could possibly get it (with an extra velocity drag)
hey, got a weird issue with sensor colliders that's driving me nuts. hoping someone can point out what i'm missing here.
so i'm working on a portal system and have sensor colliders on each portal to detect when the player enters/exits the boundary. player has a capsule collider (radius 0.4, height 1.6), sensor is a sphere with radius 6.0. i'm using CollisionEventsEnabled and observing CollisionStart/End events.
wall portals work perfectly fine, collision starts when entering, ends when exiting, everything makes sense. but floor/ceiling portals are completely broken. CollisionEnd fires way too early even though the player is clearly still inside the sensor volume.
here's what i'm seeing when falling through a floor portal:
COLLISION START: boundary with player
Player at Y=1.13 (distance from portal: 1.125)
Player at Y=0.89 (distance: 0.891)
Player at Y=0.77 (distance: 0.766)
Player at Y=0.64 (distance: 0.637)
Player at Y=0.51 (distance: 0.504)
Player at Y=0.37 (distance: 0.365)
COLLISION END: boundary with player <-- wtf?
portal center is at Y=0.0 and the sensor radius is 6.0 units. player at Y=0.37 should definitely still be inside the sphere but collision just ends anyway.
i've tried making the sensor absolutely massive (cuboid 10x10x10, sphere radius 6.0), removed any debouncing, verified the entities aren't being despawned, tried both sphere and cuboid colliders. same issue every time with floor/ceiling portals.
the only difference i can see is the orientation. floor portals have their normal pointing up (0, 1, 0), walls are horizontal. the sensor is a child entity so it inherits the portal's rotation.
is there something weird about how sensor/capsule collisions work with different orientations? or am i just completely missing something obvious here? this has been bugging me for hours lol
using bevy 0.17 and avian from main branch gh
i added CollidingEntities to the sensor and logged both the distance and whether avian still thinks they're colliding when CollisionEnd fires:
COLLISION END: player with sensor - distance: 0.910, still_in_CollidingEntities: false
so when CollisionEnd fires:
- player is 0.91 units from sensor center
- sensor is a sphere with radius 6.0
- CollidingEntities component says they're NOT colliding
this happens consistently. the player is clearly still inside the sphere (0.91 < 6.0) but avian's own collision tracking thinks they've separated. it's not just the events being wrong ,the internal collision state is wrong too.
the only difference i can see is the orientation. floor portals have their normal pointing up (0, 1, 0), walls are horizontal. the sensor is a child entity so it inherits the portal's rotation. wall portals work perfectly, floor/ceiling portals have this bug every time.
@cinder summit I don't know if you have thoughts on this. When only using Position, it should be fine to sync from TransformToPosition only once in RunFixedMainLoop before the fixed loop, no? What would be the use case to do the TransformToPosition every time in FixedPostUpdate (Prepare)?
Also when I insert a Bundle; if I understand correctly it adds Position::PLACEHOLDER because of required components, which adds Transform::Default because of required components. Then the first TransformToPosition sync will convert from Transform::default() to Position::default()
In my game I never do transform->position, but if you were using Transform outside the simulation I guess you'd do Transform -> Position once before the loop yes. And ofc you need the hooks to set up the position properly if you spawn something in the simulation
It's not just Transform, it's also mass property updates and some other things IIRC
So are you saying that it needs to stay in FixedPostUpdate because of that?
Imo if you don't need what the transform sync plugin does, you're better off disabling it and applying changes as needed in your own system
Running preparation systems in the same schedule as physics is run in ensures that the state is up-to-date, running it elsewhere seems a bit sketchy
yes that's what i'm doing, I disabled the plugin, but by default the plugin runs TransformToPosition runs in FixedPostUpdate so I'm trying to understand if I can get away with running it somewhere else.
I tried doing TransformToPosition in RunFixedMainLoop::BeforeMainLoop and PositionToTransform in PostUpdate, which seems to work
I guess it works under the condition that the user doesn't touch Transform during FixedMain or Update and instead relies on Position.
If you know what your simulation will and won't do then you can move them, yes
I personally only use a system to sync Position/Rotation -> Transform in RunFixedMainLoop::AfterMainLoop
Hello, I updated my project to 0.17 and I get this warning:
Dynamic rigid body 79v1 has no mass or inertia. This can cause NaN values. Consider adding a MassPropertiesBundle or a Collider with mass
which goes away only if I add MassPropertiesBundle, not sure what a Collider with mass refers to.
The problem is I want to set the angular inertia but I can't see how to set it with MassPropertiesBundle within spawn
MassPropertiesBundle has an angular_inertia field for this
The warning though is a bug somewhere, which I'm hoping to fix soon, you shouldn't be getting it unless the body has no collider or the mass properties have been manually configured to invalid values
thanks for your help. That means that I have to first spawn the entity and then query the MassPropertiesBundle to change its field, I can't do it directly at the time of spawning, right?
No you can just set it at spawn
commands.spawn((
RigidBody::Dynamic,
MassPropertiesBundle {
mass: Mass(MY_MASS),
// Note: In 3D, this has a principal inertia and orientation
angular_inertia: AngularInertia(MY_INERTIA),
..default()
},
// ...other components
));
Or better, just use the raw components and not the full bundle
commands.spawn((
RigidBody::Dynamic,
Mass(MY_MASS),
AngularInertia(MY_INERTIA),
// ...other components
));
The MassPropertiesBundle mainly exists because of the from_shape helper, for computing all the mass property components based on a given shape and density. If you're manually specifying the mass and angular inertia, it's cleaner to just use the components directly
Unfortunately both solutions do not get rid of the warning. It goes away only by using MassPropertiesBundle::from_shape, I guess it's due to the bug you were referring to
Should AccumulatedLocalAcceleration also be rolled back? Is it used for one-time forces? Does it every get persisted past one PhysicsStep?
I see there is also VelocityIntegrationData
both of them are cleared every physics tick, so you shouldn't need to roll them back
i.e. the state doesn't persist, it's recomputed every tick
Thanks.
Another issue I have is that I had a system that queried Position, Mass, etc. and ExternalForce
but now i can't query Position along with Forces because of access conflicts
I'd rather not use a ParamSet or anything like that; would it be possible to make the fields inside Forces public?
oh i see helper methods are provided ..
I guess it's not exactly the same because you cannot mutate 2 fields at once if you have to go through the helper methods, as opposed to accessing the field directly. But maybe it's fine
Oh those helper methods are internal only
nice this is bevy_fps_controller right. I couldn't really get sloped terrain to feel terribly natural
yes its based on bevy_fps_controller but i rewrote a great deal of it. i made it fixedupdate and it now uses force impulses instead of manual transform translation mutation. also uses avian gravity and damping instead of the old gravity and friction system, as well as other minor changes .
I really appreciate you making bevy_fps_controller, would've been difficult for me to get the base yaw/pitch/accel stuff working. bhop is king!
yeah slopes at first were very finnicky but i made it a floating controller and slopes are pretty good now, the current issue im having isnt due to the controller, but due to a ghost collision, as far as i can tell. it happens occasionally on flat ground as well
instead of the collider being on the ground, there is a force pushing it up constantly, making it slightly above the ground. for me this gave me free walking up stairs, and i dont slide down slopes.
@vestal minnow I haven't had too much time to look into Avian's implementation but I'm curious how much allocation Avian is doing in its systems.
I've been investigating if it's a good idea to introduce support for low level scratch space for efficiently managing ephemeral allocations.
And physics and rendering are the two areas where it seems to be a good match.
So this would be similar to an arena allocator that gets freed for example after every time step? Box2D uses those a lot, and I could probably use them too for things like constraints
I think constraints would be the biggest thing where that may be helpful
Most other data is more long-lived and persisted, and not as perf-critical
It is exactly an thread local arena allocator. Likely scoped to the lifetime bounds of a schedule..
At least that's what I'm thinking right now
The intent would be to allow for some cheap scratch space that can be shared between systems
Mostly to avoid the churn of moving entities and components around on short timescales.
What Box2D does is it allocates a bunch of things to a global arena allocator on the world, distributes some data there, and then frees them after the solver. For example here it allocates some space for SIMD contact constraints
https://github.com/erincatto/box2d/blob/cfa9ef1b76256f92ec3e26a1a20521e50dddac19/src/solver.c#L1468
that it distributes to graph colors
https://github.com/erincatto/box2d/blob/cfa9ef1b76256f92ec3e26a1a20521e50dddac19/src/solver.c#L1494
and later uses in a thread-local context in the solver
https://github.com/erincatto/box2d/blob/cfa9ef1b76256f92ec3e26a1a20521e50dddac19/src/contact_solver.c#L1807
I'm guessing this would probably be a bit different in Rust land
Yeah I'm a bit conflicted since this would require either some intricate lifetime weaving
or require fallible handles instead
In my case, I currently just have this for the "graph color"
pub struct GraphColor {
pub body_set: BitVec,
pub manifold_handles: Vec<ContactManifoldHandle>,
// This is the relevant part
pub contact_constraints: Vec<ContactConstraint>,
}
Each constraint within a given graph color can be solved in parallel. In Box2D's case, it doesn't store a vector, but points to some chunk in the arena allocator, unless I'm misunderstanding what it's doing
Also the graph colors in my case are stored in a ConstraintGraph resource currently, it's just a Vec of graph colors
since you're doing this in parallel, this is all just allocated up front, right?
The constraints are, yes
I'm extremely interested in this for networking; I was looking at BlinkAlloc in the past
@vestal minnow what do you recommend for this? (accessing Position/Rotation/etc. at the same time as Forces)
I'm thinking of writing a plugin that should get us 90% of the way there and pave the way there for experimentation, but a complete option will likely need deeper integration with the ECS.
We can probably add more public getters for those, I originally didn't do that since Position and Rotation are generally intended more for internals, and most people would probably just use the transform, which would not have any conflicts
Or you may be able to use a ParamSet, though it's more annoying
Would making RigidBodyForcesInternal public work?
I don't really want to expose literally everything there, that trait exists primarily to allow internally sharing logic between ForcesItem and NonWakingForcesItem
I would be fine exposing getters for position, rotation, and velocity (velocity already exists), the rest feel more niche to access mutably in the same system as you're using Forces
exposing more fields than necessary risks cluttering up autocomplete and making the API more confusing
that works! thanks. https://github.com/Jondolf/avian/pull/845/files
oh wait could i also add ComputeMass? my forces often rely on the mass of the entity
Shouldn't you be able to just query for it? It's only borrowed immutably in ForcesItem, so unless you're querying mutably for it for some reason, it shouldn't conflict afaik
oh you're right, didn't know you could query multiple immutable components in the same query; it makes sense
there's an automatically generated ReadOnlyForcesItem that's kinda a footgun if you try to forces.get(e).unwrap().angular_velocity()
Hello, new forces querydata is sick, thanks for the work.
Would it be possible/make sense to have this kind of function directly integrated ?
fn get_point_velocity(linear_velocity: Vec3, angular_velocity: Vec3, point: Vec3) -> Vec3 {
linear_velocity + angular_velocity.cross(point)
}
I find myself needing it often.
I'm also curious why there isn't a apply_linear_acceleration_at_point
Added apply_linear_acceleration_at_point now. I originally just wasn't sure if it's useful, but I agree it probably is, and it's good to have for consistency / API completeness
https://github.com/Jondolf/avian/pull/846
I would like to add a method for computing point velocities, it just feels somewhat weird to have a random function floating around somewhere. In bevy_rapier it's natural since both linear and angular velocity are in a single Velocity component, so they can just have a Velocity::linear_velocity_at_point method
We could consider combining LinearVelocity and AngularVelocity under a Velocity component too
Honestly I'm not entirely sure which API I prefer
Spawning with linear velocity
// Before
commands.spawn((
RigidBody::Dynamic,
LinearVelocity(Vec3::X),
));
// After
commands.spawn((
RigidBody::Dynamic,
Velocity::from_linear(Vec3::X),
));
Spawning with linear and angular velocity
// Before
commands.spawn((
RigidBody::Dynamic,
LinearVelocity(Vec3::X),
AngularVelocity(Vec3::Y),
));
// After
commands.spawn((
RigidBody::Dynamic,
Velocity {
linear: Vec3::X,
angular: Vec3::Y,
},
));
// Or alternatively
commands.spawn((
RigidBody::Dynamic,
Velocity::new(Vec3::X, Vec3::Y),
));
Using linear velocity in a system
// Before
fn accelerate_linear(mut query: Query<&mut LinearVelocity>, time: Res<Time>) {
let delta_secs = time.delta_secs();
for mut linear_velocity in &mut query {
linear_velocity.x += 2.0 * delta_secs;
}
}
// After
fn accelerate_linear(mut query: Query<&mut Velocity>, time: Res<Time>) {
let delta_secs = time.delta_secs();
for mut velocity in &mut query {
velocity.linear.x += 2.0 * delta_secs;
}
}
I think I might actually slightly prefer a single Velocity component
And it'd solve the point velocity API problem
I meant adding it to the Forces QueryData, which i'm not sure is possible since I don't know much about it.
Mm we could add that too
I just found this message about a camera interpolation artifact and I was wondering if you got this after updating to 0.17? I get a similar problem when moving the camera interpolating between two positions which I didn't get in 0.16. Is this a known problem in 0.17?
I tried it, it works great thanks a lot.
Btw is it normal that I need a mut access to the query data in order to call that method ?
When I don't do get_mut it doesn't show up
Yeah this was updating Tnua to 0.17, but honestly the way they handle fixed timesteps is more of an afterthought, so I wouldnβt worry about it.
In my own projects, I did not get any issues, no. For the record, I donβt interpolate the camera itself, but set its translation to that of the interpolated player
I am using EasingCurve sample to interpolate non-linearly between one camera position to another and I get the following glitchiness that appeared after updating to 0.17. As far as I know easing curves and sampling have not been changed though across 0.17, or am I wrong?
Oof that sucks
I'm not aware of any changes
But I may be wrong
Maybe ask #math-dev
I think I almost have rollback working for islands. The main problem I have is on the BodyIslandNode::on_remove observer.
On rollback, I start by reverting BodyIslandNode, PhysicsIslands and Sleeping to their state at the start of the rollback tick.
The problem is that I don't have a specific order for the reverts, so I might get something like:
- revert
PhysicsIslandsto its past state - remove
BodyIslandNode, which triggers theon_removeobserver
The observer then panics here: https://github.com/cBournhonesque/avian/blob/7691ef41233f9eda9547f7bb01248855f9a6a449/src/dynamics/solver/islands/mod.rs#L1345-L1345
I guess a solution would be to have a way to disable this observer during rollback, but I don't really have a way to do this.
I guess another way could be to call return instead of panic at that line, but that's not ideal either because in non-rollback cases you probably do want to panic.
For now I will simply disable the Island plugins
for the record i have two parallel systems modifying linear and angular velocity
Are they expensive systems? In my experience it has generally been slower to run cheap-ish systems like that in parallel than just running then sequentially, at least with Bevy's current scheduler
one's just a few vector calculations and the other's that plus collision reading, so not very
it's honestly more about how i want to make them independent mechanically, and the ambiguity checker tells me when that might stop being the case
In general I would put DX and overall API "niceness" over optimizing for possible system parallelization for things like this. Bevy has kinda the same thing with Transform, where it could be split into three different components (and originally it was) but is a single component, which arguably is better at least for that case IMO
to me the question is mainly if the DX is better with a single Velocity component or split components
I've been intending to combine Position and Rotation under a PhysicsTransform for a while now, which is kind of a similar case
If both of them were combined then we could also have some more nice helpers for position and velocity integration and whatnot
(in addition to point velocity)
could make a just-the-velocities querydata
I've encountered this error in @visual sparrow's 0.17 branch of bevy_tnua, has anything changed here?
Encountered an error in run condition `<bevy_tnua_avian2d::TnuaAvian2dPlugin as bevy_app::plugin::Plugin>::build::{{closure}}`: Parameter `Res<'_, Time<Physics>>` failed validation: Resource does not exist If this is an expected state, wrap the parameter in `Option<T>` and handle `None` when it happens, or wrap the parameter in `If<T>` to skip the system when it happens.
ok i've fixed this, but i've got some more issues
it seems like collider has been changed to not have mass by default?
Dynamic rigid body 254v32 has no mass or inertia. This can cause NaN values. Consider adding a MassPropertiesBundle or a Collider with mass.
and the weapon hitbox which this is talking about is affected by gravity now
adding mass doesn't seem to fix it
and it says MassPropertiesBundle isn't a component
The performance improvements in 0.4 are very nice, thanks!
Mainly for debug builds. It was fast enough in release before, but debug mode performance is nice for productivity
do you know about the option to compile dependencies in release?
Of course π
It doesn't help avian too much for some reason, possibly too many generics
Im also getting the Dynamic rigid body has no mass or inertia bug. For my use case it happens when I use Disabled + entity cloning (prefab design pattern) which may be where the bug lies? I've found missing Clone on a component can really bork up entity cloning in hard-to-detect ways.
Interesting
Yeah, i think it's that, i have the same usecase
It looks like this bug is also messing with transform position and rotation for me and I suspect avian's involved since I use LinearVelocity and avian has the interpolation stuff. Not entirely sure could also be a change bevy made to entity cloning or disabled π’
Yeah I'll try to debug the mass problem today, definitely a bug
Neat, that's great to hear π there's still a lot more optimization work to be done, but it's definitely a big upgrade over 0.3
@vestal minnow i'm having this issue with ldtk; the visuals work fine but all the avian hitboxes spawn at 0.0 for some reason? i'm assuming it's a change upstream from bevy, or maybe i messed something up with the migration, but it could be possible there's something in avian breaking it?
Not sure why that'd be happening, but I can probably take a look later
Mmmm it seems that our 3x3 eigensolver is returning NaN values sometimes, which are later clamped to 0.0 for angular inertia
I'm not sure why this wasn't a problem before though, I don't think I've touched this code
lol, specifically this returns NaN
let mat = SymmetricMat3 {
m00: 5.3333335,
m01: 3.4465857e-23,
m02: 0.0,
m11: 5.3333335,
m12: 0.0,
m22: 5.3333335,
};
but this does not
let mat = SymmetricMat3 {
m00: 5.3333335,
m01: 0.0,
m02: 0.0,
m11: 5.3333335,
m12: 0.0,
m22: 5.3333335,
};
@light vessel @bleak wadi @visual sparrow (any others?) I fixed at least one bug that was causing the mass property warning, I'm curious if it's fixed for y'all if you cargo update
(the problem was that there's a check that tests whether the matrix is diagonal to avoid pathological NaN cases, but it was checking for exact equality to 0.0 rather than having some epsilon)
cargo tree says I'm using https://github.com/Jondolf/avian?branch=main#774f60e3
rip
did you forget to push?
no the bug was in glam_matrix_extras
oh, let me cargo tree that
uuuh
oh I see you edited
typoed, extras not extensions
that commit looks correct
so nope, does not solve it in Foxtrot at least
mm I'll just run foxtrot and try to debug there
is the issue maybe coming from rigid bodies that have no colliders at all?
because that's the case when using a RigidBody::Dynamic in combination with a ColliderConstructorHierarchy
(for exactly one frame in my case)
That's one problem yeah, but afaik that existed in previous versions too?
yep
maybe the check didn't fire back then
I suppose I could listen for the new event we added, but that seems a bit boilerplatey
Could that check just have a Without<ColliderConstructorHierarchy>?
I guess a simple fix would be to just skip the warning if the body has ColliderConstructor or ColliderConstructorHierarchy
yeah
seems to work in my test scene
https://github.com/Jondolf/avian/pull/849
nice!
Wish I could patch to test
(please consider releasing at least a -alpha next time so I can patch binaries π
)
Actually I think only ColliderConstructorHierarchy is problematic, not ColliderConstructor
How come? The Mesh may not be ready for n frames
Mm I guess yeah, my test scenes are probably just too simple to repro that
I'll keep ColliderConstructor filtered out too
It's merging once CI is done, so we can test it with foxtrot then
(I need to go afk for ~30 min)
Could it be that the quaternion multiplication here is the wrong way around? I'm seeing stutter issues with rotation extrapolation. https://github.com/Jondolf/bevy_transform_interpolation/blob/main/src/extrapolation.rs#L440
I think you're right, yeah
for a world-space transformation the original rotation should be on the right
π I can open a PR
thanks!
Warnings in foxtrot seem to be gone now π
Though there's this when pressing Quit to title
Heh
Yay!!
another pretty big release, huh
Still missing content for the What's Next section, and I need to add images and videos and run some benchmarks... otherwise I have most of this written now
avian is utterly critical to my app and it's great work
Is there somewhere I can see this?
Nah these are the WIP release notes I'll post on my website (joonaa.dev) once everything is done and I've actually released 0.4
I'm considering changes to how we do releases moving forward but for this one I'll just do things like I've done in the past
(specifically, we could do slightly smaller and more frequent releases, and have migration guides in-repo, and maybe make release notes public as a draft somewhere even before the release)
(and also a dedicated avian.rs website would be nice, I do have the domain for that)
is there a new release of avian for bevy 0.17?
Nope not yet, the upcoming 0.4 release will be for bevy 0.17. But the main branch has supported 0.17 for a while now, so you can hopefully use that
ohh ok thanks
its working. loving avian so far
bump this
.
is there any way to optimize SpatialQuery's cast_shape/cast_ray? Like, does setting max_distance to a low value help? Is a shapecast "cheaper" than a ray cast?
i'm not sure specifically if that's possible, but one method of optimization is to do an AABB test first and skip any expensive shape/raycast checks unless the AABB check passes
are you referring to SpatialQuery's aabb_intersections_with_aabb or do you mean like... manually checking AABB myself?
yah that's one way. you should be able to get the aabb from the collider
also you might be more interested in aabb being completely inside
The Axis-Aligned Bounding Box of a collider in world space.
doesn't seem like there is a function exposed to check if AABB is inside another, but it should be trivial by checking min/max
I might be able to replace my shapecast usecase entirely with this π€ Thanks!
Still seeing issues on main with entity cloning including the warning about no mass. Disabling the avian specific components shows that the starting position and rotation are correct:
#[derive(Component, Clone)]
#[require(
Lifespan::new(1.0),
//Sensor,
//RigidBody,
//Collider::rectangle(10.0, 10.0),
//CollidingEntities,
AnimationIndices::Cycle((0..=4).cycle()),
AnimationTimer(Timer::from_seconds(0.2, TimerMode::Repeating)),
Disabled
)]
pub struct Projectile {
pub damage: Damage,
pub speed: f32,
pub forward_offset: f32,
pub angle_offset: f32,
}
...
commands
.entity(projectile_entity)
.clone_and_spawn_with_opt_out(|builder| {
builder.linked_cloning(true);
})
.remove::<(ProjectileOf, Disabled)>()
.insert((
Transform {
translation: starting_position.extend(ZLayer::InAir.z()),
rotation: Quat::from_rotation_z(rotated_direction.to_angle()),
..default()
},
LinearVelocity(rotated_direction * projectile.speed),
CollisionLayers::new(
GameCollisionLayer::PROJECTILE_MEMBERSHIPS,
LayerMask::from(damage_source) | GameCollisionLayer::HighObstacle,
),
));
The translation issue is that its always moved to 0, 0 after the first frame. Removing sensor alone fixes this π€ No idea whats up with the rotation.
at what system set the spatial query updated?
i'm having an issue where an entity is despawned, but it still shows on the spatial query, and is breaking some of my logic
that is my assumption at least
A system parameter for performing spatial queries.
This is done automatically once per physics frame in PhysicsStepSet::SpatialQuery
I have a few places where I'm calling update_pipeline manually though
when two colliders collide... is there an easy way to get roughly the point where they collide? I'm wondering if my raycast vehicles could be more efficient if they use sensors vs casting rays π€
you wanna check out ContactManifold
https://docs.rs/avian3d/latest/avian3d/collision/collider/struct.Collider.html#method.contact_manifolds
A collider used for detecting collisions and generating contacts.
expected update time?
hmm, yeah. I wonder if this'll be more efficient or less efficient. I suspect it's a "measure and see" situation
So, just to be sure if I understood correct, since I'm just starting with avian2d, if I have a tilemap, which is just a grid of Vec2, the best way to create colliders for things like walls, is to use Collider::voxels, where voxel_size is 1x1 (since I'm using 32.0 as the lenth_unit, which is the pixel count of each tile, 32x32) and grid_coordinates are the "tiles" coordinates which will be a wall (collidible).
My only question is if grid_coordinates is a "local position" or needs to be in the "global" position.
don't see how it wouldn't be local to the collider's origin
length unit doesn't mean that, though; it just scales things like the sleep threshold
is there something that would prevent a child collider sensor from detecting collisions?
like, I have a rigidbody moving and I have a sensor collider which is a child of it offset so it's always in front of the parent... but it doesn't seem to detect collisions at all π€
Non-matching collision groups?
this might be it π€ I'm messing with the layers now, I thought I had them correct
Two colliders A and B can interact if and only if:
The memberships of A contain a layer that is also in the filters of B The memberships of B contain a layer that is also in the filters of A
it's funny, I read that and think "yeah, that makes sense" and then I code something that isn't that.
yeah, that was it
Hi, what is the current state of a voxel colliders?
The upcoming Avian 0.4 release (and the main branch) supports Collider::voxels and some other ways to create proper voxel colliders. I haven't tested them too much yet, they were just added to Parry and I exposed APIs for them
They should allow you to make very efficient voxel geometry without ghost collision problems (hitting the "internal edges" between voxels), as long as the sizes of voxels in a given collider are uniform
Should be local
But I have not tested the voxel colliders much yet
(they are from Parry, we just expose APIs for them)
Oh, this one is kind of nasty π€ My suspicion is that the position thing is because physics internally uses Position and Rotation components for physics positions, and if these have non-default values at spawn (which they will, because you're cloning an existing entity), they will override the Transform by default
Does it work if you insert Position and Rotation instead of the Transform there? Or alternatively disable cloning for those two components, if there's some way to do that
(to be clear, cloning use cases like this should be supported better, but I'm interested to see if it works like that)
We should probably have some integration tests for entity cloning to make sure it works like expected
Mm supporting cloning feels extremely cursed though since it might also clone various identifier components that should be unique or connect entities to external data, like the BodyIslandNode component
I feel like there should be a way to mark components as "don't clone this please" without users having to do that manually
If this is a thing, let me know lol
So just a little more wait. Thanks
I've been just looking at the new joint API recently and it's soo much nicer than before. Especially the spherical joint axes configuration is much more intuitive than it was before the rework for ragdoll editing, and the docs are clearer. Thank you for your work! 
π€ do the contact manifolds only get updated when colliders first collide? edit: ah, I was using local translations
so, I'm trying to use the contact manifolds to determine where these rectangular colliders intersect with the ground.. like, the surface point of where the block meets the ground?
I'm drawing a blue sphere on the contact points and a pink one at the "closest" point and I noticed they're like.. sunken in a bit? But then also, when I go over an edge (the red arrow), the contact points are at the edge
is it possible to get the point on the ground surface consistently?
I had to insert Position and Rotation in addition to Transform like this
Position(starting_position), Rotation::radians(rotated_direction.to_angle()),
Transform {
translation: starting_position.extend(ZLayer::InAir.z()),
rotation: Quat::from_rotation_z(rotated_direction.to_angle()),
..default()
},
This fixed the projectiles but I still get the mass warning. Disabling the cloning of Position and Rotation stopped the projectiles from moving entirely (but also got rid of the mass warning lol)
It looks like there is a way to modify a components default clone behavior: https://docs.rs/bevy/latest/bevy/prelude/trait.Component.html#method.clone_behavior
A data type that can be used to store data for an entity.
#[component(clone_behavior = Ignore)]
If you're using ContactPoint::point, I think it's effectively the world-space midpoint between the contact points on the surfaces of each body. These surface points should be separated by ContactPoint::penetration along the normal (if positive, the shapes are penetrating, if negative, they are separated and it's a speculative contact)
I believe you can get the point on the surface of either body by doing contact.point + manifold.normal * contact.penetration or contact.point - manifold.normal * contact.penetration depending on which surface you want
Oh neat! Didn't know about this
I would mayybe just use ray casts though unless you have a specific reason to use contact manifolds for this
I wanted to see if this is more efficient than doing raycasts for all my wheels
It's unlikely, computing contact manifolds is generally costlier than just simple ray casts, plus it adds broad phase overhead and whatnot
I believe you could maybe also perform the ray casts in parallel since SpatialQuery doesn't require mutable access
yeah, I am running them in parallel, I think I just have a lot of wheels sometimes and wanted to try some alternative approaches
is a shape cast "cheaper" than raycast? maybe I should ask differently... I'm really just trying to find the distance to the ground efficiently
almost certainly slower, though not by much (and it depends on the shapes)
In my mind, an intersection test with a sphere should be essentially free. Is that accurate?
Between two spheres yes, between a sphere and some other shape it depends
It basically does point projection in the latter case
assuming we're purely talking about an intersection test that returns a bool
For a shape cast it'll need to do a "Minkowski ray cast" with GJK
Except for ball-ball and maybe some other trivial combination
Hello, another question: I've added a voxel collider, but I noticed when I add the PhysicsDebugPlugin there is a heavy hit on fps (debug build), which drops from ~120 FPS to like ~20 FPS.
There is no physics yet, only a Collider::voxel with a RigidBody::Static
Is this some known/expected thing?
seems explicable to me
there's probably a "disable debug gizmos for this entity" component
Hey, hate to be that person, but is there an ETA on 0.4 release? π
I realize github is updated to Bevy 0.17, but the dependent libs are still backlogged
If there are any blockers that need an extra hand, I'd be happy to help
I think I hit some kind of bug in Avian whereby colliders don't get updated when transform scales change
oh, I think it's a slightly different problem: update_collider_scale only takes the Transform into account, whereby it should take the GlobalTransform into account. Also it should run whenever the GlobalTransform changes, not just the Transform.
wait, hmm, ColliderTransform is supposed to handle this. this is odd
Here's a fix https://github.com/Jondolf/avian/pull/851
Mostly blocked on me finishing the release notes (writing is 90% done, just need a few more images) and migration guide, plus the fact that I have a project deadline this Sunday for university stuff π
My estimate would be next Monday at the latest, but hopefully sooner
What is the easiest way to disable the persistent simulation islands
PhysicsPlugins::default().build().disable::<IslandPlugin>()
Awesome thanks! Reason I ask is because I can't seem to get around this issue trying to despawn a disabled physics entity:
thread 'main' panicked at .cargo\registry\src\index.crates.io-1949cf8c6b5b557f\bevy_ecs-0.17.2\src\error\handler.rs:125:1:
Encountered an error in command<bevy_ecs::system::commands::entity_command::insert<avian2d::dynamics::solver::islands::BodyIslandNode>::{{closure}} as bevy_ecs::error::command_handling::CommandWithEntity<core::result::Result<(), bevy_ecs::world::error::EntityMutableFetchError>>>::with_entity::{{closure}}: The entity with ID 10227v0 was despawned by .cargo\registry\src\index.crates.io-1949cf8c6b5b557f\bevy_ecs-0.17.2\src\relationship\related_methods.rs:21:19
If you were attempting to apply a command to this entity, and want to handle this error gracefully, consider usingEntityCommands::queue_handledorqueue_silenced.
Ah that's a good edge case, I hadn't considered that you can even do that haha
I'll see if I can fix that later
Ty good sir. Sorry I'm kinda pushing the boundaries of cloning and use of disabled over here π
thats good tbh
Just for future reference, nvm, I just forgot to add the optimization on my new project
[profile.dev.package."*"]
opt-level = 3
Fps went from 120 to 600 π
hallo, am I missing something about CollidingEntities? e.g. is
(
Collider::...,
CollidingEntities::default(),
CollisionEventsEnabled
)
The expected behavior is that CollidingEntities would be 1:1/track state for On<CollisionStart> and On<CollisionEnd>
I'm unsure what the actual behavior is
Ah, looking at the history of this channel, seems like other people have wondered about this. I see I'll just need to make an external colliding entities to track this
with transform interpolation I am getting this really strong jittering effect but I'm not sure what I messed up
this is with a really low tickrate for fixed update, but the issue is still there with a higher one, even if less noticeable
ok after trying to put every transform access into fixed update it went away, but having the camera movement in fixed update feels kind of bad
is that colorado
I have absolutely no clue
#1378795204747727018 message see if this thread will help resolve your issue :)
I already have separate camera and player entities though, if that is the fix
I believe Jan knows a lot about cameras and how do deal with the jitter effect. for third person, lemme see if I have some code..
ok honestly my camera controller for this is absolutely railed and a terrible example. I use my own lerped camera gimbal to move the camera along the target position
that would double interp here
but I think for me, that solves my issue π i also can't quite remember if there's a disabling component for transform interp
would prolly wanna add that
I would recommend no transform interpolation for the camera entity, but update its transform every frame
taht's what I had before and it was jittering
but that was due to global transform being outdated
I assume I am using bevy wrong, but when working with hierarchies I need global transform updated a lot more often than once per frame
it's driving me insane
There's a way to calculate this in a system. Do you know about this :o
yeah but it's still annoying having to calculate it maybe multiple times if you are accessing it in different systems
maybe the hack would be to run your code after TransformSystem::Propagate. kinda sucks in a postupdate system, but eh
I suppose inserting the updated global transform again is a possibility? Feels like a hack though
in the PostUpdate schedule
just makes proper scheduling even more of a headache for me
π hopefully with systemsets, it won't be too bad
I feel that
also I have quite a few instances of code needing global transform and then updating the transform of something else
when I tried that the changes only got rendered next frame
too offtopic though
I complained in #1425767150584594524
thanks for the suggestions though <3
- make the player a rigid body
- enable interpolation for the player
- do not make the camera a rigid body
- do not make the camera a child of the player
- in
Updateadd a system to move the camera according to the Player'sTransform(not GlobalTransform) + some offset - bonus: make the camera rotate before physics runs, see Bevy's physics in a fixed timestep example
basically what I have right now, except that I have a camera target as a child of the player
really annoying that this doesn't just work
Oh I see. Then you'll need TransformHelper to get its currently global transform
sigh
I have a lot of systems that need an up to date global transform
I feel like the current global transform implementation leads to a lot of 
Hm, I'm trying to draw some debug shapes. And I got to something like this, but this doesn't work because SharedShape is not an enum.
use avian2d::parry::shape::SharedShape;
// ...
match collider.shape() {
SharedShape::Circle(circle) => {
// Simple circle - draw at entity position
gizmos.circle_2d(position, circle.radius, color);
}
SharedShape::Capsule(capsule) => {
Any way I could do something like this?
EDIT: Sometimes asking the question leads one to the answer. It's not SharedShape, it's the TypedShape! That works perfectly.
use avian2d::parry::shape::TypedShape;
// ...
match collider.shape().as_typed_shape() {
TypedShape::Ball(ball) => {
You may want to use the PhysicsDebugPlugin, which does debug rendering for you
Are you kidding me. π€£ Duh. I did a quick google, but couldn't find it. Thanks. π
Hello, 2 questions if you folks don't mind:
- for a 2D top-down RPG-like game, I don't need
Gravity, so to disable it I just need to setGravity(Vec2::ZERO)or is there another way?
- I'm using a
KinematicBodyto move my character, and I wanna a wallStaticBodyto block to. By default, if I understood correct, theKinematicBodyisn't blocked byStaticBodycolliders, so I need to implement this "blocking" logic myself, like on thekinemaic_controller_collisionsexample, right?
There's Gravity::ZERO but yes
are kinematic bodies even affected by gravity...?
kinematic bodies you need to apply gravity yourself
Yah, so would Gravity::ZERO even be needed?
Played around with some custom gravity.
- In the first screenshot the dynamic bodies are pulled by both planets.
- In the second, only the closest planet is affecting gravity.
It's not so easy to get the bodies to sleep when there are constant forces going on.
i just hit something weird, i have a rigid body and a collider as its child, the collider is static, but the parent is moving, and the ColliderTransform of the child is updating
better: collect input before FixedUpdate, then don't even use the camera transform for anything until you recalculate it for rendering
ive been away for a while, just got back and unfortunately I still have both errors
@vestal minnow have you see this happen? #1124043933886976171 message
SyncPlugin was disabled
that wasn't it
the default for ExternalForce being persistent: true makes the most sense?
From my testing that is the only way to reliably make the bodies go to sleep.
Otherwise you have to set the force each tick and that I believe makes them not fall asleep?
hmm
How evil is it to assume that a user's static rigid body will never ever change its transform (beyond being despawned and respawned)
and how misguided is it to assume that static rigid bodies will in general be spawned and despawned as part of the whole scene, with some rare exceptions (e.g. breaking an object at runtime)
I know Avian allows to move static bodies as much as you want, and I know you can spawn and despawn them at will
but I think in practice a general purpose library (in my case navmesh and steam audio) can assume the above conditions, right?
@vestal solstice how is it in your game?
todays daily had a lot of discursion on that
players will be dynamic and npcs will be kinematic
good timing!
and I assume the level is static?
yes
and I further assume that the level won't change its transform, right?
correct
do you have any static rigid bodies that you don't spawn and despawn as part of the whole scene?
Our game never modifies static rigid bodies' transform eithier. We are, however, spawning and despawning them a lot.
spawn/despawn after the first instanciation?
thx! What's the use case for spawning and despawning them in this case? what does "a lot" mean? Every frame, every few ms, every few sec?
all static bodies are defined on a glb using skein
I mean e.g. the player activates a switch and that spawns in a big statue that is a static rigid body. Then the player throws a bomb at the statue and it gets despawned.
not at the moment
So that static rigid body would be spawned and despawned not as part of the scene, but as something dynamic
At human speeds, we're essentially at the same build rate as Satisfactory since it's an automation game. Any batch operations (e.g. blueprints, zooping) would probably be the addition of many rigid bodies in a single tick.
Aaah okay
my issue was on a Dynamic body
I'm asking because I can optimize some stuff in both the navmeshes and the steam audio stuff if I make one big mesh out of all static bodies
But that would mean rebuilding the entire mesh when a static body changes
sounds like in your case, that would be expensive
this is the avian channel, not landmass
I guess I could have markers that say "Static for real for real"
I know
I want to know how people use Avian
This is also not for rerecast, but for steam audio π
but I can share the code with rerecast once I have it
on the server it is instanciated on startup and on the client it is instanciated when moving to the room that has that scene
thx!
anything with a marker component goes through a system that collects the entities in the SceneSpawner for that scene and creates a filter with those that have RigidBody::Static and generate the navmesh from them
To be fair, you might just optimize differently based on the game. An open world / procedurally generated environment / UGC has a different set of constraints than a handcrafted level of some kind.
Yeah definitely. I'm mostly looking for sane defaults.
Raycasts and other physics queries only work on RigidBodies, right? Would it make sense to enable them for arbitrary colliders that are not RigidBody?
that first part seems unlikely
Avian is now out of the Tracy profile in my project with the 0.4 improvements. Amazing work @visual sparrow
I think my perf stuff was in 0.3, this is all @vestal minnow's work 
I know there's some overhead when generating colliders with like Collider::trimesh_from_mesh, but what about creating Collider::cuboid? Is that worth caching at all?
Eeeeh, in practice not really
Creating the cuboid is basically free
So you don't save on CPU time by caching it
However, the colliders use Arcs in the background, so if you have a large amount of cubes of the same dimensions, you could cache them and .clone() that cached collider to only represent it once in memory
that way you could potentially save RAM
for cuboids specifically though, you may want to instead use voxel colliders anyhow
And idk how those work haha
lol I haven't heard of voxel colliders, is that new?
yep!
this is a trace of spawning the player in my game and I noticed that on_collider_body_changed gets called 20 times during this process. I'm not sure if that's necessarily what's contributing to the overhead of spawning, but I suspect it's kinda wasted effort, right? Wouldn't I only really need it done once the entity is "ready" (I know that's arbitrary)?
I suppose the solution is like.. make adding the collider be the last step of creation?
Turns out the UI slowness culprit in my app was Avian. If you include the physics diagnostics UI at all you lose 1.5ms per frame on even a high end system, even if the UI isn't visible. Made a fix: https://github.com/Jondolf/avian/pull/856
Sneak peek of release notes haha
This read time plugin I have gives the release notes an estimated reading time of 40 min
though code examples and whatnot probably skew this higher
everything is done now except the cover image, "Other Changes" list, and migration guide
Mm we currently call this whenever you insert ChildOf, RigidBody, or AncestorMarker<ColliderMarker>
It updates ColliderOf whenever ancestors change, or when a rigid body is added to the hierarchy
The associated code example
https://github.com/Jondolf/avian/pull/857
Should get fixed by #858 hopefully
I believe it should already work on colliders not attached to a rigid body, unless something regressed
Yup, the ray_caster example still works
That one doesn't have any RigidBody on the colliders
whoa this sounds crazy actually
I don't understand the triangle part though
what triangle part?
composite shapes with triangle meshes? I guess like.. is that saying if I have an entity with multiple colliders that aren't touching or something?
A trimesh is a composite shape, i.e. a shape consisting of several sub-shapes (triangles). It's just saying that trimesh colliders do not collide with voxel colliders
I believe that is also the case with compound shapes like the ones produced by convex decomposition, they don't collide with voxel colliders yet
ah got it
so, it wouldn't be a problem if everything uses voxel colliders? and you'd get a performance boost potentially? am I understanding that?
Is there a way to have child entities also ignored with a raycast, if the parent rigidbody is added to the excluded entities?
I often setup the colliders in child entities instead of the root object.
you're right; thanks.
I updated my examples to avian 0.4; everything seems to be working apart from island rollbacks
If the shapes should be voxelized (i.e. Minecraft-ey) then sure, but primitive shapes and convex hulls will still probably be faster / more versatile in general
Voxels are mainly a better version of just throwing a bunch of cuboid colliders on a grid
And don't have the problem of ghost collisions between the cuboids, which is a common pain point for people doing tile maps collisions in 2D or voxel terrain in 3D
Hmm we should maybe look into whether we could provide some sort of built-in collider integration with Bevy's new tile map stuff at some point π€
Currently no, unless you use something like cast_ray_predicate and manually write a filter for this that checks whether the entity in ColliderOf is an excluded entity
it's here
https://github.com/Jondolf/website
Astro.js + some Svelte components
actual blog post content uses .mdx files
there are some custom remark plugins to preprocess the markdown, for example to automatically turn @SomeUser into GitHub user links
@vestal minnow i just wanna remind you that i still have some bugs, the warnings involving re-enabling a collider, and the one with ldtk colliders (that could be ldtk itself or bevy not sure)
Do you have some way I could reproduce the ldtk problem?
I haven't seen it in other contexts in my testing
I guess I could copy the platformer example in bevy_ecs_ldtk and adapt it to use avian instead of rapier
If I'd like to simulate train physics in avian, I'm guessing I would probably write a custom constraint to keep the train wheels/bogies on the tracks, right?
I guess could also do it by applying appropriate forces, but I'm guessing that can cause problems easily due to the required stiffness there
yeah i guess so, here's my fork https://github.com/Lenchog/bevy_ecs_ldtk
@vestal minnow would you be happy to expose a few extra things from SpatialQueryPipeline as pub? I've been implementing some extra spatial queries in a downstream project (one of them is a multi-shapecast, which might be upstream-worthy if it works well, but the other is more niche), and I've ended up having to replicate the SpatialQuery and SpatialQueryPipeline types in my own crate to do it.
It'd be nice if I could just impl an extention trait on the upstream types, but it'd need: a way to obtain a reference to the &dyn QueryDispatcher, to get an entity from an index (i.e. a method returning self.proxies[idx].entity) and to access the parry TypedCompositeShape for the pipeline (public versions of as_composite_shape[_with_predicate], which could return impl TypedCompositeShape to avoid having to make the concrete return types public)
I've got a set of changes written that I'd be happy to PR if so, just wanted to temperature check first π
Yeah these seem fine to expose for SpatialQueryPipeline
But note that a lot of it may change soon-ish with the new BVH stuff using OBVHS (still WIP) and generic spatial queries (#810)
Speaking of SpatialQueryPipeline, what might be the cause of an out of bounds panic in rebuild_range_binned here?
index out of bounds: the len is 8 but the index is 8
(...)
2: core::panicking::panic_bounds_check
at /rustc/1159e78c4747b02ef996e55082b704c09b970588/library/core/src/panicking.rs:280:5
3: parry2d::partitioning::bvh::bvh_binned_build::<impl parry2d::partitioning::bvh::bvh_tree::Bvh>::rebuild_range_binned
at /home/x/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/parry2d-0.24.0/src/partitioning/bvh/bvh_binned_build.rs:58:28
(...)
Encountered a panic in system `avian2d::spatial_query::update_spatial_query_pipeline`!
I'm in the very early stages of implementing a character controller for PC and NPCs, and this happens if I get close to one of the NPCs on the side that has a raycaster. I'm very new at everything, so forgive me if this is a stupid question., or if I left out something useful from the backtrace.
Looks like a bug on the side of Parry (the collision detection lib used by Avian). That part is
// https://github.com/dimforge/parry/blob/master/src/partitioning/bvh/bvh_binned_build.rs
const NUM_BINS: usize = 8;
const BIN_EPSILON: Real = 1.0e-5;
let mut bins = [BvhBin::default(); NUM_BINS];
assert!(leaves.len() > 1);
let centroid_aabb = Aabb::from_points(leaves.iter().map(|node| node.center()));
let bins_axis = centroid_aabb.extents().imax();
let bins_range = [centroid_aabb.mins[bins_axis], centroid_aabb.maxs[bins_axis]];
// Compute bins characteristics.
let k1 = NUM_BINS as Real * (1.0 - BIN_EPSILON) / (bins_range[1] - bins_range[0]);
let k0 = bins_range[0];
for leaf in &*leaves {
let bin_id = (k1 * (leaf.center()[bins_axis] - k0)) as usize;
// THIS PANICS
let bin = &mut bins[bin_id];
bin.aabb.merge(&leaf.aabb());
bin.leaf_count += 1;
}
In your case it somehow computes a bin_id of 8, which is just one too large
I'm guessing it might be some floating-point error when the leaf's center is close to equal with bins_range[1], which could produce a value like 8.000001 or something, when it should be just slightly below 8
the easiest fix would probably be to just do .min(NUM_BINS - 1) for the bin ID
I see cases where my collider seems to have collisions disabled for some reason. It's not deterministic but I can reproduce it semi-consistently. Still trying to understand what could be the cause.
All components seem to be there, so i'm not sure what I should be looking at to debug this
Opened this ticket: https://github.com/Jondolf/avian/issues/863
Using this commit and going to this folder: https://github.com/cBournhonesque/lightyear/tree/b5392fc0a3b31f624dfd48b2eda5ea4665474a58/examples/deterministic_replication If you run (in 3 different p...
It could be that some additional resource needs to be rolled back, such as AabbIntervals. Maybe I have a resource that's stuck in an incorrect state because it wasn't rolled back? Or is AabbIntervals re-created from scratch every time? It doesn't seem to be the case.
Other candidates: ContactStatusBits ?
Then again this could also be a red herring
I've opened a PR (#862) - happy to bikeshed on names for the new methods
I could also look at writing a new example to demonstrate a custom query, if that would be valuable
And I'll keep an eye on the OBVHS work (and keep an eye out for peck too, I guess) for any future changes - thanks for the heads up
Thanks, merged!
Are you rolling back the ConstraintGraph? Though I would imagine that you'd get panics if not, instead of just missed collisions
looks like yes
I've run it about seven times and have not hit the collision problem yet. However I noticed that if I have one of the client windows off-screen, it seemingly stops simulating things on that client, which causes a desync
(I'm using niri, a scrolling/tiling window manager)
nice, me too
also hit this
probably a bevy thing and not lightyear though
I would get that a lot when having the server open (with a window for debug) and opening the client, while loading a Gltf my PC would chug and the server window would crash
Alrighty, I finally have the release notes and migration guide pretty much done, so I intend to release 0.4 tomorrow unless something goes horribly wrong
I have to zoom out to see the whole auto-generated list of PRs in 0.4 lol
Great job, hope you donβt feel to burned out by all that work 
I've been trying again and i cannot reproduce it now ... mysterious. Will let you know if I come across this again. Thanks for trying
so will I have to depend on main once it's fixed or wait for 0.4.1 for my bugs?
it's honestly not too bad depending on main. I got through almost all of 0.16 using main
yeah, I would rather release now and do a 0.4.1 patch later than delay the release further at this point
If I want to track collision events between two components, let's say "Ball" and "Goal", using the message reader, what would be the easiest way to query for the components? since the Ball could be either collider1 or collider2
rn something like this seems the most ergonomic, but might not be the most performant to check every frame
So, is it possible to do pixel perfect collisions with Avian2D?
Pixel perfect in terms of accuracy, or the collider's shape? There's the bevy_collider_gen crate for generating colliders from images with transparency, which might work
This seems fine, though you could use something like ball_query.iter_many_mut(colliding_entities) to collapse that inner loop and condition into one thing
If you want to just react to collisions for the ball, you can use the observer API of the CollisionStart event
https://docs.rs/avian2d/latest/avian2d/collision/collision_events/struct.CollisionStart.html
A collision event that is triggered when two colliders start touching.
Attach an observer for the ball, and collider1 and body1 in the event data will always correspond to the ball
wouldn't I need to attach the observer everywhere the ball is spawned?
Yeah, if you have a lot of balls then the message reader approach might still be better
I'd like to keep the behavior attached to the ball component, so anywhere the ball component exists it will be handled properly
it doesn't like that linearvel is mutable it seems
For iter_many_mut you need to do the while loop thing like in the example docs I linked
oh i see
FYI, Chris is covering Avian 0.4 live if y'all wanna follow along π I'll also be in the chat
https://youtu.be/fwYywrVapEY
https://www.rustadventure.dev/
Rust Adventure is an ever-growing collection of courses designed to help you put Rust into production through real-world projects.
lol @knotty thicket I also thought the caching was released ages ago
For real though! Lol
For my usecase I would like two objects to gently push away from each other (possibility more if there is a whole group of them in a corner). Does Avian have any support for this?
I read through the documentation but I figured I would ask here as a last ditch attempt.
Actually reading about it bit more I'm guessing I would want to use colliders for collision detection then build my own system on top of that
ooo does this work well with skein? I was planning on tackling this specific thing in my game with colliders and skein this morning and got side tracked
I've encountered an issue while trying to upgrade Tnua: https://github.com/Jondolf/avian/issues/865
I've noticed two issues with LockedAxes in Avian 4.0. I've created a minimal example which demonstrates them: Repository: https://github.com/idanarye/demonstrate-avian-4.0-locked-axis-bug W...
I don't know if I'm completely mistaken but is PreviousGlobalTransform gone with avian 4.0? Is there a replacement?
Yep, should "just work"
is there a straightforward way to move a collider (and any meta components that get added to it) to its parent? Edit: gonna just write an On<Add observer
have the collider as a child
Having it as a child messed with my logic, so this is what I did. I do not know if it's correct though
Collider::compound(vec![( Vec3::new(0., 2.5, 0.), Quat::IDENTITY, Collider::capsule(1., 3.), )])
Hi. I am quite confused. Since i updated to 4.0 none of the joints seem to work anymore. I use RevoluteJoint on the long boards and SphericalJoint on the chain. It seems no forces are applied by the joints. Basis and anchor values seem to not affect this at all. Any idea what is wrong?
Hello, I thought the warning Dynamic rigid body x has no mass or inertia. This can cause NaN values. Consider adding a MassPropertiesBundle or a Collider with mass was solved in 0.4 but I still get a lot of warnings. Do I need more than the following to make it go away?
RigidBody::Dynamic, ColliderConstructor::ConvexHullFromMesh, Mesh3d(meshes.add(Cuboid::new(x_length, y_length, z_length)))
@vestal minnow https://github.com/Jondolf/avian/pull/866
Objective
I want to have a trimesh plz
Solution
Create a builder
Changelog
TODO
need to add docs and see if we can actually get away with not depending on bevy_render
and I need to verify that this still works the same as my rerecast version
but it's ready for a review π
Yeah it looks fine generally, left some small comments
I'm not going to bikeshed this too much though since I expect this to be a relatively niche API, and we'll probably have something else later on with upstreamed mesh and collider types
yeah agreed, this should all be upstream
Not quite sure π€ The joint examples in the repo work like normal
How are the joints set up in your scene? You could also try some simpler joint configuration e.g. copying some example in the repo, to verify that at least that works
Addressed it all 
Hmm I'm not getting the warning with this setup
just to make sure, did you cargo update? π
That one should (in theory) be fixed, though someone else was still getting some warnings when using ldtk I believe
And remember to remove any patch.crates-io or git references you had in Cargo.toml
btw I don't like the panics in there, but those will panic on the parry side anyways, so I thought it's better to make them more visible π
Oh you should rename the ball_subdivisions method too, you seem to have renamed just the property atm
Also update the doc comment and panic messages
(to use "sphere")
oh yeah good catch
done
Thanks! Looks good now, merging (assuming CI plays nice)
avian3d v0.4.0
Hi. Is there a way to fully clone entity with rigidbody component? Like with commands.(entity).clone_and_spawn or something. It only works if i change it while cloning from static to dynamic like so
commands
.entity(root)
.clone_and_spawn_with_opt_out(|builder| {
builder.deny::<RigidBody>()
})
.insert((
if is_anchored {
RigidBody::Static
} else {
RigidBody::Dynamic
},
))
or this way
commands
.entity(root)
.remove::<RigidBody>()
.insert(RigidBody::Dynamic);
but if i try to just clone it entities start floating around
mostly talking about preserving all velocities, moments etc while cloning

@vestal minnow do we have something like a weak handle to colliders?
I guess I could clone the underlying shape weakly
weren't weak handles removed?
Yeah, but Colliders are not Assets anyways
They're Arcs
So I guess I do a weak clone of them and put it in a hashmap for lookups 
rubs glasses
I guess not handles anyway but lol at "not handles, they're arcs!"
heheheehhe
Wish I had an AssetId for them and AssetEvents
Since I don't know how I would ever clear up a HashMap<SharedShape, T>
Oh wait
map.retain(|shape, _| Arc::strong_count(&shape) > 0);
this works!
Hold up, a HashMap<SharedShape, T> or HashMap<Collider, T> is useless ;-;
No Eq, no Hash
Any of you got a better idea than to... store the Debug string as a key? 
Ah also @vestal minnow I pacified the CI for https://github.com/Jondolf/avian/pull/866
pressed the button
thx!
the SharedShape Arc has Eq
so, uh, unwrap it? lol
HashMap<Arc<dyn Shape>, T>
wanders off to find the error from that
Low-level hash table with explicit hashing.
Oh whaaat
TIL!
okay, having read through this, I need to provide my own hasher
I'm not very experienced in these things
Do you have a suggestion how to go about it?
I guess the most manual way would be to downcast the shape to every possible typed shape and hash those?
Shape: DowncastSync seems helpful
the typed shapes also don't implement Hash
there's already .as_ball() and friends π
It just seems like a lot of boilerplate 
and a direct downcast lol
picked HeightField from the shapes at random and it doesn't impl Hash
hmm and even hashing the individual fields of the methods is tricky because they're f32
time for ordered float
I don't have any real great suggestions tbh, I don't really ever need hashtable, I just know it exists π
and the end goal is just to deduplicate things like Collider::cuboid(1.0,1.0,1.0)?
Not directly
it's for steam audio
I need to have a map from colliders to meshes
where steam audio would appreciate it if two identical colliders reuse the same mesh
try hashing by address then
got a snippet?
otherwise I could also fill in this beautiful thing 
RoundTriangle
c.shape().0.as_ptr().hash(..)
that's shapes with rounded corners π
π
well yeah it's address hashing
A and B are not the same
I was hoping it would hash the address of the thing behind the Arc
if it's two clones of the same arc-
is there something similar that will hash to the same value if B is a clone of A?
As in, two Arcs pointing the same way
this should do that
assert_eq!(hash_a, hash_b); fails
oooh good point
or wait

hashbuilder not hasher
ding ding ding!
That was it
thank you so much π
So do I need to store the hash builder in my collection?
In order to not rebuild it
And manually impl Hash for it?
struct ColliderKey(Collider);
impl Eq for ColliderKey {}
impl PartialEq for ColliderKey {
fn eq(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.0.shape().0, &other.0.shape().0)
}
}
impl Hash for ColliderKey {
fn hash<H: Hasher>(&self, state: &mut H) {
Arc::as_ptr(&self.0.shape().0).hash(state);
}
}
like that?
actually i'd probably put it onba Weak, for that thing you were doing earlier