#Avian Physics
1 messages · Page 39 of 1
This particular issue should be fixed now if you run cargo update, hopefully
assuming you're using main
Dis you fix the f32::MAX rotation and the NaN/inf prone position yet?
is there something that stores contacts across frames?
I believe the problem with collisions not working even for static bodies was that our ColliderAabb updates use velocity and the center of mass for expansion, and it doesn't treat static bodies differently yet. And infinite mass made the center of mass NaN, which in turn messed up the AABB. I fixed the NaN problem now so collisions should work at least
That logic should handle static bodies differently (I have this on my broad phase rework branch) and ideally static bodies probably shouldn't have mass property components at all (I have this on the rigid-body-split branch)
They're stored in the ContactGraph, and graph coloring is persisted in the ConstraintGraph
Not yet
so, what happens if I despawn a sensor while it's colliding?
There's a remove_collider_on observer that runs when a collider is removed, and it removes the collider from the contact graph and constraint graph and sends CollisionEnded events etc.
ah.. it looks like... I'm despawning the collider and then it gets added to the constraint graph
hmm, I kinda fixed it by disabling the sensor and then delaying its despawn for a couple seconds and that prevents the panic. Despawning colliders seems to be kinda tricky though... is there a safe pattern for that?
Did someone say entity disabling? 👀
thanks! you're fast 😁
Im having a slight problem w avian and tnua. I dont see a tnua help channel here. But basically my character isnt always being “pushed up” properly after walking up a shallow incline . I feel like it has something to do w the “spring “ sensor under them
But also i wonder if theres an integrator used for this
there is https://discord.com/channels/691052431525675048/1173981291801223239 is that what you're looking for?
is this the "idiomatic" way to say collide with everything but this particular thing?
Instead of CollisionLayers::ALL_FILTERS.filters you should be able to use LayerMask::ALL, but otherwise yeah that's fine
If you don't want to use bitwise ops, this should also work
let mut filters = LayerMask::ALL;
filters.remove(GameCollisionLayers::WorldBorderCollider);
I thought we had some helper that you can chain nicer, like LayerMask::ALL.without(GameCollisionLayers::WorldBorderCollider), but it doesn't seem like it
yep
I also was expecting a .without() helper
that's mainly why I came to ask
hahah
Will use LayerMask::ALL
Isn't there a way to apply a force at the local point?
No, I haven't seen a method for it in any other engine either. "Local point" is also kind of ambiguous in this context; should it be relative to the transform origin, or relative to the center of mass? Either one can be useful depending on what you're doing
You can just transform your local point into world space and apply a world-space force
@vestal minnow I can't find anything specific in the commit history, but did you happen to scopecreep any fixes for warnings and crashes (relating to diagnostics iirc) that happen when the default collider is disabled? The last commit I have in my current branch is https://github.com/Jondolf/avian/commit/81dcb5f737b6054f3089fbb536864e91f2ed9769 but I have a bunch of random changes there to make my game not crash, and I have an ungodly number of clippy warnings 
CenterOfMass::new takes x, y and z, as the local variables relative to the entity's origin, right?
I'll switch to this for my project just to be up to speed when kcc comes out.
I don't remember fixing anything there recently, but I also don't remember it being broken :P
it's very possible it has issues though, we should really test it in CI somehow to catch problems
I'm not understanding how to scale a collider... whatever I set on the Transform when the collider is created doesn't stick... but using collider.set_scale also doesn't seem to affect the final collider... I'm judging this based off of the debug shape.. it seems to always stay at scale 1.0... but I can change the shape of the debug scale if I modify the Transform's scale... not sure if that actually affects the physics though
oh wait, it's possible something else is changing the transform
🤦♂️ yeah I was resetting the scale to 1.0 lol
Is there a way to assign different collision channels? I want to spawn 100 objects at the same location, and I want them to collide with the ground but not each other
https://docs.rs/avian3d/latest/avian3d/collision/collider/struct.CollisionLayers.html is this what you're wanting?
Defines the collision layers of a collider using memberships and filters.
So, there are just 5 layers?
32
@vestal minnow
❤️ Check out Lambda here and sign up for their GPU Cloud: https://lambda.ai/papers
Guide for using DeepSeek on Lambda:
https://docs.lambdalabs.com/education/large-language-models/deepseek-r1-ollama/?utm_source=two-minute-papers&utm_campaign=relevant-videos&utm_medium=video
📝 The paper is available here:
https://graphics.cs.utah.edu/rese...
did you saw this?
Doesn't unreal engine have something to prevent that kind of issue?
Also I would like to see fluid simulation in avian, as i'll be using it in my game.
yes I've seen that
If avian doesn't have it already, I guess the best way is just recording the next position and last position and looking for an intersection if that's possible.
Avian has both speculative collision and sweep-based CCD. That paper is about a different problem, specifically inter-penetration-free collisions in particle simulations
Afaik it basically merges colliding particles into larger "meta-particles", stores the potential energy stored in the virtual bond to preserve kinetic energy, integrates movement, and later splits the meta-particles back into smaller particles
Is this possible for realtime fluid sim?
depends on what "realtime fluid sim" means
their test scenes have several seconds per frame
But do you have millions of particles? 2D or 3D? It depends on the scene
Pretty much no particle-based fluid simulation method I know of can handle large-scale 3D fluid simulations in real time on consumer hardware
But again depends heavily on how large or detailed the sim is
something like an SPH sim in the range of a few hundred thousand to a million particles should be doable, especially on the GPU
Potentially, and 2d
Btw, how long is it estimated until the kcc is finished?
I haven't really been working on it much myself, it has mostly been the KCC working group so far
https://discord.gg/GyBFraCc
I'm already in it. Understood.
is there a way to use avian with a water surface as a collision mesh? like the mesh could allow objects to go inside it a little bit and still provide some bounce /push back...?
There’s no builtin buoyancy, so you have to DIY that effect
mut query: Query<(RigidBodyQueryReadOnly, Forces)> panics because of a conflict:
&avian3d::physics_transform::transform::Position conflicts with a previous access in this query. Shared access cannot coincide with exclusive access.
Anyone know how I can query both information of a rigid body and be able to apply forces to it?
Wrapping them in a QueryData doesn't work either
#[derive(QueryData)]
#[query_data(mutable)]
struct TestQueryData {
body: RigidBodyQueryReadOnly,
forces: Forces,
}
Looks like picking out the specific components of RigidBodyQuery stops the panic
I would suggest not using RigidBodyQuery and just querying for the components, yes
I'm most likely removing RigidBodyQuery soon, it was originally not really intended for users and is also kind of big/inefficient and easily causes conflicts like this
Sounds good, I'll avoid it then
I realised that doing my own physics for a jam isn't the best idea, I've figured out a plan on how to move over to avian. I'm aware that there's Collider::compound, is that all I need to do in regards to reducing checks? I assume keep the compound colliders roughly rectangular to reduce overlapping to reduce the number of collider checks, and doing it as a grid will avoid covering open areas as much. Docs are fantastic and I assume I've managed to overlook what the recommendation is
I just don't know how much Avian does and how much I should be helping it
I'm spawning an child entity with collision, but I've noticed that if I rotate an parent(right_leg_axis), collider doesn't follow. Why, and how can I fix it?
let right_leg_axis = commands.spawn((
right_leg_axis_transform,
ChildOf(rocket_id),
LegDirection::Right,
LegAxisTag
)).id();
commands.entity(rocket_id).add_child(right_leg_axis);
let right_leg = commands.spawn((
Mesh3d(leg_mesh.clone()),
MeshMaterial3d(shader_material.clone()),
Collider::cuboid(LEG_WIDTH, LEG_HEIGHT, LEG_THICKNESS),
CollisionLayers::new(0b00100, 0b00010),
Transform::from_xyz(0.0, LEG_HEIGHT / 2., 0.0),
ChildOf(right_leg_axis),
LegDirection::Right
)).id();
commands.entity(right_leg_axis).add_child(right_leg);
is it expected that OnCollisionStart doesn't trip if a collider is spawned colliding with another collider?
actually it seems to be working now. but maybe it's inconsistent
When rocket's y location is lower than 500
Colliders are static by default. I think you want to make the parent a kinematic rigidbody
So, I made parents(axis) kinematic bodies, and now its more static than ever xD
Should adding an ExternalImpulse component to an entity with a RigidBody::Dynamic be enough for the impulse to take effect on the body, or is there something else to it? The examples in the docs only show an ExternalImpulse being added when the entity is spawned, but I'm assuming it should work when added to an existing entity too? (Of course I am asking because so far it is not working for me 😸 )
I have a player who is a circle and I want to just handle them as a circle, completely balanced and without anything sticking out. I would like to add some things sticking out that would then put it off-balance and I'm not sure what the best way to deal with it is - the bits sticking out is a head and legs (head slides, legs pivot)
The simple solution is to attach them to the dynamic body but I don't want a leg placed at a specific angle to cause the character to rotate weirdly or bounce in the wrong direction. The next solution is that I stick the head and legs onto a kinematic body and put it on a physics layer where it doesn't interact with the dynamic body, and then pre update I predict where the dynamic body will go (position and rotation, it may be placed overlapping a solid), then avian handles collisions and then after I move the kinematic body to where the dynamic body actually is. There may end up being a slight difference in head and leg positions but it's purely visual
I think that there's no way to have a dynamic body and for it to ignore if a part that does collide collides with something, and I'm assuming that what I want to do is niche enough to not have a ready made solution. But I feel like I should ask just in case I could do it a better way, ideally I'd do physics for the dynamic body, and then move the kinematic body and do physics again but it's also not that important
Does Applies a linear impulse at the given point in world space. The unit is typically N⋅s or kg⋅m/s mean that impulse in apply_linear_impulse_at_point should be multiplied by deltatime? Why is it newtons multiplied by seconds?
An impulse is an amount of force that was applied over a duration, accumulated and applied all at once iirc
As opposed to just a force, which is applied over time for as long as it is relevant (either 1 tick or until you remove it if it's a constant force)
Newtons are over time, impulses are instantaneous. To integrate from something over time to something instantaneous, you multiply it by the time it was applied.
In practice, you wouldn’t think about it in terms of time, so don’t multiply it by dt.
For example, a punch transfers an impulse of about 60 Ns. Use that as a starting point 🙂
You can also look at Ns as kg*m/s, which is mass * speed. No time needed in there! A 1 kg block falling on the ground with 1 m/s will transfer an impulse of 1 Ns
Should I treat it as a newtons over a second, or over a single frame?
It’s instant
If I apply force with apply_force_at_point to the child, will it also affect the parent, e.g. will parent be lifted? And what if I just apply_force at the child. Would there be any difference between applyying force at the children's point, or applying force directly to the children?
You can only apply forces to rigid body entities. But you can apply the force at the position of a child entity, which in effect is like applying the force to the child
If the head and legs are purely visual, you could probably just not give them colliders, and to give them a lower Dominance than the player so that they don't affect the player
(default dominance is 0, so you could set it at -1 or something for the head and legs)
I'm assuming you're using joints for the attachments here
Yep, I'm just drawing my concern with attaching it to the player atm
As a rough idea, the leg in that position would push the circle into a new path because it's attached to it, would setting a vevy low dominance avoid that?
I guess I would be happy with having legs rather than swing they could slide, along with the head, and they can be round so shouldn't affect anything - or combined linear and rotational. I'm just aware that in this scenario the leg doesn't really have anywhere to go, I was just going to leave it up to the kinematic body to figure it out, I guess it might just push the leg out to the side
Oh right so they're not purely visual but do collide with the environment, they just don't affect the player or the things they're colliding with
The lower dominance should do that, but the head and legs might kinda freak out in some cases like that where they're essentially being forced into impossible positions
Ah perfect, yeah I'm fine with them freaking out as long as the player's path would be the same with or without them 👌
adding some compliance to the joint (i.e. lowering the stiffness) might make it handle cases like that a bit more gracefully instead of blowing up
Ahh
I've been trying to figure out how to make a springy joint and is that something I'd have to do myself, setting a force to push it to the neutral position? Been playing around with constant forces and there's world space ones but the neutral position changes angle as the character rotates, but that's very easy to calculate as it's just based on the character's rotation, and then local which has no effect as it's moving with the leg so either it's parallel to the centre of mass to joint and does nothing, or it spins. Is there some kind of middle ground where a parent can apply a force to children? So I could attach the leg to some shape and that applies a force down and to the right, and the leg may hit things and move out of place but have the force return it?
A DistanceJoint is kinda like a spring, though maybe not as configurable as you might want, and only constraints positions, not rotation
Ah yeah RevoluteJoint with force just being updated every frame may have to do
At least with the PrismaticJoint I can use local force there
It would be cool if I could attach a local force that negates rotation. Something like spawning the RigidBody pointing out 45 degrees bottom right, and then slap on a ConstantLocalLinearAccelerationWithoutRotation::new(100.0, -100.0) (long name, or would it be WithRotation? Absolute? It's kind of like a world space but just on a local space so could have the awful name ConstantLocalWorldLinearAcceleration) and it just counters its rotation and doesn't care about the world
How do you check for collisions with an object?
There are multiple ways. https://docs.rs/avian3d/latest/avian3d/collision/collider/struct.CollidingEntities.html is often the simplest.
A component for reading which entities are colliding with a collider entity. Must be added manually for desired colliders.
yeah I believe this would be a joint motor like in Box2D or Jolt, which is planned in the future
Ah
it'd drive the bodies to a target relative transform or velocity; if the other body is static/non-existent, it'd only drive that single dynamic body to the desired target
with optional force and torque limits and spring parameters etc.
Ouh that would be cool
Thank you for your work, I'm here after messing up my physics engine, it only needed to handle a dynamic circle against static circles, aabbs, and obbs with bouncing and rolling - I'm taking part in a jam and I had time and figured I'd do it myself yesterday, it's got TOIs and everything should work fine (I have unit tests and it works exactly as predicted) but circles randomly give huge velocity when a dynamic rolled down to about 35 degrees (not 30, not 45, I might have been able to understand but it's between them), and when they weren't going between circles they were climbing up the side and resting at the top. I did also add in a polar coordinate physics engine which handles swinging on tethers which actually worked well tbh, but turns out that it's not a great idea to merge coordinate systems, when swinging can be handled in cartesian coordinates fine
What if it has 2 or more colliders?
Does the circle collider use vertices?
no, almost all geometric primitives like circles, rectangles, capsules, and so on are represented by their properties like the radius or half-extents
simplices (line segments, triangles, tetrahedra), polytopes (polygons and polyhedra) and triangle meshes use vertices
https://www.youtube.com/watch?v=A0L_PZwuGHY new triangle collider 🤭
Thanks to Jane Street for supporting this video. Check out their open roles, programs and events: https://www.janestreet.com/join-jane-street/
Here is the original "Is there an equation for a triangle?" video. https://www.youtube.com/watch?v=4K-Jx914NcQ (I'm taking suggestions for what Part III should be named. Comment below.)
And thanks to ev...
Good. Just make sure, I almost forgot that using vertices is faster than rendering an image.
So that's why the debug plugin displays it that way.
https://youtu.be/iUT-E7-mSdI
https://graphics.cs.utah.edu/research/projects/avbd/Augmented_VBD-SIGGRAPH25.pdf
doesnt have the patent problems xpbd had 
My implementation of Augmented Vertex Block Descent by Chris Giles at al.
https://graphics.cs.utah.edu/research/projects/avbd/Augmented_VBD-SIGGRAPH25.pdf
Source code: https://github.com/Raikiri/LegitParticles
I'm definitely glad that we finally have something that actually sometimes works better than PBD, but AVBD has quite a few more paramet...
#math-and-physics message 😄
fair enough
Probably a silly question but how do I use the most up to date version of avian2d? Github says avian3d = { git = "https://github.com/Jondolf/avian", branch = "main" } but that's for 3d, I tried to select crates/avian2d but got a 404, I haven't needed to get a dependency from git that wasn't the default. This is to use the force rework
How can I detect collision with a specific entity? E.g. I want to despawn en entity after it hit other, specific entity
Does avian use delta time or fixed timestamps?
Both, fixed and looks at the delta time
Edit: I think you mean is the ticks dynamic or fixed - it's fixed. Delta time would be used for both
Is there a way to make it just fixed? So if there is no "lag", and program just runs slower with more elements
It is fixed, sorry my reply was half a joke
By default it uses Time<Fixed> which has a fixed delta time (= fixed time step)
What is the fixed time stamp? 60fps?
.insert_resource(Time::<Fixed>::from_hz(100.0)) whatever you want
What do you tend to go for? Hz and substep
How would it behave when there are lags? Would it just multiply it by delta time and "jump", or would it just move at the slower rate?
Whatever is most suitable for the given project to get the desired perf and stability. I have a mild preference for 60 Hz, but usually I just start with Bevy's default of 64 Hz and 6 substeps, and adjust the substep count if needed
The motivation for Bevy's 64 Hz is
This value was chosen because using 60 hertz has the potential for a pathological interaction with the monitor refresh rate where the game alternates between running two fixed timesteps and zero fixed timesteps per frame (for example when running two fixed timesteps takes longer than a frame). Additionally, the value is a power of two which losslessly converts into f32 and f64.
https://docs.rs/bevy/latest/bevy/prelude/struct.Fixed.html
The fixed timestep game clock following virtual time.
But in practice, I had never seen this "pathological interaction" or needed lossless conversion when using the old default of 60 Hz. And switching to 64 Hz had the downside that movement becomes very choppy on 60 Hz monitors (like mine) unless you're using transform interpolation, since on some frames you skip physics
I see, I see
It's not too bad, since you probably want interpolation for higher refresh rates anyway, but it is a bit annoying, as it makes the default experience on 60 Hz monitors stuttery
Yeah
Bevy's fixed updates accumulate real time and then consume it in fixed steps. So if a frame took for example 1.0 / 30.0 seconds and you had a fixed time step of 60 Hz, it would run schedules like FixedUpdate twice to try and catch up to real time
The downside is that you can get stuck in a "death spiral" where frames always take more and more time because it's running fixed updates in a loop to try and catch up
You could limit the maximum number of time steps per frame to alleviate this, though I don't remember if Bevy supports it. The downside with that is that it will no longer be guaranteed to be caught up with real time, and things can slow down at low frame rates
This is the result that I would like to achive, to have as stable delta time as possible. E.g. to always be 0.01 sec for the sake of this simulation
Btw. I spawn 20 objects(Collider for tube and 4 colliders for legs, so the total of 100 colliders) and they start to lag as hell, when they hit the ground
It's the opposite isn't it? At 64hz you're doing physics twice on every 15th frame. Kinda funny I guess that to avoid the 'pathological' case it instead just guarantees there will be jumps :p
Any idea why? 100 seems like a very small amount
This is leg's entity
let front_leg_axis = commands.spawn((
front_leg_axis_transform,
ChildOf(rocket_id),
LegDirection::Front,
LegAxisTag,
)).id();
commands.entity(rocket_id).add_child(front_leg_axis);
let front_leg = commands.spawn((
Mesh3d(leg_mesh.clone()),
MeshMaterial3d(shader_material.clone()),
//Collider::cuboid(LEG_WIDTH, LEG_HEIGHT, LEG_THICKNESS),
//CollisionLayers::new(0b00100, 0b00010),
Transform::from_xyz(0.0, LEG_HEIGHT / 2., 0.0),
ChildOf(front_leg_axis),
LegTag,
LegDirection::Front
)).id();
commands.entity(front_leg_axis).add_child(front_leg);
And the collision is added at the real time
Right yeah you're correct, I always think of it backwards :P
for (leg_child_entity) in leg_axis_children.iter() {
if let Ok((_)) = leg_query.get_mut(leg_child_entity) {
commands.entity(leg_child_entity).insert((
Collider::cuboid(LEG_WIDTH, LEG_HEIGHT, LEG_THICKNESS),
CollisionLayers::new(0b00100, 0b00010),
));
println!("ADDED COLLIDER!");
}
}
Yeah if those are primitive shapes like cylinders and cuboids, it definitely shouldn't be slow. Are you running in release mode or with debug optimizations? That can make like a 100x difference in performance
Debug without optimisations
yeah that will be extremely slow with any Bevy app, especially with physics stuff
see this for configuring it
https://bevy.org/learn/quick-start/getting-started/setup/#compile-with-performance-optimizations
building with --release flag should build it with all the optimisations, right?
a lot of optimizations, but not all, there's stuff like codegen-units = 1 and lto = "thin" if you want to squeeze out even more perf for release builds at the cost of longer compile times
the Bevy docs describe that a bit more
I was playing around with the prismatic joint example and it doesn't seem to like the joint axis being in line with gravity causing it to jump
let anchor = commands
.spawn((
square_sprite.clone(),
RigidBody::Kinematic,
//AngularVelocity(0.00075), // Changed. Slight turn and the jumping goes away
))
.id();
let object = commands
.spawn((
Sprite {
color: Color::srgb(0.7, 0.2, 0.2),
custom_size: Some(Vec2::splat(50.0)),
..default()
},
Transform::from_xyz(0.0, -50.0, 0.0), // Changed, it being +50 with +Vector::Y is the same effect
RigidBody::Dynamic,
MassPropertiesBundle::from_shape(&Rectangle::from_length(50.0), 1.0),
))
.id();
commands.spawn(
PrismaticJoint::new(anchor, object)
//.with_local_anchor_1(Vector::Y * -50.0) // Having the anchor outside of the shape doesn't change it
.with_free_axis(-Vector::Y) // Changed
.with_limits(20.0, 200.0) // Changed
);
Try putting SleepingDisabled on that dynamic object, I'm curious if that fixes it
if so, it should be properly fixed once I finish the simulation island PR
Yes, that's fixed it
It's kinda weird but I think it currently has a bug where the body goes to sleep for a frame when it's resting at the bottom, and is immediately woken up by the joint, but it was still simulated for a part of the frame or something, so it falls down a bit and then the joint limit snaps it back
or something like that lol
A square's hypnic jerk
Can I ask about this again?
It should work the same for 2D and 3D 🤔
[dependencies]
avian2d = { git = "https://github.com/Jondolf/avian", branch = "main" }
I think you can explicitly choose a specific package from the workspace using package = "avian2d", but it should also be able to find it automatically based on the dependency name
Ouh I see, I didn't realise
Also is it intended behaviour that Collider::round_rectangle(width, height, radius) will result in a rectangle that is expanded by radius on each side (width+radius*2.0, height+radius*2.0)? I just expected it would give back a rectangle that is width by height with corners rounded. Seems yes, I guess it might be designed for a different purpose
How can I gen an acceleration?
Is there a built in function or do I have to calculate it myself?
Yeah that's how it works in Parry (the underlying collision detection library) and most physics engines. The collision algorithms can't just directly make an arbitrary shape round, it typically needs to be done by inflating the shape by a radius
The API could be designed to automatically subtract the radius from the shape's extents to avoid inflating them, but this wouldn't work well for more general shapes like rounded polygons, and would break in cases where the extents are smaller than the border radius
to apply an acceleration you can just use linear_velocity.0 += acceleration * delta_secs
or alternatively the Forces API if you're on the main branch
or do you mean how you can get the current acceleration of a body?
I want to receive an acceleration, not apply it
exactly
Oh, I made a typo
now see
right, I thought you meant "generate" haha
I came up with something like this to get an acceleration in the local space:
for (mut accelerometer, transform, solver_body) in accelerometer_query {
accelerometer.current_velocity = solver_body.linear_velocity;
let acceleration = (accelerometer.current_velocity - accelerometer.previous_velocity) / time.delta_secs();
accelerometer.acceleration = transform.rotation.inverse().mul_vec3(acceleration);
accelerometer.previous_velocity = solver_body.linear_velocity;
}
Yeah that should work
There is no first-party thing for getting the total current acceleration since you need to figure out all the contact forces and joint forces and their effects on the bodies, which requires running basically the whole solver. So the best you can do is to estimate it based on the current and previous velocity, like you're doing
Ah, makes sense, ty
I didn't realise that a rounded polyline was a thing, that does make what I'm doing a lot simpler which is nice
Nvm, it seems to only exist for solid convex shapes
the trait bound `RoundShape<avian2d::parry2d::shape::Polyline>: Shape` is not satisfied
the following other types implement trait `Shape`:
RoundShape<avian2d::parry2d::shape::ConvexPolygon>
RoundShape<avian2d::parry2d::shape::Cuboid>
RoundShape<avian2d::parry2d::shape::Triangle>
required for the cast from `std::sync::Arc<RoundShape<avian2d::parry2d::shape::Polyline>>` to `std::sync::Arc<(dyn Shape + 'static)>`
Not sure why it wouldn't be possible, I get that concave corners wouldn't be rounded but that's fine
Nvm, I got the terminology mised up, it's not a hull, it's a line
Actually that should still be possible it's just that it would expand on both sides. It surprises me that I'm the first to say "round polyline" here or in dimforge's discord server and I feel like I'm missing something obvious which would lead people to not think to want it
@vestal minnow any idea what these errors are all about? 🤔
a round line is a capsule, so you could combine multiple capsules
Oh yeah of course, I assume there's no concerns with overlapping colliders sharing edges
Maybe try cargo update? I see a lot of errors about methods related to SymmetricMat3 not being found for AngularInertiaTensor which is from bevy_heavy, but they should definitely exist on main
https://github.com/Jondolf/bevy_heavy/blob/942fe8ea21c90bdc341e90487a98f7bd3c6ad378/src/dim3/angular_inertia.rs#L171
Or maybe you or some other dependency is also depending on bevy_heavy directly and there's a version conflict
Okay yea a cargo update fixed those errors ... But not the ```rust
cannot borrow *self.contact_status_bits as mutable, as it is a captured variable in a Fn closure
and ```rust
expected a FnMut((usize, &mut T)) closure, found F
mm is that with parallel disabled?
Yes, why would sdf collisions enable parallel for the end user 
Also so damn many warnings and they aren't even from my changes 
heck okay I'll fix that one asap, not sure how I didn't notice that our par_for_each thing is broken on single-threaded lol
Oh that's cursed, the function wants to be FnMut for single-threaded but Fn for multi-threaded
because par_chunk_map_mut takes Fn but .iter_mut().for_each(...) takes FnMut
and the single-threaded narrow phase kinda needs FnMut right now
this was a macro before, which didn't have this issue, but it broke RA
Just to save going down the wrong path, I did search first, Position in Collider::compound is relative? As such if I were to combine a bunch of points into capsules I would want to convert them into local space, probably make the middle of the aabb (0,0) and then also return a Transform to move that midpoint such that points line up with where they ought to be?
it's relative to the position and rotation of the collider, yes
Perfect, thank you
@cinder summit #802 should fix that along with many other errors and warnings, like those annoying warnings about unused diagnostic stuff
🥳
Draft for part 1 of the fabled Joint Rework
https://github.com/Jondolf/avian/pull/803
Uhhhh yeah don't worry about the PR size 
-# it's not done
yeah I need to somehow write a proper cohesive description for this later, just wanted to put it out there already
a part of the PR is that it technically lets you use Avian without any XPBD since it's now properly isolated and feature-gated
with the intent that we just swap out the XPBD constraint implementations later when the new joint solver is done
I also made the joint components much more general and moved most solver implementation details out of them, so that they could technically be used with any solver
which would also be nice for a future bevy_physics if we want it to support multiple physics backends
The main remaining work is figuring out the details of how the JointFrame API should work 🤔 I like having the Auto variant, but it can also be quite confusing and unintuitive sometimes
I might start off with having just the Local and FromGlobal variants, and leave the automatic frame stuff to a follow-up
and default to local identity frames like the current defaults
Sharing for if anyone else needs a round polyline in the future, it's in 2 parts, one for getting a translation back so that points given go to where they should do, and another which doesn't process points and it just preserves shape, but could just be round_polyline and ignore the transform
https://gist.github.com/zeddash/a52735835396ca3c67824dbf014aa264
How do you check if a component with CollidingEntities collides with a certain component?
aka what would go in
for (entity, colliding_entities) in &query {
}
at that point?
I usually have a separate query for the components I care about and check if one of the entities in the collision exists in that query
like, if using CollisionLayers doesn't make sense for whatever reason
Is there some sort of the event that fires when 2 entites collide?
yeah you can opt into collision events and then listen for them
not sure if this is the best place to ask, but has anyone implemented recording physics and then playing it back? I'm wondering how feasible it'd be to add a replay mode in my game
@vestal minnow there wouldn't happen to also be a compile error with serialize enabled by any chance?
Depends on what you mean by recording, that does sound a bit like rollback 👀
There are ofc ways to do it
Avian is deterministic
Just save parameters
rollback?
yeah, so far I haven't been opting into the deterministic features.. I guess "saving parameters" would be like.. tracking what each entity is doing each frame? 🤔
Yea, the networking magic where you record a bunch of values, then play everything back when you receive data that was in the past
No. Just save e.g. linear, angular velocity, torque, mass and transform and the set all of these back on the entity
hmm, I guess if I do that, I'd need to make sure everything is deterministic
Yes
But that shouldn't be a problem
If you want to add randomness, just also save random numbers you generated and added into physics
would just... disabling physics and only "recording" transforms and then play it back work too though?
Hello, i am trying to speed up the game by setting the speed of the virtual time,
however, this causes the physics to slow down, effectively movig at the same speed. Is that ment to happen or did i messs something up?
How do I do that
there's probably better ways of handling this but something like this works for me
fn handle_vehicle_collisions(
mut commands: Commands,
mut collision_event_reader: EventReader<CollisionStarted>,
trees: Query<Entity, With<IsTree>>,
vehicles: Query<Entity, With<IsVehicle>>,
) {
for CollisionStarted(entity1, entity2) in collision_event_reader.read() {
match (
trees.get(*entity1),
vehicles.get(*entity2),
trees.get(*entity2),
vehicles.get(*entity1),
) {
(Ok(entity), Ok(_), _, _) | (_, _, Ok(entity), Ok(_)) => {
// "entity" is the tree that got hit
}
_ => (),
}
}
}
I have one system where it's iterating over the collisions and then comparing different scenarios. (The match is a little gross, I wrote it a loooong time ago and just haven't revisited it)
that's iterating over the CollisionStarted events but.. I think you could do something similar
So you can't check which entities something collided with with CollidingEntities?
I might not be understanding your question..
are you trying to do something like this?
fn my_system(query: Query<(Entity, &CollidingEntities)>, vehicles: Query<Entity, With<IsVehicle>>) {
for (entity, colliding_entities) in &query {
for colliding_entity in colliding_entities.iter() {
if let Ok(vehicle) = vehicles.get(*colliding_entity) {
// current entity has IsVehicle component
}
}
}
}
thread 'main' panicked at avian/src/dynamics/solver/mod.rs:478:21:
Contact pair not found in graph: ContactId(0)
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `avian3d::dynamics::solver::prepare_contact_constraints`!
Encountered a panic in system `avian3d::schedule::run_physics_schedule`!
thread 'main' panicked at avian/src/dynamics/solver/mod.rs:482:51:
index out of bounds: the len is 0 but the index is 0
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
Encountered a panic in system avian3d::dynamics::solver::prepare_contact_constraints!
Encountered a panic in system avian3d::schedule::run_physics_schedule!
I ran into this a few times when I have a collider touching a sensor collider while I despawn the sensor collider
Huh ... I don't even think I'm despawning anything, but I might remove components for rollback or disable entities 🤔
it's possible that causes it too. I ended up disabling the collider, waiting a few frames and then despawning
Well, if it's related we'll probably want this to just ... not crash 🫠
I'll test later today
Yeahhh I still need to repro these, I haven't managed to get panics with my various test scenes in a while
I know there's still one that happens when you change a dynamic or kinematic body to a static one while a collision is still happening
Let me test if this also happens on my bevy_rewind example, if so that's somewhat minimal
Interestingly only my game's client crashes, while the server doesn't
So I assume it's caused by something rollback does
Huh ... it doesn't? That's odd 🤔
Is there some way to add logging for the conditions causing these two crashes?
Cause afaict the problem originates from elsewhere
They happen when the ConstraintGraph has contacts that don't exist in the ContactGraph anymore
so the contacts are not being updated correctly somewhere
most likely related to adding or removing colliders, or changing the body type, or something like that
Let's see if I can spot any trends in when it happens if I just ignore the errors 
I don't think I ever modify the body, but I do remove some required components
mm, I wonder if maybe some observer is querying for a component that you've removed, which then breaks contact management
feels unlikely, I don't think the observers that respond to removing colliders etc. really use queries
These are all the components/resources I currently roll back
.register_authoritative_component::<Position>()
.register_authoritative_component::<Rotation>()
.register_authoritative_component::<LinearVelocity>()
.register_authoritative_component::<AngularVelocity>()
.register_predicted_resource::<ContactGraph>()
.register_predicted_component::<CollidingEntities>()
Meaning they can get removed too
Should I add the ConstraitGraph here too? 🤔
maybe?
it's persisted across frames and updated as contact pairs are added/removed
Also turns out this is damn near impossible
Absolutely everywhere in avian starts panicking 
Okay no more crashes now ... but why are my collisions broken? 
Broken as in not being detected, or behaving wonky?
I wonder if this change is even valid 
let sdf_local_min_point = (start + sdf_local_up * *at).into();
-let gradient = sdf.gradient(sdf_local_min_point);
+let gradient = Vec3A::from(sdf.gradient(sdf_local_min_point));
let world_normal = sdf_iso.rotation * -gradient;
-let point1 = Vec3::new(0., *at - self.half_length, 0.)
- + self_iso.rotation.inverse() * world_normal * (self.radius + dist.max(0.));
-adder.push(
- point1,
- sdf_local_min_point,
- world_normal,
- self.radius - dist,
-);
+let dist = dist - self.radius;
+let anchor1 = world_normal * (self.radius + dist * 0.5);
+let world_point = self_iso.translation + anchor1;
+let anchor2 = world_point - sdf_iso.translation;
+
+adder.push(world_point, anchor1, anchor2, world_normal, dist);
Wait that sign on the penetration is wrong ...
Okay changing that makes no difference ... Wouldn't expect a wrong penetration value to cause such a casual phasing trough the floor anyway
... Wait do I still get the errors now? Gotta make sure it's not related to that ...
Okay no more crashes now that I roll back the constraint graph ...
Okay it seems I did have some collision bugs, I fixed them, yet I still fall trough the floor 
... The client doesn't update AABBs? Huh ... That can't be a good sign
@vestal minnow am I supposed to add VelocityIntegrationData and TimeSleeping manually for Forces to work? 
Note that SleepingPlugin is not enabled
Yesn't, the former should be automatically required for SolverBody by the IntegratorPlugin, and the latter requirement should be added by the SleepingPlugin
We could maybe make the ForcePlugin also register the requirements to allow Forces to work without the other plugins
Or make TimeSleeping an optional component in the query
probably that
Definitely that is sleeping stays optional (which is always useful for debugging and stress testing)
Oh the other one works again now ... Huh, I must've messed something up earlier then ...
Yet I keep falling trough the floor 
I do see gizmos with absolutely massive lines, so I'm a bit confused as to why I just fall trough 🤔
yep
Would I just need to combine CollisionStarted and CollidingEntities or does CollidingEntities have something like that in store?
the two serve different purposes. CollisionStarted is an event that fires whenever two colliders hit. CollidingEntities is a component that has the list of entities that are colliding with that entity
Not getting errors with serialize, unless there's some specific feature combination that happens to be broken
CI also runs tests with it enabled
Huh, that's weird. For me one specific type breaks 🤔
which type?
ContactEdge breaks because of one of the fields containing a SmallVec or something 🤔
Ah, that might just mean smallvec needs the serde feature enabled
I'm guessing something is enabling it for me locally then, like maybe some dev dependency 🤔
not sure which one
yep
I'll make a PR to enable it when serialize is enabled
I somehow can't even figure out where it happened now, which means the cargo update earlier might've hidden the issue. Definitely want to set that correctly though
Yeah, i'm saying how do I check if that entity has a component?
you might need to be more specific with what you're trying to do. It's unclear what you mean by "that entity" and again, CollisionStarted and CollidingEntities are.. idk, somewhat orthogonal abstractions in my mind
Something like this
if spell_radius.get(entity).is_ok() {
}
For a query for the component.
is "spell_radius" something like Query<&SpellRadius> ?
what you wrote there is like.. I imagine you're iterating across everything an entity is currently colliding with (CollidingEntities) and checking if one of them has the SpellRadius component
yep
I.. might not understand what you're asking. What you wrote is a way to check if that entity has that component
Well, I figured out that, i'm just trying to debug something else and let it sit until I either figure out the issue or solution.
Yeah couldn't figure it out, but here
fn magic_mouse_collision(magic_mouse: Query<(Entity, &CollidingEntities), With<MagicMouse>>, spell_radius: Query<&SpellRadius>) {
for (entity, colliding_entities) in &magic_mouse {
if spell_radius.contains(entity) {
info!("oof")
}
}
}
SpellRadius is spawned with a collider
Also tried
Query<&Collider,With<SpellRadius>>
And nothing
contains() won't return true
fn magic_mouse_collision(magic_mouse: Query<(Entity, &CollidingEntities), With<MagicMouse>>, spell_radius: Query<&SpellRadius>) {
for (_, colliding_entities) in &magic_mouse {
for entity in colliding_entities.iter() {
if spell_radius.contains(*entity) {
// hit spell radius
}
}
}
}
yes, you don't need the Entity in the magic_mouse Query but it also depends on what you're doing in that function (i.e., you might end up needing it once you start doing whatever it is that happens when it hits a spell_radius)
potentially.
I'm not sure what the best up-to-date bevy tutorials are, but this helped me a lot understanding the ECS stuff: https://bevy-cheatbook.github.io/programming/ecs-intro.html
wooo Avian shout out in the birthday post
Is there a CollidingEntities to see if objects are overlapping? If not, how do you do it in a version that is like CollisionStarted?
As in overlapping, not just colliding.
In practice those are basically the same thing. If two objects are colliding, they are touching (or expected to start touching within the time step) or have inter-penetration
You only get a contact between separated shapes if it is a speculative contact
If you want to filter out speculative contacts, you can get the collision data for each contact pair from Collisions, use find_deepest_contact to find the contact point with the largest penetration depth, and check that it is non-negative
Understood. The issue that caused me to ask that question is resolved.
hi. im trying to use the main branch of avian to use the new Froces API.
Im trying to use the Forces in query
pub fn movement(
mut query: Query<
(
&ActionState<Action>,
&mut Transform,
&mut LinearVelocity,
&mut AngularVelocity,
&mut Forces,
),
With<Player>,
>,
time: Res<Time>,
) {
for (action_state, position, vel, mut forces) in &mut query {
and gettign an error
`avian3d::prelude::Forces` is not a `Component`
the trait `bevy::prelude::Component` is not implemented for `avian3d::prelude::Forces`
consider annotating `avian3d::prelude::Forces` with `#[derive(Component)]`
the following other types implement trait `bevy::prelude::Component`:
no &mut, it impls QueryData directly
that query will have a conflict anyway, have to also remove the &mut velocities
(can get them back with Forces:: lin_vel_mut and ang_vel_mut)
perfect. thank you.
o7
seams a bit more more logical and cleaner so far.
im moving over from rapier3d
how do we use the mesh from a gltf asset for the terrain?
You can use the ColliderConstructorHierarchy component
A component that will automatically generate Colliders on its descendants at runtime. The type of the generated collider can be specified using ColliderConstructor. This supports computing the shape dynamically from the mesh, in which case only the descendants with a Mesh will have colliders generated.
It's similar to the AsyncSceneCollider in bevy_rapier, but more customizable and flexible
sweet. thats what we were using
wow its working. changed over 7 systems in our game to use avian. and we get to bring our speed constants back to something reasonable. our force vector was like 10000 before and now its more like 10
its deff smoother on mac m1 so far.
i was using a capsule_z for my boat. but i only see capsule.
it feels like such a more stable simulation
on the mac with lower frame rate the simulation on rapier would get all wonky. now its like not bad because everything goes where it seams like it should when the frame drops a little.
is there a debug display so i can see how to rotate my capsule?
A plugin that renders physics objects and properties for debugging purposes. It is not enabled by default and must be added manually.
What if one collider is inside the other?
and the ends aren't touching
is that still a collision?
yes
unless that shape is hollow from the inside, like a polyline or 3D trimesh
but then they would not be overlapping anyway
A system that determines if one or more scheduled systems should run.
for doing simulations i had my scale about 1 unit in bevy equals 10 feet. and it was working pretty awesome with avian. i tried scaling up the 3d model to a 1:1 so my boat is like 50 feet long. and the simulation breaks. it slows down and needs insame amount of force which i think might be breaking it...
what kinda scale is recomended? maybe do i need ot switch over to f64 and DVec3? thanks
i set the colider density to 10 and its working pretty good with a 1 unit = 10 feet
Did you ever end up making that version where spatial queries return the actual surface normals and not the separating axis?
Not yet, that needs to be added directly to Parry (or Peck)
or I guess we could have a trait in Avian and implement it for Parry's shapes, though at that point I'd just upstream it to Parry anyways
how much does enabling determinism affect performance? is that a "it depends" question?
Avian is locally deterministic by default. enhanced-determinism makes it use libm for cross-platform deterministic math, which can be meaningfully slower, but I haven't measured exact numbers
Ideally we would have a nice way to use the libm versions only for the operations where it's relevant, in the places where it's relevant, instead of glam just having a global "use libm" feature
Box2D is fully cross-platform deterministic and doesn't even have an option not to be. The performance cost was basically negligible for it
oh wow. Maybe doing a record and playback feature wouldn't be too bad. I think I've seen issues in my game in the past where when I slow down the physics time, the physics seem to behave differently.. like, not equivalent to what would happen at full speed... but, that could be caused by my code incorrectly introducing deltatime in places where I'm using fixedstep, right?
Behavior should be consistent as long as Time<Fixed> has a fixed delta time. To speed up or slow down physics without losing determinism you'd have to run physics more/less frequently while keeping that fixed time step. I think changing the relative speed of Time<Virtual> should have that effect
And yeah your own code that affects physics needs to correctly consider delta time and be deterministic as well
my slowdown/speedup code is changing Time<Physics> 🤔
A caveat for something like record and playback is that there is cached state like the ContactGraph and ConstraintGraph that affect behavior. To properly reproduce the same behavior, you may need to record those as well, which can get expensive
hmm.. yeah I was considering either... using physics and recording inputs.. or just trying to record transforms of everything, take out physics and interpolate
bevy's 3d pbr lighting is technically based around the idea that 1 unit = 1 meter btw
Side note, this video pretty neatly shows some of the differences you can have with a stateless (Unity DOTS Physics) vs. stateful (Havok, Avian, Rapier, Box2D, Jolt...) physics engine
https://youtu.be/Uv7DWq6KFbk?si=KqquMUSDxFVomXeB&t=804
This session gives an overview of the physics systems and workflows powering our Data-Oriented Technology Stack (DOTS). Viewers will gain insight into design considerations underlying Unity Physics, how its use cases differ from those of Havok Physics, and how both offerings express concepts familiar to users of our classic GameObject-based phys...
The stability difference is pretty massive; though they have improved on it more recently with some interesting (mildly cursed) heuristics
https://youtu.be/EGv3u8GgUlI?si=EUezfnwaN5XMRMJj
The Unity Physics DOTS package, developed in partnership with Havok, needed to be cache free in order to better support scenarios such as simulation rollback for networked simulations. Stacking rigid bodies tends to require a cache, spanning multiple frames, to produce stable results. Here we will talk through some heuristics needed to resolve t...
"Free"
How to get the normal between 2 objects in a collision?
ahh.. good to know. thank you.
i think i will need to scale my stuff a bit. but wow this is really really fun to use compared to rapier.
i believe you need to get the contact manifold, and then get the normal from that
such as
let point = contacts // contacts: Res<ContactGraph>
.get(projectile_entity, object_entity) // Colliding entities
.and_then(|pair| pair.manifolds[0].normal)
I just wanted to say working with avian has been lovely. I am just starting to do integration tests using bevy_mod_scripting, and it works nicely:
(red line is an intercept point, and the arc and arrow are the missile torque and thrust commands)
I was spawning lots of spheres and a few trimesh got this xD
thread 'main' panicked at /Users/choc/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/avian3d-0.3.1/src/collision/collider/mod.rs:508:9:
assertion failed: b.min.cmple(b.max).all()
stack backtrace:
0: __rustc::rust_begin_unwind
1: core::panicking::panic_fmt
2: core::panicking::panic
3: <Func as bevy_ecs::system::function_system::SystemParamFunction<fn(F0,F1,F2,F3,F4,F5) .> Out>>::run::call_inner
4: <bevy_ecs::system::schedule_system::InfallibleSystemWrapper<S> as bevy_ecs::system::system::System>::run_unsafe
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Encountered a panic in system `avian3d::collision::collider::backend::update_aabb<avian3d::collision::collider::parry::Collider>`!
Encountered a panic in system `avian3d::schedule::run_physics_schedule`!
Encountered a panic in system `bevy_app::main_schedule::FixedMain::run_fixed_main`!
Encountered a panic in system `bevy_time::fixed::run_fixed_main_schedule`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
I'm not really sure why this debug_assert would trigger, I never call grow or change the size of colliders after spawning them. I don't really know how to reproduce, I was just spamming them.
/// Increases the size of the bounding volume in each direction by the given amount.
#[inline(always)]
pub fn grow(&self, amount: Vector) -> Self {
let b = Self {
min: self.min - amount,
max: self.max + amount,
};
debug_assert!(b.min.cmple(b.max).all());
b
}
Either some part of Vector is negative or hitting inf or smth?
Here's my usecase for simulating a robot in bevy env. Cuttently it's rapier, but idk about switching to avian.
How's avian now for robotics? I'm currently using rapier but it behaves in certain cases, such as stiff collisions and funky momentums in UAV simulations.
I have mujoco bevy bindings, where bevy is just a renderer, and I need to construct scenes dynamically from bevy.
Finished refining my intercept logic. The estimation is very good once it's got the expected speed.
Rapier is likely better for robotics right now as it supports reduced-coordinate joints (multi-body joints aka articulations), joint motors, 6DOF joints, and also has a built-in URDF loader
which we don't have yet
I'm unsure where to invest time if I want an accurate robotics sim on rust. It all goes to simplifications made along the way to make it suitable for gamedev, but unusable for robotics. There's a ton of movement in python land with a differentiable accurate GPU physics, but i need that in rust. Rapier is funky in robotic cases.
is there a way to not link children's colliders to their parent's rigid body on spawn?
do I have to manually remove ColliderOf?
or can I just mark them as sensors
Is there a way to get more information about why Trimesh generation might have failed? I am trying to generate colliders for chunks of voxel terrain so they're not nice shapes, truly just a bunch of triangles that are unlikely to be connected together. Convex won't work, I really just need polygons/triangle based colliders.
I'm trying to replicate the bush behavior from tunic as seen here.
Right now I'm trying to use a SphericalJoint with a static rigidbody on a "below-ground" bone and a dynamic rigid body on the bush bone. So its two bones and a mesh child on the second bone. The intent being that the below-ground bone is static and never moves while the above ground can rotate around the ground position.
I want it to interact with a "player" (just a sphere collider right now) and the ground in terms of collision, and to prefer returning to the original neutral position.
Does this sound reasonable or am I overcomplicating it?
I see an align_position on Joint, but not entirely sure if that could be used to do the "return to neutral" force. I also tried a persistent ExternalForce on the bush in the Y direction but that felt a bit weird.
could there be a way to create a hitbox for a tile depending on he surrounding tiles? using ldtk if there's any inbuilt thing that could help
you could have two joints with different stiffnesses
where would the second joint be?
oh you mean like another on top hmm
(i was a little excessively worried there would somehow be a spoiler in that video, i should probably buy that game)
I made sure it was a nondescript part of the game 😅
Okay I hit that issue again, and the new changed fixed it 🙏
Isn't it possible to just get character position and just tilt the thing depending on how close the character is and it's direction ?
yep, and that seems to be similar to how tunic actually does it. (the bushes don't interact with each other and non-player items that roll around seem to not really interact either). enemies do, so just using the player position as input wouldn't be enough. I was hoping to take advantage of the physics/collider systems to not have to safelist entities into affecting the movement, for example.
Shape cast with filters to avoid having to safelist them ?
yeah I guess I should just commit to having the layers for the filter there anyway instead of trying to avoid it
Yeah, layers can be useful.
theres no way to have the bone springy towards it initial orientation?
I think this is joint motors in this scenario, which is "future work"
this conversation basically
interesting.
and what are the joint motors?
afaik, a motor is just a built-in way of enforcing a constraint. So instead of using just AngularVelocity you could set a max force, target velocity, etc and the Motor systems would take care of the details
I'm just reading about them now though, so grain of salt with my explanations 😅
with a really simple smooth_nudge-based "motor"
Noice !
for some reason it didn't occur to me that the colliders would end up inside each other. I think the simpler non-physics solution is what I'm going to go with instead
they seem to push inside the character it's weird?
yeah, could put some work in to make the correction only apply if not in contact, etc, but at that point I feel like I'm re-coding it anyway
Yeah distance direction to angle is pretty straight forward and also is cheaper computationally i think.
yeah
Aren't folliage "physiscs" usually just shaders?
as far as I know for more realistic/complicated ones yeah. That's what I did for some tree leaves recently
I was trying and make some simple projectiles by using sensors and despawning them when they collide with something, but if I make them too fast they seem to just magically collide with the floor even though they are traveling away from it
I don't quite understand what's going on
try despawning them when their velocity changes too much instead
Very possible these are ghost collisions with <0 penetration. You might also need better CCD modes for this to work
Hello, what is the general wisdom when it comes to dynamic rigidbodies that only have colliders in their children.
I can't seem to get it to work, right now I get this error:
thread 'main' panicked at \avian3d-0.3.1\src\collision\collider\mod.rs:508:9:
assertion failed: b.min.cmple(b.max).all()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `avian3d::collision::collider::backend::update_aabb<avian3d::collision::collider::parry::Collider>`!
Encountered a panic in system `avian3d::schedule::run_physics_schedule`!
Encountered a panic in system `bevy_app::main_schedule::FixedMain::run_fixed_main`!
Encountered a panic in system `bevy_time::fixed::run_fixed_main_schedule`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
(the line referenced is about the aabb grow() method)
This is the offending code I think:
commands.entity(entity).insert((
RigidBody::Dynamic,
Mass(1.0),
children![(ragdoll.transform, ragdoll.collider.clone()),],
));
make sure that transform is valid and e.g. doesn't have a scale of zero
typically that error means you have NaN somewhere
Removing the transform results in the same behavior, also the error is not deterministic so it's hard to test
also it seems like I'm missing something to get the rigidbody moving, I always forget the checklist, idk if it's written down somewhere
Other common things that can cause NaN or infinite values are stuff like division by zero, using .normalize() on a zero vector, and so on
It should be enough to just have a dynamic body with mass (and angular inertia). And mass properties are automatically computed from colliders unless specified manually
If there are NaN values then that might mess things up though
I think there's also a case with placeholder AABBs, I fixed that in my branch. Don't think parry can cause that behavior though
If I have the collider at the top level it works fine, but I want to be able to offset it so I put it in a child but that results in a non falling object
Ah wait, that really could be placeholder AABBs 🤔
I discovered a sleeping bug on main but otherwise this works like expected for me
commands.spawn((
Mesh3d(meshes.add(Cuboid::from_length(1.0))),
MeshMaterial3d(materials.add(Color::srgb(0.2, 0.7, 0.9))),
RigidBody::Dynamic,
children![(Collider::cuboid(1.0, 1.0, 1.0), Transform::default())],
));
setting the speculative margin to 0 and adding ccd fixed it, thanks!
The confusing part is that simply having the collider at the root solves my problem (but then I lose the ability to independently place it), but i'm not able to make a simple reproduction so it might be something else, looking into it
I got a pretty minimal version of the bug working:
//on setup
commands.spawn((
Zombie,
children![(
Mesh3d(meshes.add(Cuboid {
half_size: Vec3::new(0.5, 0.2, 0.2),
})),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(1.0, 0.0, 0.0),
..default()
})),
)],
))
.observe(|trigger: Trigger<RagdollTrigger>, mut commands: Commands| {
commands.entity(trigger.target()).insert((
RigidBody::Dynamic,
//Collider::cuboid(0.5, 0.2, 0.2), If the collider is at the root instead, it works as expected
children![Collider::cuboid(0.5, 0.2, 0.2)],
));
});
fn trigger_ragdoll(
mut commands: Commands,
keyboard: Res<ButtonInput<KeyCode>>,
zombies: Query<Entity, With<Zombie>>,
) {
if keyboard.just_pressed(KeyCode::Space) {
for zombie in zombies.iter() {
commands.entity(zombie).trigger(RagdollTrigger);
}
}
}
The bug here is that if the collider is not at the root, the mesh will get it's transform set at 0 0 0 and will not move at all with the rigidbody, but if it is at the root, then it works as expected
Is it possible to have avian3d + aviand2d in one project?
(or use 3d physics, but apply it to 2d sprites in some way?)
I don't expect them to interact with each other, but using 3d physics for the 3d objects, and 2d Physics on the 2d layer (UI/Overlay)
they'll probably act like different crates with two copies of everything non-external
can anyone help ?
A question to frequent users of the crate- do you use mostly Dynamic rigidbody or Kinemtaic?
I've been using kinematic with some complex calculations and I keep running into weird edge-cases
I thought of switching to dynamic with the built-in calculations but that would require me about a week of work, which I'm not sure would pay off
I exclusively use dynamic and static rigid bodies
But this heavily depends on the kind of game you make
bump
yea i feel like this is hard to say without understanding the application. character controllers are a good example of where kinematic rigidbodies may be useful but I also only really have used dynamic + static in the past.
Well
If you both use only dynamic and static, then that's probably enough
My game doesn't really have any special physics, that's why I thought using kinematic would be enough to begin with
Ok figured out my previous issue, collider generation requires indices. Now it's working but the collider looks pretty different to my mesh 🤔 . I tried a few of the trimesh flags but they didn't seem to make a difference.
It's possible my naive index generation isn't lining up with my generated vertices though, still need to check that. Bevy renders the mesh fine though with those indices
If I try spawning all the components directly it works fine, it seems that dynamicly adding is what causes the "bug", can anyone help ?
Can't you just use the bevy mesh to make the collider?
I am
Is there a Q&A Avian somewhere?
I just started using dynamic rigidbodies and Restitution doesn't seem to work
if I have a rigid body with colliders as children will the collisions with those colliders point towards the rigid body entity or the collider entity
all collisions are relative to the collider
@vestal minnow the Contact edge not found in graphs have come back to haunt me again ... This time it's when I switch maps (which naturally despawns everything that was colliding)
I already clear both graphs when I exit that state so idk why it still crashes though 🫠
bump :(
🤔 does the child have to be a rigid body too?
that didn't solve it.
If I don't insert the components dynamically and have them be there from the start, then it works just fine wtihout two rigidbodies
oh lol this is not an Avian bug, it's just a Bevy footgun
you're inserting children!, which overwrites the Children component and the existing relationships, so the mesh becomes orphaned
if you switch to .with_child there, it should work
commands
.spawn((
Zombie,
children![(
Mesh3d(meshes.add(Cuboid {
half_size: Vec3::new(0.5, 0.2, 0.2),
})),
MeshMaterial3d(materials.add(StandardMaterial {
base_color: Color::srgb(1.0, 0.0, 0.0),
..default()
})),
)],
))
.observe(|trigger: Trigger<RagdollTrigger>, mut commands: Commands| {
commands
.entity(trigger.target())
.insert(RigidBody::Dynamic)
.with_child(Collider::cuboid(0.5, 0.2, 0.2));
});
I haven't done it, but I don't see why it wouldn't work. You'll just have duplicate type names, like RigidBody from avian2d and RigidBody from avian3d, so you'll need to be careful about imports or define your own type aliases to disambiguate
This thread is the most active and generally the quickest place to get a response, but there is also the forum-style GitHub discussions in the repo
There's also an FAQ in the docs
Oh thank you, that completely makes sense
You can also post questions in #1019697973933899910, though I don't look there as much (unless someone pings me ofc)
Like, things don't bounce at all even though they have a non-zero restitution?
What's your setup like?
Thanks
Yes
I'll send a video soon
so here's what it looks like
that's my physics bundle
and that's the physics bundle each has
(I found no relevant information in the FAQ or in the discussions forum)
It's kinda hard to tell, it could be that you explicitly set velocity for the movement which negates the bounce, or maybe the damping is so high that the bounce is barely noticeable, or something else like that
some things you could try
- Make sure you're not accidentally just overwriting the velocity somewhere
- Reduce damping, and try making the restitution way larger just to see if it really doesn't work or if it's just too low here
- If it still doesn't work, maybe try making an even simpler test case, like a circle with some initial velocity bumping into another stationary circle, just to have some simple functional scenario. Then go from there to try and figure out the problem with your actual setup
- I always
+=the velocity - I will make restitution 1 just to test (that's the maximum, right?)
(it'll take a while until I'm back with an update because my rust is being funny)
You can have a restitution coefficient larger than 1, but it means that the bodies will gain energy when they collide, which can cause explosive behavior and isn't possible in the real world
So it's typically not recommended, but it is something you should be able to technically do
it's described a bit in the docs too
https://docs.rs/avian2d/latest/avian2d/dynamics/rigid_body/struct.Restitution.html
A component for restitution, controlling how bouncy a rigid body or collider is.
oh that is cool actually
but yea, I wouldn't want them to behave this way
Ok so I tested with 1.0 and I don't see any difference
time to test with 20.0 on both hehe
Ok it works with 20.0
Like, very visibly so
I guess I could just leave it this way as a "recoil factor"
Yeahh a restitution of 20 is... mildly questionable, but if it works then why not lol
uhhh has someone seen this before?
consistently getting it in CI
Use nightly-2025-08-07
thread 'Compute Task Pool (2)' panicked at
A triangle mesh must contain at least one triangle.
Ah, so close haha.
so, if physics are on fixedupdate and everything is interpolated.. should I handle player input on fixedupdate or update? I feel like handling on update might be introducing some determinism issues 🤔
but then it's like.. if you have a high framerate you're not getting less input latency 🤔
Handle the input for the character controller on fixed update, and the input for the camera in update. See the Bevy example for physics in fixed update.
You’ll need some form of input accumulation as described there
I didn't know that existed. Of course, you and Jondolf are on the latest changes 😅
Easy for me to know, I wrote it 😄
Ok got it working smoothly now xD feels good
Only slight footgun is parry can't handle empty mesh as source for trimesh collider, whereas bevy is fine with it, so check first if mesh.count_vertices() >= 3
this is good stuff, thank you 🙏
Probably on me though, I should have something before this step that early exists for empty mesh and just removes the renderer and collider entirely
That’s annoying. We could add that to the constructor.
The from_constructor method IIRC returns an Option
So we could return None for empty meshes
imho no panic is on you, Bevy or Avian should not panic outside catastrophic events, period
A triangle mesh must contain at least one triangle.
stack backtrace:
0: __rustc::rust_begin_unwind
1: core::panicking::panic_fmt
2: parry3d::shape::trimesh::TriMesh::with_flags
3: parry3d::shape::shared_shape::SharedShape::trimesh_with_flags
4: avian3d::collision::collider::parry::Collider::trimesh_from_mesh
Another small one I found was in init_collider_constructors in avian, when there is no Mesh3d on the entity that had a ColliderConstructor added it explicitly panics. The code around it does error logging and handles weird situations fine so it wouldn't be big to modify that panic to a error log. I won't spam the console either since the constructor marker is removed in that system
Next step, navmesh generation 😛 do you play favourites with any of the libraries that work with rerecast @visual sparrow 😛 ?
Landmass just made a PR for integration if you want to try it out 🙂
I like landmass because it already has local avoidance out of the box
oooh
But if you prefer polyanya, vleue_navigator has an example for how to manually import rerecast navmeshes.
There will be tighter / automatic integration for vleue_navigator once François has more time
If you also do asset preloading and state scoped levels, you may be interested in how I use the landmass integration:
chefs kiss
Is that marble madness? 😄
Approved and merging this finally
https://github.com/Jondolf/avian/pull/517
pushed some changes to revert some of the API changes
I get the reason for the accumulated input, but it's true that in this example's implementation it somewhat is equivalent to just reading the input on the fixed update since it's only using the last frame, right? (obviously, if there was something like a boost, that would get missed without being implemented in the accumulated input)
oh dear
i knew this day would come
i seriously hate despawning entities inside observers for this exact reason lol
the chainboom game has a good example of handling this by using a "Despawn" component and despawning toward the end of a frame
Physics in avian is natively lerped correct?
You need to enable it
No, doing so would only read it in the first fixed update of the current frame. If your frame has 3 fixed updates, only the first will "see" the input, resulting in stuttering movement
/// Responsible for rotating our character, applies angular velocity. No smoothing operand added
/// Note - This does not adjust our character
fn handle_rotation(
mut rotating_entity: Query<(&Rotating, &mut AngularVelocity, &Rotation), With<Controller>>,
time: Res<Time>,
) {
for (Rotating(quat), mut ang_vel, rotation) in rotating_entity.iter_mut() {
// Differential between camera rotation and current controlled entity rotation
let delta_rotation = *quat * rotation.0.conjugate();
let desired_ang_vel = delta_rotation.to_scaled_axis() / time.delta_secs();
ang_vel.0 = desired_ang_vel;
}
}```
Which I guess is what is happening here
I've thought about this yes but i rely a lot on despawning happening immediately
i don't tolerate frame latencies
have you tried using the Disabled component? The chainboom's approach despawns in the same frame..
i have used Disabled but not for these specific entities actually
i don't mean despawn latency
i meant everything else in my game logic that relies on despawning
but really that probably won't work well because i have quite a lot of observers too
specifically OnRemove
I was assuming fixedupdate was 60hz and update was something higher... but you're saying this is flexible enough to handle the opposite: where fixed update happens multiple times within an update?
... the fact that this error is not reproducible and just happens randomly is also really annoying
i suppose i should just enable RUST_BACKTRACE everytime i run so when i do catch the error i can at least see the stacktrace
Is gravity applied automatically to dynamic rigidbodies?
I just noticed that my player always falls really, really slowly (the game is top-down)
Yeah. For 60 Hz each fixed update is 16.666 ms, let’s say 17.
If the accumulated lag it 15 ms, you get no fixed update this frame. But if you have a tiny lag spike next frame and the accumulated time goes to 40, that means that frame will have 2 fixed updates. The accumulated time is now 40 - 2*16.666 = 6.668 or so
Yes. Is your scale off? For example, in 2d you may be having 1 unit = 1 pixel, which means the gravity would be very low comparatively
I think I never set up a scale, so probably yes 😆
Which would also explain why I had to set the recoil factor to 20
Wait, how do I cancel the gravity?
Hehe yep
sorry
oh no
Maybe I'll wait with setting the scale then and hop players wouldn't notice they're falling
ok so that's how to set global gravity
https://docs.rs/avian2d/latest/avian2d/dynamics/integrator/struct.Gravity.html
A resource for the global gravitational acceleration.
got it, that makes sense
Is there an elegant way of extracting colliders as a reflect? I'm trying to figure out how to save/modify them on the run.
No way. You need to go through ColliderConstructor
I figured it was something like that.
I'll have to create bindings then.
Thank you for that !
Joint rework PR (part 1) is just about ready finally, updated the description now
https://github.com/Jondolf/avian/pull/803
I'll probably do final testing and polish tomorrow and then merge hopefully
so.. I know avian is deterministic by default.. I'm trying to implement a replay/demo system and I'm running into small differences and am wondering what might be introducing them
A: Frame(1) Linear velocity: 20.0, P: Vec3(-1686.242, -65.70028, 898.1884) R: Quat(0.0, -0.5428654, 0.0, 0.8398197)
B: Frame(1) Linear velocity: 20.0, P: Vec3(-1686.242, -65.70028, 898.1885) R: Quat(0.0, -0.5428654, 0.0, 0.8398197)
A: Frame(2) Linear velocity: 20.002808, P: Vec3(-1685.9379, -65.70708, 898.0514) R: Quat(9.830844e-5, -0.5428622, -7.871953e-5, 0.8398218)
B: Frame(2) Linear velocity: 20.00281, P: Vec3(-1685.9379, -65.70709, 898.05145) R: Quat(9.743288e-5, -0.54286206, -7.81078e-5, 0.8398219)
these are the first two frames where A is when I was recording and B is the playback of the recording which happens on the same run of the app. It's recording a collider with the only force acting on it (aside from gravity) is it's spawned with LinearVelocity 20.0 on its forward vector. Are these differences just f32 rounding I can't avoid?
It is? Then why are my spatialqueries returning distinct results every frame?
🤷♂️ Jondolf says "Avian is locally deterministic by default"
I think he has setup multiple unit tests that check for determinism. I suspect I'm just not finding where I'm introducing non-determinism
actually, I think I found what was causing it
maybe 🤔
IIRC you need to enable libm through the enhanced-determinism feature or trigonometric function calls go through the OS, resulting in a loss of determinism
Or was that only necessary for cross-platform determinism 
I'll try that but I thought it was for cross platform too 🤔
well well! apparently this was my fault, i.e. defining commands that return a Result but uses panicking methods from EntityWorldMut
my determinism seems worse with enhanced-determinism 🤔
ok, I determined that... if I relaunch the game... it matches.. like it is deterministic across runs of the game (i.e., if you take the transform output of the first X frames and compare to another run's first X frames they do match)
but, if I clear everything and reload the game without exiting and replay the same inputs... that doesn't match (i.e., frames 1-500 don't match 501-1000) So... I suspect either I'm missing something that I'm doing that's breaking determinism or.. is it possible that starting the same physics scenario on a different frame generates different results? I'm not sure if that falls under determinism or not 🤔
is it possible that something needs to be reset in Avian if I'm effectively reloading the world from scratch? Like the Time<Physics> ?
it might be the jitter of small objects 🤔 my game has a truck and when there are objects in the truck's bed, the truck behaves non-deterministically
Run Collisions::clear() maybe?
clears the contact graph and constraint graph
I'll try that but I think it's the items in the truck bed 😞 when I take them out, everything behaves more deterministic
I think the thing with the contact graph is that it maintains a sort of linked list and free lists for nodes and edges. When you add pairs initially, it can just push them, but if you later remove nodes/edges, you get vacant nodes/edges and the insertion order can be different
So unless you fully clear those structures, you can get different results when "resetting" a scene
But across runs it should be deterministic
hmm.. yeah, I don't mind the jitters if it's deterministic 🤔 gonna try that out in a few
Hmm maybe I could fix this with an ID pool that uses a min-heap for free IDs 🤔 I believe the current contact graph is LIFO (last removed edge gets reused first), but what we want might be "lowest ID first"
That way, the contact removal order shouldn't affect the insertion order, and they should always be pushed in the same order when starting from a state of no occupied contact edges
first few attempts after doing this look promising at least
The RaycastHits API is a bit confusing. I don't understand the purpose of count. Is using the vector.len() not enough? If count is supposed to represent the hits including those missed because max_hits was reached it should probably be called lost or ignored or something.
Currently RaycastHits::len returns count, so missed hits are included in the count, but if you iterate you might get less. But then as_slice returns the vec from 0..count which indicates count could be less than the actual length of the vec, otherwise it could just be &vector.
If count is there to account for hits that went above max_hits then it probably shouldn't have a single len function, because it's not obvious whether it should include those outside max_hits or not. It should have something like hits(), lost(), and total(). Even then I don't really like hits() because it's easy to assume that actually means total() but I can't think of a better name off the top of my head.
pub struct RayHits {
pub(crate) vector: Vec<RayHitData>,
/// The number of hits.
pub(crate) count: u32,
}
After testing it seems count doesn't include missed/ignored hits over max_hits, so it seems unnecessary 👀
Maybe it used to?
The ray cast code include comparisons to count, but I am unsure what they are trying to do xD
if (hits.vector.len() as u32) < hits.count + 1
Lol I have not looked at this code in like over a year, but it looks silly
I think the intent there is that count allows vector to be never cleared, and items are instead overwritten, because somehow 2023 me thought it'd be better/faster that way
ahh, yea I see where that's coming from. I was confused that I saw hit.count = 0; but no vector.clear also
But like, I'm pretty sure it should be fast to just clear and push, since the vector allocation is reused anyway
yea exactly, vec is already doing that work in push. doing the check then assigning might actually be slower, since rust will still need to do the bounds check internally when assigning to somewhere in the vec buffer 😛
yeah
I kinda love the debug visuals in avian haha. The little arrows on raycast hits are neat. I'm a little unsure where a big red line is coming from, only seems to appear while I move the camera 🤔
the direction the raycast hit has moved since the last update maybe?
I believe the red arrow is from the ray cast or shape cast origin to its maximum distance
so like if a ray is cast from point a to b (where b = a + direction * max_distance), the arrow would be between those points
Hmm, the raycast is dead center (it's on the same entity as the camera) pointing forward, so I am unsure if it would be showing up like that. Though maybe it's from gizmo having a delayed position
Yeah it might be a perspective thing + small delay that makes it look weird, not sure
I'd be curious to see if this PR removes the need to clear the contacts
https://github.com/Jondolf/avian/pull/807
It seems to work for our determinism test scene at least
I'll check that out once I get into a stable spot 👍
Fixed here
https://github.com/Jondolf/avian/pull/808
In a follow-up, I'll probably rename
RayHitData,ShapeHitData->RayCastHit,ShapeCastHitRayHits,ShapeHits->RayCastHits,ShapeCastHits
Or maybe RayCasterHits and ShapeCasterHits for the latter?
It'd associate the names more closely with the RayCaster and ShapeCaster components, while the RayCastHit and ShapeCastHit types are also used for SpatialQuery APIs
hmm does the hit belong to the raycast or to the raycaster? 🤔🤔🤔
RayHitData and ShapeHitData (the current names) are the output types for ray casts and shape casts, and RayHits and ShapeHits are components that store one or more of those hits for a RayCaster or ShapeCaster
oh you're probably asking more semantically whether the hits belong to the raycast and therefore RayCastHits makes sense, or if they belong to the raycaster and therefore RayCasterHits makes sense
ya
🔥 looks good 😎
avian is faster than rapier? @vestal minnow
Is there an example of getting collision normals in avian2d?
I remember asking a simular question and someone answered with a manifold example, but the exact query wasn't shown to get manifolds of a collision/collider.
mostly Res<Collisions> if you're not doing event handling i think?
I need the direction the mouse is facing based on which direction it is from an object. That can be done with math, but I feel it's more elegant for avian to handle it.
Basically mouse snapping kind of.
i don't understand that at all, sorry
seems to work in place of the .clear, but I'm still introducing non-determinism somewhere and it's driving me nuts
what does your determinism test look like?
Simulate for 500 steps, computing a transform hash every frame with djb2, check that the hash is the same across runs and when resetting the scene
https://github.com/Jondolf/avian/blob/main/crates%2Favian2d%2Fexamples%2Fdeterminism_2d.rs
this is a lot better than my "that can looks like it's in the same place I think" approach 👍
if the mouse is left from the center to the object, the preview object will snap to a position where it's right side is touching the hovered object's left side.
Kind of like plotting a grid, but what would be there appears when you're hovered over a spot in the grid.
How can I mutate the shape of a prexisting collider? Increase values like radius and so on
Or rather, how do you get normals from collidedentities if possible?
Res<Collisions>
apparently in avian2d that's not a resource.
oh, it's a systemparam now
apparently i missed an update
systemparam?
parameter for a system
also apparently i didn't miss anything, i just misremembered
like Query or Res
I tried res and query, didn't work
Isn't a resource apparently
...yes
A parameter that can be used in a System.
@vestal minnow Sorry for ping, but when is it safe to get collider aabb information?
I am running this system basically the moment the collider is added, and it returns me a is that supposed to happen?
On later frame he is normal
2025-08-20T19:44:44.052757Z DEBUG psycho_lag_compensation: collider=ColliderAabb { min: Vec3(inf, inf, inf), max: Vec3(-inf, -inf, -inf) }
fn handle_no_child_collider_scenario(
query: Query<(Entity, &Collider, &ColliderAabb, &LagCompesated)>,
mut commands: Commands,
) {
for (entity, col, collider, lag_compensated) in query.iter() {
if lag_compensated.collection().is_empty() {
debug!(?collider);
commands
.entity(entity)
.with_related::<LagBoxOf>((*collider, Name::new("Lag compensated collider")));
}
}
}
In avian 0.3 the ColliderAabb is only updated at each physics tick (so in FixedPostUpdate by default). On the first frame before physics has run, the AABB will use the invalid placeholder value that you're seeing. If you want to, you can manually compute the correct AABB with collider.aabb(position, rotation)
I believe on the main branch it should be initialized correctly right after spawn though
Took a nap. Now I know what you meant.
Cool, final question: Expanding a collider aabb will necessarily make it so his collision ratio will be bigger? Or do I need to update collider to (build one from it)
Has anyone done ragdolls with avian? any tips?
I already added (compound) colliders to each bone, but I can't get the joints to behave
are the joints trying to intersect two colliders
I don't have collisions enabled between them, only to the floor
If I understand spherical joints correctly, for a right shoulder the twist axis should be -X and the swing should be Y, but the cone ends up looking UP instead of to the side?
https://docs.rs/bevy_math/latest/bevy_math/primitives/struct.Cone.html tip toward local +y, do you account for that?
oh i meant this cone
but now that you say it i think i'll try to draw some gizmos
What's the difference between marking a collider with Sensor and just not inserting a RigidBody?
Also why does one have to insert a RigidBody here:
https://docs.rs/avian2d/latest/avian2d/collision/collider/struct.Sensor.html
A component that marks a Collider as a sensor, also known as a trigger.
It's the same (AFAIK), but If you already have a rigid body, you may want to attach sensors to it that don't contribute to its mass etc.
you also get ColliderOf if you have rigidbody/sensor, which can be really nice for direct "root entity" access
In that particular example the RigidBody is unnecessary since it's static anyway, but you could for example attach a sensor to a moving dynamic or kinematic body to have it detect intersections but not cause a collision response
In the future it is also likely that sensors will be a fully separate thing from "normal" colliders, at least internally
I.e. they would not compute contact manifolds, but would just detect intersections with separate optimized logic
(this is how e.g. Box2D does things, sensors are not really in the narrow phase, but have their own thing)
(source for that here)
Sounds good to me
Thanks guys!
Is there a built in way to check collisions on the very frame a collider is created?
after physics (FixedPostUpdate), yes, before that, no
if you needed to, you could manually get entities that intersect the shape at some position via SpatialQuery
or use a shape cast which also includes some contact data
but it's not the same as the narrow phase collision detection
Alright
Thanks
If I understand correctly- if a collider was spawned on another collider, a CollisionStarted is emitted. Also, if a colliderwas despawned while touching another collider, a CollisionEnded will be emitted.
They always store whether they're touching or not, and when that status changes, and it doesn't matter why, the appropriate event will be emitted
(right?)
yes that sounds correct
Woah, new heart color spotted
is there a way to prevent the character from sort of sticking to walls and also losing horizontal speed when bumping its head? (i'm using tnua if that changes anything)
There's a friction component you can use for that
thanks
it still kinda bounces off the walls a bit? any way to fix that?
when you're moving into it
How expensive it is to update a collider continously? I mean reinserting it every frame. Is there a better option, to lag-boxes scenario?
Extending his collider aabb in my mind would be more optimal
@vestal minnow compilation broken on main if debug-plugin feature isn't enabled
-# Add the minimal features CI step
🤔 are raycasts deterministic?
I setup this system that hashes the transforms of every rigidbody every frame and I can see this frame has the same hash but on one run of the game my raycast hits and on another run it doesn't. The raycast starts from the same point, goes in the same direction and would hit the ground.. but in one run it does and one run it doesn't.
update_pipeline!
that actually helped. Still running into non-determinism but I feel like I'm getting closer 💪
where did you put the raycast system?
try putting it inside PostUpdate after running fixed update
in my experience, Avian (and by extension, bevy) is very deterministic in a lot of things and can be relied on for frame-perfect logic, people just need to order their systems 😉
i believe update_pipeline is called in PhysicsSchedule on PhysicsStepSet::SpatialQuery at some point
PhysicsSchedule itself is run as part of FixedPostUpdate, which is run by PostUpdate on a system set i forgot the name of
yeah 😂 I have a lot of things that trigger other things to spawn so I've been peeling everything back and one-by-one adding stuff in. Right now I'm just calling update_pipeline right before I use it but eventually I'll try to change when that system runs
you might also want to do it in FixedPostUpdate instead, to make sure all your raycasts trigger after a physics update is executed
i suspect that in your two runs, one raycast observes an "outdated" physics world because the fixed tick rate hasn't been reached yet
yeah, I think so too. Everything is running deterministic-ly now. I still have to re-add all the things I disabled but I can see the light at the end of the tunnel at least
nice! good luck!
Cube marching?
no, FixedPostUpdate is run by FixedMain, just like FixedUpdate
all fixed schedules run between PreUpdate (or right after StateTransition) and Update
wait, for real...?
The schedule that contains the app logic that is evaluated each tick of App::update().
wow, just made myself a huge source of misinformation there
Why would it?
yis
i’m confused
how can i access multiple components from that query in that loop
numcollisions is already the component (or Mut<T>), but your query is malformed
#general message
is there another way to use oncollisionstart apart from doing .observe(...) like in the docs
the buffered events don't use On: https://docs.rs/avian3d/latest/avian3d/collision/collision_events/struct.CollisionStarted.html
A buffered collision event that is sent when two colliders start touching.
You mean Trigger right? 
nope, I mean the event name prefix: OnCollisionStart vs CollisionStarted
Ah, well, that's something Jondolf is gonna have to change for the next release now I bet 🫠
On<On<On<On<
trivial change tho, Trigger<OnCollisionStart> vs On<CollisionStart>. (CollisionStart isn't taken in avian afaik)
Ah, clever ... Annoying autocomplete but it works
yeah, bit offtopic for the channel but the On* eventname prefix convention was really nice for documentation discovery
Ok, so, I'm working on a top-down 2d game (think kinda roguelike-esque though not turn based and not grid based) and I'm looking at using Avian for collisions and line of sight. Right now, my naive thought is in my player movement system to store the old position before moving, then after moving to check Collisions for anything intersecting the player entity, and to reset the player's location if so. Something like this:
fn player_movement(
keyboard_input: Res<ButtonInput<KeyCode>>,
mut player: Query<(&mut Position, &mut Transform, Entity), With<Player>>,
collisions: Collisions,
mut qt: ResMut<Quadtree>,
) {
if let Ok((mut position, mut transform, player_ent)) = player.single_mut() {
let backup = position.0;
for key in keyboard_input.get_pressed() {
match key {
KeyCode::KeyA => transform.rotate_z(PLAYER_TURN_RATE),
KeyCode::KeyD => transform.rotate_z(-PLAYER_TURN_RATE),
KeyCode::KeyW => position.0 += transform.up().truncate() * PLAYER_MOVE_RATE,
KeyCode::KeyS => position.0 -= transform.up().truncate() * PLAYER_MOVE_RATE,
_ => {}
}
}
collisions
.entities_colliding_with(player_ent)
.for_each(|_ent| {
// If the player is bumping into something, record that position as "known"
// then reset the player's location to before they moved
qt.insert_point(position.0);
position.0 = backup;
});
}
}
That doesn't really seem to work, though, as resetting the player's former position is still placing it in contact with the collider, so it gets stuck.
Is there a "better" way to accomplish this?
Jondolf was involved with this change upstream
@visual sparrow Do you happen to have a clue why the windows CI just hangs on cargo-binstall for an hour before cancelling?
https://github.com/Jondolf/avian/actions/runs/17179888337/job/48740920697?pr=811
the heck 
no
doesn't seem to be spurious, it has failed on that many times in a row even across different PRs
Welp, time to replace it with cargo install cargo-binstall maybe
Or remove binstall entirely and use cargo test instead of cargo nextest
which is slower for avian (I checked), but faster than waiting 50 minutes lol
btw want me to incorporate the bevy linter in the lint action at some point?
@dusky brook do you have an idea?
hmm yeah maybe after the RC is released and we've migrated to that
It hangs on this, before any nextest stuff
Normally it's this
can confirm that taiki-e/install-action works too as an alternative for cargo-binstall
ha, good to know
idk, maybe an issue with the @main version of the action
although that is what the action's readme says you should use
v1.15.0 was released 2 days ago
fixed and added the minimal feature CI check
https://github.com/Jondolf/avian/pull/811
https://github.com/Jondolf/avian/pull/812
edit: had a problem where spatial queries were hitting things that were despawned previously. Turns out that you have to have physics running for things to update 
Could also manually update the pipeline I think, seems like a bit of a flaw if you just have physics paused or something though 🤔
soon-ish it'll be changed to incrementally update the BVH, so spawns and despawns should update it immediately via observers
@little maple You're good at breaking Avian, wanna try the simulation-islands branch when you have time? Just to see if you get any new surprising panics
https://github.com/Jondolf/avian/pull/809
tbh I'll be shocked if it works perfectly first try without any new crashes lol
it's a lot more tricky graph bookkeeping and managing linked lists and spawns and despawns and whatnot
I should be able to try it out at some point later today 👍 I saw your post in #showcase and was excited to try it already
Jondolf's beta tester group consisting of 2 people 
Hello, I got sidetracked a bit, but was that bug what was causing the
thread 'main' panicked at \avian3d-0.3.1\src\collision\collider\mod.rs:508:9:
assertion failed: b.min.cmple(b.max).all()
``` error ?
NaN values most likely
NaN value in what ?
The Position or Rotation of whichever entity is causing the crash
I'd imagine either some wrong math for calculating forces, which NaNs velocity, or something moving or spinning very fast
No, it was a different thing
I've only once seen avian itself cause NaNs and it was because of the placeholder position/rotation when you don't set them and don't have transform propagation
if I insert a rigid body on a fixed update... how many fixed updates would pass before it "exists"?
It should fully exist after the first time physics (i.e. FixedPostUpdate) runs for it
It will "exist" before that too, but won't have collisions and won't (currently) show up in spatial queries until physics schedules have run
is it at all possible that spawning a rigidbody while physics is paused affects its Transform in some way? Like.. if I'm spawning the same rigidbody at the same Transform::from_translation across runs of my game... there shouldn't be a difference of like 0.00004 in their X coordinates, right?
ok, it might be because I was switching one vehicle's collider while things are loading. I am constantly surprised how changing something by such a small fraction breaks determinism. It makes sense, but every time it surprises me
Change the number at all and float precision will take care of the rest for you
getting a weird thing with slab and get_disjoint_mut
thread 'main' (3379639) panicked at forks/avian/crates/avian3d/../../src/dynamics/solver/islands/mod.rs:728:17:
Neither body 375v1#4294967671 nor 163v1#4294967459 is in an island
@vestal minnow it seems to be complaining about this?
entity 375v1 is the gray uhh divider underneath the sign and entity 163v1 is the collider of the sign
if I move it up just a smidge so that they're not touching it doesn't crash
also, another thing I noticed when iterating over rigid bodies with this..
Query< ( Entity, &Position, &Rotation, Option<&Name>, Option<&LinearVelocity>, Option<&AngularVelocity>, ), With<RigidBody>, >,
the order isn't quite the same across runs. Again, I'm trying to setup replays in my game and I'm testing the determinism by iterating over everything on frame 1, outputting its position/velocity, and then doing the same on 500 and then doing a diff to see where the non-determinism is.
On the simulation-islands branch, the step 500 has a different order between runs for rigid bodies that haven't moved which is interesting.
and yeah, I had to set slab to use slab = "0.4.11" since get_disjoint_mut was added in 0.4.11 I think
query iteration order is not guaranteed. you have to sort if you want that
I can't find a reference in the Query docs, but this comes up in the examples and such: https://github.com/bevyengine/bevy/blob/0257d6e27b1dc5ec1c9985807c1ffd64aae677f5/examples/ecs/entity_disabling.rs#L66-L67
I thought it was somewhat determined by insertion order? Regardless, I can add the sort since this is just for debugging but I thought it was worth pointing out just in case it's a hint at some other problem.
I am seeing some non-determinism getting introduced about 50 frames in but it likely is something in my code
system ordering is also not guaranteed across runs
yeah, I've been adding a lot of chain() and systemsets 🫠
a little off topic, but I think the main thing tripping me up right now are Commands that queue Commands. I've been converting them into observer triggers which seems to be helping
Hey, quick question, does anyone know how can avian2d use collisions to not let movement, like what system pr plugin uses avian2d for knowing if you can move infront of you or you can’t

Cause in a proyect I got it was pretty straightforward, just put the collisions and if component static body haha you can’t move
But now I implemented my own rendering system
Soo it kinda hard to keep track of the real size of things
usually you just apply forces to a dynamic body and it stops on its own when it hits something
can use shapecasts or collision events otherwise though
But like I’ll need to apply them explicitly on a system, righr?
I was going with the collision event aproach
But I got stuck in thete
be more specific?
Like there aren’t avian plugins for doing that without me implementing
I have to implement when the collision happens and how I want the forces to interact with the rigid body
not if i'm interpreting you vorrectly
*c
avian's a physics system, dynamic bodies collide with each other
Like, there’s not an already made plugin for handling basic collision stuff, like: “there’s a wall, don’t mive to that direction”
Aldo statics and dynamics, right?
static & kinematic also act on dynamic bodies, yes
But now, the thing is, I created 2 components, each of them with rigid bodies, colliders and the collisiom events activated
And they detect the collisions, but they don’t anything besides that
show the code?
Well it’s kind of a big proyect
Like I could give tou the repo
just need the part where you spawn the physics objects
Ohhh sure
use avian2d::prelude::{
Collider, CollisionEventsEnabled, LinearVelocity, RigidBody, SpeculativeMargin, SweepMode,
SweptCcd,
};
use bevy::{
ecs::system::{Commands, ResMut},
log::info,
math::{DVec2, Vec2},
transform::components::Transform,
};
use crate::{
ecs::{
maze::{
components::maze_meta_data::MazeMetaData,
systems::utils::maze_tile_centroid::get_tile_centroid,
},
player::components::player::{Player, RayCaster},
},
global::PLAYER_COLLIDER_RADIUS,
};
//TODO: change this for being in the needed schedule
// just for game_start
pub fn spawn_player(mut commands: Commands, maze_meta_data: ResMut<MazeMetaData>) {
// when first created, this will be the position of the player, cause it will be the first spawn_tile pos
let spawn_position = get_tile_centroid(maze_meta_data.spawn_tile_initial_pos);
commands.spawn((
Transform {
translation: spawn_position,
..Default::default()
},
Player,
CollisionEventsEnabled,
SweptCcd::default(),
RigidBody::Kinematic,
Collider::circle(PLAYER_COLLIDER_RADIUS),
RayCaster {
..Default::default()
},
));
info!(
"Player Spawned at: {},{}",
spawn_position.x, spawn_position.y
);
}
Here’s the player
pub fn generate_maze_tiles(
mut ascii_maze: ResMut<AsciiMaze>,
mut maze_meta_data: ResMut<MazeMetaData>,
mut commands: Commands,
) {
for (row_index, ascii_row) in ascii_maze.0.iter().enumerate() {
let mut tile_row: Vec<TileType> = Vec::new();
for (col_index, ascii_tile) in ascii_row.iter().enumerate() {
// for knowing where should the tiles begin
let y0 = row_index as u32 * TILE_SIZE;
let x0 = col_index as u32 * TILE_SIZE;
let mut tile_entity = commands.spawn_empty();
// for tyle properties and rendering
let tile_type = match ascii_tile {
'+' | '|' | '-' => {
tile_entity.insert((
CollisionEventsEnabled,
RigidBody::Static,
Collider::rectangle(TILE_SIZE as f64, TILE_SIZE as f64),
)); // only the walls will have static bodies
Wall
}
' ' => Path,
'O' => {
maze_meta_data.spawn_tile_initial_pos = (x0, y0); // for having easier acess to the imporant positions
Spawn
}
'E' => {
maze_meta_data.exit_tile_intial_pos = (x0, y0);
Exit
}
_ => {
//shouldn't happen, but just in case
error!("Character {ascii_tile} not recognized in the ascii_maze");
ErrorTile
}
};
// just for managing general stuff and following the ECS architecture
tile_entity.insert((
MazeTile {
initial_pos: (x0, y0),
tile_type: tile_type.to_owned(), // cause of the borrow checker
},
Transform {
translation: get_tile_centroid((x0, y0)), // for having the correct position
// for the rigid body
..Default::default()
},
));
// for ease of rendering
tile_row.push(tile_type); // but in here I can pass it fully
}
maze_meta_data.tile_types.push(tile_row);
}
// we remove all the ascii char, cause we don't need them anymore
ascii_maze.0 = Vec::new();
info!("MAZE TILES LOADED");
}
Here the “walls”
"Kinematic" -> no physics, only velocity
When I try with dynamic didn’t worked as well
Or maybe I didn’t had the plugins correctly set up
Like
default())
// all of this plugins are for PhysicsPlugins to work correctly
.add_plugins(TimePlugin)
.add_plugins(TransformPlugin)
// resources for collision detection
.init_resource::<CollisionDiagnostics>()
.init_resource::<SolverDiagnostics>()
.init_resource::<SpatialQueryDiagnostics>();
After adding those plugins the collisions started to work, but before those plugins I got it on dynamic
are you using PhysicsPlugins?
i'm assuming that's the bit before the default
Yep
Those are from the physicsPlugin
But I’m not using bevy’s default plugins
Cause I made my own renderer
i assume that means debug gizmos are a no-go?
Nope, cause i don’t use any of bevy’s rendering plugins
if you cut out most of the structure and just have your renderer, a ball with velocity, and a wall, does it work?
unless that would be overly difficult
Mmmmm, I’ll try it
But maybe tomorrow (it’s 2am)
I’ll tell you how it goes
if you're getting collision events with a dynamic body, but it's not being affected, it's probably a somewhat tough issue
If they dynamic ball experiment doesn’t goes well
I’ll be ditching rigidbodies and just sticking with avian’s colliders
Luckly I don’t need complicated physics
But I didn’t want to implement ot
It*
yeah, it's a little overkill here
A bit, but meh. If it does work I would just need like 20 lines
Less
8 lines
Vs 30 lines of my own implementation
Well thx, you are a live saver :D
@sweet sundial It did worked, but I think it wasn't working cause I didn't have the Diagonistic resources
🤔 Jondolf hasn't posted anything in a couple days...
I was just gonna comment on how Jondolf talked to me yesterday and Jondolf appears 🤣
uni started up again this week, I'm here but a bit more busy
Are both of the colliders regular rigid bodies? Or are there sensors or colliders without RigidBody involved
I believe that panic is because for some reason neither body has BodyIslandNode, which is meant to be added automatically for dynamic and kinematic bodies
the bottom divider collider is a static rigidbody built with trimesh_from_mesh. the sign is a dynamic collider that is sleeping and is built with convex_hull_from_mesh
and they're just barely touching. Again, just moving the sign collider up so it's not touching seemed to fix the panic
sorry 😅 that was more of a "hope everything's OK" than anything else
Was just searching through to see if I could find anything about bsn release date and I found this. It's enough to make a grown man cry
also given that 0.17 is behind schedule by a lot at this point lol
itll land when it lands, cant rush open source
If 0.18 were just BSN and it came out a month later I'm sure all the crate maintainers would be mad but I'd be happy
For most crate maintainers, it would be as simple as changing the bevy import version, and pushing it to crates.io... What's annoying is a lot of name changes/refactoring of logic
we did get relationships + a better spawn API in 0.16, which could be argued are a part of Cart's "next gen scenes"
and we do have BSN for people to play around with and experiment already, it's just in a PR, not landing for 0.17 :P
What is BSN?
pronounced bee ess hen
-# Still better than B-Scene
Be seen
that's so cool
ok I have a bit of a question, I copied the kinematic character controller and I want to make it stick to the ground. I ended up adding a system that modifies the position by the length of a shape cast, but that ends up giving it velocity so it ends up clipping through the ground
is there a better way to approach something like that?
I don't understand what this is
Also- is there a way to make a collider apply recoil by resizing?
What I mean is
Let's imagine we have two cubes not touching one another
Now I scale up the transform for one of them until it touches the other cube and beyond
Is there a way to make the other cube affected by this scale change and actually move?
right now it does nothing
Guess I can apply velocity manually OnCollisionStart
what is the rigidbody type you're using?
It works mostly like expected in my test
Some caveats
- The collision won't consider the speed at which the scale is changing, because from the engine's POV there is no velocity there, it just sees that the penetration depth is suddenly larger.
- There's a
SolverConfig::max_overlap_solve_speedproperty that limits how fast overlapping objects push each other apart, for stability reasons. By default this is 4 units per second, but you can increase it if needed. Also make sure you have a reasonablePhysicsLengthUnitif you're using pixels for object sizes, since it scales the overlap solve speed.
Oh this is good actually
I wonder what I'm doing wrong then
I know that the player's velocity works well, so it has to be the blast
RigidBody::Static,
Collider::circle(260.0),
Mass(300.0),
CollisionLayers::new(
[CollisionLayer::Enemy],
[CollisionLayer::Collectable, CollisionLayer::WorldCollider, CollisionLayer::Orb, CollisionLayer::Player],
),
DebugRender = stone_head_blast_circle_debug_render(),
)]
pub struct StoneHeadBlastFinalCircle;```
Anything wrong with my setup?
In this video the player seems to stay sleeping the whole time, which implies that the collision probably isn't being detected
(see the player's collider's color remain dimmed out)
omg random aside, someone added Avian next to Bevy in Bévy on wplace
that is so cool
I see
Thanks!
any best practices regarding performance tuning? I'm just spawning a lot of RigidBody:Static 1x1x1 cubes that are not colliding and just by virtue of existing my framerates go to ~2fps vs ~450fps without Colliders (both in release mode) - profiling tells me Avian BroadPhase system is the culprit (running on a AMD 9800x3d)
how much is "a lot" ?
Aww 
at around 48K colliders the FPS starts dipping below 60FPS, around 54K colliders it's below 10FPS
Ideally I would like to push the number much higher .. is 50K colliders doing nothing creating such performance overhead normal or is there anything I can tweak?
I'm also thinking I could enable collisions per entity dynamically since I dont need collisions on all entities at all times but I'd like to avoid frequently adding/removing components if possible
The problem is the broad phase overhead since it's currently not very optimized and even does work for static bodies. It should be fixed with the new BVH broad phase coming Soon™
that sounds promising, yeah as I wrote in my first post profiling also identified BroadPhase as the culprit
is there any way I could mark colliders to be skipped/ignored for broadphase?
ColliderDisabled should work
A marker component that indicates that a collider is disabled and should not detect collisions or be included in spatial queries.
But note that it'll also disable spatial queries like ray casts for it
Ok so here's the thing. No collision ever starts until I apply velocity to the player manually?
here's one with the Collisions iterator
Why would it only detect collisions if I move?
I made the velocity optional in the query too, and of course both always have transform
Oh that blast thing is a static body right? Collisions are not computed between sleeping and static bodies since, well, they're not supposed to move
Does it work if you make the blast a kinematic body?
(also for pushback from a blast, I would personally maybe just manually apply a force/impulse/velocity to bodies inside the blast radius, since that might be easier and give you more control over things; but depends on what exactly you want of course)
Hello, dumb question, but I forgot if there was a component or way to make it so that a scene root will have trimeshes generated for all it's meshes. Or maybe I need to make it myself
Oh right I forgot to turn it back after testing that!
Thanks!
Yea haha I decided to take this approach, which is why I made this system
I just want things to only knock back when they hit the blast and not right when it starts
A component that will automatically generate Colliders on its descendants at runtime. The type of the generated collider can be specified using ColliderConstructor. This supports computing the shape dynamically from the mesh, in which case only the descendants with a Mesh will have colliders generated.
solver_body.linear_speed shows values in m/s, right?
This is my code to write it on the screen:
pub fn print_debug_data(
rocket_query: Query<(&SolverBody, &Transform), With<RocketTag>>,
mut ui_query: Query<(&mut Speedometer, &mut Text)>
){
for (solver_body, transform) in rocket_query {
for (mut speedometer, mut text) in ui_query.single_mut() {
text.0 = format!(" speed: {}\n altitude: {}",
solver_body.linear_velocity.y,
transform.translation.y
//transform.rotation.
);
}
}
}
It prints e.g. 50, but the object doesn't look like its moving at 50m/s pace
it's in units per second, in 2d that's pixels for the default camera
if an entity with collidingentities colliders with an entity that is the colliderof another entity, will the parent entity be added to the collider entities
Currently it includes just the entities of the colliding colliders, not their parent rigid bodies
Either in FixedPostUpdate with .after(PhysicsSet::Sync) (note: on the main branch Sync was renamed to Writeback) or just in FixedLast
It should be pretty easy to map "colliding colliders" to "colliding bodies" with ColliderOf
shweat thanks
Does solver_body shows "net" speed, without e.g. any forces, or if I want to read it, after I added forces working in opposite direction to the speed in previos frames, it should show modified speed?
This rocket have height of 6.6m(units). There is no way that is falling at the speed of 138m/s.
The speed print is just printing linear_velocity's Y. Although the transform print looks ok, the size of the rocket to translation pace doesn't match
pub fn print_debug_data(
rocket_query: Query<(&SolverBody, &Transform), With<RocketTag>>,
mut ui_query: Query<(&mut Speedometer, &mut Text)>
){
for (solver_body, transform) in rocket_query {
for (mut speedometer, mut text) in ui_query.single_mut() {
text.0 = format!(" speed: {}\n altitude: {}",
solver_body.linear_velocity.y,
transform.translation.y
//transform.rotation.
);
}
}
}
Are bevy's shapes using same units as location in the space and avian's physics?
let mesh = meshes.add(Cylinder::new(ROCKET_DIAMETER / 2., ROCKET_HEIGHT));
let leg_mesh = meshes.add(Cuboid::new(LEG_WIDTH, LEG_HEIGHT, LEG_THICKNESS));
although I would probably need a new collidingentities structure that keeps track of the count that an entity is colliding with you
that or I just have collidingentities on all the child colliders and then merge them each fixedupdate but that feels messy 
Okay apparently the ColliderOf doesn't work how I thought it did at all. I thought it would mean that the collision event raised would contain the parent entity (colliding body).
So I ended up making a pretty scuffed couple systems.
One just reads all the collision events and then raises more collision events but with the colliding body instead.
Then I made a ManyCollidingEntities component that contains HashMap<Entity, u32> and keeps track of the colliding entities.
Needs to track the count since it now holds the colliding body, which may have many colliders with ColliderOf pointing to it - so the collision ending with one might not mean another isn't still active
it is fairly scuffed but now it all works :) so good stuff. I've finished my refactoring moving from rapier -> avian
I've been pronouncing it as "bee scene" 😨
Jondolf is there a good way to handle objects colliding through portals? From my perspective an object will only collide with stuff on one side of the portal
I've been thinking a lot lately about the idea of "collision proxies", which would be collision shapes that mirror other objects modulo some transformation. Then collisions with that proxy are transformed and forwarded to the mirrored body instead. Very useful for applications where the world is not flat and continuous:
- Portal/Superliminal
- big_space cells
- mixed reference frames
- worlds that wrap at the edges
So I've got a couple questions:
- what would it take to convince you this is something that should be in Avian, and
- could you mentor me if I wanted to implement it?
sensors?
Not exactly. Basically I want an object that says "when something hits me, apply the resulting contact resolution to this other body instead"
And ideally it would support transformations as well. I can try to give examples if it's still not clear wth I'm talking about 🙂
Oh wait, are you suggesting a way to implement portals using sensors?
@remote oxide this seens to be your expertise
Here's an example of what I'm talking about. The ball wraps around at the edge of the screen. To handle this graphically, I introduce a "visual proxy" when the ball starts to overlap the edge. You can see though that when I move off the left edge and wrap to the right, the visual proxy starts to overlap the white rectangle. As far as avian is concerned, those two objects are 10 meters away. It's only when I actually wrap the object's position that it starts looking for collisions, at which point it discovers (to its chagrin) that they are deeply interpenetrating.
My hypothetical solution would allow you to spawn a relationship component onto the ball proxy that says "you are a collision proxy for the ball". The physics engine will look for collisions between proxies and external collision shapes, then generate contacts that act on the external bodies and the ball, not the proxies.
Was thinking you might be able to use sensors as collision proxies, because physics engines can provide that info from a sensor, but it is not a two-way interaction. This is one reason I've been working toward physics simulation islands for big space, trying to get things to behave reliably between cells with this kind of technique sounds painful.
Someone a while back mentioned they did this in the past with Unity(?), so it's definitely doable.
Yeah, admittedly trying to use this for big_space cells does sounds very awkward considering you'd only have a handful of layers to work with. Tbh I only included that one because it's technically overlapping design space. On the other hand, simulation islands doesn't lend itself terribly well to what I'm trying to do with it (collisions interspersed throughout nested, non-inertial reference frames), so I think there's still a lot of value in this approach.
Interesting about the unity impl, I'll have to track that down maybe!
i have a complex glb model and i need to give a collider to it. on blender i can add simple mesh and spawn it with
commands.spawn((
SceneRoot(asset_server.load("models/complex-model.glb#Scene0")),
ColliderConstructorHierarchy::new(None)
.with_constructor_for_name("Collider_Mesh", ColliderConstructor::TrimeshFromMesh),
RigidBody::Dynamic,
Transform::from_xyz(0.0, 2.0, -3.0),
));
and it works. but i dont want to see this collider mesh, it only needs to be a collider. how can i do that? or is there a better way to add simple collider to complex model
Multiple ways! You can just make the mesh invisible for starts, or you can add a primitive collider like a capsule as a child of the rigid body 🙂
yeah i thought about the second idea but that model kinda weird shaped so i wanted to give a custom mesh
How do you make a vertex based collider?
just added a new mesh and changed its vertex positions to fit complex model
for the first idea, how im i gonna do that? just make the mesh transparent in blender?
Hello, I have just a flat plane and a low poly car, with both having trimesh colliders and the car being a rigidbody, and for some reason it just doesn't stop bouncing around, doing flips and stuff.
It doesn't bother me particularly but I thought it might be good to share. Might be something to do with the generated colliders or smth
You can also build it with things like ColliderConstructorHierarchy::new(ColliderConstructor::ConvexDecomposition)
Insert Visibility::Hidden on it in Bevy
Will this allow me to change the contents of it on run time?
without recreating it
Usually, the move is to observe a Trigger<OnInstanceReady> and iterate through the hierarchy with iter_descendents, then do something for every entity that holds a Mesh3d
Well, I never tried, but you can downcast the collider to a parry trimesh or compound polyhedron (depending on your construction method) and then change whatever you want in there
But that complex mesh and collider mesh are on the same glb file
Thats why im spawning like this
Yeah, look at the correct child mesh
E.g. by its Name
Is there a way to use a square collider and do the same?
Instead of making one with ConvexDecomposition
As in I still want to be able to edit the cube but not have to type out the parameters, with it still being something that can be downcast and edited
Whether it be a convexdecomposition or not
If not I can just type out the vertices and indices
Sure, you can convert most primitive colliders to a trimesh 🙂
I do that in avian_rerecast, for example
I need a secret knowledge about creating collisions for procedurally generated meshes
It's there a way to have multiple physics worlds? For simulating multiple scenes at the same time
Can you turn them into a trimesh collider?
What do you mean?
Put a https://docs.rs/avian3d/latest/avian3d/collision/collider/enum.ColliderConstructor.html#variant.TrimeshFromMesh on the mesh
A component that will automatically generate a Collider at runtime using Collider::try_from_constructor. Enabling the collider-from-mesh feature activates support for computing the shape dynamically from the mesh attached to the same entity.
Or manually call https://docs.rs/avian3d/latest/avian3d/collision/collider/struct.Collider.html#method.trimesh_from_mesh
A collider used for detecting collisions and generating contacts.
Thanks, I will take a look on this
I've added TrimeshFromMesh into my chunk
let chunk_entity = commands.spawn((
Mesh3d(meshes.add(mesh)),
MeshMaterial3d(ground_material.material_handle.clone()),
TrimeshFromMesh,
Transform::from_translation(location),
)).id();
And ColliderConstructor::Sphere {
radius: 1.,
}
into my player:
let player_entity = commands.spawn((
Player {
velocity : Vec3::ZERO,
gravity : 9.8,
speed : 20.0,
},
Transform::from_translation(Vec3::new(32., 32., 32.)),
Visibility::default(),
MovementMonitor::new(Vec3::new(32., 32., 32.)),
MovementComponent { },
ColliderConstructor::Sphere {
radius: 1.,
}
)).id();
commands.entity(player_entity).add_child(camera_entity);
But the player can still move trough chunks. Fresh avian install, no other things done. Did I forgot about anything?
maybe give it RigidBody::Static?
I'v added Static into the chunk, and Dynamic for the player, but still the same
How would I use ColliderConstructorHierarchy as a collider as well as querying it to edit it?
The hierarchy doesn't exist anymore after it's done its job. All it does is create a Collider for you at every child that has a Mesh3d
so you need to query Collider
So Collider::convex_decomposition would work for spawning?
sure 🙂
What would I do then if I want to edit the vertices and indices?
collider.shape_scaled() to get the underlying SharedShape
The shape of a collider.
then call the correct function to get the mutable actual shape
In your case probably .as_convex_polyhedron_mut().unwrap()
which gets you a ConvexPolyhedron
A convex polyhedron without degenerate faces.
or maybe you'll have a compound of polyhedra, dunno
How exactly you can then mutate the polyhedra I don't know
but it's something along these lines
Sorry if I'm vague, as I said, I haven't ever actually mutated a collider at runtime 🙂
