#Avian Physics
1 messages Β· Page 36 of 1
@vestal minnow there's no Avian API to convert a collider into a trimesh, right? I have to go through the parry shape, I believe
Would you be up for a PR that added rasterization to colliders?
its implemented for these shapes
And I've already implemented it once for compound shapes by unpacking them first
So it'd return a trimesh Collider?
Or a Parry TriMesh
Well, what I need is the "standard" representation of a triangle list mesh:
struct Mesh {
vertices: Vec<Vec3>,
triangles: Vec<[usize; 3]>
}
Or similar
whether that data is in a TriMesh, Collider or whatnot doesn't matter
Which is what that parry method gives me:
fn to_trimesh(&self) -> (Vec<Point<f32>>, Vec<[u32; 3]>)
This struct is similar to Bevy's own Mesh, but that should not be used for things outside of rendering
Mm it'd be nice if Bevy had a "math" TriangleMesh type that is just this and not a rendering mesh
Yeah absolutely
For context, I need this because the navmesh algorithm I'm porting expects regular old meshes
But yeah it'd probably be fine to just have something like
fn to_trimesh(&self) -> (Vec<Vector>, Vec<[u32; 3]>)
Cool! Can I put that into a struct, too?
Maybe ColliderMesh?
or RasterizedCollider
or something like that
Though that may be confusing because it does not return a Collider::trimesh()
Maybe fn rasterize?
I think for now just the tuple unless we intend to add other functionality to it, I would probably expect Collider::trimesh and Collider::to_trimesh to have the same input/output
Oh good point
alright, can do tuple
@vestal minnow update: some trimesh conversions need a number of subdivisions, and some shapes cannot be rasterized
fn to_trimesh(&self, subdivisions: u32) -> Option<(Vec<Vector>, Vec<[u32; 3]>)>
I think the return value now looks quite confusing as a tuple inside an option
yeah all the rounded shapes need subdivisions
and something like a half-space definitely doesn't really have a mesh representation :P
yeah same for e.g. polyline
rounded polygons/polyhedrons probably don't have mesh conversions implemented either since that seems tricky
and custom shapes are a problem
What's up with this?
#[cfg(feature = "dim3")]
#[cfg(feature = "alloc")]
/// A convex polyhedron.
ConvexPolyhedron(&'a ConvexPolyhedron),
When do we activate "alloc" on parry?
It's a default feature
Oh, then my rust-analyzer is just lying to me lol
Or it's not necessarily a default feature, but spade is, and that also enables alloc
@vestal minnow I just checked what oxidized_navigation does, and it takes the inner shape for the rounded colliders
thoughts on that?
It's definitely not quite correct
but also maybe better than nothing?
Also, cargo check -p avian3d also tells me that ConvexPolygon is not enabled by default
And I'm not sure which Avian feature enables it 
(and "polytope" is the n-dimensional term)
TIL
Thought on this? Do I return None for rounded shapes or just the trimesh of the inner shape?
I vaguely recall Parry also using just the inner shape for something that didn't support the rounded version but I can't find it
I'm not sure here, for small rounding that'd probably be fine but if you have a large border radius then you just have a totally different shape
I imagine for a navmesh it'd still be fine but more generally ehhh
If we think about navmeshes, I would definitely prefer the too-big mesh over nothing
Agreed it's a bit iffy, but I think it's fine considering we have no API at all for this yet
But your call
I don't use rounded colliders anyways lol
Mm I'm increasingly not sure if we really we want this API on Collider since
- It doesn't (and can't) support all shapes
- You need to provide a subdivision count that only applies to some shapes (and you might want different subdivisions depending on the shape anyway)
- Rounded colliders would need to use the inner shape, producing inaccurate meshes
If the primary motivation is to produce navmeshes, then maybe it'd just be better to have it in the navmesh library instead of trying to make a general API, though it is annoying :/
Fine by me, I don't need any internals π
@vestal minnow just bumping an older message, if I clone an entity with rigid body, which components do i need to clone (right now i clone w/e i use to spawn) and which component s do i need to modify to translate the clone? (global transform gets reset by some physics system)
my best guess is some Sync logic is resetting my cloned, updated global transform
I'm not sure how entity cloning works π€ does it not consider required components or run hooks?
i think the components i don't copy are inserted through required components
because things like Position Velocity, etc. exist on the clone
and hooks only get custom behavior for relationships
If you use the same as what you spawned the entity with, and use some initial transform, I don't see why it wouldn't work
Specifically set the Transform or Position/Rotation, not GlobalTransform
GlobalTransform is generally kinda read-only in Bevy since it's driven by Transform
i froze the physics using the plugin you have in your examples, then created a clone, this is how the components look like
if i run the system in PostUpdate the position is correct for 1 frame (sprite flashes), but then it jumps to 0, 0 even with physics frozen
and previous global transform is still 0, 0 even with that
A minimal reproduction of the behavior could be useful
i can try
Thanks!
@cerulean zephyr setting Position and Rotation seems to work here, but yeah I'd probably count this as a bug
Hmm I'm not sure if it's really related to physics, it feels like something that'd rather be a Bevy example
fair, there is just some special treatment needed because of avian
like filtering what you clone, certain components crash the app xD
I imagine some stuff with entity references (like nvm that should be fine) or internal indices might be something you don't want to cloneColliderOf
or it depends I guess
Yeah I suppose a simple example could be fine, it might also be a good test case to make sure we don't break things
joints aren't relationships so cloning them doesn't actually work on the clone π«
odd behavior, revolute joint is trying to simulate collision between parts, but those parts are set to not collider (you can see them intersect on the bottom)
@vestal minnow i feel like this is intended to some degree
i think it's pretty clear between those 2 frames, static bodies in the first one, split seconds of bodies being dynamic on the second one
Are these compound colliders?
Could try it without the joint first to minimize factors and make sure they don't collide like that
Joints are completely separate from any collision stuff so that shouldn't have any impact
Yup, compound of rectangles
I added the joint last, before that, they had no collisions and could go right through eachother
Could joints impact collision layers somehow?
No
Can you check if there's really a collision? With collision events or CollidingEntities or Collisions or w/e
Sure, I can do that when Im back at the PC, will you still be up in ~1-1.5h?
I probably will be, I really want to get my AVBD impl working properly lol
it's so clooose
is there still a character controller working group discord
there hasn't been much activity lately (people got pulled in different directions, work, etc), but the discord still exists: https://discord.gg/KzvVqGJhva
Is there a right way to insert Friction? just adding Friction component for some reason screams that Friction does not implement Bundle
Friction implements component, so it should be good 
Is your issue maybe that your bundle is over 16 elements long?
Or bevy version mismatches
Right, that will also give you the same issues
run cargo tree -i bevy and cargo tree -i avian3d
yeeeeah. Is that a problem? π
upd: Oh, I see. Bundle implemented only for up to 16 element tuples. I guess it's a reasonable default
You can do
(
A,
B,
C,
(
D,
E,
F,
)
)
tuples of bundles are themselves a single bundle π
IIRC it's the same default as the standard library uses for things of "arbitrary" length. Rust has no variadics, you need this trickery
But because tuples of bundles are a bundle, in practice, a bundle can be infinitely long π
Thanks!
Hi, I am currently making space-sim (very very very early) and for now I am planning on doing ships and their interiors. Ships shouldn't collide with each other, interiors of ships shouldn't collide with each other, characters and objects in interior should collide with each other.
I have encountered 2 issues:
- Collide layers are restricted to just 32 . So I am not sure how I would go about each interior having it's own layer. Maybe don't have any layers for now and then use collision hooks to prevent collisions between interiors ? How would you go about it ?
- I would like to have interiors as children of ships but this causes issues with walls, which are static, and ships, which are dynamic (Dynamic bodies too). Moving the ship with forces causes the static bodies to remain in place. Do I have to manually move the bodies or is there a better way ?
Wouldnβt all interiors be in the same layer that does not collide with itself?
In general, having rigidbodies be children of other rigidbodies is not well behaved. Can you not have a single dynamic rigidbody for the entire ship and make the interior walls child colliders?
That's what I have and is causing issues
Your message reads like you have a hierarchy like this, did I misunderstand you?
- dynamic rigid body
- collider
- static rigid body
- collider
Got AVBD working btw π #math-and-physics message
There's a lot to do though before I have fancy 3D demos to show for it
it'd be so cool to replicate their demos of the balls twisting around the ropes and the ball dropping into a chain mail net
maybe with Jasmine's work on solari we'll soon have real-time ray tracing too to get the fancy physics demo look right π
What does AVBD stand for? Google keeps correcting me, and refuses to spit out a useful answer lol.
Augmented Vertex Block Descent
https://graphics.cs.utah.edu/research/projects/avbd/
I kinda summarized some of the differences to XPBD here #math-and-physics message
We still currently use XPBD for joints, but an impulse-based solver for contacts
AVBD is again very different from both :P basically requires rewriting the solver from scratch
probably ? sorry
(bruh how do you do these lists ?)
for indented lists you use two spaces (or I do at least)
- Item 1
- Sub-item 1
- Sub-item 2
- Item 2
- Sub-item 1
- Sub-item 2
- entity
- dynamic body
- ship
- entity
- static body
- collider
- wall
like this ?
using 4 messes up formatting, I've done that a lot when copy-pasting from elsewhere where I use 4 lol
thanks
Try
- entity
- dynamic body
- ship
- entity
static body- collider
- wall
Just remove that static body
is it possible to model artificial gravity as two forces such that standing inside a spaceship doesn't accelerate it downwards
tried that and now player with dynamic body could move the whole ship and adding mass with zero to the walls didn't help
how's the player controlled
I am collecting input from keyboard and applying it as LinearVelocity
need to apply opposite forces to the ship then
(i got around this by practically only applying external torque)
though if you're okay with it you could just give the ship higher priority
Dominance allows dynamic rigid bodies to dominate each other during physical interactions.
thanks, will probably do that
https://www.youtube.com/watch?v=bwJgifqvd5M when is augmented vertex block descent coming to avian
Chris Giles, Elie Diaz, Cem Yuksel
Augmented Vertex Block Descent
ACM Transactions on Graphics (SIGGRAPH 2025), 44, 4, 2025.
Project Page: https://graphics.cs.utah.edu/research/projects/avbd/
(including a 2D online demo and source code)
Vertex Block Descent is a fast physics-based simulation method that is unconditionally stable, highly parall...
1 week? 2?
go through #math-and-physics for my progress on AVBD, starting from #math-and-physics message
right now I'm trying to get a very π§ͺ hybrid solver working that combines our existing solver for contacts and AVBD for joints
since so far, our contact solver still seems to be more well-behaved than the AVBD version I implemented (might be a skill issue tho), but I suspect AVBD will be much better for joints
wtf I was kidding. That's sick though
this revolute joint really doesn't want to behave 
(I'm moving the box with fixed rotation)
it's probably some error in the Hessian...
holy shit it works maybe, hold on
it just broke gravity lol
Looks like a very untrained person wildly swinging a weapon π
For a turn-based game that needs physics, how can I simulate exactly 1 second of physics as fast as possible (ideally within a system)?
#general message and others
maybe exclusive system with a loop of incrementing the physics timer and running the physics schedule, but iirc someone listed a more comprehensive method
ah here
More AVBD related stuff:
https://news.ycombinator.com/item?id=44334403
https://www.youtube.com/watch?v=xxyniqSLJik
https://www.dropbox.com/scl/fi/zozvqbqmw5tr4dl5e66by/Offset_Geometric_Contact_Final.pdf?rlkey=7awhktk03hlhb47g5jqmxak4f&e=2&st=ltqxxkpl&dl=0
We present a novel contact model, termed Offset Geometric Contact (OGC), for guaranteed penetration-free simulation of codimensional objects with minimal computational overhead. Our method is based on constructing a volumetric shape by offsetting each face along its normal direction, ensuring orthogonal contact forces, thus allows large contact ...
My π§ͺ experiments appear to be (almost) working properly π
This is using an AVBD point-to-point constraint for the grabbing, while using our existing TGS Soft solver for contacts
A special thing here is that unlike our current TGS Soft + XPBD hybrid solver, this AVBD implementation is collision-aware; this means that AVBD runs first and only produces a "prediction velocity" that the TGS Soft solver will then apply over several substeps, but contacts can apply impulses to the velocity before the body is actually moved.
In practice this means that joints won't overpower contacts nearly as easily as with our XPBD hybrid approach.
Here you can see how our current XPBD approach lets the joint pull objects through walls with barely any resistance, which generally isn't desirable:
However I do still have some bug because this isn't meant to happen 
Another neat thing is that the AVBD loop and TGS loop are fully separate here, so you can have different iteration counts for joints and contacts depending on your needs
I did also try to embed AVBD into the substepping loop somehow, but didn't have great success with that approach
Interesting how there appear to emerge two distinct singularities on the line
Looking at this, I can't help but wonder if I'm underutilizing constraints. I briefly used them to model a lid on a container, but then never touched them again. My pickup stuff is done with velocities, for better or worse, to mirror the HL2 implementation.
Outside of things like chains and other kinds of strings, are there some good everyday gamedev examples of things that one should use constraints for? Ragdolls come to mind.
Simulation games use those more
Do you have examples? I'm curious
Car suspension
Oooh that makes sense. Would that be a PositionConstraint?
Personally im a fan of physic sims in sandbox games, so everything cool there is joint based
I believe so
You mean like how you can attach stuff to each other in GMod?
I kinda fixed that particular issue (though it makes the integration with TGS more annoying...) though it's still a bit weird
Thats a very old example but yes
also I need to fix the static attachment being so weak
Do you have some newer ones? π
Take stuff like algodoo, scrap mechanic, main assembly
brb googling those
Oh wow Algodoo looks like it would have made highschool and college physics much easier to learn π
- LBP joints
- Human fall flat has a lot of physically simulated mechanisms, wrecking balls, etc.
- Ragdolls
- Vehicle stuff (depending on the desired accuracy)
- Grabbing stuff, like in my demo
- Anything with realistic ropes
Damn why has no one showed me ;-;
What are LBP joints? Google is telling me "lower back pain" π
π
probably why I got interested in physics simulations lol
what kind of joints are there in LBP?
Like, can you define your own?
Or does the level just have interesting ones?
Oooh I see. So a bit like the physgun in GMod?
no idea what that is
but you can joint objects together when creating levels, and set their properties like the strength and motorization etc.
and you can create logic circuits to activate motors and stuff
Something like spider legs also use joints, but im pretty sure that's a whole different set of solutions
when stepping on a button or pulling a lever for example
Alright, that's a bit more advanced than GMod π
Cool, thanks for giving me some insight into what constraints are used for π
You can also make simple cloth and soft bodies, especially if a basic mass-spring-damper model is enough
By patching together lots of tiny squares with constraints or something like that?
yeah, just some squares or circles with distance constraints (and bending constraints if needed)
you can also have volume constraints, though we don't properly support it atm
either a global volume constraint (computes the volume of e.g. a whole trimesh and tries to maintain that volume) or for better results you can tetrahedralize the object and have tetrahedral volume constraints
I did a global volume constraint for that one XPBD demo ages ago
Would that simulate something like a bouncy ball?
yeah like this #showcase message
hehe
this behavior reminds me a lot of the physics in valve games
I'm now at the point of debugging this that I forked AVBD's web demo to be exactly the same as my scene visually, replicated the exact scene and setup in both, and am running them side-by-side to compare
Like my version is so close overall, but why the heck does it have inconsistent gaps in the chain and sometimes some parts of the chain are kinda dislodged to the side, while their version has a perfectly uniform chain
And these gaps are also at weirdly consistent distances from each other at specific spots
i'm losing my mind over this, why does it do that 
i've triple-checked the math for the Hessians and everything
it's always every sixth chain segment even with longer chains, like whyyyy???
It seems more like every 6th one is actually correct
Could it be an issue with rendering/ interpolation?
Like, pure graphical
It's too stable for this to be error adding up then cancelling out perfectly
That just doesnt happwn
@vestal minnow what happens when you setup something notoriously chaotic like a double or tripple pendulum in both?
Because thatβs a pretty strong point
wait what the hell it's based on the number of iterations
6 iterations = every 6 segments
3 iterations = every 3 segments
etc.
wtf
oh funny I was going to suggest that but I thought it was probably wrong
Lol
Are you declaring a mutable variable inside the loop instead of outside?
it's probably something wrong with how I manage position updates and how it carries over to the next iteration, but I've been looking for an error like that for the past four hours and have not found it
I use position deltas instead of actual global positions which does make the logic slightly harder to follow
I guess for now I could copy the reference impl exactly and use global positions directly but ehhh it's annoying to change and I won't do that for the final impl anyway
Sounds almost like some sort of perturbation that's seeded by an impulse at one end each step start/end and propagates up the chain at a rate of 1 link/substep, if you're able to change the substep count at runtime it'd be interesting to see if the period of the error changes along the whole chain instantaneously or propagates one step further with each simulation step
It seems like it's a bug in how I limit the position correction for hard constraints (sec. 3.6) since using a finite stiffness fixes it
However I'm not sure where exactly the error is because I'm pretty sure I'm doing it just like the reference impl π€
maybe your code is correct and this is actually how reality works π€
Encountered an error like this, what might cause this issue?
thread 'main' panicked at .../.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/avian3d-0.3.1/src/collision/contact_types/contact_graph.rs:401:18:
swapped entity has no entity-to-node mapping
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic when applying buffers for system `bevy_state::state_scoped::clear_state_scoped_entities<game::state::GameState>`!
Encountered a panic in system `bevy_ecs::apply_deferred`!
I'm using Scoped entities and when the game is finished, all entities will be automatically despawned.
I've had same error, I think its a weird scheduling bug that appears when despawning huge amount of entities.
My intuition is that its related to relationship regarding Rigidbody and Collider, I've worked around since so no real debugging info etc, sorry :/
Yeah it's some problem with despawning colliders, but I'm not sure what it is since I haven't been able to really reproduce this π€
I also have scenes where I despawn all physics entities, and in Chainboom (our jam game) we also use state scoped entities, and those don't panic
so a minimal reproduction could be useful there
What are best practices for fast moving and numerous bullets? Is this entirely solved by Swept CCD? Are there examples somewhere?
in Chainboom y'all are using a Despawn component that despawns in PostUpdate or something which might help avoid that
Typically fast-moving projectiles are best handled as a sequence of ray casts / shape casts unless you need specific rigid body behavior (like bullets hitting each other) for whatever reason
I'm pretty sureDespawn and DespawnAfter are only used to despawn things when they die or explode or to despawn decals and gibs after a while. But the whole level and the gibs are state scoped
Oh there is actually a clear_scene system too to despawn enemies and decals when you enter the loading screen
oh hell nah
naaah
so the chain bug is because the query iterates over entities in ascending Entity order, while the reference impl has a linked list that has the exact opposite iteration order
if I collect the query into a vec and .reverse() it, it works fine and is like the reference impl
so it is quite iteration order-dependent
Heck
can't nock it if it works, ig?
for the best behavior we would probably shuffle the iteration order
aren't most IK solvers pretty order dependant as well? seems like that would be hard to get rid of with a long chain.
all Gauss-Seidel solvers (like our existing one) are order dependent, I just haven't seen it manifest quite like this :P
I think it should be better once I do graph coloring
also the paper does say
We have observed that in some difficult cases, such as those involving a series of connections
with high stiffness ratios, randomizing the order with which the
colors are processed can improve convergence. However, we do not
randomize the order for any results presented in this paper.
I'm pretty sure graph coloring by itself will also inherently change the order to not be purely the spawn order, which should help even without shuffling the colors
I was not able to reproduce it consistently. The good thing is that it doesn't happen frequently, it's kind of rare. Could you please elaborate more on how you used Despawn/DespawnAfter to walk around the issue?
I'm trying to setup a basic collider for a character, i have an issue where the mesh gets a vertical offset when i add a capsule collider, which doesn't happen without. What am i doing wrong ?
do i have to make one the child of the other or should this work this way ?
Oh they're just custom components for our game jam game to defer despawning to the end of the frame or to a later time, it was just for gameplay reasons, not to work around any specific issue
That looks like the mesh's origin might be at its feet even though colliders are centered at the local origin
You can either center the mesh (if it is offset like it looks) or use a child entity to offset the collider or mesh to the correct position
i see, i'll offset the collider in a child entity then, the mesh origin is indeed at 0,0,0
thanks
Well Despawn is because triggers panic otherwise
Despawn just makes sure everything gets despawned at the end of the frame, meaning that nothing inside the frame can access any entity after it was already despawned, as that would cause a panic
Oh right that too, I was thinking it was to simplify some of the chain explosion logic and other cases where insta-despawning might create some problems
wha
Yeah that case wasn't really too representative of an actual scene, since it was a lot of iterations with not so many bodies, so the multi-threading was just adding a ton of overhead for little benefit
(interesting that the overhead is that bad tho)
In a more "realistic" scenario with just 6 iterations but 50k bodies, it's a lot better
Single-threaded
Multi-threaded
so like, nearly a 5x improvement from parallelism there
this is just a very long 2D chain tho
I would be interested in knowing what is causing that overhead.
Well it's basically just doing this
for _ 0..num_iterations {
// Primal update
for color in colors {
body_query.par_iter_many(&color.bodies).for_each(...);
}
// Dual update
constraint_query.par_iter_mut().for_each(...);
}
In that case num_iterations was 100, and there were only like 100-200 bodies and constraints, so I assume the overhead was just from spinning up small parallel tasks 100 times in a row?
With 6 iterations and 50k bodies it seems a lot more reasonable like can be seen here ^
(also there are just 2 colors in this scene if that matters)
it would be interesting to try the same with forte though once I can properly use it for this sort of thing
Adapting it to use rayonβs par_iter, if thatβs possible, would be the first step.
I'm working on a top-down 2d game, so gravity isn't a problem. I just want to use colliders to prevent the player from moving the character through the level (walls, etc). Is there a good example of how to use colliderst effectively for that purpose?
just like real life!
Probably more due to waiting for the last task to get scheduled and finished.
And this happens 100 * 3 * 64? times per second
@thorn solstice would it be possible to have OBVHS avoid building trees with a depth great enough for it to panic in the validation? I've been running into that particular crash quite often in the spatial query code
What line does it panic on? We can't reasonably automatically limit the tree depth. It would either make things super slow to build or super slow to traverse. Are you hitting the limit with BVH2? Really deep trees are usually indicative of something pathological in the scene.
I guess another thought it to put an option for it to automatically set the max stack depth in BvhBuildParams, and/or maybe we can estimate it better during building without additional cost.
It's in the validation function where it asserts that the depth is less than the max depth
But yea it's definitely strange that it happens, if I shrink the scene it stops happening however π€
this got recommended to me, unprompted, I haven't watched anything physics related in a while π
taking a break from AVBD to try and finish up the force rework and BVH stuff... just finished writing 700 lines of nothing but component type definitions and docs
not even done with docs or clean-up yet 
this will be a rather large PR
if i want to generate contact pairs between colliders and a custom collider, what system set do i run in? i presume the narrowphase runs on every substep?
ehhh you're not really supposed to add contact pairs manually unless you want to also handle the relevant state updates and constraint generation etc. manually
but the narrow phase updates are done in NarrowPhaseSet::Update in the PhysicsSchedule, not on every substep, that would be wayy too expensive
you can do collisions between custom colliders easily by just implementing AnyCollider (and ScalableCollider iirc?) for your collider type and adding the relevant plugins with that collider passed as a generic, but collisions between different types of colliders is non-trivial and not supported very well
You can also implement custom shapes for the existing Collider, but I think that's currently limited to just single contact points computed via support mapping and GJK+EPA
id like to swap out the collision detection backend lmao
thanks for the info, i'll see what i can do later today
Opened a PR for the fabled force rework finally
https://github.com/Jondolf/avian/pull/770
Objective
The current force APIs are very limited, confusing, and cumbersome to use.
The "persistent" vs. "not persistent" force split is confusing. You cannot ...
I still need to test it more to make sure all the APIs actually work correctly, and fix how kinematic bodies are handled
Feedback on the general API would be appreciated though π
Also I'm not sure what the best name would be for the ForceHelper system param... I also considered RigidBodyForces and PhysicsForces or even just Forces as potential names
Can you see if this PR resolves the issue? https://github.com/DGriffin91/obvhs/pull/5
Note: I'm not sure how much stack space you have on the GPU. That is often extremely limited, so while this may resolve the panic, the scene may not be possible to correctly render depending on your available stack space.
@cinder summit how did you approach sdf physics with avian? did you do that at all or nah
I implemented AnyCollider, ScalableCollider, and the QueryCollider I'm working on
This example shows a minimal setup for custom collider backends
https://github.com/Jondolf/avian/blob/main/crates/avian2d/examples/custom_collider.rs
Is it overkill to use Avian if I only want sensors?
not if you cherrypick the plugins
thread 'main' panicked at .cargo/git/checkouts/obvhs-910b4198c23e914d/288190a/src/bvh2/mod.rs:433:9:
assertion failed: result.max_depth < self.max_depth as u32
```Still seems to crash
What is the minimal set of plugins for sensors?
not really imo
you don't really pay for anything you don't use
and the setup is not any more or less complicated either way
So I wouldn't bother cherrypicking
wow crazy, do you have the code up? Or like what settings are you using, can you print out both result.max_depth and self.max_depth?
Might want to add that to the assert π€£
lol good point
I guess it might affect compilation times but maybe not that much. In this project I've been wary of adding crates for that reason, especially when I only use a small portion of them.
Just added that to the pr
wonder if they are maybe equal or something
result.max_depth (187) must be less than self.max_depth (187)

<=
187 node deep bvh??? what the fuck
This might be due to some weirdness of how avian initializes things π€£
thats a fuckin useless bvh if its 187 nodes deep
Definitely, but it shouldn't crash the whole app the second this happens
lol fixed
agreed
(note it only does this in debug, and I think I'll add a warning since it's indicative of a bvh that isn't usable)
The most common reason for this kind of thing is having a bunch of identical or almost identical geometry in the same spot, which is just generally untenable for physics/ray tracing/rasterization.
what weirdness?
on main it should (in theory) initialize Position, Rotation, and ColliderAabb with the correct values on spawn
I think I did partially grab those changes, but all AABBs now get expanded so it's hard to avoid invalid AABBs, and my SDF code can have situations with invalid AABBs
will there be a way to use ForceHelper with parallel query iteration? my first thought is how I would apply forces to a bunch of entities
Yeah that's kinda the tricky part. Earlier on I was trying to get a QueryData API like this working
fn apply_forces(query: Query<RigidBodyForces, With<Foo>>) {
for forces in &mut query {
forces.add_force(force);
}
}
This would let you use all the query APIs like normal. However it needs to query for some optional components, and later batch-insert them if they're not already present, kinda like a get_mut_or_insert API, which is currently not possible with QueryData.
So I changed it to the ForceHelper system param that handles it for you. However this then requires the manual APIs like entity for actually accessing the APIs. We could probably add helpers like iter, iter_mut, par_iter, etc. that would take in a given query, and allow for a more efficient way to apply forces, it just needs some work
Mm or we could probably get the QueryData API working too... The main problem is local forces since they need to be accumulated into a separate component, unless we're willing to ignore the force direction changing between substeps
and I don't exactly love storing that extra component on every dynamic body just in case people apply local forces
yeah, that does some to go against the goals of the rework
for world-space forces too, if we don't accumulate forces and acceleration into their own separate components, it would mean that actually applying forces is a bit more costly since it needs to apply the mass properties to each individual force rather than applying them once at the end to the accumulated forces
implementing and supporting two different APIs to do the same thing just to support parallel in one of the APIs also is kinda ooph
we could also expose an unsafe entity_unchecked method similar to get_unchecked for parallel contexts, but ehh that's not ideal
We could probably add helpers like iter, iter_mut, par_iter, etc. that would take in a given query, and allow for a more efficient way to apply forces, it just needs some work
I like this idea, but I don't know how infeasible it is.
yesss I think I got manifold-level graph coloring working finally
-# excluding an out-of-bounds index panic I get sometimes
so if two bodies share many contact constraints, they are all spread out to their own colors to avoid race conditions
changing it from pair-level coloring (which was UB for multi-manifold cases) to manifold-level coloring was a painnn but it seems to work now, and not be meaningfully slower
I'll hopefully have a PR ready soon-ish, and then we'll be faster than Rapier π₯ (given enough threads, in scenes with large islands)
then I should be able to do wide SIMD contacts π
really fast-forwarding the tech evolution on avian
I added PhysicsDebugPlugin::default(), but I don't see my debug renders
Has anybody encountered anything similar lately?
Did you activate the gizmos?
what version are you on? I'm pretty sure you just need to add the plugin for it to start showing collider shapes at least π€
make sure you also have PhysicsPlugins and whatever plugin Bevy uses for rendering gizmos (it's in DefaultPlugins)
Here is a draft PR for the big one, a parallel contact solver!
https://github.com/Jondolf/avian/pull/771
Lots of juicy benchmarks and other performance stuff there
is this in a stable enough state that I could point my game at it and try it out?
I think a few things are still broken, like how contacts against sleeping bodies are ignored, but other than that it should be fine
I'll try to fix that one in a sec
mm there is also an occasional panic still :/ they're so annoying to track down
@little maple I fixed those bugs so it should hopefully work properly now π€
got CI passing too
nice, gonna try pointing to it
I don't remember what your main bottleneck is, but this should primarily improve solver perf which is commonly the most expensive part of physics
my main bottleneck is ||my own bad code||, but I mostly notice dips when things start colliding aggressively
I did redo a few things based off suggestions you made which helped a lot and haven't bothered to remeasure
thread 'main' panicked at forks/avian/crates/avian3d/../../src/dynamics/solver/constraint_graph.rs:325:25:
Contact edge not found in graph: ContactId(233)
and
thread 'main' panicked at forks/avian/crates/avian3d/../../src/collision/contact_types/contact_graph.rs:576:26:
moved edge should exist
actually hold on... this might be unrelated.. I think one of my files got corrupted
Yeah those are the common panics with this branch :/ I've fixed a million of those bugs already but it's very possible there are still some left
I would just need to consistently repro it lol, I haven't hit any panics so far after I fixed the sleeping bugs
I'm not sure what you mean. I added this as a component: DebugRender::default().with_collider_color(Color::from(PURPLE)) to something with a rigid body, a collider and collision layers
I have all of those:
DefaultPlugins
PhysicsPlugins::default(),
PhysicsDebugPlugin::default(),
I do
Also a new problem I came upon- how do you guys handle collisions in a tile grid?
My recoil-applying system (I use kinematic bodies) keeps making my player exit the grid (like, fly far far away)
I have scenes where I spawn and respawn everything, scenes with mesh colliders and other compound colliders, etc. and none of them are panicking π₯²
ok, I admit this is weird and I thought I had corrupted my gltf files but I checked and just switching the avian branch I'm using causes this
that's like, the same place in the game
Can you try on main? That's probably https://github.com/Jondolf/avian/pull/760
sure, trying now
I think I've had that mess up transforms like once or twice for generated colliders but it's sooo random
ah, you're right... this happens for me on main. So, mesh transform thing exists in main, but also I'm not seeing those panics on main either.
I will say, it like puts a bunch of stuff inside of other things so that could be contributing to the odds of panicking. It looks like it consistently messes up some stuff but not others so I might be able to pinpoint what causes it at least. I'll dig into that more tonight
yeah.. my world mesh uses trimesh_from_mesh, my vehicles are capsule colliders and then I have items that use convex_hull_from_mesh... not sure what's interacting with what that causes a panic
This probably doesn't fix the issues you're having, but fixes another panic I was getting, and should also fix the problem where removing ColliderDisabled sometimes doesn't work
https://github.com/Jondolf/avian/pull/772
I'ma try running Chainboom with the graph coloring branch to see if I can repro any of the bugs :P
yeah, I'm trying to rule out more.. as far as I can tell though, I'm getting the "moved edge should exist" when my truck's bed (which uses convex_decomposition_from_mesh) has a lot of small items in it (which use convex_hull_from_mesh) and the truck is moving... not long after that it panics
Do you have a backtrace of what line the panic is from?
there's a few different instances of that same message
I'm guessing it could be from ContactGraph::remove_pair_by_id around line 561 or 576
Encountered a panic in system
avian3d::collision::narrow_phase::update_narrow_phase<avian3d::collision::collider::parry::Collider, ()>!thread 'main' panicked at forks/avian/crates/avian3d/../../src/collision/contact_types/contact_graph.rs:576:26:
moved edge should exist
thanks, that should narrow it down a bit
I even loaded the whole Caldera hotel scene and I don't seem to be getting this 
side note: holy shit we need the broad phase rework and incremental BVH updates badly 
I have gotten the bug like a handful of times in the past even with super simple scenes, but it's like a 1 in 100 chance
I was thinking that maybe it's something where it takes a longer time for the mesh to be loaded, which messes up some ordering, but it doesn't seem like it
ah actually, I did just figure this out, just a sec
I have a setting in my game that lets me scale the "world" mesh because I hadn't really decided at the time what felt good size-wise for everything. So, it's at 0.8 for this map. The way it works is it loads the scene with a transform with that scale and then I have hooks on things that add colliders and stuff to specific meshes. SO, what it looks like is that everything that has a collider in the world mesh gets set back to 1.0 scale. If you look at the comparison pic again there's that big OUTER 277 sign sticking out. It's at 1.0 scale because it has a collider, but the "bigger" sign behind it is at 0.8
so.. that's at least why that was happening to me. I think you're right it's related to that PR you linked
but also that uh, I'm doing something unusual
hmm okay that sounds like a different bug than what I've seen, but also good to know
the problem I've seen a few times is some meshes just being teleported to the world origin like their global transform was reset
though scaling scene transforms does seem to work normally for me π€
I'll check my world origin, but once I set the scale to 1.0 everything looked right.
OH I managed to repro but... differently? The mesh does get scaled but the collider didn't 
Or it did get scaled originally, but then snapped to a scale of 1.0
I think for me it's... the scene root is scaled.. and then in blender I have meshes that have their own scales which seems to affect the scale of the colliders underneath?
yeah, I'm not sure... honestly there could be a couple contributing factors for my situation like the scaling code I have
Do you happen to use Position or Rotation directly somewhere when spawning things?
or just Transform
I have a consistent repro of this now... it also messes up scaling stuff so it could be related
I'll look into it more tomorrow
sorry for the delay, just Transform
still no luck with this? Have you tried running a simple example with it, like what's on the debugplugin page? https://docs.rs/avian3d/latest/avian3d/debug_render/struct.PhysicsDebugPlugin.html
A plugin that renders physics objects and properties for debugging purposes. It is not enabled by default and must be added manually.
Still no luck
I did try a clean example
Thanks, will give it a go soon
looks like I have both
hi trying to get a shapecast to work and need a sanity check
let Some(hit) = space.cast_shape(
&Collider::cuboid(0.6, 0.5, 0.6),
trans.translation + Vec3::Y * 0.75 + *forward * 0.3,
Quat::from_rotation_arc(Vec3::Z, *forward),
forward,
&ShapeCastConfig::from_max_distance(0.1),
&SpatialQueryFilter::default(),
) else {
continue;
};
I want to cast from the middle of the 1 unit tall character so add Vec3::Y*(0.5+0.25 from cuboid height) and add forward*0.3 from cuboid width and rotate by arc to forward
i believe this is a correct representation in gizmos
gizmo.cuboid(
Mat4::from_scale_rotation_translation(
Vec3::new(0.6, 0.5, 0.6),
Quat::from_rotation_arc(Vec3::Z, *forward),
trans.translation + Vec3::Y * 0.75 + *forward * 0.3,
),
Srgba::GREEN,
);
however it currently isn't hitting consistently (image isn't meant to be a hit btw) - anything i'm doing wrong?
@little maple Could you try the fix-transform-bug branch when you have time? It seems to fix some of the collider transform bugs in my testing
https://github.com/Jondolf/avian/pull/773
checking..
this definitely fixes like 99% of problems I was seeing. There's entity that is spawning at origin but also.. I don't think it interacts with avian
Neat! I'll merge it in a sec and then try to repro and fix the panic you were getting with the graph coloring branch
I think the remaining problem I'm seeing is due to my code spawning an entity with a rigid body and collider and then inserting a Transform of where I actually want it with entity_commands afterward... and with that change I think it causes the entity to spawn at the origin and get stuck. But... that seems correct because that would mean the collider/rigidbody is using the transform that's there which is the default Transform. I just need to change my code for that, I think
Something like this?
commands
.spawn((
RigidBody::Dynamic,
Collider::cuboid(1.0, 1.0, 1.0),
Mesh3d(meshes.add(Cuboid::default())),
MeshMaterial3d(materials.add(Color::WHITE)),
))
.insert(Transform::from_xyz(3.0, 2.0, 3.0));
Or does it insert it at some later time?
This simple case ^ works for me at least
my situation is a bit more complicated, I'm afraid. I use this scene hook which processes the entities as the scene loads so that when it finds the part of the gltf that I want to generate a collider from, that's when it puts the rigidbody/collider on the root. I think it creates this race condition where.. depending on how quickly that happens, the collider gets added while the Transform is default or after the Transform has been updated. Again, I think I just need to change that code
Yeah I still have no luck reproducing this :/
I've tried quite a few different collision scenarios with various shapes and stuff, no crashes so far
I'm not sure how it'd even be possible to crash there, I think it'd require there to be duplicate or invalid contact IDs which shouldn't be possible π€ probably missing something though
@little maple I added some more info to that crash message on the graph-coloring branch in case you can reproduce it
Mainly just the involved contact IDs and pair index
yeah I just did the transform tweaks I needed to do in my code and now going to try that branch π
thread 'main' panicked at forks/avian/crates/avian3d/../../src/dynamics/solver/constraint_graph.rs:325:25:
Contact edge not found in graph: ContactId(191)
Oh interesting that's from a different place now
That one is when a collider is despawned or disabled
I needed to update my graphics driver π₯Ή
Okay this I can at least reproduce
It's when you despawn a collider that has a contact pair with multiple contact manifolds
ok, I got another one for ya
thread 'main' panicked at forks/avian/crates/avian3d/../../src/collision/contact_types/contact_graph.rs:579:25:
error when removing contact pair ContactId(127) with pair index 49: moved edge ContactId(140) not found in contact graph with 211 edges and 67 active pairs
yeah okay that's the original one, with the more detailed message I added
those values don't look too weird so I have no clue what's happening there
somehow the edge is removed and the corresponding contact pair isn't, or the ID becomes invalid
would be nice if I managed to actually reproduce that panic 
also got this one π
thread 'Compute Task Pool (0)' panicked at forks/avian/crates/avian3d/../../src/dynamics/solver/mod.rs:472:51:
index out of bounds: the len is 1 but the index is 1
sorry π for the record, I'm just posting this if it's helpful, I'm not like eager to use this branch for anything in particular
Nah it's super helpful for making sure things aren't broken, your project is clearly good for finding bugs lol
haha yah π ||π ||
I figured something out! I have a bunch of large colliders that are rigidbody static senors for triggering different things
I have two large ones that overlap slightly and basically whenever I'm within one of those sensors the physics gets weird and also the crashes happen
Ooh thanks, it's probably sensors breaking stuff then
I did test that sensors still detect things but didn't try actual physics with other contacts happening simultaneously
I'll see if I can figure it out
crash 1 out of 3(?) fixed, the one related to despawning entities
lol yeah sensors really fuck up the collisions, though I haven't gotten a crash (edit: reproduced a crash!)
yeah, again I have two big sensors that are inside of each other and it's like when entering a spot that was within both of the sensors.. that triggered a crash a lot
Hi all, I am trying to figure out if I have a performance issue or not, I am on an M4 MacBook Pro (M4 Max) and am playing with bevy and avian3d and I am essentially taking the 3d cube example from the readme and just spawning a lot of those cubes (a lot being 100 in this case) and things get real choppy and I am trying to figure out if I am making a mistake with how I add these cubes or if this is in line with the expected performance for that number of Dynamic RigidBodys on that kind of machine.
There is some shader stuf happening as well but that wasn't choppy when the cubes were not physics objects / when I switch to a StandardMaterial performance doesn't change all that much..
In the video I am restarting the app to show the initial choppiness, it seems to calm down a little once the cubes stop moving / the number of collisions is reduced.
So yea, I am new to bevy as well and as such I wanted to check what the expected performance is to figure out if I am spawning the cubes in an inefficient way or am making some other mistake. But first I wanted to ask what performance I should expect with 100 colliding bodies.
Hope this is the right place to ask that :/
Maybe this would make sense to add (Cargo.toml) ... I just made the project some days ago so I should be on a current version of the relevant crates:
[package]
name = "bevy_shader"
version = "0.1.0"
edition = "2024"
[dependencies]
bevy = "0.16.1"
bevy_asset = "0.16.1"
bevy_render = "0.16.1"
rand = "0.9.1"
avian3d = "0.3.1"
I suggest check out this page https://bevy.org/learn/quick-start/getting-started/setup/#compile-with-performance-optimizations
Cargo.toml setup to improve performance and others
Thanks,indeed I have not switched on any optimisation ( I guess it's a debug build ... Not sure about the terminology). I guess I (possibly naively) assumed those optimisations will represent constant factor improvements and as such the fundamental relation between number of objects with colliders and the performance might stay the same regardless (e.g. if it is something quadratic in the number of entities or so).
Going to give the shape cast a try for the first time
So far from looking here: https://docs.rs/avian2d/latest/avian2d/spatial_query/struct.ShapeCaster.html
It looks real good π πͺ
A component used for shapecasting.
I wanted to make a pr with this as an example for Avian2d but said I'd put it here first
Who thinks it's clear and important enough to be submitted as a pr (with subtle changed)?
It's a file from my game that showcases shapecasting for velocity clamping (specifically for walls as of now)
So it slows you down based on distance as you approach walls?
It's a cool idea, but maybe a bit too niche to be an example imo
For examples I generally want to scope them to one of these three:
- Demonstrates a specific feature and how to use it
- Demonstrates how to use the engine to implement physics functionality for a common gamey use case (like a character controller or some n-body sim or buoyancy etc.)
- A sample or stress test for demonstrating the engine's stability, performance, or accuracy (these could probably have their own folder)
Your example would probably fit category 2, but it feels a bit too specific maybe
Also it seems like you could just specify a SpatialQueryFilter for the ShapeCaster to handle the layer filtering, instead of manually filtering results in the system
It ensures that you won't pass the wall
Like, if the next physics update would make you pass the wall, it makes you get to the wall instead
I think it's useful
I don't know what that is and would research that
Thanks
We already have built-in CCD for dynamic bodies, and if you're doing that for kinematic bodies, then you're essentially implementing a collide-and-slide algorithm which is typically used for character controllers
Contains components and functionality for Continuous Collision Detection.
(the character controller working group has a prototype kinematic character controller using collide-and-slide too)
Oh ok cool
Thanks!
Heyyy @little maple wanna try the graph coloring branch again when you have time? I fixed quite a few problems involving sensors and kinematic bodies and some other stuff :P
I couldn't repro one of the crashes you got, but I'm hoping it was related to the sensor bug I fixed, which was otherwise messing up contacts for me
loaded it up and played for a few minutes. no crashes or weird physics π
Yay! I'll merge it later this weekend then, once I've cleaned it up a bit more and written the migration guide
I'm pretty hyped to finally get graph coloring done, now I'll be able to do wide SIMD to really make it shine
I even have bevy_math_extensions done in preparation for it (and the joint rework)
yeah generally im always building release. bevy in the default debug profile runs gets slow very quickly even without avian
In a basic 2d example I was inadvertently running debug on my iphone and it was peaking at 200+%cpu vs ~60% on release. Iirc there is also a mac bug atm that causes higher than needed cpu usage
Hejhej! I've only made some games where I had very simple collision detection etc. via my own naive implementations and it worked ok on my laptop.
Now my question is:
I ran the 3d example from the avian repo and it seems like I only get around 10 fps on my somewhat old laptop. Is this to be expected?
I'm a bit scared, that I will run into performance problems later on.
Should I use avian only if I really need realistic physics and opt for parry if I just need collision detection? (I think bevy recently got their own raycasting system right?)
When using EventReader to handle collision events, is there a way to get a specific kind of entity as the first one without checking whether it's the first, swapping the pair, then checking again?
Pretty much like Observers, where trigger.target() is always the entity that has CollisionEventsEnabled. (If both colliding entities have CollisionEventsEnabled, then it calls the observer twice for the same collision.)
- Make sure your project is setup to compile with performance optimizations as per https://bevy.org/learn/quick-start/getting-started/setup/
I know you said you're on an example, but it could be you imported it into another project or something so I thought I'd mention it.
- Try running with
cargo run --release
Thanks a lot! you were right, I didn't do those 2 things! π
But also the naive collision detection in the breaktout example performs a lot better and probably is fine for my use case. I will continue to play around with avian though and I think it's a super fun project π
It's almost always the case that specialized solutions will be more performant then general ones so that makes sense. I'm glad you figured it out!
the breakout example basically does O(n^2) collision detection which will scale very poorly
on my machine with the recent work, I can easily have 10k dynamic bodies at 60 FPS, at least in 2D (but I do also have a fairly powerful PC)
The current broad phase though does scale quite poorly too for tons of colliders, but the BVH broad phase coming SoonTM should fix it
That's what I thought too, but I really need to get a simple example running with about 20 colliders for a showcase. So the overhead hurts this more than the O notation
am i silly or is there no way to define collision with existing colliders?
do i have to re-implement all colliders i want?
like a custom enum
correct, that would be a pretty massive pain to implement and probably way slower, idk how I'd make the narrow phase dynamically query for the correct type of collider for each entity in each contact pair
but you could just do
// pls use better names
pub enum MyCollider {
Parry(Collider),
Custom(MyCustomCollider),
}
or something like that, and use the default impl for Collider-Collider collisions and your custom logic for the rest
i seeee
hmm
so its expected that all colliders in a scene are the same type
what happens when they arent
you can have more than one collider type in the scene, but each collider will only interact with colliders of the same type
i see
doing NarrowPhasePlugin::<MyCollider>::default() essentially just defines a narrow phase instance for collisions between colliders of type MyCollider
so, i could just hook in my custom narrowphase implementation here
datura
makes sense
the narrow phase has quite a lot of complexity, even more-so once I merge the graph coloring PR, so it's not really trivial to fully replace the narrow phase or just "hook in" a custom implementation there
the main supported way is just using the AnyCollider approach like in the example in the repo
in the case of Peck I just derive AnyCollider for the Shape2d/Shape3d enum and boom I have working colliders
cool
for the Parry Collider it instead stores a SharedShape which is an Arc<dyn Shape> so it can store any type that implements the Shape trait from Parry
Shouldn't the revolute_joint allow for a different axis on each body to be aligned? E.g. I want a wheel rotating around Z axis to be aligned with the X axis of a car
similar to how it has separate local_anchor1: Vec3 and local_anchor2: Vec
Or am I misunderstanding how it's meant to be used?
How do i measure the diffs between 2 rotations?
Is that possible? i don't see it in https://docs.rs/bevy/latest/bevy/math/struct.Quat.html#impl-Div<f32>-for-Quat
A quaternion representing an orientation.
huh, weird
I guess there's inverse and product
multiply the conjugate/inverse
no, quat addition just isn't meaningful to quat rotations
can sphere-average with an add and renormalize, though, so they're still useful
Merged graph coloring!
I haven't actually had a need for this yet, but if a collision occurs how would you determine where in world space the collision is?
is collidingentities less reliable than collision events? I notice im sometimes missing collisions using the former
How much work is it to DIY a character controller?
Just the basic 4-directional movement, maybe jump, bit of acceleration on start and go, not flying off on bumps
as i understand it, collidingentities gives state as of most recent pass & collision events give every collision since the last eventreader clear
add the Position of the entity you have relative coords to
how DIY do you want? a rolling ball with a gravity multiplier would meet those reqs
incidentally I rolling ball is what I have right now
But I want something that stops on its own and doesn't roll or slide down slopes unless idk they're slippery and steep I guess
The typical, with nothing fancy
You could maybe add some kind of angular anti force on the sphere ?
And you set the friction of the material really high
you mean drag?
OK it's sounding very hard
i just use tnua
if anyone is curious, after refactoring to use triggers, it's much more consistent, which i guess makes sense!
rapier_context
.cast_ray_and_get_normal(
position.extend(300.0),
Vec3::NEG_Z,
bevy_rapier3d::prelude::Real::MAX,
false,
QueryFilter::only_fixed(),
)
.map(|(_, intersection)| intersection.point.z)
```What would be the Avian way to do this? For a specific point in 2D, I get the height (highest point) of some collider
in a 3D space
So for a given x and y I find the z (the collider is my ground)
The only initialisers for ColliderMassProperties are ZERO and one that takes a density?
is that related?
Not beyond that it's also me trying to migrate from rapier on the same project
ah I see I think I should just be using Mass instead
What is the Avian counterpart to rapier's Velocity component?
LinearVelocity?
thanks
did you figure this out?
No
Looking into rays, Avian's RayHitData doesn't even say where in world space the hit was
only entity, distance and normal
Wait, that's not what a normal is, is it
normal is going to be a unit vector?
yes
I could do the math based on the original ray's starting point, angle and distance, but I'd really rather not
you may be looking for the raycaster component or the spacialquery systemparam
Nah because I need it on demand, sometimes multiple times per frame
isn't it always going to be at some fixed heright and pointed at -y?
Well, the one thing I said before is ok once per frame, but there are some related things
Nah the terrain is like
I am doing 2 things that involve raycasting, one of them may not really need it
I am casting a vertical ray down to get the height at any given point, I think multiple things use this but one is the thing that prevents things from going underground
the world is a trimesh
and I am casting a ray from cursor to the terrain to see what has been clicked or dragged
you can paint colours onto the terrain
you want the spatial query system param
A system parameter for performing spatial queries.
Yeah, but the raycasts on it don't seem to communicate what they hit
I mean the point they hit
they give entity, normal and distance
if you're casting a ray using SpatialQuery then finding the contact point is as easy as origin + dir * hit.distance
π
since I only need z there is space for a micro-optimisation xdd
Two colliders A and B can interact if and only if:
The memberships of A contain a layer that is also in the filters of B The memberships of B contain a layer that is also in the filters of A
is this and or or
why are there so damn many different vec3s
I get a Dir3 from Bevy, but Avian wants a Dir, which I can .into()
but elsewhere I was apparently using a Vec3 and I can't .into() that
oh Dir is just an alias for Dir3 derp
(presumably only when using avian3d)
Dir3::new, Dir3::get or deref
I needed Dir3::NEG_Z, they can pry vertical Z from my cold dead hands
I deleted a bunch of components having faith that the new required components thing would insert any that looked boring and defaulty
compiling now π€
deleted their insertions I mean
This ended up being```rs
spatial_query
.cast_ray(
position.extend(300.0),
Dir3::NEG_Z,
avian3d::math::Scalar::MAX,
false,
&SpatialQueryFilter::from_mask(GameLayer::Terrain),
)
.map(|ray_result| 300.0 - ray_result.distance)
I kinda wanna hardcode the gravity direction less, but to do that I would have to give up extend I guess. and instead do something like + some gravity vector * 300.0
maybe that's not too bad
Everything is working except my ball falls through the world
have you tried using the debug plugin?
not yet
I just did the most 1:1 migration I could think of from Rapier to Avian
to get it to compile
My terrain has ```rs
CollisionLayers {
memberships: GameLayer::Terrain.into(),
..default()
},
/// Adds physics simulation property to the avatar.
fn give_avatar_physics(mut commands: Commands, avatar: Query<Entity, With<Avatar>>) {
let avatar = avatar.single().unwrap();
commands.entity(avatar).insert((
Collider::sphere(0.5),
Mass(1.0),
RigidBody::Dynamic,
CollisionLayers {
memberships: GameLayer::Avatar.into(),
..default()
},
));
}
```And here is my avatar
it's kind of interesting that I have a separate system just to add physics to the thing, because I have 1 module with all my physics. I don't think that today I would bother to split it up like that
why aren't those required components
that didn't exist when I wrote this
and I don't think it's worth bothering now, it seems like a very lateral change
Is it the new idiom to shove as much as possible into required components?
Now what xd
I removed all the filters and such in case that was the problem
what is the problem you're facing?
After migrating like 1:1 from rapier, there appears to be no collision between the trimesh terrain and the spherical collider "avatar" (the only two colliders I have)
i think the best practice here is still evolving a bit, but i don't really like to put much there, feels like just adding more places to look in order to get the full picture for a specific entity
looks like the sphere is floating above the terrain, what's supposed to happen?
That's just it being teleported out each time it falls below
I guess it does teleport it a bit higher than needed
it's my DIY anti-tunneling xd
it's kinda difficult to tell from that screen shot.. it does look like it's floating in the right spot
I was just showing that the colliders exist, not sure what else debug can do
I got it π I was missing a RigidBody::Fixed on the terrain
I don't really know how that happened, did Rapier have that as a default and Avian doesn't?
do you mean RigidBody::Static?
hi i wanted to try out avian2d for my project, but i noticed some bizare behavior idk what to do about it. Adding a RigidBody to an entity disables the Sprite component, resulting in the second image. commenting it out results in the first image, which is the intended behavior except for the missing RigidBody ofc. i have PhysicsDebugPlugin in the project to show colliders, as you can see in the image, removing it doesnt help.
heres the snippet where all the things in my player are:
entity.insert(Player::default())
.insert(Sprite::from_image(asset_server.load("main-char.png")))
.insert(RigidBody::Kinematic)
.insert(Collider::rectangle(16., 16.))
.with_children(|commands| {
commands.spawn((
Camera2d,
Camera::default(),
Msaa::Off,
Transform::from_xyz(0., 0., 0.).with_scale(Vec3::splat(1. / SCALE_FACTOR)),
));
});```
i couldnt find anything via normal search engines and discord search for threads is terrible so idk if anyone had this issue here either
the versions should be up to date
AHA same issue with sprite rendering
oh uh. huh. what? the sprite moves down to below the game world. i guess its some render ordering thing
huh, wonder if it changes the z-index
the player transform is probably at Z zero because im spawning it from an ldtk map
so the same map as the tilemap in the background
them overlapping can create issues like that
moved the sprite here and raised it 10 units now its on top while having a RigidBody
while im here can the debug render for colliders and such be toggled at runtime?
there are a couple configurations in the docs, I haven't actually tried this but I suspect if you replace this resource with the output of this function it might hide everything?
https://docs.rs/avian3d/latest/avian3d/debug_render/struct.PhysicsGizmos.html#method.none
Gizmos used for debug rendering physics. See PhysicsDebugPlugin
this IIRC
fn toggle_debug_rendering(mut gizmo_configs: ResMut<GizmoConfigStore>) {
let (mut config, _) = gizmo_configs.config_mut::<PhysicsGizmos>();
config.enabled = todo!("toggle this");
}
PhysicsGizmos is just a GizmoConfigGroup so you can toggle and configure it like other gizmos in Bevy
No
just saw this on hackernews. about collision detection https://cairno.substack.com/p/improvements-to-the-separating-axis
I think I have a fix for this on obvhs main now (and on the max depth pr). I've reworked the bvh2 leaf_collapser to be a lot more parallel and fixed a possible race condition with the old parallel version (I think the issue you ran into here). I'll probably cut a new point release with the fix sometime in the next couple days.
With the new version, single-threaded collapse is around 1.4x as fast, and multi-threaded collapse is around 2.5x as fast. On the medium build preset single-threaded bvh building is around 1.14x as fast, and multi-threaded is around 1.5x as fast averaged across the tray racing scenes (total bvh build time, not just collapse).
New version is up! obvhs 0.2.1
@vestal minnow, Hi!
What do you think about using component hooks on ColliderAabb to push an entity into AabbIntervals immediately when it's spawned?
So that we can guarantee the iteration order even if the entities are at the same X position.
And also get rid of sorting in the broad phase.
This is already done on the , but it's unrelated to the broad phase algo. Sorting extents along an axis is the core thing that makes sweep and prune work.main branch
We're going to replace it with BVHs soon but it will still be deterministic.
Avian is already cross-platform deterministic with the enhanced-determinism feature, you can try the determinism_2d example to verify this. Our CI also has a test for this so that we never break determinism.
The only exception is currently if you have a chain of joints, as they currently use query iteration order (this will change later). But I believe even that should be deterministic across runs.
"Determinism issues" in Avian in the context of networking are primarily from how (rollback) networking interacts with the contact graph and warm starting.
Sounds pretty sweet π could be cool to see updated tray_racing benchmark results comparing all the BVH libs at some point
Oh sorry no, it's not done on the main branch yet, I was thinking of another PR where I changed collider disabling to use observers in the broad phase... But once we switch to the BVH stuff, it will use observers
hello friends, i want to ask if it is possible to have rigidbodies that are not able to push each other, but still prevent other bodies from passing through them
i thought that is what kinematic rbs where but i realized kinematic rbs dont interact with other kinematics at all :/
So you want them to collide normally with some bodies but pass through others?
Or do you want that they are immovable when colliding against each other, but still don't allow each other to pass through
this
Mm that's kind of tricky with built-in contacts because you essentially want both objects to be immovable but to also not overlap, which are somewhat conflicting requirements from the physics engine's POV (since to resolve overlap you kinda need to move the objects)
I feel like this should probably be a kinematic body with a collision algorithm like collide-and-slide
like most kinematic character controllers
yeah i figuered itwould be like that
meh i think its too much effort :P
im sure my infallible pathfinding will prevent stuff bumping into each other right
hey, just checking; does Avian currently have problems with entities that spawn with Disabled (and re-enabled later)? i'm typing this as i try to compile a minimum reproducible example...
In 0.3 yes, on the main branch not that I'm aware
π¦
do you have any workarounds i could use for ""delaying"" entity spawning with physics components? or should i just use the main branch
Or I haven't tested this specific case, it's very possible this has some problem too
The bug I fixed is with re-enabling sometimes not working
But I didn't test starting in a disabled state at spawn iirc
ah, okay. i'll try switching to main and see if it gets fixed then
otherwise i'll post that minimum reproducible example on a new issue report!
to be clear, it's toml [patch.crates-io] avian2d = { git = "https://github.com/Jondolf/avian" } and cargo update, right?
Yep
Thanks! Yep, that's the plan. But I want to get the insertion_removal stuff merged in first. And then there's a bunch of other misc perf stuff I've been working on. Will probably get that all together then release a 0.3 and redo the tray_racing benchmarks with updated versions of the other bvh libs.
Nice, I didn't realised that!
Not related to determinism:
A while ago I wrote here about weird behavior with quickly rolling objects, slowly passing through ground.
Recently I figured out that this happens because TGS caches contact points in the local space of the body.
This heuristics works especially bad with fast rotation.
The deviation increases with each substep, thereby reducing the support force:
Yup, that's why our contact constraints store fixed world-space anchors from before the substepping loop
https://github.com/Jondolf/avian/blob/1c93e6c7d1194ea213293d49909e72f02cbdba64/src/dynamics/solver/mod.rs#L578-L581
same as Box2D and Rapier
or hmm
Yeah so more specifically, the fixed anchors are used for computing the relative velocity, which makes it so that it won't drill objects into the ground due to an incorrect velocity direction. But it computes updated anchors for the updated separation depth, which may be wrong for rolling objects like this. But I believe it shouldn't matter generally
(I think, I'd need to test some things to double-check how it behaves)
As I understand, separation is computed from local contacts:
let r1 = body1.delta_rotation * point.anchor1;
let r2 = body2.delta_rotation * point.anchor2;
let delta_separation = delta_translation + (r2 - r1);
let separation = delta_separation.dot(self.normal) + point.initial_separation;
By locality I mean temporal locality, i.e. relative to the position at the previous substep.
That's correct yeah, but what I'm saying is that in practice it doesn't really affect behavior that much there
The bigger problem would be using the local contacts for the relative velocity, which is why we use the fixed anchors for that part instead
With the current approach of using local contact data for the separation depth and fixed anchors for relative velocity, rolling at a high speed looks like this
With local contact data for relative velocity too, there's some weird resistance and you can see the object sink in the ground
(ignore the debug rendering lagging behind a bit, it's not interpolated here atm unlike the mesh)
This becomes problematic on a car moving at 100km/h.
I think we need some threshold for rotation speed.
And for fast rotating objects compute local contacts without taking rotation updates into account.
Pretty much all physics engines I'm aware of that use substepping use this same approximation based on local contact points. The alternative is running the narrow phase at each substep, which is not feasible
Yeah we should probably limit it by default
We do have MaxAngularSpeed already
It's just uncapped by default currently
Yeah, I used that
Have you observed this causing problems with current Avian?
With 0.3.1 yes
But it is no longer a problem for me though, because I no longer use contacts for wheels
I have a custom solver for wheel-ground constraint
Avian is really nice for implementing custom constraints
I wish there be functions for computing effective mass for common DOFs
With XPBD? That's very much subject to change though I will still try to keep it possible to implement custom constraints
No, I use impulse based solvers without warm starting, for wheel-ground and car-wheel suspension, inspired by your TGS Soft implementation
Right, cool
We're most likely switching the joints to be impulse-based soon, so they'll probably have some helpers for computing the effective mass for various constraints
is there a way to get the world space point where two entities collided?
You're probably looking for contact manifolds:
https://docs.rs/avian3d/latest/avian3d/collision/contact_types/struct.ContactManifold.html
A contact manifold describing a contact surface between two colliders, represented by a set of contact points and surface properties.
Hey, I'm having a strange issue with Colliders. I'm trying to create a minimal repro but it's being difficult.
I have a case when I spawn 2 rigidbodies at the same time with disabled colliders (i.e. ColliderDisabled), and then immediately remove ColliderDisabled.
Somehow, sometimes (not always!) the colliders don't seem to detect collisions with each other. CollidingEntities returns empty.
If I add/remove ColliderDisabled, without changing anything else (no transforms changed), suddenly the colliders start reporting collisions again.
It feels like the engine is somehow not detecting the removal of ColliderDisabled... sometimes?
Is this a known issue? Anyone else notices this? Any clues would be helpful
it works! reenabling entities work
do kinematic bodies not fire collision events? despite having Sensor and CollisionEvents components?
seems like i have to shapecast manually...
You might need CollisionEventsEnabled
https://docs.rs/avian3d/latest/avian3d/collision/collision_events/struct.CollisionEventsEnabled.html
A marker component that enables collision events for an entity.
yes; i meant CollisionEventsEnabled. i have added it
the "hey???" never prints
i would say so, yes
oh, sure i'll try checking against that
wait, i have to add it manually?
Yes
or is this unrelated to the collision event/trigger systems
You need to add CollidingEntities manually for it to be populated by avian
You could probably check collisions too, I just usually find CollidingEntities more ergonomic
it is empty
i have never once touched collision layers
You don't use them at all?
it's just RigidBody::Kinematic and Colliders
yes
the kinematic body is probably the problematic part
Hm 
It shouldn't be. I use kinematics only too
Although I don't use events. But I do get colliding entities populated
Is this 2D or 3D?
3D
2d
Collisions::entities_colliding_with(...).len() also reports 0 lol
Oh I thought capsule collider was 3d
although i wonder if this is the result of the entities being Disabled at first; let's try factoring that out
Are you literally running into my issue...?! lol
yeah that's definitely it.
aaAARHHGHHHAHAHAAHAHAHAAAAAA i'm going insane
yeah this does sound very similar
Maybe this is a bug
if only there's a way other than [Collider]Disabled to delay spawning entities rahhh
definitely is-- before switching to main the bug was even worse: after re-enabling the colliders won't even exist, and gizmos don't draw
I'm curious, is your issue 100% repro? Cause for me, I only get it sometimes. Mine only shows up in tests cause that's when I spawn both bodies in 1 frame. And it only happens 2/5 times
it is 100%, yes
But that could just be due to race conditions in my own systems
1 frame
that could be the cause?
fixed update and some other things
my delay is 2 seconds before i remove the Disabled component
From my POV, it just looks like the engine isn't updating the physics state on ColliderDisabled removal when entity just spawns
ah, so mine's more subtle... it just refuses collisions
For me, bodies spawn, they're visually colliding, ColliderDisabled is removed, CollidingEntities reports empty until I add/remove ColliderDisabled
Yah so maybe a bit different.
no doubt it's related to insertion/removal hooks tho
so i guess we'll have to find some other way to disable colliders (or even entities) until this gets resolved π
there's that hey??? i was looking for π
although actually @oak vigil, i wonder what happens if we re-insert the Colliders?
i.e. ```rs
commands.entity(e).queue(|mut e: EntityWorldMut| {
let collider = e.remove::<Collider>().unwrap();
e.insert(collider);
});
In theory physics state should update if collider/transform state changes... so yah, i'd expect it to work
Although I haven't tried it, cause I thought that exact code you have is too naive
Since it happens all in one frame, it might still not "kick" avian
I dunno. Try it
well, if avian relies on Added<> or on_insert/on_add, it should probably do it
since it increments the change tick
let's see...
crap, removeing doesn't actually return the component since it accepts a Bundle
I think the function you want is take
oh damn i didn't know that existed, thanks
okay yeah that didn't work.
i only considered RigidBody and Collider though, maybe there's something else i should consider?
(or, a more cursed idea is to delay removal and insertion by 1 frame)
Are your rigid bodies root entities?
uhh, no they are not
the parents don't have physics components, though, only Transform and Visibility
This might be your root cause. In my project, I had issues where collider positions of child rigid bodies wouldn't update correctly.
In my case, I have a system which swaps the RigidBody in/out for all child entities, so that all my rigid bodies are root entities
fn spatial_attachment(
attach: Query<(Instance<Spatial>, &RigidBody), With<ChildOf>>,
detach: Query<(Instance<Spatial>, &AttachedRigidBody), Without<ChildOf>>,
objects: Objects,
bodies: Query<Entity, With<RigidBody>>,
mut commands: Commands,
) {
for (instance, body) in &attach {
let this = objects.get(*instance).unwrap();
let new_body = this.query_ancestors(&bodies).last().unwrap();
commands
.entity(*instance)
.remove::<RigidBody>()
.insert(ColliderOf { body: new_body })
.insert(AttachedRigidBody(*body));
}
for (instance, AttachedRigidBody(body)) in &detach {
commands
.entity(*instance)
.remove::<AttachedRigidBody>()
.remove::<ColliderOf>()
.insert(*body);
}
}
I could probably optimize it with triggers, but it's good enough for now
i see
is there a component that would allow me to ignore collisions on a specific entity? like, if i insert a component on an entity it will pass through other entities without affecting them
I'm trying to implement a ghost like entity (it'a a kinematic body)
hm, i just realised I can probably do that just by removing a collider... I still want collision events though π (If a ghost reaches the player, I want to get a coliision event when that happens)
You can make it a Sensor collider
Thanks! I think that's exactly what I wanted π
i've been using the force-rework branch and am really enjoying it. lovely stuff β€οΈ
only problems i ran into was needing different values between 0.3.1 and force-rework and the transform issues where a plane would shrink which i think was fixed in https://github.com/Jondolf/avian/pull/760
i needed about 100N to throw something with a mass of 0.4, which seems odd compared to the 1N for 0.3.1. i suspect something is off on my end, maybe too much dampening or some such
worst part by far is having to switch back to 0.3.1. i got myself hooked on ForceHelper
Glad you like it! I'll probably polish and test things a bit more, but it should land for 0.4 π
And yeah, I still need to verify that all the forces and impulses are actually physically correct and I haven't gotten units mixed up somewhere. It's possible that something is currently wrong there, especially if the values are vastly different from before
I finally figured out what was causing this issue where when my car goes fast it trips over edges in the ground collider. It was ghost collisions and turning off speculative collisions by setting default_speculative_margin to 0.0 totally eliminated the issue. I know tunneling is a concern but so far it's been good π€·ββοΈ
is it normal that hitboxes can clip a little bit into each other? if not, how do i fix it? and if so, how can i fix collision when walking over different tiles
Try to add CollisionMargin to the ground
Hi everyone, I'm starting a game with chunk-based procedural generation. I'm running into a performance issue with avian3d which I don't fully understand
Here's my setup: I have a character that runs around. As the character changes position, a dedicated system despawns chunks that the character is no longer close to, and spawns chunks that they become close to
For now chunks are just composed of a simple gltf-based static body
So in a nutshell, you have a bunch of static bodies all over space, with some spawning and some despawning as time goes
Here's my issue: the frame rate is ok at first, and as I move around it goes down and down. I'd understand if it were just going down as the bodies are getting spawned, and it went back to normal after. But no, even if I don't move after that, the frame rate remains very bad
Any idea what this might be due to?
Are the chunks' positions accidentally mutated every frame? That might keep them from sleeping.
No they're not, but hang on
I spent hours on that issue, and just as I'm asking my question I realize the chunks that are supposed to despawn might not actually be despawning after all -_-
Ok that was the issue. Sorry for the noise everyone, I swear I tried to debug my issue for a looong time, but I guess writing it down here unlocked my brain
And thanks to you for suggesting something
hehe, classic π
It's definitely not the first time that kind of thing happens to me π
happens to everyone! π
I dont know if you ended up figuring this out but i was trying to figure out the same problem and thought to post my solution for posterity.
You'll need the two entities colliding, and these queries:
contacts: Res<ContactGraph>,
pos_rot: Query<(&Position, &Rotation)>,
let (projectile_pos, projectile_rot) = pos_rot.get(projectile_entity)?;
let (object_pos, object_rot) = pos_rot.get(object_entity)?;
let hit_point = contacts
.get(projectile_entity, object_entity)
.and_then(|pair| pair.find_deepest_contact())
.map(|points| {
(points.global_point1(projectile_pos, projectile_rot)
+ points.global_point2(object_pos, object_rot))
/ 2.0
});
anyone please let me know if there's a better way to do this :)
in my case i assume getting the average is probably really unnecessary since the points are very close together and I don't care about that precision
ah, global_point! I got close to this and then started working on something else but I think I was using point1 and point2.
its still pretty inconsistent, but its better
hm thats because i have something detecting the angle of the collision, so if it hits the side of the collider instead of the top it doesn't like that
weird sometimes thats not even it
https://graphics.cs.utah.edu/research/projects/avbd/ <-- anyone considering this for avian? π
Joona has a branch for it, yeah
@vestal minnow did you ever make an issue SpatialQuery Collider component access conflicts? Can't find anything on GH. #1124043933886976171 message
- Out of interest, what is the tl;dr of the fix that you meant here?
- It looks like the only thing that uses
SpatialQuery.added_collidersandSpatialQuery.collidersisSpatialQuery.update_pipeline, and in my cases, I actually never use that function, I just usepoint_intersectionsandshape_intersections, so I guess it's interesting that I even reached for theSpatialQuerysystem param in the first place...seems like a lot of cases people have here should just be reaching forRes<SpatialQueryPipeline>, right?
You mean the system param conflicting with queries accessing Collider/Position/Rotation?
Cause my SpatialQuery rework just outright removes that issue π€£
Is there some way to make a physics object look harder for collisions only when it is more energized in some way?
The problem with our existing solver that uses TGS_Soft for contacts and XPBD for joints is that while TGS_Soft simply applies impulses that modify velocity, XPBD directly applies positional corrections, and because it runs after the impulse-based contact solver, contacts don't see those positional corrections until the next frame
Which lets joints kind of "break through" contacts quite easily
We're most likely switching the joints to be impulse-based as well, which should fix it
Joints will be solved first, and contacts will "see" those impulses before the positions of bodies are changed, giving contacts higher priority in the solver
same as how other engines handle it
My TGS+AVBD hybrid experiment kind of hacked together a similar effect in that AVBD didn't apply positional updates to bodies directly, but rather computed what the resulting velocity would be, and then contacts are solved afterwards, which kinda makes them joint-aware
But yeah I guess to answer your actual question, the main way to give collisions a higher priority is to just solve them last. That way they can react to what the earlier constraints have done.
Or you could also scale the contact softness parameters (mainly the frequency) based on some criteria. For example we make contacts against static bodies stiffer than contacts against dynamic bodies to prevent tunneling
Yep thatβs what I meant.
Oh nice. I havenβt seen it yet. Iβll go looking.
I don't think it's public or at least finished yet
or the branch might be public but there's no PR just yet
I think my "fix" was to just remove the Querys from SpatialQuery and to provide them from the outside in some public update_spatial_query_pipeline system. That way it'd purely be a wrapper around the SpatialQueryPipeline resource, though arguably the wrapper feels kind of unnecessary then
I never got around to implementing this though, but I'd accept a PR for it (though Nise's stuff should also fix it)
But I think we do want to keep SpatialQuery around, because we will soon most likely change the SpatialQueryPipeline to be something like ColliderTrees with separate trees for active bodies and static/sleeping bodies, considering we want to reuse them for the broad phase. So SpatialQuery would be the abstraction for querying all the trees conveniently
(details here are TBD)
FWIW at least from a naming perspective SpatialQuery seemed to be the obvious dependency to use to query, whereas SpatialQueryPipeline actually sounds more complicated.
But anyway, I didnβt know the resource existed until I saw your linked post above and itβs gotten me out of trouble with that error so Iβm happy for now.
Sounds like thereβs a bit in flux so I wonβt bother doing any PR related to your initial thoughts above.
Yeah, SpatialQueryPipeline is definitely intended to be more of an internal thing, so I'd like to keep SpatialQuery as the primary user-facing API (excluding the current conflict problem you're having)
Yea, no PR for my changes yet. I think the changes to the pipeline are done, but I have yet to make the parry collider work again (if you want to get this work in soon I'd imagine you'd be faster at implementing that)
Is it possible to lock the rotation of a child collider but still have the parent able to freely rotate?
Yeah I think I just need a joint and two separate entities
How do I set up things to be able to speed up the simulation while retaining determinism?
I tried changing relative_speed of Time<Physics>, but that changes the outcome, which makes sense as my other systems (which interact with the physics) still run as normal.
Is there maybe a schedule I can hook into?
@vestal minnow hey jondolf, do you use Res<Time> from bevy to get the delta time on your phsics simulation?
would it be possible for a component containing the collisions for a physics-abled entity to exist alongside it?
so that instead of:
fn projectile_airborne(p: Single<Entity, With<Projectile>>, c: Collisions) -> bool {
c.collisions_with(*p).next().is_none()
}
we can do:
fn projectile_airborne(c: Single<Collisions, With<Projectile>>) -> bool {
c.next().is_none()
}
I found it weird that checking collisions breaks the ECS query pattern of bevy
I suspect there will be a performance-related reason behind the decision
there's CollidingEntities
There's CollidingEntities but storing the actual collision data on the entities would be bad, it'd mean you're storing the same data in three separate places, i.e. on each of the two entities and in the ContactGraph, and you'd need to keep all of that in sync
Yup, though if you're running the PhysicsSchedule manually, you can manually set delta time for physics using Time<Physics>
With the default scheduling, Time<Physics> is derived from the Time used by the schedule where physics runs, so Time<Fixed> in schedules like FixedUpdate and FixedPostUpdate, or Time<Virtual> in PostUpdate
Whooops, somehow I missed that in the docs π₯²
That will about do it, and yeah I suspected this
thanks β€οΈ
The way relative_speed works is that it scales the delta time so that the physics simulation is advanced in larger or smaller steps, which visually speeds up or slows down the simulation. But this inevitably affects the simulation since the time step is not constant.
For proper determinism and consistent behavior, the delta time used by physics must remain constant. The only way you can really speed up or slow down the simulation in this context is to run physics more or less frequently, but keeping the time step constant.
I think you should be able to do this by scaling the relative speed of Time<Virtual>, which would then advance Bevy's virtual time faster or slower, causing schedules like FixedUpdate to also run more or less frequently π€ with this approach you don't have to touch physics scheduling at all
Of course the caveat is that this also affects how frequently your own systems run inside FixedUpdate, which may or may not be desirable
Alternatively you could set up some custom scheduling that runs physics at its own fixed time step independent of Bevy's fixed updates
Note that in slow-mo, the fixed time step will be exaggerated, so you will need transform interpolation to keep movement looking visually smooth
iam asking because the Res<Time> issue from bevy
what Res<Time> issue
Yeah that shouldn't affect Time<Fixed> determinism-wise since the delta time in that is always fixed
I believe that issue is primarily just that even if you had well over 60 fps, and had vsync enabled to lock Bevy to the display frame rate, you wouldn't get 0.016666... ms every frame even though you technically should
That affects Time<Real> and Time<Virtual>, which in turn also affects how often FixedUpdate runs, but the actual fixed delta time in Time<Fixed> should still be truly fixed
remember, Res<Time<()>> gives the current schedule timer
is there any way to prevent bumps with tiles of colliders?
Something something ghost collisions
Sorry for the vague answer, but I never use tiles, so I don't run into this. But I believe that is the term you'll want to search for on Discord π
lmao there was someone right there with the solution to my problem, and i didnt even notice!
idk what tunneling is
hehe
i can selectively enable speculative collisions right? i can probably just disable them for characters and enable them for projectiles
I believe so π
But again, I don't have any first hand experience with how to deal with ghost collisions in practice π¬
maybe that wasn't the best idea lol
it's ok, the bumps aren't really noticeable
my main problem was that i wasn't handling angles of -180
which is identical to 0 obviously, but my code did not realise that
I've been thinking around and wondering why physics engines are always using floating points.
Wouldn't it make sense to scale at compile time and use fixed point so the extra 8 bits of floating point mantissa are use for increased resolution/playground size?
That would lead to over/underflow errors at the boundaries, but wouldn't mean a more powerful physics engine within those boundaries?
i mean, i think it could use normal ints as miliseconds
like 1000 mileseconds
etc
instead seconds
it will always take miliseconds for stuff, never less than that
so far i remember godot haev a GetMSecs() stuff
it return a longint
I mean for all the positional computing. I meant all the vectors to be fixed points.
i think avian is determistic
Locally deterministic but that is not the point.
I'm talking about the data type for vec2/vec3 being a float32.
I was thinking of why use float32 instead a a fixed point.
The only compelling reason to use fixed point (that I'm aware of) is that you get the same precision regardless of the distance from the origin and can therefore get identical results regardless of where in the world the simulation is run. But this is very rarely needed for game purposes, and f32 is enough for pretty good results even when you're farther than 10 km from the origin. We (and many other engines) use constraint anchors that are relative to body positions, and collision detection also happens in body-space (excluding the broad phase, but accuracy is less important there), so those computations are always pretty accurate. Excluding edge cases like if you had a single collider that's massive, but that's usually a bad idea anyway.
The main problem with fixed-point math is that it's just much slower and more tedious to work with. I suspect that effective vectorization via SIMD would also be more difficult, and you'd at least need to develop your own math library from scratch for this. I'm not aware of any vectorized fixed-point math libraries, at least in Rust
People often say that you need fixed-point math for cross-platform determinism but that's just straight up not true. Avian, Rapier, Box2D, and some other engines all support cross-platform determinism despite using floating-point math.
That makes sense.
I was thinking of that mainly for some sort of space game that had sparce entities over large areas.
But yeah 10km from the origin already gives a lot of leeway especially when you can scale it to your needs.
I mainly came over to ask the question to people who knew more than I about physics engines.
Fixed point math ends up just signed int and a scaling factor in the end no?
Yeah, and we do also support f64 if you need it (though we'll probably rework this later to only use f64 for stuff like positions and not literally everything). In the future I do also want to support big_space which would make physics work at ridiculously large scales
That is really cool and probably make sense for sparce things like I want to do where the amount of objects is limited.
Oh my, I didn't know about that library... that is pretty damn impressive and probably a math nightmare...
Switched bevy_heavy and Avian to use a custom SymmetricMat3 type for 3D angular inertia tensors
https://github.com/Jondolf/bevy_heavy/pull/5
https://github.com/Jondolf/avian/pull/777
Using my new crate glam_matrix_extensions
This is an improvement by itself, but is also important for the wide SIMD stuff
I'll probably update the force rework PR first before doing wide SIMD though, hopefully get it in a mergeable state
how this help performance wise?
Thereβs a neat writeup in the PR descriptions π
It's a fairly small difference, but SymmetricMat3 stores 6 floats while Mat3 stores 9, and it can take advantage of the symmetricity to speed up most operations.
Here's a benchmark against Glam's Mat3
Glam also has a Mat3A that is aligned for SIMD at the cost of taking even more data and being more expensive to construct. SymmetricMat3 is still faster than that for most important operations, like inverse and transforming vectors
Additionally, this makes SolverBodyInertia 32 bytes instead of 44 in 3D, which is nicer
And for wide SIMD scatter/gather stuff we will want the data to be minimal for maximum efficiency
Also it's just nice to enforce symmetricity for the inertia tensor at the type-level since an asymmetric inertia tensor would be wrong
(more accurately the inertia tensor should be a symmetric positive semidefinite matrix, but enforcing it to be positive semidefinite is more annoying and costly and probably not worthwile)
Hmm... a mildly scuffed way we could support an efficient iteration API with the ForceHelper stuff is to simply expose a public RigidBodyForces query data that has the components used by the force APIs, so you can do something like this:
fn apply_forces(mut query: Query<RigidBodyForces>, mut force_helper: ForceHelper) {
for rb_forces in &mut query {
force_helper.get(rb_forces).apply_force(Vec2::new(0.0, 10.0));
}
}
as an alternative to the usual API:
fn apply_forces(query: Query<Entity>, mut force_helper: ForceHelper) {
for entity in &query {
force_helper.entity(entity).apply_force(Vec2::new(0.0, 10.0));
}
}
This would also trivially work with parallel iteration without any separate APIs on the ForceHelper, which @little maple was asking about earlier
But there is a small weirdness factor and you might wonder why you can't use RigidBodyForces directly for applying forces and need to also use the ForceHelper
The nicest API would still be this
fn apply_forces(mut query: Query<RigidBodyForces>) {
for forces in &mut query {
forces.apply_force(Vec2::new(0.0, 10.0));
}
}
But it requires either
- Somehow storing and applying a command buffer on
RigidBodyForcesto add missing components (not supported by Bevy yet) - Accepting that we store an additional six or nine vectors on every dynamic body
yeah, part of me is like ooph, I might feel the removal of parallel iteration, but... also maybe the other changes would overall make it perform better anyway?
Nice, now give us character controller π«
Or hmm. I bet I can make this work alright and only store up to two extra vectors on each dynamic body, which would be acceptable imo
The tradeoffs are
- We'd need to store an extra 12 bytes in 2D or 24 bytes in 3D per dynamic body, for local acceleration
- The force methods would immediately turn forces into acceleration rather than storing forces separately. This means that torque ignores changes in the inertia tensor between substeps (which should be probably acceptable) and also if you apply more than one force to a body at once, you'd pay the cost of applying the mass props for each individual force
What are the plans for 0.4?
But the benefits are
- Way nicer API (IMO)
- Works with both serial and parallel iteration with zero problems
- No need to have branching and hash map queries inside the force methods
- No need to do weird component insertion and removal shenanigans
So it might also be a net positive for the performance of the force API
I'm pretty biased where I care more about the parallel iteration than the amount of byte space.. I haven't really run into memory bottle necks π€
but.. I get that's important for something like this
Yeah definitely, memory isn't really too critical here, in general I just want to try my best to avoid storing potentially unnecessary and unused data on all bodies (or dynamic bodies in this case) if it can be avoided
24 bytes is definitely fine tho
Mostly performance work
- Benchmarking CLI tool (merged)
- Solver bodies (merged)
- Parallel solver with graph coloring (merged)
- Wide SIMD contact solver (WIP)
- Broad phase and spatial query pipeline rework (WIP)
And some new features and improvements - Support for Parry's voxel colliders (merged)
- More robust
PositionandRotationlogic (merged) - Force rework (WIP)
and several more minor improvements and fixes, and whatever else I end up having time for
Also more progress on the joint rework, but that might be delayed until the next cycle again because there's still more experimentation I want to do to make it good
I could probably get the impulse-based joint stuff ready for 0.4 if I dropped everything else, but then there's also the AVBD stuff which would be really interesting to explore more for joints, it just requires a lot more research and work to make it actually usable for our purposes
Wait is the only thing on that list that you aren't doing entirely alone the BVH-related stuff? π€
Medium related to Avian specifically but thanks for making bevy such an exciting engine to work with. Between Unity's various controversies (not to mention the seemingly random creation and abandonment of new crates) and Unreal engines clunkiness/performance regressions it's crazy to work in an engine that just seems to get better and better. Thank you for being such a big part of it getting better!
I need an Alice to manage the issues and other peoples' PRs
I'm not exactly doing a great job at responding to issues unless they're particularly interesting or related to something I'm working on 
At the start of the project I was responding to everything and fixing things regularly but nowadays I've kinda slipped from doing that as much
I just want to focus on the shiny big things lol :P
maybe I should do something similar to Alice's weekly merge train except it's me going through issues and fixing trivial problems and responding to stuff
Alice is the only person that functions without an Alice
Makes sense. Can't have infinite regressions
Or they ping you π
You're pretty good at responding to those IME haha
yeah do ping me here about issues and I will respond :P
it's just responding on GitHub that I suck at lol
-# and emails, sorry to all the companies and people who have still not heard back from me
What collider should I use for a plane in 3D? Looks like Plane3d starts from the origin which is not what I want. Polyline3d<4>?
Maybe plane is the wrong word. Not an infinite plane.
That would be a trimesh, a convex hull, or a thin cuboid
If you have a plane mesh then you can also use ColliderConstructor::TrimeshFromMesh to auto-generate it
If you did want something like an infinite ground plane, you'd probably want Collider::half_space
I have two points in X/Z. I'm creating two more points by shooting up a bit in Y. Those are basically the four points I want to create it from.
Yeah I would probably use a trimesh for that
I'm not entirely sure what Collider::polyline actually does in 3D π€ Parry supports it but I don't remember what it's like for 3D
At what speeds and sizes would I start seeing tunneling? Would a car traveling at 350km/h tunnel?
Avian uses speculative collision by default and also has opt-in sweep-based CCD so hopefully never
Contains components and functionality for Continuous Collision Detection.
The main cause of tunneling is small objects being pushed through geometry by other objects due to contact softness
Yeah last time I looked at that demo I remember Avian being incredibly good at avoiding tunneling (unlike other engines I've tried). Might be best to opt for a cuboid though. It's an invisible component anyway so it can be a bit thick.
Or if you have a rapidly spinning object, speculative collision may not fully account for that, but non-linear swept CCD should if you enable it
I just wanted to avoid the normal calculation because I'll probably mess it up :p
Also we can (and will) improve on this further too, Box2D also got some more anti-tunneling measures that are pretty nice
Graph coloring (which we have on main) has the added benefit that we can leave some colors fully dedicated for contacts with static bodies, so we can actually solve dynamic-dynamic contacts first and dynamic-static contacts last, which gives higher priority to contacts against statics
I'd want to avoid CCD anyway because I need the CPU for a bunch of other stuff. I prefer a lightweight solution this time.
Btw, CollisionEventsEnabled and RigidBody::Static do they lead to different things?
Wdym? CollisionEventsEnabled just lets you get CollisionStarted and CollisionEnded events for a collider
Ah right. Yeah it says so in the name :p. I just saw an example that didn't a rigidbody and just CollisionEventsEnabled. For a sensor do I not need a rigidbody?
You don't, yeah