#Avian Physics
1 messages Β· Page 38 of 1
Maybe? Still not 100% sure how we want to handle that split, I think the most correct would be to have a DynamicBody/KinematicBody/StaticBody split, and have them all require a RigidBody marker component. We just need them to be mutually exclusive, so we'd need to do "archetype invariants at home" and have hooks to make sure you always have exactly one of the variants
Required components at home is what got us required components early right, so surely archetype invariants at home will get us archetype invariants 
But yea having a hook on say DynamicBody that removes KinematicBody and StaticBody OnInsert seems reasonable
Also should we replace normal1 and normal2 with a world_normal like in collisions? π€
For shape casts?
For collisions the normal is the outward surface normal on shape 1, but for shape casts you might expect it to be the normal on the shape that was hit by the shape cast
Yea I'd expect it to be the normal on what was hit ... Having both normals is very easy to get wrong though since you're always just kinda guessing 
But I guess since it's ShapeCastHitData it might already be implied that it's data related to the hit shape
+ &mut |hit| {
+ let slope_angle = hit.normal2.angle_between(Vec3::Y);
+ if slope_angle < best_angle {
+ best_angle = slope_angle;
+ ground.best_slope = Some(hit.normal2);
+ }
+ if slope_angle < MAX_SLOPE && hit.distance < distance {
+ ground.closest = Some(hit.entity);
+ distance = hit.distance;
+ }
+ true
+ },
);
- for hit in spatial_query.sphere_hits(ray_cast, ground_cast.radius, false, &filter) {
- let slope_angle = hit.normal.angle_between(Vec3::Y);
- if slope_angle < best_angle {
- best_angle = slope_angle;
- ground.best_slope = Some(hit.normal);
- }
- if slope_angle < MAX_SLOPE && hit.time_of_impact < distance {
- ground.closest = Some(hit.entity);
- distance = hit.time_of_impact;
- }
- }
```Actually had this diff which got it wrong π
(My old spatial queries only had the normal from the shape that was hit)
Or it's actually called ShapeHitData
we should probably rename them as RayCastHit and ShapeCastHit
I think ShapeHitData might be used in other places too, but if so that's easy enough to fix
Also we should have a point in world space for collisions, ray casts, and shape casts, it's easy enough to compute but people keep asking about it and it's nice for convenience
Guess we should fit some API reworks into that BVH rework then
Cause it's gonna be breaking anyway 
Actually thats not too different. I missed that when I was looking over #770. Do you think some component to cap this for an entity would be a good idea in conjunction with this then?
The constant acceleration components apply an additional acceleration on top of the body's existing movement. They don't control what the total acceleration including gravity, external forces, collisions, etc. will be. Controlling or limiting a rigid body's acceleration in a reliable way isn't really possible, because the engine operates on velocities, not acceleration.
For example, contacts apply impulses to modify the body's velocity directly and resolve the contact, rather than computing some force and the acceleration caused by that force and then applying that acceleration.
Mathematically speaking, the theoretical contact force for a rigid body is infinite at the time of impact, as the collision would have to happen in zero time with zero deformation (not quite true with non-zero time steps though); if you were to limit the acceleration, high-speed collisions would lead to bodies sinking into each other, as the contact would not be solved instantly but over a longer time with a limit on the contact force.
So I guess to answer the question, you could control the acceleration caused by external forces (gravity, user-applied forces, etc.) but that is largely up to the user to control what external forces they're applying. But limiting the total acceleration, including stuff like contacts, doesn't make sense to me / I don't know what that would look like
I figured that was the case for this but wanted to check anyways, thanks!
hah, PartialReflect has an is_dynamic method, so if we made RigidBody a ZST, this still compiles
rigid_body.is_dynamic()
that's a fun one
Maybe leave an is_dynamic implemented that panic!s?
- a deprecate if you go that route π€
Hmm this does get mildly cursed, let's say someone does this for some reason
commands.spawn((DynamicBody, KinematicBody));
DynamicBody::on_addruns -> command to removeKinematicBodyis queuedKinematicBody::on_addruns -> command to removeDynamicBodyis queuedKinematicBodyis removedDynamicBodyis removed- oof
I think we can work around this by queuing a custom command that only removes the component if there are other conflicting components left, so that
DynamicBody::on_addruns -> command to try removeKinematicBodyis queuedKinematicBody::on_addruns -> command to try removeDynamicBodyis queuedKinematicBodyis removed- Oops, removing
DynamicBodywould leave no body variant left; skip this DynamicBodyis left
It's somewhat ambiguous which one you would expect to be left in this case, but I think it's better to leave the one listed first, as it's consistent with required component priority behavior
Probably emit a warning when that happens too π€
Maybe, and slap a #[doc(hidden)] on it so it's not visible in rustdoc?
But yea, I think that's just something we'll have to live with and use it as a reason to say "Archetype invariants pls" for the millionth time π€£
Or we can not remove the other ones, and just emit a warning in the hook if the others are present
and a #[deprecate] for good measure
Hmmm, though that warning needs to be delayed too, since you might .insert(DynamicBody).remove::<KinematicBody>() and that would fire the warning if it happens in a hook/observer
WIP branch with a DynamicBody/KinematicBody/StaticBody split
https://github.com/Jondolf/avian/compare/main...rigid-body-split
Migrated pretty much everything and got collisions working like normal, though joints seem partially broken atm
haven't accounted for all the potential edge cases yet
What's the purpose of this change?
This is still very much open to changes and not finished, but mainly the motivations are:
- Way less unnecesary data stored: static bodies don't need mass, velocity, force components, and so on, and kinematic bodies don't need mass either
- Queries can filter by specific types of bodies directly rather than having to e.g. check
rb.is_dynamic()in loops, which is both more ergonomic and performant
I guess once we get the opposite of required components, whatever that is called, this would become a lot better too?
If you mean archetype invariants (like an entity with X cannot have Y) then yes, for now I'm doing it manually with hooks
Currently with my implementation, if you .insert(DynamicBody) on a StaticBody, it should currently remove StaticBody automatically to replace it with DynamicBody
because both existing at the same time would be an invariant
From an ECS philosophy standpoint it also feels to me like the different types of rigid bodies should have their own components. They all share RigidBody behavior (non-deformable physics object) but behave in fundamentally different ways, and have different behaviors and systems acting on them based on the type of body
||It removes a third of the code in Avian Pickup /j||
Soooooo many
let Ok(rigid_body) = rigid_bodies.get(trigger.target()) else {
return;
}
if !rigid_body.is_dynamic() {
return;
}
I will say that seeing RigidBody::Dynamic or whatever replaced with just DynamicBody in the diff feels strange after seeing RigidBody for so long, but I think it's just a matter of getting used to it
the shorter names are nice, just weird atm lol
Yeah I'll also have to get used to it, looks weird.
But agreed, this is not bad, just my monkey brain going "different, me no like"
The lack of the Rigid prefix feels mildly weird too, but if we look at engines like Box2D, Jolt, or Bepu, they actually just use names likeb2BodyDef or Body or whatever and a separate b2BodyType or EMotionType, the "rigid" prefix is largely redundant in type names
In this case the body is still a RigidBody but the body type is specified via compositional inheritance using the separate components like StaticBody, which feels more ECS-y I think
(side note, "EMotionType" is a funny name to me)
hehe
How it will look when Avian has soft body? Imp SoftBody component? Can entity have this KinematicBody and SoftBody component or SoftBody will have it's own sub types?
kinematic softbody? static softbody?
depends on the actual api, but those both sound like a rigid body with a weird collider
I don't think kinematic or static soft bodies are really a thing, it would just be a rigid body then
If it's kinematic or static then it isn't affected by forces so it just doesn't deform like a soft body would
But we could just provide aliases like type StaticBody = RigidBody::Static something something idk
Doesn't work for what we're trying to do, since the goal is to have correct top-level "driver components so the required components can finally make sense (and as a result reduce memory usage with tons of static bodies)
completely random question, can things "float" in Avian due to density diffenrence?
they can't right? at least not without putting in some work I guess
Doesn't that require a Fluid Body/Simulation then?
I don't think air is simulated, only gravity...
yep, for accurately simulating it ofc π
but you never know what clever hacks hide around
I think you can make your own system for it pretty easily though, assuming you only want to simulate air...
if an entity has a ColliderDensity and a Mass component... does the ColliderDensity do anything?
@vestal minnow Is there a way to get the volume of a collider/physics body?
IIRC the way it works is that ColliderDensity determines what density will be used for computing ColliderMassProperties, and when computing the mass properties of the rigid body, it combines the mass properties of each collider but uses the Mass etc. components instead of ColliderMassProperties if they are present
So yes it affects the mass properties computed for the collider itself, but when computing mass properties for the rigid body, the components like Mass will have higher priority in a sense
You can use collider.mass(1.0) because mass = volume * density and if density = 1 then mass = volume
No but I would like to add an example of buoyancy, so you'd have e.g. a cuboid-shaped sensor collider that acts as a pool of water that bodies can float in
there's a few ways to do it depending on the level of realism desired
Jolt has built-in buoyancy
If you can simulate air you can also simulate water right? It's just much denser I would assume
Well yes, but then you would have to either deal with the transition between air and water, where osme of the objects volume is in the water, and som is in the air, or have the entire world "be water"
It's easy to simulate a body that is only ever in a single fluid, because you just add a bouyant force to it, based on the bodies volume and the fluids density
Reminder that OpenUsd and Gltf physics formats doesn't have explicit separation between static/kinematic/dynamic rigid body and contain bool "Is_kinematic" and static body is considered static if it only has collider without rigid body (IIUC). Doesn't mean we should follow this approach but Avian should be able to parse these formats properly.
At least Unity and Omniverse USD Composer have bool is_kinematic on Rigid body component and static rigid body only has collider without rigid body component in the same way as mentioned formats (IIUC).
https://www.youtube.com/watch?v=Y3xkgpCukow
https://youtu.be/RfD8-X0Zyoc?t=57
Here's what I learned about Rigidbody in Unity...
Unity's Physics Engine allows us to use the Rigidbody Component to let a GameObject be influenced by the physics.
In this video, we'll take a quick rundown of the component, and we'll discuss some important tips as well!
Support me on Buy Me a Coffee! β Your support helps me create more in-dep...
This tutorial will teach you how to set up the deformable body, a physics extension in NVIDIA Omniverse USD Composer (formerly Omniverse Create).
NVIDIA Omniverseβ’ is an open platform built for virtual collaboration and real-time photorealistic simulation. Complex creator, designer, and engineering visual workflows are transformed as users a...
Yeah the tricky part with buoyancy is figuring out the submerged volume when bodies are only partially submerged. One super simple approximation is to compute the whole volume of the object, uniformly sample some points inside of it, and use the ratio of how many points are submerged to estimate the submerged volume. Another more sophisticated approach that Jolt uses though is to actually figure out the exact submerged volume; for some shapes like spheres this is pretty trivial, but for general polyhedra it gets more complicated, the Game Programming Gems 6 book describes an algorithm for this
Yeah I think we'd probably just find trees with colliders but no rigid body and add a StaticBody to the root entity in that case
It is worth considering that sort of split in Avian itself too though, where "statics" are separate from rigid bodies; Bepu actually does that too, though it's probably more for optimization reasons
Functionally a StaticBody marker doesn't really do anything and just adds some overhead since you need to attach colliders to that and manage those relationships rather than just making each collider act as its own static thing
The question is more what kind of mental model we want here and what "makes sense"
More reasons to have physics_dev channel where we can ask this question.
If we were to copy the model of an "is_kinematic" bool exactly, with an IsKinematic marker component (or just Kinematic), one of the problems I have with that mental model is that turning a dynamic body into a kinematic body fundamentally removes and changes behavior. It effectively forces infinite mass so that it cannot react to any forces, it disables gravity, it should (but doesn't yet) disable collision checks against other non-dynamic bodies, and so on. Components in the ECS should generally be designed to be composable and additive instead, or otherwise they should be treated as mutually exclusive
i.e. adding a component should typically not disable the behavior of another component IMO
unless it is very explicitly for that purpose like Bevy's NoWireframe component, though even that is not overriding a component, it's overriding a global resource's setting for an entity
Worth noting that we do already sort of break this philosophy with Collider and Sensor. A Collider attached to a RigidBody acts as a solid shape that other bodies can bump into, but Sensor kind of "removes" that behavior and makes other bodies pass through it. This might be even weirder as we make sensors a more separate thing with their own intersection graph and broad phase tree and possibly their own events etc.
I've been kind of toying around with the idea of a theoretical split like this
PhysicsShape: An asset storing a shape used for physics.Collider: A component for aHandle<PhysicsShape>that acts as a collision shape that dynamic bodies can collide with.Sensor: A component for aHandle<PhysicsShape>that detects when other shapes intersect this one.RigidBody: A component for a non-deformable physics object with optionalColliders andSensors attached to it.DynamicBody: A dynamicRigidBodywith non-zero mass that can be moved by velocity and forces.KinematicBody: A kinematicRigidBodywith infinite mass that can be moved programmatically with velocity.
In this theoretical split, colliders and sensors would be fully separate concepts, but they would both store a PhysicsShape
Colliders would always be actual colliders, meaning dynamic bodies can collide with them, not pass through them if they're sensors
it feels weird to call something a collider if it doesn't have collisions
but yeah anyway this is all very hypothetical and needs to be thought through and designed properly
I probably won't merge the DynamicBody/KinematicBody/StaticBody split for this release since it feels a bit scary, people aren't sure about it, and IMO there are still some unknowns there
not sure yet
If Alice makes #physics-dev and I can first discuss it there π
This this image applies to Alice as well 
Also π I think we're using slightly wrong contact points in the solver
Parry returns local_p1 and local_p2 on the surfaces of the two shapes, and then for the solver we just transform those to be in world space relative to the center of mass of each body, but we should be taking the midpoint of those two world space points and making that relative to the centers of mass
So right now the solver is using different two points in world space for the contact point while they should be using the same point, just relative to each body
oh I actually have a question that is probably suited for physics-dev more than here π€ about advice on controlling dynamic objects that are flying around
we have a physics dev channel
#1397333422401392792
it's right there in the name
let's just start refusing to discuss anything that is not directly related to Avian and then we can send a million examples of why we need #physics-dev to #1397333422401392792
true
just imagine how many times the avian api would change by then
||that's a joke pls don't stop improving avian π ||
actually, maybe what I want is to post in #math-and-physics
Does someone have a small body or 3D model that is jittery even when resting on the ground? I'm curious if the contact point bug is the reason for it
I guess I can just make a very small cuboid and maybe stack some of them
nope still seems jittery, hmm
happens with f64 too, which leads me to believe it's not a precision issue but some fundamental bug
I also have an important question for #1397333422401392792
Why does TriMesh look so right, but tri_mesh looks so wrong 
I have wondered the same thing
for what it's worth, I did notice just now having one of my items on the ground with high friction made it jittery
is it ThreadPool or Threadpool in code? what about threadpool or thread_pool? is it Thread-Pool, Thread-pool or Thread pool or Threadpool in pose?
yeah I need to double check and then triple check that the 3D friction implementation is correct
it has had some stability bugs in the past that should be fixed, but it's possible something is still wrong there
it happens with friction 0.0 too π€·
hmm
Yeah okay Rapier is perfectly stable here with small cubes, so it's an Avian problem. I'm going to prioritize trying to fix this now
Also bevy_rapier seems to have a fun bug where transform scale doesn't seem to be working on the first frame so everything just overlaps and explodes lol
unless I set it up wrong
I'm using Collider::convex_hull_from_mesh for that one
okay Rapier is... strange, how do I even set a fixed time step
- Tries
.in_fixed_schedule()-> warning thatTimestepModeis set toVariable - Tries to insert
TimestepModemanually (since it's a resource) -> nothing changes - Finds a
with_custom_initializationmethod for plugin init ->RapierContextInitialization::InitializeDefaultRapierContext(what is this name?) hasIntegrationParametersandRapierConfiguration, but neither of them haveTimestepMode
Okay you need to insert the TimestepMode resource before you add the RapierPhysicsPlugin, otherwise you get the warning
that's... mildly questionable DX but whatever
I'm annoyed by so many API decisions in bevy_rapier that I kinda want to dedicate a week to fixing them lol
Believe me I'm so happy that I was able to stop using Rapier in favor of Avian, mainly for API and documentation reasons π
what have I done
let's make this another "dont normalize twice for no reason" campaign
get 60 different people to keep the chain going
-# please no
component for moving with velocities + component for changing velocities due to forces (et c)?
-# Don't calculate AABBs twice for no reason
pretty good idea 
ok so now mine here redirects to yours and yours to mine here, but now it looks like you're spamming #memes, so you could delete the first one and then we'd be left with the cyclical chain without the start
oh that's another great idea
Done
Yesss it works 
Take that, LLM scrapping bots >:D
(hope they get stuck lol)
tbh this is another reason we need a #1397333422401392792, making a mess here surely has less visibly
GOOD point!
why does ColliderBackendPlugin require ScalableCollider and not just AnyCollider
what even is a detail: u32
why is there a 0.4 here, thats curious. i wouldnt expect a 5^-1 factor in sphere related maths
impl ComputeMassProperties3d for Sphere {
fn unit_principal_angular_inertia(&self) -> Vec3 {
Vec3::splat(0.4 * self.radius.squared())
}
}
lol why is Rotation in a module named position
it deals with transforms, which have scale
where
isn't anymore on main
I think I copied it from Rapier, some shapes like spheres or capsules don't support proper non-uniform scaling in Parry so you need to use a discretized mesh approximation in those cases
now it's in physics_transform, I'm also going to combine Position and Rotation into a PhysicsTransform soon
Cool resource, thanks π
How does avian currently respond if Position and/or Rotation get removed from an entity? π€
(Note: there is no SyncPlugin)
if i wanted to have a custom transform type and not use Transform, how hard would it be to get avian to play with that
On the latest release, just disable SyncPlugin and make your own. On main? things changed so probably hard π«
is there anything besides gravity acting as a force on a body in freefall with no linear damping?
I'm drawing a trajectory arc with the following, and doing a shape cast along each line to find the point of impact. I'm getting really really close, but it's always slightly off and I can't figure out why.
points[0] = point; // Initial firing position
for i in 1..STEPS { // loop through an arbitrary # of steps to draw a line
velocity += gravity.0 * gravity_scale * TIME_STEP;
point += velocity * TIME_STEP;
points[i] = point;
}
// draw a line between each point, etc...
does the timestep match the fixed post update rate devided by physics substep count?
in this case 64 Hz / 6 assuming default settings i think
There are only a handful of very specific systems that propagate Transformer <-> Position / Rotation. You should be able to easily replicate those. I think on main itβs just 2 systems IIRC.
Youβll also have to do your own interpolation, but thatβs also not that hard
Good question. I will give that a check!
alright, so I switched to ensuring Im updating with the same time step, and now using avian's integrators, but still running into the same issue with my shapecast being slightly innacurate π€ maybe theres some collider margin im not including?
points[0] = initial_translation;
for i in 1..STEPS {
points[i] = points[i - 1];
integrate_velocity(
&mut velocity,
&mut angular_velocity,
Vec2::ZERO,
0f32,
ComputedMass::new(1.0),
&ComputedAngularInertia::new(0.0),
LockedAxes::default(),
ball_gravity,
time_resolution,
);
integrate_position(
&mut points[i],
&mut rotation,
velocity,
0f32,
LockedAxes::default(),
time_resolution,
);
}
Hi, I would like to integrate Avian into my project in a limited way where I expose just the basic collision detection functionality (and any logic which would help with calculating how to resolve collisions geometrically) but otherwise running all my own logic to resolve things in a kinematic manner for all colliding entities.
Are the any recommendations on how best to do this? I naively assumed I might get away with enabling only the parry-f32 feature and then adding the default plugins but this is not building.
Thanks :)
edit: Now building since I added the "2d" feature. Nonetheless the question stands. Would be interested to know if there are any particular architectural considerations here.
its really unfortunate i cant do type Context = Gizmos<'static, 'static>; in AnyCollider
no DerefMut
What's the best way to debug which colliders might be triggering this? It's happening here in avian2d 3.1
thread 'main' panicked at /Users/choc/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/avian2d-0.3.1/src/collision/collider/mod.rs:508:9:
assertion failed: b.min.cmple(b.max).all()
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Encountered a panic in system `avian2d::collision::collider::backend::update_aabb<avian2d::collision::collider::parry::Collider>`!
Encountered a panic in system `avian2d::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`!
can you get more backtrace with the environment variable?
wait, this should only trigger if grow is given a negative vector
do you have a negative collision margin?
I'm not sure the circumstances that would cause a negative collision margin to exist. I have some colliders that are moving very fast which is the only physics thing happening at the moment. I don't understand the correlation between the speed of collider and collision margin
i'm just looking in update_aabb for the word grow
well I worked around it by removing the Collider after I no longer need it. It was for picking up coins that moved towards the player mouse after being clicked, they speed up the longer it has been since the click. At high speeds they sometimes trigger that panic π€·
So I remove the collider as soon as they're clicked and the problem stopped happening.
this was assuming the aabb was already valid, but that'd mean Collider as AnyCollider has some invalid shape when it's calculating the aabb
They're all just Collider::circle(5.), and I don't touch the collider or scale after creation, only the translation
typically this means your position or rotation is NaN for some reason
Are there any video tutorials about avian physics?
Is there any way to toggle debug rendering at runtime?
Yeah, you can toggle the gizmo config. Check Foxtrot for an example
(Canβt link well because Iβm on the phone rn, but itβs in src/dev or something like that)
I don't think so
the main learning material currently is the docs.rs documentation and the examples in the repo
game jam games that use Avian might also be a useful reference for "real-world use"
most of the core features and concepts also tend to be largely the same across different physics engines even outside of Rust, so looking at other engines' docs and resources can also be useful for understanding things
(as for why there are barely any video tutorials, I imagine that's because both Bevy and Avian have rapidly evolving APIs and features, and are quite young)
PR for changing ContactPoint to store a world-space anchor1 and anchor2 relative to the center of mass, and a world-space point, and a normal_speed
https://github.com/Jondolf/avian/pull/792
FYI @visual sparrow, the normal_speed is another way to judge how "strong" a contact is, -normal_speed is equivalent to an "approach speed" indicating how fast the objects are approaching each other at that point
Unlike a normal_impulse, this is not dependent on mass or the time step since it's just a relative velocity
(also cc @cinder summit since you might need to adjust your SDF contacts a little for this lol, it shouldn't be too bad though)
the diff for the built-in Parry contact manifold computation is like this
(the old one might be a bit unclear but it's just passing local_point1 and local_point2 to ContactPoint::new)
Ah thanks!
Hello, I just came back from holidays and my app runs now at 60fps whereas it used to run at 120fps. It's not necessarily due to Avian but does anybody have a clue? I cargo updated the project but it was already bevy 0.16.1
Avian should be faster, not slower π
to be fair I updated after seeing the fps drop hoping that would fix something but it didn't
You could take a look at tracy to profile
the thing is that I didn't change a single line of code since. Also, I tried building in release mode and it's still at 60 fps. So I'm not sure tracing would be beneficial at all. Also, if it was about performance, it should probably go lower than 60, but it's like there's a cap that prevents from going up
vsync is enabled by default in Bevy so if you're on a 60 Hz monitor, it caps at 60 fps
it was the monitor settings indeed! thanks a lot π
Huge stability improvement! Especially for small objects or objects with low angular inertia ;)
https://github.com/Jondolf/avian/pull/794
Before
After
@little maple @hoary turret I bet this fixes (or significantly reduces) the jitteriness and instability you were seeing
Note that these are 10 cm cubes (i.e. sides have a length of 0.1) at a gravity of 9.81 m/sΒ² with 6 substeps
I can go below 1 cm and the cubes are still not jittery on the ground (though gravity is too high at that point to keep the stack from falling over)
yeah okay below 1 mm is fine too if you lower the gravity
rendering is scuffed though, I need to tweak the camera
Merged already, but do let me know if it causes any new weirdness
Brother you're the goat
I'm going to test it straight away
β€οΈ
Did you forget to call time.unpause()?
Jokes aside, that's wayyyyyyyy better. Impressive!
I may be able to stack cans on top of each other again π
They were a bit jittery before haha
@vestal minnow I'm getting lots of compile errors after updating to the latest commit π€
but theoretically it's pointing to bevy 0.16
imma try cargocleaning just in case
(its over, 15 minutes compile time heh)
Running fine for me π€ What are the errors about?
Mostly related to what seems like a version missmatch with I think is glam?
it was complaining about Vec3s and Scalars
if it's still wrong after cargo clean I'll start giving it a thought
fuk
okay everything is bevy_math
I mean I've got nothing weird going on
Those modules don't even exist on main anymore
sync or position or prepare
Do you have two conflicting versions of Avian? One using main and one using 0.3
maybe through another dependency if you happen to have something else that uses it
you might want to patch the dep
https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html
also make sure the Cargo.lock is updated and not somehow broken
Uh wait, maybe this could be the problem?
I'm using bevy_trenchbroom which integrates with Avian
bevy_trenchbroom = { git = "https://github.com/Noxmore/bevy_trenchbroom.git", rev = "a8454bf28292158f5b843cacf44d3023c6260260", features = ["avian"] }
so it is probably pulling the latest release of avian and it cannot work together
this makes me sad big time because I truly want to test that out immediately π₯²
I think Imma temporarily fork bevy_trenchbroom just to test this haha
Hey, I have a weird issue where if I raise the time scale (Time<Virtual>), I get really bad FPS, even if I have no rigid bodies in the scene. I've been debugging/profiling and it seems like because time delta is larger, it causes FixedPostUpdate to run more frequently, which increases the time delta, which causes FixedPostUpdate to run more... and so on! Until it stabilizes at an awful frame rate. Is this normal?
What's the correct way of controlling time with avian? I couldn't find any examples
Zoomed in:
I could get around this by using Time<Fixed>::set_timestep, but that makes the movements very choppy. So I'm not sure if that's the correct way
Also, it feels odd to me that Fixed time is derived from Virtual rather than Real time. π€
Cause then what's the point of Time<Physics>::set_relative_speed?
If I set Time<Virtual>::set_relative_speed to 2x it would cause physics to update twice. But if I set Time<Physics>::set_relative_speed to 2x as well, wouldn't that cause things to move 4 times as fast?
would you rather Time<Virtual> not effect physics?
I'm not sure. I was assuming to control time scale, I would have to set virtual time relative speed and also physics time relative speed to "synchronize" them
But from what I see, that isn't correct
And if virtual time affects the number fixed steps, then also what's the point of SubstepCount?
how do i increase the timestep hz?
specifically, the physics simulation runs every FixedUpdate, and during that a shorter inner loop repeats SubstepCount times
so i should increase fixedupdate?
https://docs.rs/bevy/latest/bevy/time/struct.Time.html#method.from_hz and a ResMut<Time>
will that speed everything up so i would have to adjust movement values to match?
no
I get that, but I guess I'm confused about what happens during step vs. substep.
Maybe I'm misunderstanding the docs. But in my mind, substep is specifically to handle accuracy in high time delta.
So I was assuming if I increase the relative time speed, for example, I'd have to also increase the substep count to maintain accuracy
For if I increase the virtual relative time speed, the Fixed update will be called more, which WOULD maintain the accuracy
So then why would I ever have SubstepCount not be 1?
substeps are only a little bit of the overall simulation, they don't even do collisions iirc
Ah maybe I misunderstood the concept then
oh this is great, thanks.
System sets for the substepped part of the constraint solver.
is there any reason not to set the timestep to multiple hundreds
of?
hundreds of*?
ah sorry, hz
yeah, performance
for a metroidvania it shouldn't be too much of a bottleneck right? at least in the cpu frametime it seems to have very little effect
i had mine at 144hz for a while, but it turned out to be expensive and unnecessary
currently at 72 hz, dropped it to 24 hz for a while to fix issues in my math that aren't obvious at high time resolutions
Doesn't raising it make movement choppy though?
interpolation
@vestal minnow something whacky is going on with the trimesh of a Plane3d 
i had a lot of ghost collisions at the default 64hz, i've got it at 256 now and it's really smooth
i might turn it down though
let shape = Plane3d::new(Vec3::Y, Vec2::splat(25.0));
let collider = Collider::from(shape);
let trimesh = collider.shape().as_trimesh().unwrap();
println!("trimesh: {:?}", trimesh.vertices());
PhysicsInterpolationPlugin::interpolate_all + explicitly exclude camera + hermite easing on small objects
Prints
trimesh: [[10000.0, 0.0, -10000.0], [-10000.0, 0.0, -10000.0], [-10000.0, 0.0, 10000.0], [10000.0, 0.0, 10000.0]]
Is it possible that the collider ignores the plane's half size?
Oh lol I see
Is that intentional?
That should be self.half_size instead imo
probably copied from the unsized plane
ooooooh that makes sense
Lemme PR then
Or from Plane2d, which is also unbounded π
wow bevy_math's got weird names
Simple as
thx for the hint @sweet sundial
Also added support for InfinitePlane3d using the old behavior while on it
The infinite 3D plane was surprisingly not actually supported yet
if you need a punchline i have a bunch of (Collider, Mesh3d), most of which are just IntoCollider + Into<Mesh>, the lone exception being (Collider::half_space(..), Mesh3d(Mesh::from(Circle{..})))
Relatable, here's my rasterization code:
Also had to just give up for those haha
Hold up, why shouldn't InfinitePlane3d be a half space instead 
because things can be on either side
oh, fair enough
could be modeled as two halfspaces with different collision layers i suppose
by the way i made a really big sphere to try and have visible ground to match the atmosphere shader, but as soon as i made it a static body it started jittering constantly
Time::<Physics>::set_relative_speed scales the delta time used by physics, but it does not affect how often physics is updated. This means that with 2x speed, it would take 2x longer steps, unless you also reduce the time step from e.g. 64 Hz to 128 Hz or something. So changing the relative speed of physics affects behavior.
Time<Virtual> is meant to be kind of like a gameplay clock determining how fast the gameplay is. So it makes sense that it also affects schedules like FixedUpdate. However the difference for physics is that the relative speed of virtual time does not change the physics time step, it only affects how frequently physics runs. This keeps behavior consistent and deterministic even if you had some slow-mo effect, unlike when changing the relative speed of physics, at the cost of a lower update rate when in slow-mo (needs interpolation to look smooth) and a higher cost in fast-forward.
I think it just didn't originally exist and I didn't implement it yet when it was added to Bevy
there might be a few more 2D shapes like that
Substeps are only for the solver, a single physics step is roughly like this (simplified)
Broad phase collision detection -> Narrow phase collision detection -> Run solver for N substeps
Constraints such as contacts and joints are solved iteratively, and using substeps helps things converge on the solution better
Increasing the time step Hz can have the same (or better) effect, but you need to pay for the more frequent collision checks, which can be expensive
And oftentimes you might want your gameplay logic and physics to run at the same rate, and might not want a super high update rate for your own logic
So it's a balancing act of stability vs. perf
@vestal minnow did you see my messages? after reading this it seems substeps could be good for my usecase?
Depends on what interactions you have going on, if there is no stacking of rigid bodies or other more complicated collision scenarios then you probably don't need many substeps
Using a higher tick rate (Hz) can be useful if you do need more frequent collision checks for some reason, like to reduce ghost collisions in your case
for ghost collisions you can also try to set the SpeculativeMargin to zero to disable speculative collisions (but you risk tunneling at high speeds or clipping into things slightly), try more rounded shapes, try to manually maintain a small separation from the ground, etc.
or if this is a 3D triangle mesh collider, use TrimeshFlags::FIX_INTERNAL_EDGES, but your game is 2D afaik?
Now that this has been reworked, how do we want this to reflect in ShapeHitData? I should probably wrap up that spatial query rework, but I still need to fix the sillyness in those types (especially things like the QueryCollider trait allowing you to return an Entity, which will always be overwritten anyway)
Thanks for the explanation. π In my game, I mainly scale the time up (i.e. speed up). Does this mean I should use TransformExtrapolation instead of TransformInterpolation?
Interpolation and extrapolation are both just ways to ease transforms to make movement appear smooth. Interpolation eases between the previous and current transforms, while extrapolation eases between the current transform and a predicted next transform. It's mostly useful if your fixed update rate is lower than the monitor's refresh rate
In general you should just use transform interpolation
The trade-offs are that interpolation can lag behind a bit since it's using old positions (usually not very noticeable), while extrapolation is more snappy but can cause jarring movement when the prediction is wrong, for example when your movement's trajectory suddenly changes
It's mostly useful if your fixed update rate is lower than the monitor's refresh rate
This is currently what I'm doing on higher time scales to help with performance:
fixed.set_timestep(Duration::from_micros(15625 /* 64 Hz */).mul_f32(ratio));
I tried using interpolation last night, but my entities (kinematic, velocity based) would over/under shoot their targets on higher scales
Interpolation seemed to help, but it's still a problem
Hmm, maybe something like this? π€
pub struct ShapeCastHit {
/// The entity of the collider that was hit.
pub entity: Entity,
/// How far the shape travelled before the initial hit.
///
/// If negative, the shapes are intersecting, and this represents the penetration depth.
#[doc(alias = "time_of_impact")]
pub distance: Scalar,
/// The hit point in world space.
///
/// If the shapes are penetrating, this will be the midpoint between the closest points
/// on the surfaces of the two shapes.
pub point: Vector,
/// The outward surface normal on the hit shape at the hit point in world space.
pub normal: Vector,
}
I think it'd be waaayy less confusing and much easier to use than the existing setup
For penetrating cases you can also still figure out the points on the surfaces of the bodies based on the world-space point, penetration depth, and normal, if you needed that for whatever reason
The downside is that a world-space point is subject to precision-loss at large coordinates, but eh idk if it's really a problem. We could still additionally store the points relative to the shapes' positions if we wanted to
Yea, that would work π
Should help with some of the footguns when using the API, and it makes implementing this trait a lot easier
Yeah Parry's version is a bit less... user-friendly
Not that the API in avian 0.3 is particularly great either, especially since it's not consistent with collisions
yeah imo it's nice if the different types of hit results are mostly consistent with each other, do what you'd expect, and are in world-space so you don't need to manually transform things from local space
I'm not sure when a typical user would need local-space values
I'm still getting some slight jitter but idk, it might be partially the collider shape and the size of the entity. I realized the other day that my game's scale might be kinda small.
it's definitely better though
this was before
I experience similar jitter for cans of realistic proportion IIRC
I believe I hacked around it by increasing their mass / density
maybe it's just cans π€
is that a Collider::cylinder or a mesh or convex hull?
@vestal minnow said something about Parry not being very accurate for some shape combinations
Collider::convex_hull_from_mesh
I made that one a long time ago and haven't gone back and change it. I think using a cylinder collider would make more sense
yeahh I mean it's kinda hard to tell what is collision detection inaccuracy and what is a simulation bug, for a while I thought the problem with small shapes was a Parry problem but it was more of an Avian thing with the friction bug
a decent way to tell if it's an Avian thing is to try the same with Rapier
Avian Pickup still has weird workaround code in it because Parry's raycasts often falsely return no hits 
if they both have the same problem, it might be Parry, or a fundamental simulation limitation
I wonder if rolling resistance would help for this specific problem
I could implement it if y'all have a use for it
(Box2D has it too :P)
or just throw some AngularDamping on it
It's honestly not a big deal for me
for my use case
I mean, I get that "no, it has to be right!" perspective lol
why does bevy_rapier wrap the hit points and normals in a separate ShapeCastHitDetails struct
is using them so unergonomic that they need to be hidden from the API 
oh it's if you don't compute the points and normals, right
Does it go away when you increase the density?
Okay, changed the API and this actually seems like it makes a lot more sense in my codebase, why did I not do this from the start 
And the shape intersection point/normal/penetration I internally have in the trait now actually gets returned ... I'll have to see if that's viable to keep when I add the parry impl though
Never made sense to me how shape intersections don't tell you what they hit, just a boolean
is this the correct way to pull per-frame avian logic into FixedUpdate and run my own stuff before/after?
pub struct AvianPlugin;
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct PrePhysicsSet;
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct PostPhysicsSet;
impl Plugin for AvianPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
PhysicsPlugins::new(FixedUpdate),
avian2d::debug_render::PhysicsDebugPlugin::new(FixedUpdate),
))
.add_systems(FixedUpdate, add_colliders.in_set(PrePhysicsSet))
.configure_sets(
FixedUpdate,
(
PrePhysicsSet,
(
PhysicsSet::Prepare,
PhysicsSet::StepSimulation,
PhysicsSet::Sync,
),
PostPhysicsSet,
)
.chain(),
);
}
}
haven't tried that.. the mass is 10
I thought that... if I am setting the mass then the colliderdensity doesn't get used?
Yep
By default it runs in FixedPostUpdate and you'd run your own code in FixedUpdate I think ... That's how I do it in my game (or well I technically use my own schedules called Simulation(Pre/Post)Update)
I was asking about increasing the mass through any means, sorry for the confusing wording π
Why not run your systems that want to be after Avian in FixedPostUpdate, scheduled after avian?
Seems like less of a hassle
Yep, if it needs to be after I'd suggest throwing them in FixedPostUpdate with a constraint or FixedLast
That works too, how would I shedule it after Avian though? Something similar to the example I posted?
app.add_systems(
FixedPostUpdate,
my_system.after(PhysicsSet::Sync)
)
or better
app.configure_sets(
FixedPostUpdate,
(
PhysicsSet::Sync,
PostPhysicsSet
).chain()
)
Note that you don't need to schedule your pre-physics sets if you use them in FixedUpdate π
@vestal minnow what's your take on Vec3A vs Vec3?
(you might want a chain in that second one)
Ha, good catch, thanks
For the navmesh stuff, I just naively used Vec3A everywhere because "Unga bunga SIMD π "
But when interacting with Bevy API, it consistently requires Vec3
So I have a ton of Vec3::from(some_vec3a) in the Bevy integration 
Of course the real answer is "profile and find out", but do you have some rule of thumb or experience to share before that?
Oh btw, the trimesh from mesh stuff was not the problem: #1364848195670114325 message
Thanks for helping me debug that π
Right now Avian just uses Vec3 almost everywhere because we have f64 support and the feature-dependent Vector shenanigans, and I don't want to deal with special-casing f32 just for Vec3/Vec3A conversions everywhere, but if we
(or reduce) f64 stuff then we'll probably use Vec3A a bit more
Ah so that's the reason. I was wondering why Avian used Vec3 so ubiquitously
I don't have a specific rule though, if you do a lot of SIMDfiable ops somewhere then it's good to try Vec3A and ideally profile if it's better
I generally wouldn't just default to using it everywhere, but idk I haven't benchmarked it much
Also I'd really like to do this, IMO we should only support f64 for positions and any other world-space values that can have large coordinates
For the solver internals or velocity or material properties or anything like that it doesn't really make sense
I'm more iffy about the API
I guess you can support larger/smaller mass properties with better accuracy but at that point you might hit the solver's limits anyway
Since exposing Vec3A makes it inherently friction-ful (what's the right word?) with Bevy
makes sense
Yeah I would generally just use Vec3 for public APIs (and maybe like impl Into<Vec3A>) but use Vec3A for internals where performance matters and it has an actual benefit
Sounds reasonable. Thanks for the chat π
impl Into<Vec3A> ALL the things!
Sync has been split into Prepare and WriteBack?
Hello, sorry for the silly question. I think I am missing something conceptually and could use some help. I am making a simple scene where this cylinder is the ground, and generating a collider for it.
// circular base
commands.spawn((
Mesh3d(meshes.add(Circle::new(20.0))),
MeshMaterial3d(materials.add(Color::WHITE)),
Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
ColliderConstructor::Cylinder { radius: (20.0), height: (0.5) },
RigidBody::Static,
));
Though when I am looking at it with the debug plugin, it appears to orient perpendicular like it isn't getting the Transform rotation for the mesh. What am I missing?
Thank you in advance!!
A circle mesh in Bevy is on the XY plane by default. But cylinders are upright with the circular bases on the XZ plane. So they're perpendicular to each other in your case
You could make either the mesh or the collider a child entity and transform that separately
Or alternatively use a cylinder for the mesh too
That is very good to know. Thank you!!
(also the reason for this is that for 2D shapes like circles you need to have them on the XY plane since the camera is pointing toward -Z, but for 3D shapes like cylinders you kinda expect them to be upright and to rest on the ground by default)
OOHHH! Ok that makes a lot of sense. Does that extend to squares and cubes/rectangular prisms, etc as well
Yeah circles, ellipses, rectangles, polygons, etc. are on the XY plane, and cylinders, capsules, tori/toruses, cones, and so on are upright
Ok great. This intuition I am sure will be useful many times in the future so thanks for that
I moved my avian logic to a different crate and now when I try to run the game I get:
I have no idea what changed
Has anybody ever had anything similar?
would it be a good choice to rely on Avian's determinism for a p2p deterministic game? or should I roll my own physics?
Avian is fully deterministic if you enable the enhanced-determinism flag AFAIK, so you can use it.
I'm aware of the flag, my question is more about how well it works. I had some issues with determinism with Avian in the past.
There are tests in place to guarantee determinism. If you run into an issue, itβs a bug and will be fixed.
Where to enable it?
Itβs a crate feature, enable it in your Cargo.toml π
Ok, thanks
it works well
Does it also work cross platform?
Can I include somewhere in avian things like air resistance, drag coefficient etc?
with enhanced-determinism yes
that feature should really be called cross-platform-determinism or math-determinism or something
Avian is locally deterministic even without that feature, it's just for cross-platform deterministic math via libm
You can use LinearDamping and AngularDamping to slow rigid bodies down over time using exponential decay, which can emulate a basic air resistance-like effect. Aerodynamics and accurate drag are way more complicated and out of scope though, they are heavily dependent on the shapes and orientations of objects
Yes, so I want make en as accurate simulation as possible. What parts of the avian can I use. Gravity, some functions to add/modify e.g. angular rotation, and collisions, but is there anything more that would be usefull?
Depends on what you need. The APIs for applying external forces and torques to bodies might be useful (note that these were recently reworked on the main branch), and maybe spatial queries like ray casts
and of course mass properties, but that's handled automatically unless you want to manually configure or compute them
How can I extend avian to add my own computations or integrate my own calculations into it in any other way
For aerodynamics stuff I would imagine you just compute a force and torque to apply to the body and then apply them in FixedUpdate like normal gameplay logic
Or you could schedule your own systems directly inside the PhysicsSchedule or even SubstepSchedule, but those are more prone to breakage and changes
Does any of the examples showcase this?
Or even replace some of Avian's plugins with your own, but again, you need to know what you're doing there and internal physics logic can easily break or change in a future update
I think there's one for a custom broad phase and one for a custom distance constraint
but like it all depends on what you're trying to do, you need to figure out the scheduling and stuff from the system sets if you're trying to insert your own systems in Avian's internal schedules
I don't know any other engine where you can even insert your own logic like that (and I don't generally recommend it) beyond dedicated hooks for specific things like contact modification, which Avian does have too
@vestal minnow what's your opinion on this set of traits and types btw? https://github.com/NiseVoid/avian/blob/generic_spatial_query/src/collision/collider/mod.rs#L345-L470
And do you think these would be easy to implement for parry?
-# (For parry, CastShape and Shape would probably be either Collider, a type like it without scale, or just SharedShape)
Can you point which ones are showing this?
the ones called custom_broad_phase and custom_constraint
Oh, right...
Could've guessed xD
- We should probably make
AnyColliderreuse the bounding trait instead of both having their own versions of AABB methods - We can probably make
ColliderAabba wrapper overAabb2d/Aabb3dif we only supportf32anyway for the BVH. Then we can returnAabb2d/Aabb3dfromshape_aabb(I would maybe call thisaabb_with_context) - Does
QueryColliderneed to implementAnyCollider? Or could it be a fully separate thing with its ownContext? ray_normalfeels strange to me. If you have the normal, then you should typically also have the distance. I would just call theseray_distanceandray_castor something, whereray_castreturns aQueryRayCastHitshape_hitshould just beshape_castIMO- I would rename
hits_pointtocontains_point - I would maybe rename
shape_intersectiontocontact? Though I think I would personally just have a method to query for AABB intersections with the BVH, and then users can further do their own contact computations for those shapes, whether that's withcontactorcontact_manifoldsor something else - FYI, the intent with the shape intersection methods that just return a bool is that they can be way faster than computing actual contact data. You never need EPA, and a lot of the analytic intersection tests are also more optimized than the contact computations
Also I wonder if there's a way to hide the Context stuff from the API with a ContextShape wrapper or something π€
If only the Bread Phase PR landed, this would be much easier to understand 
Oh wait ray_normal takes a point and not a ray 
Yea, ray_normal just computes the remaining info when we know a hit actually needs it
So like, not one that is filtered out for not being the best hit
1: That makes a lot of sense actually
2: Yea, ColliderAabb was getting a bit clunky too,
3: I think these are in theory seperate, so we could split them appart
4: see above
5 + 6: Makes sense
7 + 8: Yea, probably makes sense to change that API a bit, my SDF collider impl basically just wraps contact_manifolds, though in theory I could make a slightly faster one that just returns a bool (but ime that's often not enough data)
On 1 specifically .... The weird bounding trait that gets context was originally just a quick hack to get things to actually work, so I never considered the fact that colliders could use it too 
Would the non-manifold contact method still be on QueryCollider or just on AnyCollider with a default impl that just does the manifold but then
s the manifold data?
I'll see if I can cook up something nicer, I hate that Context param on the bounding trait π€£
If we get rid of that I think we can also just use Bounded2d/Bounded3d directly too ...
Hmm, I think either not have it at all on the traits or have it on QueryCollider
AnyCollider should be scoped to what colliders need to function as colliders, meaning what they need for the broad phase and narrow phase and for rigid body sim
QueryCollider can be for additional geometric queries and spatial queries
I mean if we don't have it at all then it would regress shape intersection perf for parry no? π€
We already don't have a spatial query for contact computations, we only have shape_intersections which doesn't compute contact data and just returns intersecting entities
Also just curious, what data do you actually get if you try to get a boolean contact check, is it just a boolean, or is there something like the penetration depth and direction there? π€
Parry supports three levels here
- Intersection test: Just does the minimal work to determine if two shapes intersect. For example, a ball-ball intersection test is literally just
center_distance_squared <= sum_radius_squared. - Contact: Computes a single contact point between two shapes, with a penetration depth and normal, typically just running GJK+EPA for most shape pairs.
- Contact manifold: Computes a whole contact manifold in one shot, often consisting of multiple contact points. Typically uses SAT and/or GJK+EPA and contact clipping.
The middle one with a single contact point is usually the least useful IME unless you're building contact manifolds incrementally or something
For a lot of gameplay things just getting that contact can be all you need, but for the actual physics it's not particularly useful π€
And of course sometimes intersection test is all you need too, like "Can I place this here or does it overlap anything?"
Or even something like selecting all entities in some selection box or lasso selection tool or something
But for cases like "Did this AoE hit an enemy" you might start to care about where the hit was so you can put some vfx there
Gameplay logic gets so annoying when you start adding vfx 
Hey how do you recon a high detailed mesh would perform on the physics end? Like, instead of using a heightmap for terrain I'm thinking of sculpting it in something like Substance Modeler and converting to meshlet for the rendering side.
I guess I could run it through a decimator if I have to
Decimating it + using convex decomp can do a lot compared to using a high poly trimesh
A lot of terrain workflows rely on doing exactly that too
Do you have a good strategy on how I could better automate the convex decomposition process?
it would be pretty complex terrain like something out of Star Wars Pod Racer
yeah highly detailed meshes can perform quite poorly for collisions since you can end up with shapes doing collision tests against a ton of triangles at once and have to compute contacts against each of them
this wouldn't be as bad if we had manifold reduction to prune contact points, but we don't have it yet
(neither does Rapier)
Avian can do the convex decomposition (or technically parry does I think?), but I don't think we have cool things like using asset preprocessing for it yet like we probably should
oh wow ok
And while I'm here, do you guys happen to know if a big meshlet would even work for terrain? Like, does it lower the detail of the entire mesh based on distance, or is it all localized?
Legend has it Jan made something for caching at least, but idk if that persists across reboots π€
ok so probably a pretty expensive operation eh? I could split the mesh tho
Probably worth splitting the mesh in general if it's big
Yea, plus if it's big enough, loading the terrain can be done in chunks that are relevant rather than all at once
yeah which may work quite well in my case because I'm making it very canyon-y
hmm, it could be interesting to try and offload convex decomposition done at runtime to some async tasks to avoid blocking the main thread
well how involved is it from the user perspective? am I just passing some verts into a function?
if parry does it I could probably help with this if you want
I want to build up a whole terrain strategy/pipeline for bevy
We have a thing for that, it's called bevy_asset 
the convex decomposition part is just Collider::convex_decomposition or Collider::convex_decomposition_from_mesh
or if you have a scene then you can use ColliderConstructorHierarchy to generate the colliders automatically
awesome
Benefit of making the terrain chunks too is that the convex decomp resolution starts to become consistent
But again this can be very slow and expensive for anything remotely detailed
so this is the jist of my strategy atm:
- sculpt in blender or whatever
- export into a lossless format, whatever is the smallest
- use
meshopt(C++) orbaby_shark(Rust) to decimate - split into regions
- convex decomp
- meshlet
ya I hear you
I can fix that though, happy to contrib
fix by running it async lol
By slow I mean like up to several minutes depending on your PC and the size of the scene
Convex decomp being wildly slow, and trimeshes being wildly inefficient is literally how I ended up making SDF collisions after all π€£
For the Ferris crab model it's a few seconds in debug mode for me
it's really not too bad tbh. What matters for speed is being able to preview changes fast with a flycam. Then when it's time to walk or drive around it, you have to run it thru the various processing steps
in release mode it's a little faster
Like, baking shit with Nanite can take like 30 minutes on a beast PC so its just the way she goes I guess
Yea, if we get an actual asset processing workflow for this one day (probably when we finally have scenes and can translate a gltf file to a set of assets among which a scene), then this would be very doable on premade geometry
i'm building a terrain editor π
it's in the 10s of millions of verts
...although I have an RTX 5080
On procgen games with slightly less detailed meshes it would probably be workable too as long as you tune the parameters and run things in the background
And then you have the cursed usecases like my game:
- Procgen everything
- Nothing is low poly
- The server has a single thread
haha
ya.. the problem I'm running into is file sizes
shit is just a lot of data
as soon as you're moving away from heightmaps its like oh shit i have to store the verts
or something
Typically I'm pretty sure static terrains in a lot of open world games just use low detail trimesh colliders
A lot of games crank the poly count waaaaaay down, yes
example scene from Horizon Zero Dawn using Jolt
I'm sure we've all seen the collision vs visual mismatches π
*Horizon Zero Dawn I mean
looks like heightmaps for the actual "dirt" tho
but ya
neat to see
Localized π
Itβs split into submeshes, those are the titular meshlets. And those submeshes can change detail independently of each other
Simulation islands π
(I'm moving the boxes here)
Next step is to wire up the sleeping and waking
[Places a little alarm clock in each simulation island]
Idk jondolf, you might have gone a bit insane, because those don't look like islands... just cubes... Maybe it's time to take a break from this programming stuff?
[Hands Jondolf yet another little alarm clock]
For your island
commands.spawn((
RigidBody::Dynamic,
Transform::from_xyz(0.0, 100.0, 0.0),
Mesh3d(mesh),
MeshMaterial3d(material.clone()),
Collider::cylinder(radius / 2., cylinder_height),
Mass(100000.),
));
No matter how big mass I set the cylinder always behaves the same. Why?
what is it interacting with?
if it's just on static ground or all the other dynamic objects also have that same mass then it shouldn't really change behavior much
Its just falling on the static ground, nothing more
But shouldn't the object with the bigger mass fall faster?
no, a 1 kg box will fall just as fast as a 10000 kg box, assuming they have the same shape
Air resistance is not simulated in avian, is it?
it's not
Then any object, with any shape should fall the same speed right?
yes, I just mean in real life the shape would affect things (unless you're in a vacuum)
fair fair
here is a mathematical explanation I wrote a while ago https://discordapp.com/channels/691052431525675048/1124043933886976171/1366470105315410101
also see Galileo's famous experiment
https://en.m.wikipedia.org/wiki/Galileo's_Leaning_Tower_of_Pisa_experiment
Btw. Are there a specific units in which avian operates?
SI units are recommended, so meters for distance and length, kilograms for mass, seconds for time, and so on
But it doesn't really matter as long as they're dimensionally consistent, like speed is "distance units divided by time units"
This could be meters per second, or pixels per second, or however you want to interpret values
Note that the 3D renderer assumes SI
Bevy assumes SI?
So 1 unit is 1 meter?
The renderer does, yes
yep
Also, if you're not using 1 unit = 1 meter, it's recommended to set the PhysicsLengthUnit. This doesn't scale any of Avian's imputs and outputs, but adjusts some internal thresholds and stuff to improve stability for your expected scale
In 3D*
In 2D, the base assumption is 1 unit = 1 pixel, but you're very free to change that to your needs in 2D
I think the renderer mostly assumes SI for lighting units, like intensity is in lumens and illuminance in lux (which is lumens per square meter)
not sure if it necessarily assumes units elsewhere
Probably also for some of the pbr equations
So takeaway is that renderer is SI, and 2d is whatever you want
Volumetric lighting too I believe, due to the scattering coefficients
For extra fun, try feeding the renderer negative numbers. It often doesn't crash but produces very wild visuals 
I really hope I get to have a good reason to use that for a game at some point
for even more unique visuals, consider rendering the world a few dozen kilometers from the origin
StandardMaterial::depth_map is also very trippy when set to random data
hehehe
For even more unique visuals, consider wearing those drunk goggles
For even more unique visuals, consider normalizing twice for no reason
For even more unique visuals, consider also drinking funny water (If your at legal age of course!)
For even more unique visuals, please give us #physics-dev
speaking of visuals, I kinda want to just slap an atmosphere on most of the 3D examples, I'm bored of all of our scenes looking like this lol
or at least change the color scheme
also have some camera controller and maybe the grabber plugin thingy
(maybe not for examples that focus on demonstrating some specific feature, but for more general samples)
I mean a ShowcaseUtilsPlugin could be useful
That just adds a camera, and object picking
an environment light map also makes things way more interesting IME
We have an ExamplesCommonPlugin already, it just doesn't do that much atm
SubstepSolverSet runs during SolverSet::Substep, right?
yes
but specifically inside the SubstepSchedule
SolverSet::Substep is where the SubstepSchedule is run
IntegrationSet::Velocity will be the best to apply drag/air resistance, right?
there're drag components already, can either check their impls or use them directly
Ye, but If I remember corrently, its very simplistic, and doesn't take e.g drag coefficient into account
yeah
But, how is it exactly called? I can't seem to find it
LinearDamping and AngularDamping, they're just exponential decay
(or specifically the PadΓ© approximation of exponential decay)
π
There might still be some small error in the island splitting logic since it sometimes takes a while for it to split things properly, but it's mostly functional now
this looks neat but what does it mean
ah fixed it, much better now
Simulation islands are like collections of bodies connected by constraints, where each island forms a graph-like structure. Islands are fully disjoint from each other and can be simulated independently. Their main purpose though is to allow sleeping and waking; if all bodies in a given island have a low enough velocity for some time, then that island can be set to sleep. And if any body in an island is woken up, the whole island must be woken up.
Here the red boxes are just visualizing which bodies belong to the same island. It's drawn around their combined bounds, but that doesn't really mean anything beyond that
The difference to our current scuffed sleeping is that we only have per-body sleeping, which doesn't allow bodies to sleep when they're interacting with other dynamic bodies, either via colisions or joints
Whereas with simulation islands we can handle sleeping and waking properly, as can be seen with that whole cube stack sleeping when it's resting for a bit
Some engines like Rapier also use islands for solver parallelism, but we use graph coloring, which supports parallelism within islands, not just between islands
So these islands are used only for sleeping and waking, and persisted across time steps, doing incremental updates to minimize overhead, and deferring splitting (the expensive part) so that only one island is split per time step, the sleepiest one
is this new? I thought you had some island-like thing implemented before? if not I think I maybe just heard about it here at some point
I mean, it looks great, especially that second one and I can see how useful it is
It's new, I haven't had any island stuff before, though graph coloring has some conceptual similarities (a graph where bodies are nodes and constraints are edges)
I have been talking about wanting simulation islands for a very long time tho
livin' the dream
that island life
we're moving into the big boi league now with these simulation islands, graph coloring, the BVH broad phase (Soonβ’) etc.
Iβve had islands for a long time, because I needed to track them anyway for CSG. I didnβt run them in parallel though since Bevy makes that difficult. I also use a BVH for the broad phase. Iβll probably do graph coloring if I implement AVBD. Iβm not sure any of this counts as the big leagues after seeing the latest SIGGRAPH demos.
One thing I use islands for is to force conservation of energy to help with stability.
Identifying islands is the union-find algorithm once you have an intersection graph.
By "big leagues" (half-joking) I mean having implemented a lot of the fundamental optimizations and getting close to (or exceeding) the performance of existing popular game physics engines like Box2D, Jolt, or Rapier
I do not really consider any GPU-based implementation (that I have seen) for rigid body dynamics to be in the "big leagues" for game physics, as I consider that to be a totally different category. For a general-purpose game physics engine, running on the GPU tends to be a non-goal IME
every time I show my game off people tell me how great the physics are and I'm like "thank you Jondolf π "
As for AVBD specifically, I'm still fairly unconvinced based on the results I've seen or even replicated, but I'm interested to see how it develops
Maybe, but I think the algorithms will converge as GPUs become more powerful and CPU cores more numerous (I have a machine with 80 cores now.)
I like it on principle. Iβm not happy with primal or dual solvers, and they both have clear weaknesses, so it seems like a good idea. The fact that it makes parallelism easier is a bonus.
If AVBD doesnβt work right away, it might be worth fixing.
Yeah it has some really nice characteristics, like handling both high stiffness ratios and high mass ratios well, and allowing vertex coloring. But from what I've seen and heard (both with my implementation and their own 2D demos) it's just way too unstable for collisions, requires a ton of tuning to behave well, breaks Newton's third law, and doesn't seem like it'd work as nicely with wide SIMD
They recently updated their 2D demo to use post-stabilization, which removes the need for tuning the alpha parameter, and should prevent adding extra energy to the system, but it made contacts even less stable and more jittery :/
Like I said, weβre getting more CPU cores, but not wider SIMD. Physics laws are more like guidelines in games π Stability is nice though.
I'm really struggling to get avian to run on a custom schedule.
app.add_plugins((
avian2d::PhysicsPlugins::new(CustomPhysicsSchedule).with_length_unit(50.0),
PhysicsDiagnosticsUiPlugin,
PhysicsDiagnosticsPlugin,
))
.add_schedule(Schedule::new(CustomPhysicsSchedule))
.add_systems(GgrsSchedule, (move_players, step_physics).chain())
.add_systems(CustomPhysicsSchedule, foo) // this prints "foo" and that shows up in the output
I modified avian/src/schedule/mod.rs a bit to debug:
println!("schedule: {:?}", self.schedule); // this prints CustomPhysicsSchedule
app.add_systems(
schedule,
run_physics_schedule.in_set(PhysicsSet::StepSimulation),
);
app.add_systems(schedule, foo2); // this system doesn't print anything??
I genuinely cannot figure out the difference between foo and foo2. It's the same schedule so why does only foo run?
Guys, I am migrating to the new Forces. I have modified my old projectile spawning command to look somewhat like this:
fn spawn_projectile(
In(config): In<SpawnProjectile>,
mut commands: Commands,
mut force_query: Query<Forces>,
) {
let entity_id = commands.spawn((
Projectile { [...] },
config.transform,
RigidBody::Dynamic,
// ExternalImpulse::new(config.force),
)).id();
if let Ok(mut forces) = force_query.get_mut(entity_id) {
forces.apply_linear_impulse(config.force);
} else {
info!("NO FORCES");
}
}
There is no Forces querydata ready for the entity when this runs. Do I need to add an observer here and then add the impulse in the observer after a sync point?
can't you just have a Velocity in the bundle?
I'm reading the implementation of apply_linear_impulse & yep, it looks like I could just add the velocity on spawn. The new component is LinearVelocity for anyone who stumbles across this in future π
if you really needed to use an impulse it'd have to be after mass is calculated, which is probably an observer; either queue it separately (Commands), put it after a sync point, or figure out observer ordering
if it's a schedule system rather than an observer then you'd need to do something persistent
Which queries should I use in order to impact the velocity, end rotation?
inside the solver you need to use SolverBody, it has linear and angular velocity
What is the best way to create a shockwave that will push rigidbodies along with it, a sensor that gets velocity and gives velocity upon collision, or is there a way to do it with some kind of spatialQuery?
There's SpatialQuery::shape_intersections for getting all the collider entities intersecting the given shape
a sensor could also work if you want it to persist for several frames or to automatically move with some velocity
Are you running your CustomPhysicsSchedule anywhere?
I've came up with something like this rn, it compiles but I'm not sure if this is correct:
let substeps = app.get_schedule_mut(SubstepSchedule).expect("add SubstepSchedule first");
substeps.add_systems(
air_resistance_substep.in_set(IntegrationSet::Velocity)
);
The schedule you give to PhysicsPlugins::new determines what schedule the PhysicsSchedule is run in, but it doesn't run your schedule for you
oh right you said that the first foo system still prints something, hmm
According to the example, I should rather work with some draits dedicated to the velocity, right?
https://github.com/Jondolf/avian/blob/main/crates/avian3d/examples/custom_constraint.rs
substeps.add_systems(
solve_xpbd_joint::<CenterDistanceConstraint>.in_set(SubstepSolverSet::SolveUserConstraints),
);
// Run the app
app.run();
}
/// A constraint that keeps the distance between the centers of two bodies at `rest_distance`.
#[derive(Component)]
struct CenterDistanceConstraint {
entity1: Entity,
entity2: Entity,
rest_distance: Scalar,
/// The relative dominance of the bodies.
///
/// If the relative dominance is positive, the first body is dominant
/// and is considered to have infinite mass.
relative_dominance: i16,
compliance: Scalar,
/// Data stored from before the solver step.
pre_step: PreStepData,
}
impl PositionConstraint for CenterDistanceConstraint {}
impl AngularConstraint for CenterDistanceConstraint {}
impl EntityConstraint<2> for CenterDistanceConstraint {
fn entities(&self) -> [Entity; 2] {
[self.entity1, self.entity2]
}
}
impl XpbdConstraint<2> for CenterDistanceConstraint {
fn solve(
&mut self,
bodies: [&mut SolverBody; 2],
inertias: [&SolverBodyInertia; 2],
dt: Scalar,
) {
Some kind of equivalent of this code
I'm not sure if I'd model air resistance as a constraint
You're just applying a force, no? I'm not sure if there's really a specific constraint that it'd need to satisfy
but I haven't looked much into how realistic air resistance tends to be implemented
I guess you could model drag as some sort of damping constraint that aims to dampen velocities rather than explicitly using forces, but idk seems more complicated
I didn't mean constrain
Some equivalent of this code for the velocity
AngularVelocity, PositionVelocity traits, I'm not sure if such things exists
Yes. Force, and rotation
Ok, I think I found the best example
Hey, is there a method to get a random position inside a collider?
iirc some bevy_math primitives have volume sampling methods
I see bevy primitives. Are you suggesting converting the collider into a bevy primitive and using that?
If that's the case, I might just implement the function to work directly on collider
i think theres a way to go from bevy primitive to collider
but that may be unreleased peck stuff
I can't import it
Are you on 0.3? There you can just use LinearVelocity and AngularVelocity inside the solver, but on the main branch things are quite different
I'm at 0.3.1
yep solver bodies don't exist there yet, they're new (or added like over a month ago, but not released on crates.io)
just use the velocity components for now ^
or use the main branch or some specific commit
this is what I meant about the internal schedules being very prone to changes here, and (generally) recommending to just use the built-in stuff and running logic in FixedUpdate :p
How can I do this
in Cargo.toml do
avian3d = { git = "https://github.com/Jondolf/avian" }
if you want to lock to a specific commit, you can use rev = something where you replace something with a commit hash or whatever it's called
Thanks, I didn't know about this
Hmm
you need to update Rust, it's a feature that was stabilized in a new release a few weeks ago
Whoa, we can do that now? Neat
Or I don't remember that specific syntax π€ but let-chains were stabilized at least
with &&
let chains were stabilized???? πππ
I was thinking of making different physics "worlds" like the different surfaces in Factorio. Would this make that possible? Also, I assume this will make proper integration with Big Space a reality?
Yeah that was at the end of June
https://blog.rust-lang.org/2025/06/26/Rust-1.88.0/
This is a different feature, for multiple physics worlds/contexts we mostly need each world to have its own broad phase and BVHs so that the bodies cannot interact with each other
Or if we wanted to go further with this and allow simulating each world fully independently, like advancing one world but not others, we would need first-party query-by-value functionality in Bevy, or to rework our internals to rely on the ECS less
I had a prototype for multi-world support implemented already using bushrat's index query PR, but the work on that stalled on Bevy's side
Why?
a hack to support two mutually exclusive dimensions in a single code base, same as what Rapier and Parry do
Do I have to add SolverBody manully into my entity? The breakpoint doesn't hit
have you added MaxLinearSpeed to the entity?
No
SolverBody is added automatically for dynamic and kinematic bodies, MaxLinearSpeed is not
(might change that though, we probably want to have some default bounds on linear velocity and especially angular velocity for stability reasons)
Could it be done with relationships instead? Each physics context would be a one-to-many to physics objects in the world, then you query the relationship and loop over them to do the simulation once for each group?
Yeah it probably could be a relationship, I need to see what the performance of query.iter_many(entities) is compared to query.iter() though
With index queries we can split archetypes based on the world that each body is assigned to, and theoretically have ideal iteration perf that way, but idk how much worse iter_many is
This is interestingly a rare case where I think many-to-many is actually a bad fit too, I think as a design principle you only ever want a physics object in a single context. It saves on performance and you don't need to wait for the Bevy implementation of many-to-many.
Whatever the performance impact is I think is probably an engineering trade-off that would be acceptable if contexts are opt-in.
I'm not sure how I'd make it opt-in without duplicating the systems to have both a "contextful" and "contextless" variant
it'd need two different queries and to do the iteration in two different ways depending on whether you're simulating a specific context/world or not
I used bevy_mod_debugdump and foo is the only thing in the schedule. Is there any way I can check the schedule of the run_physics_schedule system?
digraph "" {
"compound"="true";
"splines"="spline";
"rankdir"="LR";
"bgcolor"="#0d1117";
"fontname"="Helvetica";
"nodesep"="0.15";
edge ["penwidth"="2"];
node ["shape"="box", "style"="filled"];
"node_System(0)" ["label"="foo", "tooltip"="rounds::game::physics::foo"]
}
Here's the entire file if it's helpful
I'm on mobile rn so I can't really read it :/
We have this test that creates a custom schedule to make sure we don't have scheduling ambiguities, that one should work at least
https://github.com/Jondolf/avian/blob/main/src%2Ftests%2Fmod.rs#L187
I'm not really sure why your case wouldn't work
run_physics_schedule should run in the schedule that you give to PhysicsPlugins::new
my only guess is that Interned schedules don't work properly but I assume someone would have already come across that
Yeah, probably just starting with seeing if there is much impact at all if iter_many is used directly, then perhaps conditional compilation on a Cargo feature could keep the code unified if there needs to be a divergent system?
Well, and the default schedule is also interned so that wouldn't be the issue. I'm very lost
I didn't think this mattered but apparently I have to add the schedule before I add the avian plugin
Ah, add_schedule says it overwrites the previous schedule with that label
yeah you might want edit_schedule instead
I don't even need add_schedule lol. I just copy pasted that from an older project
that's definitely a nasty footgun though
The docs for with_length_unit make it sound like it I shouldn't have to adjust stuff like gravity. But the default gravity doesn't even move my character at all.
For reference, I set the length unit to 50.0 and my character is 50x50 pixels
I mean it does say "Note that this is not used to scale forces or any other user-facing inputs or outputs." and that it only adjusts some internal tolerances and stuff for stability
Hmm, it says "the physics engine will interpret 100 pixels as 1 meter for internal thresholds" so I guess I interpreted that as my character would count as 1 meter in size so the default gravity would be fine
but I guess I glossed over the "internal thresholds" part
When adding to solver_body.linear_velocity, should I include delta time into account?
#physics-dev π
probably, unless the other value is already a velocity
I've been bamboozled again :<
@echo parcel I'm also interested in creating a flight dynamics plugin for Avian, though I have barely looked at it besides reading some game dev books. The new changes in avian main sound promising.
I wonder if a thread on #physics-dev for general FDM approaches would be useful
We can stay in touch then
in my editor how can i dynamically turn on and off this ?
.add_plugins(PhysicsDebugPlugin::default() )
it seems like i cant like .. enable or diasable that... ?
app.add_systems(
Update,
(|mut gizmo_configs: ResMut<GizmoConfigStore>| {
gizmo_configs.config_mut::<PhysicsGizmos>().0.enabled ^= true;
})
.run_if(run_once.or(input_just_pressed(KeyCode::F1))),
);
This toggles the gizmos on pressing F1, and it will be off by default (because of the run_once)
Using lambdas as systems... Why did I never think of that...
Rust is just cool like this I guess
Hello, need some help with applying forces to already spawned rigidbodies
all the documentation shows how to spawn a rigidbody with a force aswell, but no way to add a force to something already spawned (unless it's hidden somewhere I haven't found yet)
let mut force = ExternalForce::default();
// calculate force
force.apply_force_at_point(calculated_force, cool_place, mass_center);
// typical example in docs
commands.spawn((Stuffs, force));
// but I wanna apply at runtime
item.apply_force(force) //this sort of thing kinda
required component or insert with commands
at runtime
commands is runtime
so like add a lifting force for car
you could also swap to main and use the new force api
how do you add a force to an existing rigidbody with the new api?
Query<Forces>
so I just query the force and then .apply_force onto it?
Yeah with the new API you would do this
fn apply_forces(mut query: Query<Forces, With<Car>>) {
// Apply a force to every car
for mut forces in &mut query {
forces.apply_force(my_force);
}
}
You can also use the current/old API in 0.3 and query for ExternalForce and modify it, but that old API is a lot more limited and footgunny than the new one
With the old ExternalForce API, all forces are persisted across frames by default, so you need to manually clear them, or alternatively configure the forces to be non-persistent (and you couldn't apply both persistent and non-persistent forces at the same time)
With the new API you can just use Forces to apply forces or impulses that are cleared automatically, like what you'd see in most game engines, and there's a separate component-based API with components like ConstantForce if you want persistent forces
so I can just use normal 0.3.1?
or like how to query for "main" in toml file
do you just to avain3d = "main"
If you want the new API then you need to use main
[dependencies]
# optionally also specify rev = "the SHA of some commit"
avian3d = { git = "https://github.com/Jondolf/avian", branch = "main" }
thx
kinda new to avian & bevy as a whole, but noticed lack of docs on avian3d
https://thebevyflock.github.io/bevy-quickstart-book/2-basics/actual-physics.html this was a really good resource for me
Note that if you have other dependencies that also use Avian, you might get a version conflict and need to patch or fork things to get it working
I noticed that there are like no tutorials out there that show how to query for rigidbody
bcs you cant query rigidbody directly for some reason
The docs.rs documentation should generally be alright, but some more "book-like" content and tutorials and better examples would be nice
owm to making a car game tutorial
w avian3d
using very very valet general car game (they coded it in unity) tutorial as basis
Query what specifically? Like the RigidBody component or things like velocity etc.
specifically Angularvelocity and linearvelocity (i think) but querying them as is (as the tutorial did) works
components don't directly impl QueryData, only references to them
but then you have to ang.0 +lin.cross(position) to find velocity_at_point
The docs for RigidBody do briefly show an example of querying for velocity to move bodies
A non-deformable body used for the simulation of most physics objects.
that specific example is what throws erropr
when also getting transform
so
let rb = Query<stuff from there>
let car = Query<Transform, with car>
Yeah it would be nice to have a helper for that, it's just a bit awkward since the components are separate, it we had a combined Velocity component then we could just have a method on that
mut car_stuff : Query< ( &Transform , &mut AngularVelocity , &mut LinearVelocity ) , With<car>
this is what ended up working
Like @sweet sundial said, you can't query for components without & or &mut
since just the component by itself doesn't implement QueryData
that's more of a Bevy thing and not something that necessarily belongs in Avian docs
mut car_stuff : Query< &mut Transform , With<car> >,
mut rb : Query<RigidBodyQuery>,
here is old stuff
that should work yeah
1 sec
probably aliasing between two &mut Transforms
it was a panic
I don't think RigidBodyQuery has a Transform
{ git = "https://github.com/Jondolf/avian", branch = "main" } throws errors on all let statements
you can do rb.position
that's not a Transform
thread 'main' panicked at /home/gobbe/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0.16.1/src/system/system_param.rs:409:5:
error[B0001]: Query<RigidBodyQuery, ()> in system brumm::bil::fjΓ€der accesses component(s) Position, Rotation in a way that conflicts with a previous system parameter. Consider using Without<T> to create disjoint Queries or merging conflicting Queries into a ParamSet. See: https://bevyengine.org/learn/errors/b0001
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
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!
got error
(that's the old error)
do you have other queries in that system? beyond the two you showed
fn fjΓ€der(
kΓΆ : SpatialQuery,
mut bil : Query< &mut Transform , With<brumm> >,
mut rb : Query<RigidBodyQuery>,
tid : Res<Time>
) {
let HJULEN : Vec<Vec3> = vec![ Vec3::new(4.0 , 0.0 , 7.0) , Vec3::new(4.0 , 0.0 , -7.0) , Vec3::new(-4.0 , 0.0 , -7.0) , Vec3::new(-4.0 , 0.0 , 7.0) ];
for dΓ€ck in HJULEN {
let bilen = rb.single_mut().unwrap();
let pos = **bilen.position + dΓ€ck; // dΓ€cken roterar inte, de sitter fast lΓ€ngs axlarna
let hjulet : Transform = Transform::from_translation(pos);
if let Some(trΓ€ff) = kΓΆ.cast_ray(pos , Dir3::NEG_Y , 100.0 , true , &SpatialQueryFilter::default() ) {
...
}
}
}
what I can tell its just that bil and rb are same
components of car:```
Transform::from_xyz(0.0 , -3.0 , 0.0),
//mesh stuff
//collider stuff
RigidBody::Dynamic,
brumm
Source of the Rust file src/spatial_query/system_param.rs.
because it has both transform and rb
Right SpatialQuery is currently internally querying for Position and Rotation (components for the physics transform, mostly intended for internals) and some other things, and RigidBodyQuery is also querying for them mutably. You can't have multiple queries mutably accessing the same components in the same system unless you explicitly make the queries disjoint using Without<T> filters
Here I would recommend just not using RigidBodyQuery
I'm probably going to remove it soon too since it's not really intended for users, it was originally more to clean up internal logic
oh
(and it's big and slow and somewhat footgunny)
thought it was transform n rb on same object :P
Is trimeshing a big world of colliders something expensive?
Obviously it becomes expensive if you have millions of colliders lol
Like, rasterizing a lot of primitive shapes into trimeshes?
yep
But for something like Chainboom's level that is made of a bunch of convex hulls and convex decomps
My current design for rerecast doesn't neatly allow offloading that onto its own thread
And I'm worried about hiccups
But I think something like that shouldn't be too expensive, right?
Probably not too expensive, the methods are pretty straightforward. You can check them here
https://github.com/dimforge/parry/blob/master/src/transformation/to_trimesh/convex_polyhedron_to_trimesh.rs
thx
Hmm, I suppose I could turn the backend into an async task
then we just shift the problem from "rasterize everything this frame" to "copy all colliders into a separate task this frame"
would be so much easier if we had first-party colliders ;-;
Oh, convex hulls and decomps and whatnot all use the same function under the hood for rasterization?
that indeed looks trivial, nice
Every 3D convex hull is just a ConvexPolyhedron and a convex decomposition outputs a Compound of ConvexPolyhedron shapes
aaah that's good to know, thanks π
is there a good way to do one way collision platforms?
@vestal minnow how come the feature is called debug-plugin and not debug_plugin?
Asking because I'm also doing a gizmo plugin for rerecast and checking prior art
Also, you don't use any retained gizmos, right?
most of our features that aren't named after a dependency use a hyphen
and I think I did that because I was originally copying Rapier for it 
hmm I'll stick to _ then 
simply for the parity with bevy
I would probably accept a PR renaming them to use _ consistently, though Bevy is also inconsistent
lol
not yet, but I'd like to change stuff like colliders to use them for perf
via CollisionHooks, the one_way_platform_2d example showcases a way to do it
I'm currently struggling with how to design an API around them 
I've noticed that ExternalForce is no longer available in the newest commits. What should I use instead to apply force to an entity
Forces or ConstantForce
What is the difference between them? Source code doesn't clarify it unfortunately
Thanks
Draft PR for a JointGraph and a JointCollisionDisabled component to disable collisions between bodies attached by a joint
https://github.com/Jondolf/avian/pull/799
I have such code. My problem is that the velocity goes up to the infinity in about 20 iterations. I'm not sure if I have a problem with calculations, or if I just misunderstand how forces in avian work
pub fn apply_air_resistance_forces(query: Query<(&SolverBody, &Transform, &mut ConstantLocalForce)>,) {
for (solver_body, transform, mut local_force) in query {
let rotation = transform.rotation;
let tilt = tilt_angle(rotation);
let area = calculate_reference_area(tilt, 2.0, 0.1);
let drag_coefficient = get_drag_coefficient(tilt);
let drag = calculate_air_resistance(drag_coefficient, 1.2, area, solver_body.linear_velocity.length().abs());
local_force.y = -drag;
println!("Drag: {}, Vel: {}", drag, solver_body.linear_velocity);
}
}
fn calculate_air_resistance(drag_coefficient: f32, air_density: f32, area: f32, velocity: f32) -> f32 {
let result = 0.5 * drag_coefficient * air_density * area * velocity.powi(2);
result
}
Was just playing around with Foxtrot a bit and thought the physics was working perfectly but then I noticed objects don't always go to sleep. Is this because of the incline here or something else? Just curious why this happens.
It's jittering too much to start sleeping, likely due to contact instability. My current guess for where it's coming from is this https://discordapp.com/channels/691052431525675048/1400203671077130448/1400532313179291862
You can tune the SleepingThreshold to make it easier for bodies to fall asleep
I see, interesting. Have you looked into if this happens in other engines?
I haven't yet, but I should try with Rapier at least since it also uses Parry
that should help confirm that the problem is what I think it is
I can see now it even happens on the flat ground. I would say that doesn't happen with other engines but it might be a different sleep threshold value as you said.
I'm guessing this degrades performance quite a lot in bigger scenes?
I find this seriously impressive π (sorry about bad recordings, have two screens with different resolutions and OBS doesn't seem to like that)
From what I've seen it's mostly convex polyhedra and triangle meshes that have multiple faces in contact at once, but yes potentially
hehe that's satisfying
Hello, sorry if this is a common question, but how would one have cumulative forces from different systems applied to a rigidbody ?
Is there a built-in way to do it, or should a query for an existing external force and if it exists, add to it or otherwise insert a new one ?
assuming that you are using avian, this might help
// using ExternalForce, avian 0.3.1 and below (main branch has a better force method)
fn setup (
mut commands : Commands
) {
commands.spawn((/*other stuff*/,ExternalForce::defualt.with_persistence(false); // set to true if you want the force to never stop
}
fn cumulative_stuffs (
mut cumulative_force_query : Query<&mut ExternalForce>
// query for some force here
) {
let Ok((force)) = cumulative_force_query
else {
return // no force was found
}
// handle the other force query
force.apply_force_at_point(/*the force here*/ , /*point*/ , /*center of mass or pivot*/);
}
oh, forgot ExternalForce::apply_force is a thing, thanks a lot
no worries
So in every system i'm forced to check if there is an existing force, if there is add to it and otherwise insert it ?
easier if you make it a required component for something
alternatively, commands.entity(e).entry().or_insert(_).and_modify(|_|{})
Thanks, i'm facing another issue now
impl Plugin for CharacterController3dPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Update, handle_hover);
}
}
/*
Character controller is spawned with:
pub fn character_controller_bundle() -> (
RigidBody,
CharacterController3d,
Collider,
RayCaster,
ExternalForce,
) {
let capsule_height = 1.0;
(
RigidBody::Dynamic,
CharacterController3d {
hover_height: 1.0,
move_speed: 1.0,
drag_multiplier: 1.0,
},
Collider::capsule(0.1, capsule_height),
RayCaster::new(
Vec3::new(0.0, -capsule_height / 2.0, 0.0),
Dir3::new(-Vec3::Y).unwrap(),
),
ExternalForce::new(Vec3::ZERO).with_persistence(false),
)
}
*/
fn handle_hover(
time: Res<Time>,
mut commands: Commands,
mut controllers: Query<(
Entity,
&LinearVelocity,
&RayHits,
&CharacterController3d,
Option<&mut ExternalForce>,
)>,
) { for (entity, linear_velocity, hits, controller, maybe_external_force) in controllers.iter_mut()
{
//stuff
let total_force = (damp_force + bounce_force) * time.delta_secs();
if let Some(mut external_force) = maybe_external_force {
println!("external: {:?}", external_force);
println!("total_force: {:?}", total_force);
external_force.apply_force(total_force);
}
}
}
This logs:
external: Mut(ExternalForce { force: Vec3(0.0, 0.0, 0.0), persistent: false, torque: Vec3(0.0, 0.0, 0.0) })
total_force: Vec3(0.0, 66.86302, 0.0)
external: Mut(ExternalForce { force: Vec3(0.0, 66.86302, 0.0), persistent: false, torque: Vec3(0.0, 0.0, 0.0) })
total_force: Vec3(0.0, 48.842857, 0.0)
I'm very confused as to why there is still some external force on the second frame when the persistence is off ?
Can anyone help ?
you're running that in Update instead of FixedUpdate, so if Time<Fixed> uses a lower rate than your refresh rate, you might apply the force multiple times per physics tick
nonono , just add a resource with all the forces and add them together in one system
#[derive(Resource)]
struct forces {
// force 1
// force 2
}
then you just query in the systems with a force you want to add to the sum
mut forces_query : ResMut<forces>
note that on the main branch it's much nicer, and you can just use the Forces API without having to worry about components or configuring persistence or anything like that
yup
thanks, I always preferred having physics stuff in update, even if it means they are only applied on fixed intervals, as it makes sure inputs work fine (no skipping) and it also gives more precision to the input (sub physics tick movement).
But I understand there are drawbacks as well
you could do
fn input_Update() {
// handle input and store it
}
fn physics_stuff_FixedPostUpdate(){
// fetch input from where you stored it, and act on it
}
Yeah, wish we had input timestamps in Bevy so inputs in FixedUpdate would work more nicely :/
yes there are workarounds but I wished it worked more nicely out of the box as other games engines do
depends on type of game you are making, but an input que/buffer is still usually just a workaround :/
What i'm describing wouldn't have anything to do with a queue.
You apply forces to the rigidbody every real frame, and every fixed update, the sum of these forces gets applied and stuff actually moves
what are you making ? :P
A 3d character controller, why ?
so like fps or
yes
yes, but it is an entirely different subject in my opinion, it should be implemented as a feature on top of a robust engine
what forces are we talking about, like forces from ground n stuffs?
mostly outside sources, like inputs, force fields, etc.., collisions and stuff would probably still be on fixed
Polish is cool by default
Im testing this just now
and I'm not seeing great improvements out of the box, I'm going to test it for a bit
first Imma replicate your test scene
with simple cubes stacked
with my ldtk level i have thousands of staticbody squares, im looking into optimising that on the ldtk side (most of them are oob) but also none of those squares are actually asleep, possibly because they're all touching each other? if i could send them to sleep i think it would be a lot better
The reason you cannot put them to sleep is because they're in contact
with how things are right now if you want sleeping behavior you have to make them not be in contact or hack around it
Dynamic islands will fix that, or at least that's what Jondolf said couple weeks ago
Quite crazy what this small difference in size makes @vestal minnow
the cubes on the first stack are lets call them 1x1, the towers on the right are 1x2, and the middle tower is 4x4
I've read thru some stuff here regarding Disabled. I guess Avian RigidBodies don't respect Disabled due to some peculiarities of Observers or something ?
They should on main
Hello, I have a question related to future Avian development. You'll eventually replace parry by peck. What will be used for the BVH?
@vestal minnow is there a reason why static bodies can collide with each other? it doesn't seem very useful
They can't
How are your bodies set up?
Or there might currently be an edge case where if they are originally not RigidBody::Static when the contact pair is created, and you then change them to static bodies, the contact pair won't automatically be removed until they stop overlapping
#[derive(Component, Default)]
#[require(
CollisionLayers::new(
PhysicsLayers::Ground,
[
PhysicsLayers::Enemy,
PhysicsLayers::Player,
PhysicsLayers::PlayerHitbox,
PhysicsLayers::EnemyHitbox,
],
),
RigidBody::Static,
Collider::rectangle(128.0, 128.0),
)]
struct Wall;
idk if they're actually colliding; the issue is that they're not going to sleep
which i assume is because they are colliding
Static bodies do not have sleeping because they can't move to begin with
They're not simulated anyway
Sleeping is for deactivating active bodies when they're resting
i am having a performance hit, i guess i should just optimise it on the ldtk side to try and reduce the amount of entities it creates
You could use the PhysicsDiagnosticsPlugin and PhysicsDiagnosticsUiPlugin to see where time is being spent
requires the diagnostic_ui feature
it will also show you if you do have collisions, and how many
cool
we're using it for the upcoming broad phase and spatial query rework too, even before peck
Hmm, I'm thinking of doing a "joint rework lite" for 0.4
- Support
JointAnchorenum withLocal,FromGlobal, andAutovariants for easier and less error-prone initialization of joint anchors - Expose way to set reference orientations or angles for
FixedJoint,PrismaticJoint,RevoluteJoint, andSphericalJoint - Expose joint forces and torques with a unified
JointForcescomponent - Move all solver related data into separate types or components like
RevoluteJointSolverData, making the user-facing joint components purely descriptions of joints and making them more solver-agnostic (or even engine-agnostic) - Make joint components immutable (useful for making simulation islands and the anchor stuff more robust)
I feel bad delaying it every release because the new joint solver stuff still isn't ready, but I could probably get a lot of the important API improvements done before that
Is it better to use LinearVelocity with LinearDamping or the new Forces api to move stuff in a system for a 2d game
Depends on what you're looking for, but I think LV with damping is probably easier to control for something like a character since you can specify the exact speed, and forces would be useful for stuff like interacting with physics events (wind/explosions/etc.) but someone correct if this is inaccurate
The end result should be the same itβs just a matter of approach and ease of use no?
For my player I am using LV with damping rn, but wanted to try the new forces api for pushing enemies away and knockbacks
forces would make sense for any impulse based mechanics too, like air dashes, where you dont really want to override the velocity just nudge it
Increasing/decreasing Time<Physics> alter the speed of time in physics (On retrospective given the name I guess it makes sense lol). How can I increase the rate at which physics are simulated without altering the speed of them?
Because Increasing Time<Physics> and decreasing Time doesn't seem like a good idea hahah
Time<Fixed>
Time<Virtual> -> Time<Fixed> -> Time<Physics>
okay so that means Avian runs its simulation in sync with how many times bevy systems run
there's an extension trait for Time<Physics>, but it's just relative speed & pausing
if they're in FixedUpdate
you can improve accuracy a little by increasing the SubstepCount
jondoooooooooolf
π why does returning f32::INFINITY from ComputeMassProperties3d::mass make a collider not collide with anything
this should make it immovable
or at the very least the mass should not be taken into account on RigidBody::Static colliders
lol vero over here testing Avian's limit
oh really?
its usually specified in terms of inverse mass
aaaaah that makes sense
so you can say 0 mass to mean immovable
never thought of it that way, but makes total sense. Thanks!
Now do negative infinity next!
lmao
negative mass is a funny thing that is actually possible in real life theoretically
well, negative mass density
mass shouldnt be used in calculations when a rigidbody is static
im trying to figure out why avian does this
hmm, running into this when I despawn a sensor collider
thread 'Compute Task Pool (1)' panicked at forks/avian/crates/avian3d/../../src/dynamics/solver/mod.rs:478:21:
Contact pair not found in graph: ContactId(667)
I am despawning in PostUpdate after TransformSystem::TransformPropagate π€
oh, I think it's because the sensor was missing the Visibility component
nope, that's not it π€
is it reasonable to want a "wide simd" AnyCollider option
like i wanna be given 4 or more collider pairs at a time to process
preferrably lined up so that collider 1 is the same on all of them and the other 4 are different or smth like that
From what I understand, ShapeCaster updates every PhysicsSchedule which happens about every FixedUpdate, so once every few frames. Is there a way to make it check hits every frame instead?
Why do you want that?
I have an entity that's being moved by a tween (it shouldn't react to physics things other than certain collisions) and I'm trying to clamp its movement to that collision
Since the clamping happens once every few frames, it jitters
I'm currently considering using regular raycast instead
Aah interesting, makes sense! Donβt know either how to fix it, was just curious π
Yesn't, Bepu uses wide SIMD for its narrow phase (because of course it does), but it'd require some heavy refactoring and definitely wouldn't be compatible with Parry
I'm not sure how exactly it works in Bepu, but you need to batch by shape pairs and spit out wide contact manifolds
yeah that should work
lemme test
probably only meaningful for box/box tests
or other simple ones like spheres
anything using gjk or similar is not going to work
too much divergence
no Bepu uses wide SIMD for pretty much all shape pairs, including convex hulls
different number of vertices, different number of required iterations etc, different size of simplices
it uses Tootbird search for its depth refiner to find the minimum depth between convex bodies