#Avian Physics
1 messages ยท Page 33 of 1
yeah I remember aaronfranke was also here asking about opinions on glTF physics and what would work for Bevy back then
(starting here #math-and-physics message)
There are two physics proposals in Gltf repo. This is another one https://github.com/KhronosGroup/glTF/pull/2258 . But it seems the one I mentioned earlier is going to be merged (repo link was mentioned in the video ).
Hell yeah
Yeah rn its really hard to support the current extension for physics ( omi ) just because of how bevy's asset loading works rn with gltf
It makes it hard to do it for a 3rd party crate ( like avian ) it would be fine for bevy but bevy doesn't have the physics structs upstreamed and the gltf loader doesn't have a good way for us to hook into it and apply our own transformations
If we had some base physics structs upstreamed representing things like colliders, static vs dynamic vs kinematic, etc, that could then be used by both rapier and avian that would be awesome
I had a pr for avian at one point that added omi physics support predicated on another pr to bevy that never got merged that made the gltf loading more extendable
It seems the extension schema https://github.com/eoineoineoin/glTF_Physics/tree/master/extensions/2.0/Khronos/KHR_physics_rigid_bodies will not have type static, dynamic, kinematic and will instead have bool isKinematic (false meaning dynamic?). See comment https://github.com/eoineoineoin/glTF_Physics/issues/4#issuecomment-1900631052 and one below it. Quesiton.. wIll Avian be able to fully parse this extension without explicit "static" and infer it using isKinematic and remaining fields?
I guess we would just insert RigidBody::Static for nodes that aren't rigid bodies but have (child) colliders
since the spec says that colliders of nodes that don't have motion properties should be treated as static geometry
bruh the omi extension was way better
what is this ****
they put a lot of work into the omi extension it was also basically a 1-1 mapping with avian, entirely coquencidentially
this sucks fr
They are asking for feedback. Leave comments if something is missing ๐
my feedback: upstream omi_physics as is ๐
there were some big arguments between the microsoft people and the omi people over how the physic extension should be, i'm certain the feedback will not be met ๐
it looks like the msft people won ๐
I need to look closely at both of them so i can remember what's going on, i don't actually remember at this point it's been too long
the choice of no explicit static bodies is definitely interesting... I know Unity and some scene formats are like that, but at least every physics engine I know definitely has static objects as a separate thing and concept
i.e. Avian, Rapier, Box2D, Jolt, Bepu...
As the implementer of the premier physics engine for rust i would def comment maybe you could convince them!
Wait... you can't even have static compound colliders? 

How it will look can be tested using blender extension. We can add rigid body (blenders component under physics tab) to object in Blender. Now how to make this object static, dynamic or kinematic using blender physics panel and additional one?
I assume they mean that if you have multiple collider nodes as descendants of a node without motion properties (i.e. a static body), it would be treated as a compound collider. However for us it's currently important to distinguish between child colliders (every collider is its own entity) and actual compound colliders (Collider::compound on a single entity) which isn't really covered by the spec afaik
same goes for bevy_rapier I think
If something is missing we can use gltf custom properties to extend the extension as last option.
are there any KCC impls for avian yet?
or well, move and slide kinds of methods
I made my own a while back with some issues
I know some others were working on their own versions
They also implemented importer for Godot https://github.com/eoineoineoin/glTF_Physics_Godot_Importer and https://github.com/eoineoineoin/glTF_Physics_Babylon
also completely unrelated to Bevy or Avian, but Box2D recently got some character controller (or well, "character mover") features if y'all haven't seen it
https://github.com/erincatto/box2d/pull/881
namely, what it calls a cast mover, collide mover, plane solver, and velocity clipper
Made the PR for the contact constraint generation optimization stuff, somehow it actually removes more code than it adds
https://github.com/Jondolf/avian/pull/699
Objective
Currently, contact constraints are generated serially after the narrow phase. This requires iterating over all contact pairs and redoing various queries and computations, which can add me...
I think that might be the final PR for major optimizations this cycle... I'll probably start working more on release prep and minor QoL things now
Maybe I'll take a crack at those observable collision events too ๐ค
oh and I was supposed to finish the no_std branch now that my PR landed in Parry
bump @vestal minnow ๐ญ
I'm not sure if there's a good way to do that ๐ค I guess you could pause Time<Physics> so that actual physics doesn't run, but manually run FixedPostUpdate, which is where the systems that update physics transforms currently live? Assuming you don't have game logic there that you don't want to run
hmmm though that doesn't update collider AABBs since that happens inside the PhysicsSchedule
if the goal is to update the colliders such that you can do spatial queries on them then I think that should actually be fine with the current setup
i don't think i have anything running there, but it might become a footgun
and i do the spatial query on them ๐ฅฒ
i was thinking of just disabling window resizing, but i just realized that it might come up again once i start working on VR
Yeah I haven't tried this but it might work?
time.pause()(wheretimeisResMut<Time<Physics>>)world.run_schedule(FixedPostUpdate)spatial_query.update_pipeline()(wherespatial_queryisSpatialQuery)
and then unpause later
feels somewhat hacky though
ty, gonna try in a bit
and i'll just comment that it's a placeholder until something better comes up
@valid fog there's no way VR won't need pausing that requires physics to run, right? maybe you can figure something out
yep, that worked, tyvm ๐
pub(super) fn update_physics_while_paused
( world: &mut World,
p: &mut bevy::ecs::system::SystemState<SpatialQuery>)
{ world.run_schedule(FixedPostUpdate);
{ p.get_mut(world).update_pipeline(); }
}
@surreal rune So I have no_std Avian compiling, except with thumbv6m-none-eabi, because Parry uses downcast-rs with the sync feature, and synchronization primitives aren't available there :/
How important would it be to support targets without synchronization primitives?
like is no-atomic support only needed for very low-level embedded stuff or something, or is it also necessary for retro consoles like the GBA?
Yeah necessary for basically anything retro or embedded sadly. But that's ok, getting no_std is like 99% of the battle. It looks like Parry only uses the sync feature for two traits (Shape and WorkspaceData). I might try playing with Parry and see if they really need DowncastSync over Downcast
Yeah
Cool, I have the Avian PR here if you're curious
https://github.com/Jondolf/avian/pull/703
Since DowncastSync requires DowncastSend, which itself requires Downcast, I suspect you could just replace DowncastSync with Downcast and everything would be fine (maybe)
well, ping me if you find out a better way ๐
Also I had to add this thing, or alternatively handle Commands and ParallelCommands separately in half a dozen ugly cases... could be nice to have in Bevy itself, just making ParallelCommands a thin wrapper over Commands in no_std environments
Sounds like something worth PRing imo
observable collision events are working :D just need to do some documentation work and I'll probably make a PR
It does probably add a small amount of overhead, but it should be pretty minimal, especially since collision events are opt-in and this is only for started/ended collisions. I doubt people would have tens of thousands of collisions starting or ending every frame anyway :P
it's not unrealistic to expect that in ecs engine though...
I want to have a setup where I have a dynamic RigidBody that starts as a single small cube, and then I want to add cubes onto it dynamically. I'm assuming that I can just add colliders as children of the original cube, and the mass stuff will be figured out automatically, at least that's how I understood it from the docs, however what about something like impulses and forces? If I apply it to a child, will it be applied properly to the entire 'construction'? Also should I add the other cubes to the cube as children, or with joints?
So you can't currently apply external forces or impulses to colliders or child entities, you can only apply them to the rigid body entity. But you can apply forces at an offset, so you can kind of emulate applying forces to the child entities that way
If you want the cubes to be fixed together with perfectly rigid attachments then you want to use child colliders. Joints only try to constrain positions, they are not perfectly rigid and can be prone to instability in more complex scenarios, plus they are likely more expensive
And yeah mass should get updated automatically when you add or remove colliders, unless you add the NoAutoMass component to the rigid body
Ok thank you so much, I'll see what I can do with that info โค๏ธ
Yeah for 0.17 I want to go through and smooth over the public API as much as possible. I've already got an alternative to bevy_utils::Parallel which is no_alloc and no_std which should open the door for this too
Just waiting for https://github.com/bevyengine/bevy/pull/18822 to merge before going too crazy, as that'll have some awesome ramifications for feature configuration across Bevy and ecosystem crates too
I just skimmed through it, and congrats on that API! It all reads really cleanly and idiomatic, this is some fantastic work ๐
Damn, I really want to land the SolverBody stuff...
Left: Before reworked contact pair management or solver bodies
Right: After both reworked contact pair management and solver bodies
Hmm I can probably get it working before the joint rework too, just need to store a bit of extra data that wouldn't be necessary if joints didn't use XPBD
lemme see if I can get something like that working
I checked upcoming Blender Gltf physics addon.
As mentioned earlier Gltf physics schema is not going to have explicit type: static, dynamic, kinematic and will have bool isKinematic. it's similar situation with Openusd format that has PhysicsRigidBodyAPI:kinematicEnabled https://openusd.org/release/wp_rigid_body_physics.html#kinematic-bodies. Gltf maintainers also mentioned in the road map video that they try to make Gltf compatible with Openusd.
Part of comment from https://github.com/eoineoineoin/glTF_Physics/issues/4 that explains Gltf schema :
"... There's three types; static bodies (colliders who do not have a parent with a rigidBody property), dynamic bodies (nodes with a rigidBody), and kinematic (nodes with a rigidBody whose isKinematic=true) ..."
So it seems Avian will have enough information to parse the type correctly.
But how to export static rigid body from Blender?? In Blender you can only specify collider shape after rigid body is added to an object. And it seems Gltf addon https://github.com/eoineoineoin/glTF_Physics_Blender_Exporter additional physics panel doesn't cover this.
The draft spec README currently has this isKinematic boolean value: Type Description isKinematic boolean Treat the rigid body as having infinite mass. Its velocity will be constant during simulatio...
Full compatibility with Openusd/Gltf seems important if Avian is going to be upstreamed. Maybe we should take into account compatibility while Avian is in active development and it's easier to change stuff. There is also one more upcoming Gltf extension "Interactivity" that has some physics related fields (iirc).
i wonder if it'd be difficult to upstream colliders themselves, we're already halfway there with primitive shapes and colliders seem like the next step but i'm assuming orphan rules are getting in the way
Seems like a good idea. Gltf divided rigid body and colliders into two different extensions KHR_implicit_shapes and KHR_physics_rigid_bodies.
"KHR_collision_shapes is deliberately separated from KHR_physics_rigid_bodies to enable the geometries to be used by any number of future extensions, not necessarily limited to the domain of rigid body simulation. For example, node selection or 3D UI components, etc."
KHR_implicit_shapes importer can be implemented in Bevy even without physics.
oh no... I indeed got a spherical joint working with the SolverBody stuff
I have to implement it fully now, don't I 
geez louise this will be such a large PR again
And possibly controversial? ๐ค It does mean that users can't (easily) access up-to-date body data inside the solver, unless they're willing to use SolverBodys and stuff
but honestly I don't care too much about that, since having user systems deep in the internals like that is kinda sketchy anyway, and not worth losing a 3x perf boost for
which approach are you guys using right now to generate colliders?
Collider::trimesh_from_mesh(mesh) for each loaded mesh or is there something better
If you spawn a SceneRoot, you can just add a ColliderConstructorHierarchy::new(ColliderConstructor::TrimeshFromMesh) to it for the same effect; no need to iterate over the meshes ๐
In general, convex hulls a bit more well-behaved and faster to compute with, so I prefer ColliderConstructorHierarchy::new(ColliderConstructor::ConvexHullFromMesh)
yup works even better thanks
but my fps does tank quite a bit after adding colliders to everything, is this normal?
trimesh_from_mesh doesn't do any simplification for you so if your meshes are dense you may end up with very expensive colliders.
You might have better luck with https://docs.rs/avian3d/latest/avian3d/collision/collider/struct.Collider.html#method.convex_decomposition
Yeah I was thinking something similar so i also tried with cylinder but again <1 fps
Could it be because everything is always colliding with each other? I only have a couple dozen objects
Yeah, a dozen objects shouldn't be that slow unless maybe they have ridiculously complex colliders.
Did you maybe set SubStepCount to something large? Or tweak other settings off their defaults.
Nope everything default, just loading gltf and adding colliders
Huh, and it's slow even if you only give each object one simple cylinder collider? That's weird. Can you share the code?
use bevy::{
dev_tools::fps_overlay::{FpsOverlayConfig, FpsOverlayPlugin},
prelude::*,
text::FontSmoothing,
};
use bevy::{prelude::*};
use avian3d::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins( PhysicsPlugins::default())
.add_plugins( FpsOverlayPlugin {
config: FpsOverlayConfig {
text_config: TextFont {
// Here we define size of our overlay
font_size: 42.0,
// If we want, we can use a custom font
font: default(),
// We could also disable font smoothing,
font_smoothing: FontSmoothing::default(),
},
text_color: Default::default(),
enabled: true,
},
},
)
.add_systems(Startup, setup)
.run();
}
#[derive(Component)]
struct ColliderInserted;
/// set up a simple 3D scene
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>
) {
commands.spawn((
SceneRoot(asset_server.load(
GltfAssetLabel::Scene(0).from_asset("glTF-Sample-Models-main/glTF-Sample-Models-main/2.0/ABeautifulGame/glTF/ABeautifulGame.gltf"),
)),
ColliderConstructorHierarchy::new(ColliderConstructor::Cylinder{radius: 0.5, height: 1.0}),
)
);
commands.spawn((
Camera3d::default(),
Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}
i got the scene from https://github.com/KhronosGroup/glTF-Sample-Models/tree/main/2.0/ABeautifulGame/glTF
@keen light low hanging fruit: does your Cargo.toml contain the standard Bevy optimization stuff?
Nope, but my fps is going from 140 to <1 after colliders are added, does the optimization help that much?
It does when dealing with glTFs, yes
running in release mode or with debug optimizations can be like over a 100x perf improvement
[dependencies]
# Compile low-severity logs out of native builds for performance.
log = { version = "0.4", features = [
"max_level_debug",
"release_max_level_warn",
] }
# Compile low-severity logs out of web builds for performance.
tracing = { version = "0.1", features = [
"max_level_debug",
"release_max_level_warn",
] }
# Enable a small amount of optimization in the dev profile.
[profile.dev]
opt-level = 1
# Enable a large amount of optimization in the dev profile for dependencies.
[profile.dev.package."*"]
opt-level = 3
# Remove expensive debug assertions due to <https://github.com/bevyengine/bevy/issues/14291>
[profile.dev.package.wgpu-types]
debug-assertions = false
@keen light add this
source: bevy_new_2d
Also, FYI, you may be missing rigid bodies ๐
Oh, wow. I had no idea it was that significant. I've always just defaulted to the recommend optimizations.
i was thinking of just loading the environment as gltf, because its easy to import. I wouldn't need rigid bodies for that or?
Depends on what you want to achieve. I assume you want physics objects to not pass through the scene?
Then you need to add a RigidBody::Static to the SceneRoot entity
i want other objects to not pass through the enviroment
Yep, RigidBody::Static it is then ๐
and that would apply to all child objects of scene?
A rigid body can have any colliders
If you have a setup like this:
spawn((
SceneRoot(foo),
ColliderConstructorHierarchy(...),
RigidBody::Static
))
Then you end up with one rigid body that has n child colliders
Does that make sense?
but what would adding the rigidbody component change in this scenario
or is it necessary for collisions to work
If you have no rigidbody, they your colliders will just report the collision, but not act on it
ah okay makes sense
Like e.g. an invisible trigger area that tells you "the player is now in here"
A rigid body is the piece that dictates how a collision is handled
RigidBody::Static -> never move this entity, just make sure other things don't phase through it
RigidBody::Dynamic -> move this entity out of other rigid bodies
RigidBody::Dynamic is also the one you want to use for physical forces like gravity
well the optimisations took it up to 3 fps
i also added rigidbody::static and now its full speed ๐
ah
maybe self-collisions somehow messed it up?
yeah that's probably because when they're colliders that aren't attached to a rigid body, they're computing contacts against each other, but if they're attached to the same body, it filters out self-collisions
I'm thinking that we should prooobably change it so that a Collider on its own just does nothing by default, and emits some warning like "Collider must be attached to a RigidBody or have the Sensor component". It's weird that a Collider without a body is basically the exact same as a Sensor and that there's two ways to do things
Semantically, Collider should be just a shape, and then the RigidBody or Sensor defines how it's used
Completely agreed
I think we had chat about this same thing like a year ago
Because I was definitely running into confusion about that back then
once you know the avian model of rigid bodies and colliders it's fairly simple, but getting there is very unintuitive
This is how I've always assumed it worked. Never occurred to me that a naked collider would do anything.
I dont think I saw examples of physics systems, maybe it could help to have some?
or did i miss them
I was only looking at the bevy examples
Yeah agreed, I think the ideal solution would be
Collideron its own does nothing, it just emits a warning.Colliderattached to aRigidBody(on the entity or as a descendant) is part of theContactGraph. If it is not aSensor, it computesContactPairs for collisions against other rigid bodies.Colliderthat is aSensoris also a part of theContactGraph(or something like anIntersectionGraphif we want to split it) but does not computeContactPairs, it only detects intersections, sends events, and updatesCollidingEntities, if it exists.
I think really the only remaining open question I have in terms of UX is whether collision events for rigid bodies and sensors should be separate or not
that sounds clean, agreed
Some engines like Box2D have separate events like b2ContactBeginTouchEvent and b2SensorBeginTouchEvent, but I'm unsure if that's useful or just prone to causing more confusion
I feel like for sensors you might often want special behavior, in which case using observers may be the play, and if you're targeting the sensor entity then it'd make sense to only have one event since you know you're dealing with a sensor anyway
Purely in terms of efficiency, it would probably be better to have separate event types to minimize reading unnecessary events, but I'm just worried people might try to read CollisionStarted events for sensors and be confused why it's not working
Hmm there are also some weird edge cases there ๐ค If we had separate events, and you removed the Sensor component while another collider was overlapping it, should that fire an event for the sensor intersection stopping and a contact beginning? If we had just one event type, it probably shouldn't fire an event at all until they actually stop overlapping
if you're removing the sensor then couldn't you just check overlap/contacts manually right there if you need it?
in oUSD/gltf (and physx) collider without a rb means infinite mass with no velocity, so turning it into a marker would probably suck long-term
The asset thing could handle differences like that, no need to make component behavior magic to match it
even when saving to it?
Mm actually if we still include colliders on their own in the spatial query pipeline, it probably shouldn't emit a warning
I feel like it should be possible to have shapes that are only used for spatial queries, not for contacts or sensor scenarios, so that's probably something we should still support
Worth considering if we want sensors to get hit by spatial queries, I remember that causing many bugs for rapier users ๐ค
So the updated approach would be
Collideron its own is just a shape in the world, and participates in spatial queries.- Attaching a
Colliderto aRigidBodymakes it also computeContactPairs for collisions against other rigid bodies. - Making a
CollideraSensoroverrides (2) and makes it simply detect intersections and send events (and still participate in spatial queries unless you filter them out)
At least if it's all colliders it makes some sense they'd be in there though, unlike if it's just RigidBody and Sensor
you can already do that by just using a layer mask/filter
collider that doesn't collide with anything by default just doesn't make sense from the user perspective ๐ซ
and for that too
if you're really worried about it then inserting a different default layer for sensors would be a better solution
From my POV, a Collider is just a shape optimized for geometric queries. We could even rename it to Shape if we wanted to, like how Box2D has b2Shape. It really only has three purposes:
- Physics (detect and compute contacts for rigid bodies)
- Sensors (detect when entities overlap a "trigger area")
- Spatial queries (ray casts, shape casts, point queries, etc.)
A RigidBody associates a Collider with (1), unless a Sensor associates it with (2). But a lot of games might not need any collision pipelines or physics, and just want (3). Imo you shouldn't need rigid bodies or sensors to perform spatial queries; fundamentally, you're just querying a tree of shapes for geometric information, which shouldn't need any connection to physics
Ex: Maybe for efficient picking support you want to use simpler primitive shapes rather than rendering Meshes. You attach Collider/Shape to those meshes. But they shouldn't otherwise have any physics or overlap detection
yeah i'm worried about games that don't need collision pipelines or physics too, but i think making a collision library would be a better solution for them
Yes well ideally we could maybe have colliders and spatial queries in a separate crate that people can use, and then have Avian integrate with that, providing physics on top of it in some way
The broad phase and narrow phase are pretty heavily tied to physics if we want to keep it fast, so splitting that out from Avian would be pretty difficult. But I think we could technically split out colliders and some of the core spatial query pipeline stuff, providing a thin wrapper for physics-specific APIs in Avian, assuming that physics is still allowed to drive stuff like when and how the BVH is updated
is there a way to split out and upstream colliders to bevy without getting orphan rule issues?
^
We could upstream some collider type, but like, Rapier still uses Parry, so you wouldn't be able to use it there, unless it internally converted it to Parry shapes. Bevy also doesn't have convex polyhedra, non-rendering trimeshes, heightfields, etc.
which ones do oUSD/gltf have though
it was some super limited set of shapes, lemme find it
oUSD: we suggest the support of UsdGeomCapsule, UsdGeomCone, UsdGeomCube, UsdGeomCylinder, UsdGeomSphere and UsdGeomMesh, though the precise set of supported geoms might be implementation specific
I think glTF is just sphere, box, cylinder, capsule, convex hull
i can't even find hull from a quick glance
I think once we release Peck, and have the spatial query pipeline rework Nise is working on, and have reworked the broad phase to reuse the same BVH, I might try if I can do this split
It'd basically be a Bevy-native collider and spatial query crate then
yeah i was just about to say that
One part of Peck I've been dreading implementing is convex decomposition, but maybe the rational short-term solution there would be to just directly port Parry's VHACD algorithm to Glam and release that as its own crate ๐ค
rather than spending ages implementing that or CoACD from scratch (though CoACD would be nice eventually)
It seems the filed "node" is type "mesh"
https://github.com/eoineoineoin/glTF_Physics/tree/master/extensions/2.0/Khronos/KHR_physics_rigid_bodies
"Exactly one of shape or node should be provided."
6 types?
If there is "shape". Use one of 4 shapes from KHR_implicit_shapes.
If there is "node". Use mesh.
If there is "node" and convexHull = true. Use convex hull.
Extension "KHR_Interactivity" with physics related fields:
rigid_body/applyImpulse
rigid_body/applyPointImpulse
rigid_body/rayCast
event/rigid_body_triggerEntered
event/rigid_body_triggerExited
These nodes are used to apply impulses to a dynamic rigid body, useful when the mass or inertia of a motion is not known in advance.
that's not how impulses work, not in real life or in physics engines
an impulse is a change in momentum, which considers mass
In other news, I have all joints working with the SolverBody stuff, so I technically have an MVP ready... I need to do a ton of clean-up and documentation work and testing though
This requires computing and storing initial anchors and other positional data for joints before the substepping loop since the solver only has access to position and rotation deltas now... It's a fairly intrusive change :P
yeah this will be at least a 4k line PR once I'm done with this ๐ current progress, missing a ton of docs and clean-up
the branch is here if someone wants to try it for whatever reason... heavily WIP
@vestal minnow off-topic: is there an easy way to get a rigid body's center of mass?
ComputedCenterOfMass
This branch is kind of weird since some of the design decisions were partially made with future optimizations in mind (SIMD-friendly body state) that we might not get full immediate benefits from, but I'm hoping that it'll make it easier to actually implement those optimizations later
I'm also sort of trying my own thing with how I store mass properties for the solver ๐ค Box2D stores the mass and angular inertia of each body in each constraint, but I feel like that'd result in too much memory usage in our case with 3D and support for locked axes, so I instead store them in a separate Vec with a SolverBodyInertia for each SolverBody. I figured out a way to make it just 16 bytes in 2D and 32 bytes in 3D, which I'm hoping will make it good for memory locality and fast access
or right now it's 44 bytes in 3D, but it will be 32 bytes once I implement a custom SymmetricMat3 type ๐
I think I actually have an old branch with that already
@vestal minnow just ran into a maybe weird use-case: is it possible to create a convex hull from an already existing collider?
Is the best way to rasterize the collider and then feed the points to Collider::convex_hull?
I think that's the way to go, yeah ๐ค
Bummer, I'll just go with the AABB then
Is there a quick way to get a rigid body AABB?
I could build a compound shape of the collider AABBs and then compute the AABB of that
I guess you'd iterate over the ColliderAabbs of the attached colliders and use the merged method
oooh I didn't know about merged, that simplifies things! Thanks 
And here I thought my WIP stuff for spatial queries was bad
13 files changed, 992 insertions(+), 991 deletions(-)
Yeah I mean this touches the whole solver and all constraints, and involves some extra bookkeeping and writeback, so it's pretty big
The perf gains are pretty huge, but tbh I might just leave this for Avian 0.4, since I'm not sure if I'd be comfortable merging this so late in the cycle without extensive testing and getting some feedback first (if I even get this "ready" before 0.16 releases)
We have so many things halfway done that 0.4 might end up being a crazy release lol
0.3 is mostly just improvements to collision detection and related features, it's a bit smaller than average in terms of shipped things
damn, with the SolverBody stuff we have ~60 fps with 20k-30k contacts in 2D
the solver isn't even that big of a bottleneck there, the narrow phase, broad phase and BVH updates start to get kinda costly
should get a bit better with the BVH broad phase and other related improvements
"Store Impulses" being 1 ms is interesting 
Hmm I guess I'm making another modified version of petgraph's undirected graph, this is probably the third version now ๐
I basically need a mix of UnGraph and StableUnGraph, where the edge connectivity list keeps stable indices, but edge weights are stored separately and can be swap-removed to get rid of contact pairs
StableUnGraph keeps vacant edges around, which means the narrow phase would need to also unnecessarily iterate over non-existent contacts, so I can't use that. And UnGraph doesn't maintain a stable order at all for removal of nodes or edges
So I guess I'll split out edge connectivity data and edge weights and maintain a contact ID pool or something ๐ค
wow it works I think
https://github.com/Jondolf/avian/compare/main...stable-contact-ids
fixes some scuffed handling of contact removal too
nice it actually optimizes things too (left is old, right is new)
hmm right we should also have separate active and sleeping contacts to avoid unnecessarily iterating through contact pairs for sleeping bodies in the narrow phase
Box2D has solver sets which also achieves this
god there's so much optimization work we can do ๐ I'm addicted to optimizing rn
huh, Rapier doesn't have this either, it just has a TODO to not iterate over all contacts ๐ค there's definitely a lot of room to optimize things in Rapier too
norbo 2
I need to support dragging tokens using the mouse. My tokens are RigidBody::Dynamic so to collide against walls. I remember from my days using chipmunk that to properly implement dragging a dynamic entity, I had to spawn an adhoc kinematic entity and create a pivot joint with my dynamic entity.
Will the equivalent in Avian be a RevoluteJoint?
I would probably use a DistanceJoint, but a RevoluteJoint works too, yeah
I have a very old version of a grabber thing like that here
https://gist.github.com/Jondolf/166ca879fa2994ba42b5e08a8807885c
it's using an old Bevy version and bevy_xpbd (the predecessor of Avian), but it should be fairly simple to get it working with a few small changes
Thank you! That's going to be useful to learn from.
Is there a way to ensure the dynamic entity never breaks through a static collider even if its joint compliance value is near zero?
(My current workaround is to clamp the kinematic target entity distance from the dynamic entity, thus reducing the amount of 'force' applied by the joint)
Not currently, no. That might change when we do the fabled joint rework (move them from XPBD to be impulse-based) but I'm not 100% sure
A partial workaround is to limit the distance like you're doing, or to scale compliance based on distance (might cause other problems?). We could/should also add an option to limit the maximum force directly
To expand on this: With XPBD, the joints are changing the positions of the constrained bodies directly. With a large enough positional correction, it can make bodies just go through other objects, or at the very least make them overlap. But if we made joints impulse-based like contacts already are, it would instead change the velocity; if we solved joints first and contacts after, the contacts could probably react to that change in velocity, and apply an impulse to counteract it before the body has been moved
But that being said, contacts also have some softness to them (which can be configured), so it might not perfectly ensure that joints never break bodies through other objects
whyyy does this break determinism 
Are you accidentally assuming order in a hashset / map?
Maybe by iterating over something?
(I say that because I see a few iter calls in that PR, but I'm on mobile, so I canโt easily verify the involved types)
Limiting the distance seems to be working well enough - but I'm struggling with eliminating the spring effect of the joint. Perhaps I should write a custom joint with a different linear damping profile? (Have a higher damping value but make it apply non-linearly)
It was a lot of merge conflicts 
I have it compiling after rebasing it though (or at least avian2d, there are some missing trait impls for 3D types I need to sort out)
https://github.com/NiseVoid/avian/commit/ee4e8902ff179ba754f7352741c25c7ff56cccc8
Still need to implement a couple more of the spatial query functions, apply translation/rotations correctly, and then see if this trait is actually implementable as is
Also gonna need to sort out the issue where I use ColliderAabb to fill the BVH, but those are just left in whatever state they were for the broad phase
Nope it's just using vecs, except for some pair lookups where order doesn't matter... The initial behavior in the determinism_2d example is deterministic when single-threaded, but it's different after resetting the scene (i.e. respawning everything), and not at all deterministic when multi-threaded
I'm guessing the graph edges or their IDs are somehow not getting cleared or updated correctly, since edge removal now marks them as vacant (None) rather than actually removing them, and maybe that messes it up somehow? But I don't see why multi-threading would affect anything since it only adds or removes pairs serially, and the order for that should be stable
I (mostly) fixed this by making the dragging entity distance limit apply only when the main entity is already colliding with something and then increased the compliance, as well as the linear damping enough to prevent most of the bounciness.
hey guys, quick Q, how does one apply physics after a delay to an object. I want to lock axis until the terrain is generated then unlock the player. However, both unlock transform x,y,z and adding the rigid body and other components after the world has spawned to the entity seems to stop physics affecting them entirely
the new observer collision events are quite nice
I was thinking that it might be nice to add the rigid body entity to them too and to use named fields
Hmm that sounds like it should work ๐ค just spawning it with a delay or keeping axes locked until the terrain has been generated
I'd double-check (maybe by logging values) that when the player should be able to move, it has
RigidBody::DynamicorRigidBody::Kinematic- If it is dynamic, a non-zero
ComputedMassandComputedAngularInertia - No locked axes
(also the general stuff like make sure you actually have PhysicsPlugins and that physics works in the general case where you're not doing anything weird, just spawning a rigid body normally)
I'm trying to use Avian without any of the collision detection stuff, just the spatial queries and dynamics
Right now I only add these plugins and spatial queries appear to work well and the performance is decent:
PhysicsSchedulePlugin::default(),
PhysicsTypeRegistrationPlugin,
PreparePlugin::default(),
MassPropertyPlugin::default(),
ColliderHierarchyPlugin,
IntegratorPlugin::default(),
SpatialQueryPlugin,
SyncPlugin::default(),
But none of the velocity components (for example) appear to work. I'm not sure what I'm missing (probably something obvious ๐ )
For context, I have tens of thousands of entities and I only really want spatial queries against them (adding the default plugins outright crashes it)
I considered a custom solution using OBVHS but Avian has some nice convenient features and I'm not sure if OBVHS has existing support for non-ray based queries.
Not a big deal if those components won't work. Easy enough to do manually, but thought it work asking.
From my experience trying to get OBVHS into avian, I can tell you it doesn't come with queries other than raycasts and AABB intersections, they are pretty simple to build
Wrapping things up into a nice and performant API is still a lot of work though, which is exactly why I'm reworking avian rather than building my own SpatialQuery API for my SDF collisions again
Oh neat! That sounds great, I look forward to it
does anyone have on hand their commit revision for running crate examples on rc5?
I've gone back two to no avail (which is totally fine :D) but was wondering if there's a revision with working examples atm? nw if not
ah! my fault! run in crate root!
Just wondering, does avian have any support for hierarchal collisions?
by that i mean, say i want to create mesh accurate collisions but i dont want to incur the cost of a trimesh, could i simply define a series of increasingly small sphere colliders and have avian only emit a collision event for the "smallest" (or deepest) collider hit, or is that the kind of thing you have to implement yourself
nvm answered it myself (i shouldve just googled) bounding volumes are supported because of parry 
TIL
mightve spoken too soon on that, went back to avian docs and not finding anything for bounding volume stuff 
I know bvh is used under the hood for optimisation, so maybe if you just add a bunch of sphere colliders to a mesh for coverage itl "generate" the bounding volumes for you, but i wouldnt want to just assume itl do that
I'm pretty sure you can just keep adding children to a rigidbody, and then have those children have colliders. If they collide, I'm pretty sure it's the child collider that 'detects' it. I think this is along the lines of what you were asking for?
yeah if only the child emits then its probably acting like a BVH
with a BVH youd do something like have one big sphere collider for the entire entity, then two smaller colliders for their top and bottom half, then smaller colliders inside those, and keep getting smaller until you have the resolution you want.
So to check if the left pinky on that model got hit you only have to check, 20 colliders, instead of 2000 for that model (to use an extreme example) because most of them got filtered out in the earlier layers of the heirarchy so dont even get checked by the solver
Jondolf is online if you want the expert opinion :)
I would ping him but its not THAT serious 
I'm pretty sure they don't mind, I see people pinging them quite often
but yeah if it is emitting from the "youngest" child with a collider on it, then it is probably acting like a bvh, because it would be a bit silly to have behaviour for relationships like that and not take the free optimisation of just not checking the children of children that didnt collide ykyk
You could always just do a simple test
screw it
@vestal minnow you able to confirm on that?
So first off, every Collider has its own AABB to accelerate broad phase collision detection and spatial queries. Spatial queries indeed use a BVH for this, with each collider as a leaf node. But broad phase collision detection is currently using a different algorithm (sweep and prune), though I do plan on switching it to also use a BVH.
If a potential intersection is found between e.g. just two spheres, that contact is computed directly. But for composite shapes, such as trimeshes or colliders built using convex decomposition, Parry stores a separate BVH just for that shape to accelerate queries against it. So yes this optimization is kind of done automatically for some shapes
But there is currently no acceleration like that for actual child colliders in the entity hierarchy; every Collider is treated as its own shape in the BVH
Ah gotcha, is there a way to define a structure like that manually?
Or better yet is it even really necessary to do (not sure how fast primitive shape colliders resolve in the solver), like say i want to have a bunch of humanoid entities and i want to do zoned collisions on them, so each entity is lugging around 6+ colliders where realistically only one of them is relevant at any one time, could i instead do 3 layers of bounded volumes, one for the whole entity, one for upper limbs + head, one for lower limbs
There's not really a way to do it that manually, no. With a BVH, if you have a collider for each of those 6+ shapes, it already computes larger bounding boxes around them sort of hierarchically based on what the heuristic thinks is (close to) optimal for traversal speed; that's kinda the point of a BVH
And if you did a ton of nested BVHs, that'd probably just have way more overhead since you'd need to update and traverse each of them separately, possibly losing parallelism in the process. Unless of course the "sub-BVHs" or whatever remain static like meshes often do, in which case it's useful since you don't need to rebuild those
(by nested BVHs here I mean multiple layers of BVH filtering at different granularities)
Ah gotcha so if im understanding right.
if i chucked a bunch of colliders on a model, currently i could check if say a bullet passed through an armpit using a raycast and it would use bvh, because its a spatial query
but for the actual physics solving its not doing that (yet)
effectively just looking to get close to the footprint of a trimesh, but without the huge cost of a trimesh ykyk
few spheres to get coverage on an arm vs all those vertexes
Yeah pretty much, the broad phase for collision detection is currently just using a simple sweep and prune algorithm like the one described here
https://leanrada.com/notes/sweep-and-prune/
and I intend to try changing it to use the OBVHS crate (I have some WIP prototypes)
But like I mentioned, collisions against e.g. meshes do still also use a BVH for filtering individual triangles after sweep and prune has found an intersection with the whole mesh's bounding box
since Parry stores that BVH in the trimesh itself and uses it automatically
Ah sick sick 
is there anything id need to do on my end to help the broad pass do its job like compound the colliders or something?
I wouldn't worry too much about that in 99% of cases unless you notice from profiling that you're bottlenecked on it for whatever reason
Fair 
Blender is working on physics geometry nodes https://projects.blender.org/blender/blender/pulls/124093 . Currently the feature can be enabled as experimental feature. Maybe this will help exporting physics to gltf. There is "Collision shape" node (see screen), separated from rigid body.
hello. given that bevy is an ecs engine i thought it would be appropriate to have an old school rts-style deterministic lockstep netcode library that would scale well with huge numbers of entities. i couldn't find one already built so i started writing my own. i'm pretty new to this but making good progress. the problem i have run into now is that the determinism across clients is proving difficult to achieve when running a physics simulation.
my netcode strategy is this:
- client sends commands to server but does not implement gameplay effects yet
- server broadcasts new simulation ticks with all commands for that tick. this way everyone executes the same commands every tick.
- clients receive all commands for each tick and then implement the commands' gameplay effects locally.
- part of this involves stepping the physics sim by the same duration as the server's sim tick. it's not quite the same on the clients due to packet jitter, which is why i step everything manually
to this end, i start with the physics sim paused
.add_systems(
Startup,
|mut time: ResMut<Time<Physics>>| {
time.pause();
})
i send a command from a client to apply a force to a unit.
all clients receive this command which implements this
unit.apply_force(force_cmd.force);
immediately after this system i step the physics sim
fn step_physics(
world: &mut World
) {
world
.resource_mut::<Time<Physics>>()
.advance_by(SIM_TICK_INTERVAL);
world.run_schedule(PhysicsSchedule);
}
unfortunately this is not enough to prevent desyncs across clients. small changes in position after collisions eventually lead to different states across clients. I have enabled the enhanced-determinism feature for avian, but it doesn't appear to make any difference. does anyone have any suggestions for how i can make this deterministic?
@vestal minnow I threw your example into the repo, started working on making it work with SpatialQuery stuff, when suddenly OBVHS panics 
obvhs-0.2.0/src/bvh2/mod.rs:406:13:
assertion `left == right` failed
left: 10002
right: 10000
```<https://github.com/NiseVoid/avian/tree/generic_spatial_query> example `spatial_query` in case @thorn solstice wants to see what's going on (also Griffin might like the awful mess I made in `src/spatial_query/bvh_ext.rs`)
Took me a while to get the ambiguity detection to stop crashing the app too, and not just from my changes, but also existing ambiguities when multiple collider type plugins are registered ... Do we have a way to handle those currently? ๐ค
ambiguous_with_all 
or maybe preferably ambiguous_with, putting just the relevant conflicting systems in some system set... but I don't think we do that rn
I have gotten OBVHS kind of working (i.e. not crashing and detecting AABB intersections) in the past, and I think I might've run into similar issues at some point, but I don't remember what it was
i see that SyncPlugin and PreparePlugin (i'm not sure which is relevant here) run their systems in FixedPostUpdate. is there something else that happens w/ Position and/or Transform in one of the other schedules? i have two different systems that both sometimes manually set the Transform::translation of an entity. the one in FixedUpdate works, but the one in FixedLast doesn't (i.e. the entity's translation doesn't change)
i just tested moving the latter into FixedUpdate and it works
so maybe there is something between FixedLast and FixedUpdate that overwrites the translation set in FixedLast?
setting the Position instead of the translation in FixedLast works as expected
Interesting, this maybe does sound familiar. Can you try it with BvhBuildParams::fastest_build() to eliminate some variables?
If you haven't yet, take a look at the physics example in the insertion_removal branch when you get a chance. Curious to hear your thoughts. I'm pretty much done with the impl but might play with how things are structured/named a bit.
Crash seems to be gone with fastest_build ... So one of the features medium has causes the list to grow by 2 for seemingly no reason ๐ค
Yeah I vaguely recall seeing that as well
Yeah sounds familiar, maybe in this context there needed to be 1 prim per leaf or something?
Yup I saw this, I haven't had time to go through the example or implementation in too much detail yet, but I started initial work on getting the insertion and removal stuff working in Avian
that is still currently very WIP and not yet working properly, but I'll let you know how it goes when I have a chance to work on it again (probably next month)
@vestal minnow I have a question about the documentation and behavior of CollisionLayers.
The documentation states:
Two colliders A and B can interact if and only if:
1. The memberships of A contain a layer that is also in the filters of B
2. The memberships of B contain a layer that is also in the filters of A
but it doesn't say whether collision happens IFOIF one is true, or IFOIF both conditions are true.
this is making things hard to debug because I'm not sure whether or not I should be expecting objects to interact
it's AND behavior, both must be able to interact with each other
but yeah agreed, that should be made clearer in the docs
is there an easy way to suggest documentation changes, or would I have to pull the source, make a pull request, etc?
Pull request is fastest, or make an issue (or just remind me here if I forget) and I can change it when I have a chance
My goal is to identify the selectable object nearest to the player, in order to highlight it and/or know which object to interact with when interaction input happens.
To this end, I setup CollisionLayers on all the relevant colliders and implemented a shape_intersections. That works, which is great, however, when the player is near multiple selectable objects, they will all intersect. The result of shape intersections only returns Vec<Entity> so either I need to then further calculate distance to player of intersecting colliders to figure out which is nearest, or -- and the reason I'm asking here -- is that there's a better way to achieve this.
maybe https://docs.rs/avian3d/latest/avian3d/spatial_query/struct.SpatialQuery.html#method.aabb_intersections_with_aabb
and a Query<&Transform, With<Highlight>> plus cutoff? might be more efficient than a proper collider test
Seems like that also returns Vec<Entity> whereas I want just the nearest of those intersections.
that's what the query's for
aabbs.iter().filter_map(|&e|highlight_q.get(e)).min(|Transform{position,..}|(player_pos - position).length())
Ah yeah, that's what I meant by "calculate distance to player". That's a more succinct way, and probably something like that is what I'll go with if there's not a clearer built-in tool. You mentioned that AABB intersection is more efficient than shape intersection, why is that?
aabbs and bounding spheres are usually the first test when determining collisions, since they're easier to calculate, so it's likely that a shape intersection would have an aabb intersection involved when there's more than one possible other shape
hey, dumb question, am i wrong in assuming that the "name" of a mesh you use in ColliderConstructorHierarchy::without_constructor_for_name is the same as the object name in blender when exporting to gltf?
i haven't been able to skip colliders for certain meshes
commands.spawn((
SceneRoot(scene),
ColliderConstructorHierarchy::new(ColliderConstructor::ConvexHullFromMesh)
.without_constructor_for_name("fakeWall"),
RigidBody::Static,
));
inspecting the exported gltf data i can find the mesh name, though i don't know if it's relevant or not
that's the name of the object entity that is a parent to the entity with the mesh, not the mesh entity. hit the little arrow next to the orange triangle
oooooooohhhhh, yup. that works. could swear i tried that too..
thanks!
@vestal minnow It does something now!
-# the video compression is not happy though
Ooh nice! Probably a bit early to benchmark, but have you tested how the BVH build times here compare to the old Parry version?
Also I wonder if the lack of proper 2D support has any meaningful effect on it ๐ค
Probably, the whole thing is 3D now and there's conversions everywhere so that probably has an impact ๐
Mm at some point I should try how bad it'd be to add 2D support to Bvh2
I had 2D support in ploc-bvh, but that was because bounding volumes were entirely a trait
I assume @thorn solstice had some reason for not doing that. Building on the bevy_math bounding traits makes extensibility so much easier after all
For Cwbvh I assume the specific AABB representation is very important and can't easily be made generic, but I would think that for Bvh2 you should be able to traitify things more
Also I'd imagine if we really want to optimize the BVH stuff for avian, we're probably gonna need to make it use more Vec3A where possible
I didn't have any use for 2d so it wasn't even a consideration until talks re Avian started. OBVHS cares mostly about being fast, trying to give a somewhat reasonable rust alternative to some of the functionality in Embree (and in a lot of places Embree is still a lot faster). I've had some cases where traits were non-zero cost due to breaking inlining which had a somewhat surprising perf impact. I'd want to be careful to not regress perf or readability if we move to something more generic.
Yeah, definitely needs proper profiling to make sure it wouldn't regress things
Yea, though if it does perform well it could maybe be nice to have the ability to have an OBB BVH ... Last time I tested bounding sphere BVHs are a very bad idea though ๐
OBBs actually being worth it at the BVH level is somewhat niche though (and I have no clue how an efficient "merge" would work), but sometimes the intersection tests already treat AABBs as basically OBBs and it could be worth it
The stuff I've seen on OBB seemed to rarely be worth it, but maybe there are cases where it works really well. TLAS/BLAS on the other hand has a lot of benefits, one of which is that the BLAS is in the local space of the object (so OBB like). This is already doable with OBVHS and there are examples.
I'm strongly considering tableflipping and switching my studio's project over from Rapier to Avian. Is Avian mature enough that I won't have a bad time?
Unless you're doing something relatively obscure it should be
I know some joint types are still a bit weird, and the perf at very high entity counts can be less than ideal, though Jondolf has also been working on that a lot recently
Yeah joints are still missing a lot of features, and perf is likely worse than Rapier in heavier cases. Improving those is my main priority for the next release cycle though
You may want to read this issue: https://github.com/Jondolf/avian/issues/441
Hmm... needs more design work, but I got an interesting idea for component-driven collision layers
Collision detection and spatial queries use bitmasks stored in CollisionLayers to filter colliders. This needs to use bitmasks and not e.g. queries for perf reasons.
But in an ECS engine, the natural way to tag and filter entities is to use components, and it has always bothered me that we don't take advantage of this. For such a core feature, I feel like bitmasks should ideally be just an implementation detail, and the user-facing API should use a more component-driven approach.
Instead of forcing users to explicitly specify the CollisionLayers, what if we had a way to register components as physics layers:
// We could support tuples to make this less verbose.
// Mayyybe we could also do this automatically at runtime?
// Note: There is a limit of 32 layers! (but we could bump it up to 64)
app.register_physics_layer::<Character>();
app.register_physics_layer::<Enemy>();
app.register_physics_layer::<Terrain>();
This would automatically assign a number to each component for the corresponding physics layer.
Then, you could add a component like InteractsWith to specify which layers an entity can interact with:
commands.spawn((
// Belongs to `Character` layer
Character,
// Interacts with `Enemy` and `Terrain` layers
// TODO: How do we support "interact with everything *except* X, Y, Z"?
InteractsWith::new::<(Enemy, Terrain)>(),
// ...
));
Internally, there would still be a CollisionLayers component with bitmasks, but the component-driven API would automatically toggle the membership bits based on the existence of the layer components and the filter bits based on InteractsWith, using hooks or observers.
We get several pretty convincing benefits:
- The collision filtering API can be fully component-driven. You can query for collision layers, attach observers, respond to layers being added or removed, or do anything else you typically do with components. Even define bundles of layers or insert layers as required components!
- No need to have separate marker components and layer definitions; the marker is the layer.
- No need to think about bitmasks, layer numbers, or conflicting layers at all (unless you directly mess with the bitmasks). Collision layers are guaranteed to be non-overlapping at the type-level.
- External plugins can define their own layers without risking conflict with user-defined layers.
I'm not 100% sure yet how InteractsWith would be best implemented, but I'm sure it should be doable in some way
idk if scattering the code like that is a good idea
Scattering how?
The ideal workflow for this is (1) just define a marker component, which you typically already have anyway, and (2) use InteractsWith/CollisionMask/whatever to filter which layers an entity can interact with
doesn't even need to be a marker component
Right another cool idea: You could specify some visibility component as a physics layer, and then you're automatically able to filter collisions based on the visibility of an entity (assuming visibility is controlled by the component's existence)
e.g. right now i have 1 place where i have all layers, filters and masks
i can easily find everything that uses them, and if i add a new functionality that requires updating layers i don't have to search for everything spawned that uses it
You could still do that with this approach if you wanted to, just have all the layer components in that 1 place, maybe define bundles to group and compose them
And CollisionLayers would also still exist for people who do want to use it directly, the component approach would be optional (but probably the encouraged API if we implemented it)
that sounds 10 times more complicated than it needs to be, if i needed the components that match layers i'd rather have it the other way around
something like required components, but for layers ๐ค
I guess I don't really understand what practical use cases wouldn't work fine/better with this. I would imagine that the vast majority of uses for collision layers is tagging entities based on "what kind of entity is this?", e.g. Character, Terrain, Water, Prop, Interactable, Enemy... In all of these cases, it would make sense to have a marker component on that entity anyway, and especially for dynamic behavior where you might change layers, e.g. a powerup that makes you Invincible, you'd almost definitely need to add/remove components to reflect that change in behavior
wdym, all my game logic like this does things without adding/removing any components
Not to mention this would probably work better with Blender/Blenvy, you could just tag meshes with components and then filter collisions or spatial queries based on that
yeah, i'm erring on the side of caution to avoid moves too
How do you mark an entity as invincible without a marker component (unless you use a bool or an enum for toggling it I guess)
or do you do status effects as entities
probably visibility component watching for changes
ah sry I meant invinsible, as in enemies can't hurt you or touch you
oh, invincible?
right yeah with a c ๐
i have a toggle for that in the damageable component, nothing needs to query for that
This, the status effect entity sets a bool to disable taking damage or remove relevant layers
but it's a common mechanic in my case, i can see it being useful in ultra-rare cases, but in that case there's no way i'd put it on layers
Usually I don't actually modify things like layers though, because not having counters tends to introduce subtle bugs
If I did need to I guess I could have a "removed layers counter" component that's just always there
adding a required component if it's missing when layer is toggled on would be really neat though
but i also have a tag enum doing the exact same thing so idk
the entire thing definitely needs a cleanup, but that proposal sounds like it'd just add more to the mess
I just feel like it's a pretty big missed opportunity to not support efficiently filtering spatial queries or collisions based on components in an ECS engine, but idk maybe in real games directly using bitmasks is better ๐คทโโ๏ธ
it is, but you're looking at it from wrong angle
in some cases i'm already getting layers in query and checking which layer i actually hit, you could just streamline that instead
that's not filtering by components
I have an issue with bitmasks, I need to filter out collisions of a car with its wheels, but not for different cars
you can exclude entity
I feel like filtering collision events directly will be slower
not for collisions unless you make a custom collision hook for it
ah
i didn't touch collisions directly but it's definitely counter-intuitive if they happen between entities that filter each other out
I also have an issue with objects with high angular speed(wheels) getting buried in the ground
Collision events looks correct, and increasing amount of solver substeps help a bit
On the main branch you could ignore collisions against specific entities with a collision hook roughly like this:
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
PhysicsPlugins::default().with_collision_hooks::<PhysicsHooks>(),
))
.run();
}
#[derive(Component)]
#[require(ActiveCollisionHooks::FILTER_PAIRS)]
struct IgnoredCollisions(EntityHashSet);
// Define a `SystemParam` for the collision hooks.
#[derive(SystemParam)]
struct PhysicsHooks<'w, 's> {
query: Query<'w, 's, &'static IgnoredCollisions>,
}
// Implement the `CollisionHooks`.
impl CollisionHooks for PhysicsHooks<'_, '_> {
fn filter_pairs(&self, entity1: Entity, entity2: Entity, _commands: &mut Commands) -> bool {
if let Ok(ignored1) = self.query.get(entity1) {
if ignored1.contains(entity2) {
return false;
}
}
if let Ok(ignored2) = self.query.get(entity2) {
if ignored2.contains(entity1) {
return false;
}
}
true
}
}
@vestal minnow do you think it's possible to register components in a similar way to required components, but 2-way with layers?
e.g. register<Damageable>(10);
if i have layers that include layer 10, but component wasn't added = add default
if i have component, but layers don't include 10 = toggle it on
when i look at it from perspective of catching bugs then it makes total sense to do it, but i'm really not sure if that should be the main way to deal with layers
If we make CollisionLayers an immutable component, then we could handle the 2-way synchronization via hooks or observers
But I don't want to do full table scans every frame to detect all CollisionLayers components that may or may not have changed
that's why i said from perspective of catching bugs, only call checks when something is spawned instead of changed
i can totally see myself being an airhead and forgetting one or the other, then spending an hour hunting down the bug
This would also require all registered layer components to implement Default, unless we really over-engineer this and support custom constructors require-style
i don't see defaults being a problem when it's only 31 components at most
It's mainly a problem if for whatever reason you wanted to register some external component that you don't own, and that doesn't implement Default. But yeah that seems so niche that it shouldn't really be a problem
(also we might want to make CollisionLayers an immutable component regardless, since we need change detection on it to handle collision stuff)
registering link between component and layer is basically 1 step towards your proposal, but much smaller and everyone will have more time to test it and decide if that should be the main way to deal with layers
For my spaceship building game, I'm interested in implementing a localized physics system where entities inside a moving ship behave as if the ship itself isn't moving - essentially creating a self-contained reference frame. Is this approach feasible, and how might I implement it?
About collision filtering. Avian should be compatible with open usd/ gltf.
Upcoming gltf specs mentions this :
what about ousd?
state of the art for the collisionlayers blender use cases is
- custom component hook/observer to set CollisionLayers from custom Marker/enum-data Components. afaik "entity tagging" like you mentioned (
Terrain, etc) is what I've seen used the most (An enum with a list of tags makes a nice UI), but that's partially motivated by usability. - presets (write only)
It seems like InteractsWith would still require a user-written hook/observer since it theoretically requires a new() call? I think the type arguments mean different types in the reflection data (and thus different options in blender) so default impls for them might work depending on what the underlying value looked like
For context, I just implemented collision layers this week. What you describe about having to use the bit mask and such did feel odd when I went through the docs. FWIW as someone who is still relatively new to Bevy and Avian, I like the look of this direction. It appears more idiomatic. My only comment would be if it still continues to be simple to use layers in spatial queries, but overall looks great.
bitmask is super simple, but docs doesn't explain them well
if you replace mask with a single bool it makes more sense
are you using PhysicsLayer or actual bitmask?
open usd filtering examples: https://openusd.org/release/wp_rigid_body_physics.html#group-filtering
It seems like InteractsWith would still require a user-written hook/observer since it theoretically requires a new() call?
So here I purposefully didInteractsWith::new::<Foo>()rather thanInteractsWith::<Foo>::new(). My idea here was that maybe we could makeInteractsWithfully type-erased, and the methods would turn the given bundle into a set ofTypeIds (orComponentIds? but I think that requiresWorldaccess) for each component, and then we could store that. Then a hook would run, mapping those types to bits based on the global physics layer registration, and boom, we have a mapping between components and layer filters
But I have very non-existent knowledge on reflection stuff so I don't really know for sure if it'd work until I try it
definitely curious to see if you can get it to work
It's simple if you're used to them, but I don't think this is necessarily true for people starting out. I remember struggling to understand them when I was originally learning bevy_rapier, only really understood them better when I implemented collision layers myself :P
the blender interface would just be the InteractsWith type then? so basically a marker from Blender's perspective?
not sure where Foo would come from
Hmmm yeah the blender interface for that would be tricky
Can confirm, that enum variant is what I have used for usability
Off-topic: @vestal minnow mind pinging me when you release a 0.16 compatible Avian? So that I can bump avian_pickup ๐
rapier didn't do a good explanation either though :p
I feel like layers like this in general are just hard to make work nicely with Blender without a designated UI
the only reason i understand them is because there was a good explanation for unity somewhere
exactly the same here ๐
and part of the reason why it was good is that unity's objects can only have 1 layer, which simplified explanation
which basically means it was just a bool
Sure, might take until at least the end of next week though... lots of Wappu stuff (May Day? it's a big thing for universities in Finland) and events next week, and I have to do lots of release prep still
if both membership and filter are true = collide, else dont ๐คทโโ๏ธ
but rapier and avian's multiple membership really complicate everything
Yeah no worries at all, the list of projects that need updating for me to actually use 0.16 is long enough that you have no chance of being the bottleneck, haha
(I'm just using the git commit on main right now ๐ )
Out of curiosity, what does your university do then? We don't really have special days for universities in CH, I think
yeah same, I just can't publish a package with a git dependency ๐
Pretty much every day of April has several (fully voluntary) student events leading up to Vappu (or Wappu as we call it), which is a Finnish holiday (May Day elsewhere in Europe) and for university students it kinda marks the end of the school year and the start of summer
Oh wow, that sounds cool ๐
though I still have one exam after it on the 8th of May but anyway
there's a lot of student culture associated with Wappu, especially where I live
The only "event" around summer we get are smaller queues at the cafeteria because more people are on vacation ๐
Yeah I don't know if other countries really have the same thing, in Finland may day is fairly big
Anyone who could have an answer? ๐
This seems difficult to do in an actually stable way, but I imagine you'd probably want two fully separate simulation instances, one for outside of the ship and one for its interior. They're not allowed to interact in any way. Like you suggested, all physics positions and velocities in the interior of the ship would be relative to the ship's frame of reference, and you'd then have some custom sync plugin to convert those local physics positions into world-space transforms
But this approach would likely require support for multiple physics worlds on Avian's side, which isn't there yet :/ I had a prototype using bushRAT's index queries, but that stalled so I haven't worked on it more yet
The same memberships + filters approach is in e.g. Box2D and Chipmunk2D too, and in many other engines it's even more complicated I'm pretty sure
I think PhysX's approach here is "lol implement it yourself in a custom GPU shader"
https://nvidia-omniverse.github.io/PhysX/physx/5.1.0/docs/RigidBodyCollision.html#collision-filtering
Thanks a lot for telling me
Jolt also has group + mask, but it also has custom "object layer filters" and filter tables and stuff... I'm not exactly sure how it works as a whole
you make interior separate from the ship, bury it somewhere inside a giant asteroid or a planet, and make a cubemap outside
Even for 2D game?
for 2d game it's even simpler, you don't need a cubemap ๐
you basically just make a portal that shows the interior, and rotate it however you want
I mean, considering that I use big_space, I could put it extremely far away
and everything on the interior uses a collision layer that doesn't include the collider that collides with exterior
Seems like a good solution ๐
Is PBMPM a future plan for Avian?
Considering it as well started from XPBD
for the layers thing: have a resource with an Any/DynHash-to-layer table, so you can mark a component as a collision layer or group of collision layers but still keep the ability to convert (newtype'd) custom ids to collision layers
based on my interpretation of the use cases:
- static, this type of object does/doesn't collide with that type of object (component hook to add CollidesWith, typeid-only layer registration)
- unique, this object does not collide with these objects (some struct with an entity or other id in it)
- dynamic, this entity does not collide with the blue team (the team marker struct, maybe
struct Team(usize))
I've been away from Bevy/XPBD for about 10 months. Wild how much has changed
Not in the near future at least, and if we did implement it, then it'd probably be it's own thing that just has two-way coupling with Avian.
And if I was to add some form of MPM support, I'd probably first look into integrating Avian with dimforge's wgsparkl and collaborating there rather than making my own thing from scratch
Afaik it uses MLS-MPM with CPIC for two-way rigid body coupling
Yep that's it, there's also a repo using bevy showcasing MPM usage
https://github.com/robkau/mlsmpm-particles-rs
I'll be making my own PBMPM in the meantime, thanks still
Ah cool, I don't think I've seen that one before! Looks like it's CPU-only though, while wgsparkl runs on the GPU
Interested to see how your PBMPM implementation progresses. I saw your earlier MPM post in #project-collaboration, looks really cool
I'll be sharing an update once it's done, if that could pick any interest who knows!
Hey guys, who already used Avian with multiplayer (Authoritarian dedicated server and many clients, like MMO)?
Please share you experience, what did you use, lightyear ?
@cinder summit @dreamy viper
I use bevy_replicon + bevy_rewind. Works pretty well overall now. There were a couple times when updates broke determinism, but Jondolf tends to fix those fairly quickly and provide workarounds.
-# Also, it's authoritative, not authoritarian
like the error says, you have conflicting Bevy versions
Hello everyone, I'm testing out Avian but when I uses it in conjunction with bevy_inspector_egui::WorldInspectorPlugin Im getting the above error, and unable to register Collider type due to it not implementing GetTypeRegistration.
I tried a quick search over documentations, but doesn't seem to have an answer bubbles up. Does anyone encounter this situation yet?
Sorry to bother again, but I took your kinematic example code and I would like to prevent the character from jumping when there is penetration in a slope, is there a way to just snap my character to the ground ?
@vestal minnow am I right by default in Avian there is not any BVH, AABB etc spatial hashing optimizations ?
And I need to implement it by myself ?
Avian has a BVH for spatial queries and uses some optimizations for the boardphase, though the broadphase doesn't use a BVH yet
I was just curious why when I use 20k invisible (w/o mesh/material) fixed colliders, FPS is 100-120, but when I use 30k colliders it drops FPS to 3-4
What is the order of the CollidingEntities component? If multiple Entities are within my collider?
I'm assuming its the add order of entities? as in the order they enters the collider ?
It currently stores an EntityHashSet. I believe the iteration order for that is arbitrary since it's basically just a HashSet
We might want to change that to just a Vec though ๐ค
or maybe a UniqueEntityVec in Bevy 0.16
Ahh I see, in that case, idk, is it going to be a performance concern? Switching to a Vec?
Since the usefulness of ColldingEntities might require futher processing like calculating distance, ranking by health, ... That it doesn't really matter, as long as the collision detection is performant?
Avian itself doesn't use CollidingEntities at all, it exists just to allow users to efficiently query for which entities a collider is touching. Switching to a Vec should make iterating over the entities in user code a bit faster and make the iteration order stable, but make get or contains lookups and removing entities from CollidingEntities slightly slower. Either way the difference there should be pretty minimal
For an mmo I used lightyear due to the it is pre-featured room management
Whoa, we passed 2k stars! ๐
We can't properly derive Reflect for it since the stored SharedShape from Parry doesn't implement Reflect. But I guess we could use #[reflect(ignore)] on those so that the type is at least partially reflected and can be registered etc.
it just wouldn't be very useful since you still wouldn't get access to any of the actual shape's data
do you have demo/example ? Or its private repo
oh noo it wasn't just this PR that breaks determinism, the constraint generation optimization PR also broke multi-threaded parallelism
and CI apparently doesn't use the parallel feature so it didn't catch it
mm now can I fix this somehow or do I have to revert that PR
I think it should be fixable in theory
Oh right the fine print for ThreadLocal::iter_mut says "Returns a mutable iterator over the local values of all threads in unspecified order."
I guess I need to sort that somehow
Private
But I think there is a few videos of it in this server
why did you choose to use lightyear and not just "bevy_replicon + bevy_rewind" ?
bevy_rewind hasn't had an official release yet so that's definitely a big factor ๐
Hmm because replicon didnt have rewind back them
But tbh my sincere opinion is lightyear has more features and is newbee friendly. Although it does lack a little on stability and perfomance
I think the main thing here is going to be the different networking approaches either way. Lightyear is more FPS-style, while bevy_rewind is inspired by Rocket League
There is also the factor that they have different prediction styles
The rocket league approach is notably more expensive, but also necessary for doing crazy things with physics (most games don't want this when online though)
what do you think, for my 3rd person MMORPG case, lightyear will be better choice?
since I dont need that rocket league crazy physics
Lightyear approach might work, might also be possible to build some of your own stuff on bevy_replicon ... Your concern will probably be performance for a real MMORPG so it's probably worth looking at it from that angle too
well it works if I just ditch the thread-local buffers for contact constraints ๐ฅฒ I'd really prefer not to do that tho
are you going to do a release of rewind once everything is on 0.16?
Yes
I was already on 0.16.0-rc, so it shouldn't be too hard, but it is slightly behind on replicon updates iirc. And I'll have to retest my approach to replicating avian in specific ๐ค
Just wanted to chime in that cylinders jitter like crazy. using Collider::trimesh_from_mesh(&Cylinder::new(...).into()) instead of Collider::cylinder changed things from a jittery mess no matter how high I increased angular and linear damping, to being completely stable even with entities piled on top of each other with no damping.
I'm getting some "okay" behavior but occasional jittering/jumping with some cylinder stacks
What dimensions are your cylinders using?
1.0 tall, 0.2 radius
they randomly gain significant velocity every half second or so, enough that they basically can't be stood on end
doesn't matter what they're on top of
even static cuboids
like just a single one is completely unstable and will never sleep
tried fixed and not fixed schedule, 60fps 120fps, changing density, damping from 0 to like 10 or 20
if this is just me, I can share a repo, but from searching old messages, it looks like this is probably a general issue? I'm not doing anything odd I don't think
It feels like more of a Parry issue (the collision detection lib that both Avian and Rapier currently use) if it's a specific shape, in this case a cylinder
I wonder if a thin long shape like a cylinder is just kind of a pathological case for GJK ๐ค
Iirc parry always had open issues for cylinders ๐ฅฒ
I vaguely recall cylinders in general being challenging for robust collision detection
that makes sense tbh
I don't have the energy to investigate further atm, but if this is common, it could be worth adding a note to the Collider::cylinder function? or even just having it use a tri mesh internally? I even noticed issues with cubes on a very wide, very flat cylinder disk
like at the time I just thought avian had very jittery physics
but now everything is almost surreally stable
hmm maybe this in rapier is also related
https://github.com/dimforge/rapier/issues/305
(because of Parry)
that looks extremely similar to what I was seeing
like random little hops every few moments
not enough to topple more stable shapes, just enough to keep them from sleeping, but enough to topple something 1.0 tall, 0.4 wide
well now I can't seem to replicate the little jumps but instead they're doing this:
anyway I'm gonna go back to trimeshes, but yeah, I guess parry's cylinders have some issues
You could also try a convex hull instead of a trimesh, it should be faster and more robust against clipping into things since trimeshes are hollow
Made a fix for this... Non-deterministic constraint order -> just sort them afterwards lol
https://github.com/Jondolf/avian/pull/712
Not the ideal solution I would've liked, but works well enough for now
Thanks! I'll give that a shot
Hey, I read into main's docs...this has probably been asked 10x, but I was wondering if there's some easy way to calculate, for an object, what the next object it is most likely to collide with. Constraints are: no rotation, perfectly elastic collisions, no friction, perfectly linear movement, no gravity
I couldn't really find much about this other than the new triggers (which are awesome btw). Pong in other words hahaha
You could do a shape cast from the current position to the next position predicted based on velocity
Cool, I'll follow the lead. Thanks!
๐ฅ
(not equivalent to merged PRs, especially in early bevy_xpbd days I did more commits directly on main)
this is so fire holy sht
been missing out
I've been working on this asteroids shooter prototype lately and decided to port it from rapier to avian, but i'm getting lower performance. Is this to be expected and is there anything that I can do to improve this? I'm already using circle colliders for the fragments so i'm not quite sure how else I can optimize it.
it's expected, but it's slowly getting better
I'm hoping that 0.4 will be a huge perf upgrade with all of the SolverBody stuff and hopefully many other optimizations (simulation islands please) landing
Yes, simulation islands please ๐
I'll have a lot more time to work on it too since I'll have a long break from uni starting mid-May
Also Jondolf you accidentally unearthed a major problem with my rollback crate by not re-adding the pointless PartialEq derive on ContactGraph (it was on Collisions) ๐คฃ
oh lol, yeah I thought it feels dumb to compare two entire contact graphs for equality
Yea, I don't actually need to do that, Rust is just trolling me with the lack of negative traits and specialization
This trait bound makes no sense, but I have no idea how I can figure out "Is there a function to compare this type" without the trait bound ๐ค
fn register_predicted_resource<T: Resource + Clone + Debug + PartialEq>(
&mut self,
) -> &mut Self;
hi, have any thoughts about why 20k cuboid colliders vs 30k ones is 120fps vs 4fps ?
No meshes, no materials, just fixed colliders
"Fixed" as in all RigidBody::Static?
yes, sorry, misstyped
I spawn them by this:
for _ in 0..20_000 {
let dimensions = [
rng.random_range(1.0..3.0),
rng.random_range(1.0..3.0),
rng.random_range(1.0..3.0),
];
commands.spawn((
RigidBody::Static,
Collider::cuboid(dimensions[0], dimensions[1], dimensions[2]),
Transform::from_xyz(
rng.random_range(-180.0..180.0),
0.5,
rng.random_range(-180.0..180.0),
),
));
}
Not sure why the difference would be so drastic, other than if a fixed timestep takes longer than 15.6 ms with the default rate of 64 Hz, perf might dip pretty significantly as it then needs to try and run multiple physics ticks per frame to keep up
What if you run physics in e.g. PostUpdate? (for a variable timestep)
PhysicsPlugins::new(PostUpdate)
will try now. Btw, should I change these 2 too?
TnuaControllerPlugin::new(FixedUpdate),
TnuaAvian3dPlugin::new(FixedUpdate),
I think so
longer than 15.6 ms
hm, makes sense, with 20k colliders its ~14ms
Also Avian by default runs in FixedPostUpdate, so those should probably normally be in FixedPostUpdate too
nice, with just changing PhysicsPlugins::new(PostUpdate) now I have 45 FPS with 30k colliders
Are you using 0.2 or the main branch?
0.2.1
Should I try main branch?
On the main branch there's a PhysicsDiagnosticsUiPlugin (requires diagnostic_ui feature) that shows you how long different parts of the physics step are taking, I was just curious about some profiling info there
I can probably roughly reproduce it locally with your setup though
Watch it be all BVH build times ๐
Oof
The broadphase? But we early out on static - static right? 
what is broadphase ?
The broadphase is the part where shapes that could overlap are checked based on bounding boxes, it's an optimization to reduce the number of more precise collision checks necessary
Wait, if it's just on the innerloop that could be a 30k * 30k loop of early exits still
maybe the issue that I spawn static colliders and half of them spawn partly inside other colliders?
I don't think we even get to the step of checking the AABBs, because static - static collisions can always be discarded
We found that out the hard way when I accidentally made all my colliders spawn at 0, 0, 0 and the FPS went from good to seconds per frame ๐
I mean this
The inner loop starts at outer_index + 1, and also the inner loop can break if aabb2.min.x > aabb1.max.x (since the AABBs are sorted along x) so it's not quite that many, but yeah it's still a ton
Oh right ... But that does stop us from just doing if rb1 == RigidBody::Static { continue; } in the outer loop right?
And it tests overlap along y and z before the static-static early out
We can't do that in the outer loop since the inner loop could still have active bodies
More reasons for a BVH broadphase
Or hmm yeah if we don't break in the inner loop then I think we could do that, but then we'd need to check for duplicates for dynamic-dynamic collisions I think?
and we'd probably get more iteration overall
Yea, we'd be trading "everything is static" perf for "everything is dynamic" perf
Yeah BVHs should eliminate this overhead pretty much entirely, especially if we have dynamic and static trees separate
Build overhead would be zero for the static tree when it doesn't have changes, and if there are no active bodies, we don't need to do any collision tests
-# If only there was a branch somewhere that starts using OBVHS in avian already
Actually I guess there are 2 branches that use OBVHS out there
I have an old branch somewhere
iirc that one old demo with full rebuilds was like 95% functional, but the newer one doing it "correctly" with incremental updates and enlarged AABBs and "moved proxies" etc. is still very WIP and broken
(the idea with moved proxies is that the broad phase only needs to traverse the BVH for colliders whose tight bounding box moved past the enlarged bounding box, meaning we can completely skip broad phase tests for dynamic bodies that aren't moving much)
Nice beats ๐ต
Awesome, I'll keep that in mind and I'll consider making a donation
is EventReader<Collision> changed for bevy 0.16?
because it says cannot find type Collision in the scope
It was removed since it had some overhead and duplicates a lot of data, I suggest just using Collisions and iterating over that
ah i see, thank you
Sorry to poke again! Is there any way to get around using the physics calculations on collision, or even like momentum/inertia/rotation in general, but still get access to the SpatialQuery::cast_shape? or are those tightly integrated? Ideally all I would want is to use Colliders for querying...I was reading through the plugin list, but I haven't yet found a working combination
i found a pretty interesting bug. my crosshair have sensor collider, and ball have disabled rigidbody. when player shoots and two colliders touch eachother, game logs out "nice" (you can see on the vscode terminal) and ball gain his rigidbody and starts jumping. for some reason when they touch eachother from left side, no collision event happens
If you just want spatial queries, not giving anything RigidBody should cause the rest to at the very least do basically no work I think ๐ค
sorry for the minecraft music btw
I did actually encounter a couple crashes when not loading the physicsy bits but still loading SpatialQueryPlugin, so it's probably just a bug
oh wow, good idea! thanks!
how to add collider to gltf model (like ground) in proper way?
lmao, didn't even notice that captured my pc audio
You can just add it to the entity with the scene root
if you need it to be based on the mesh in the model, you can extract the mesh and use the collider::from_mesh constructors
There's ColliderConstructorHierarchy for doing this automatically, FYI ๐
A component that will automatically generate Colliders on its descendants at runtime. The type of the generated collider can be specified using ColliderConstructor. This supports computing the shape dynamically from the mesh, in which case only the descendants with a Mesh will have colliders generated.
that's super useful, I was using asset labels and extracting stuff manually
commands.spawn((
SceneRoot(assets.load("character.gltf")),
ColliderConstructorHierarchy(ColliderConstructor::ConvexHullFromMesh)
));
My player just stick to the wall at the first collision
fn move_player(
input: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut LinearVelocity, With<Player>>,
) {
let mut velocity = query.single_mut();
let mut input_vec = Vec2::ZERO;
if input.pressed(KeyCode::KeyW) {
input_vec.y += 1.0;
}
if input.pressed(KeyCode::KeyA) {
input_vec.x -= 1.0;
}
if input.pressed(KeyCode::KeyS) {
input_vec.y -= 1.0;
}
if input.pressed(KeyCode::KeyD) {
input_vec.x += 1.0;
}
velocity.0 = input_vec.normalize() * 200.0;
}
commands.spawn_empty()
.insert(Name::new("Player"))
.insert(Transform::from_xyz(0.0, 0.0, 0.0).with_scale(Vec3::splat(8.0)))
.insert(player_image)
.insert(AnimationTimer::from_fps(4))
.insert(GameMarker)
.insert(RigidBody::Dynamic)
.insert(Collider::rectangle(8.0, 8.0))
.insert(Player)
;
commands.spawn_empty()
.insert(GameMarker)
.insert(RigidBody::Static)
.insert(Collider::rectangle(1000.0, 8.0))
.insert(Transform::from_xyz(000.0, -500.0, 0.0))
;
.add_systems(PhysicsSchedule, move_player.before(PhysicsStepSet::First).run_if(in_state(GameStates::InGame)))
Huh ... I wonder if insert chaining like this would mess with any of avian's logic ๐ค
Any reason you don't do uh ...
commands.spawn((
Name::new("Player"),
Transform::from_xyz(0.0, 0.0, 0.0)
.with_scale(Vec3::splat(8.0)),
player_image,
AnimationTimer::from_fps(4),
GameMarker,
RigidBody::Dynamic,
Collider::rectangle(8.0, 8.0),
Player,
));
Not really but changing it doesnt fix the problem
try running move_player in Update, just to see if it changes something?
doesnt change anything
might be an issue with some other part of your code then? what you posted looks pretty similar to stuff I'm doing
Tried loging the linear velocity, its like it is getting stuck in the wall and cant move after
gravity?
Well those NaN values are definitely bad at least ๐
nvm not gravity, the velocity is pretty close to 200 until it breaks
oh!
you need to call normalize_or_zero or whatever it's called
(0,0).normalize results in NaN IIRC
NaN velocities would cause issues I'd imagine?
A 2-dimensional vector.
Yes, NaN +/- anything is NaN
Yes that was it, thank you ๐ฅณ
heck yeah, np, I've almost done the same thing lol
theres also a clamp_length function that's useful for gamepad input
clamp_length_max*
Lol can you tell I type 'c' 'l' 'tab' to autocomplete
Any reason why setting an entities Transform would just not work? I suspect it's something to do with syncing or something like that
I remove the RigidBody component and then insert the new transform in a command
ok yeah nvm, removing Position and Rotation fixed it
I'm a little confused why another part of my code does work even though I don't do that
does syncing differ between children of static and dynamic bodies?
Ok, so there are still some parts I don't understand, but it seems like some part of avian does something to entities that have e.g. position/rotation and maybe velocity if they have either a RigidBody OR a Collider. The docs mention avian treating entities with RigidBodies as being in a flat hierarchy, but there seems to be at least some behaviors that are predicated on colliders even in the absence of a RigidBody
admittedly this is on entities that had a RigidBody and I removed it
What are simulation islands? ๐ฎ
Island management is a fundamental low level feature of physics engines and can have a big impact on solver design and performance. This was one of the first problems I decided to work on for Box2D version 3 (v3).
Since I began working on v3 Iโve been comparing several algorithms for island management. My goal has been to make island building ...
required for proper sleeping and basic constraint solver parallelism
Proper sleeping that doesn't make my prediction cry
I snatched the avian.rs domain now ๐
I was originally thinking of avianphysics.org, but saw that avian.rs was available and it looks nice
might start working on a website for Avian at some point, it'd have the news/announcements + web demos + maybe a getting started guide
Is there any plans on making avian have Fixed-point (instead of floating point) mode for determinism by any chance? I know that it currently relies on other crates like parry and therefore that might not be something that can even be considered now.
Unless you need position independence, I don't think fixed point should be necessary
fixed point doesn't really have anything to do with determinism beyond making behavior the same at different positions in the world
afaik in general it can be much more expensive than floating point math, and I don't know how well SIMD would work with it
so no, fixed point math isn't really in the plans at the moment since I haven't really seen any convincing reasons for it
floating point math is fine for cross-platform determinism (provided you use e.g. libm for non-deterministic operations), and for far-from-origin scenarios we'd ideally have support for big_space
is there a way to offset a collider without spawning another entity?
You could use Collider::compound with a single shape with the given offset, but in general I'd recommend just using a child entity
Some collider types can also encode an offset, like capsules
I still really like the idea of Translated, Rotated, Scaled, and Transformed wrappers so you can just do shape.translated(my_translation), I started writing up a proper design doc for it a while back
It'd remove the need for all the _local versions of methods, and could theoretically get rid of some unnecessary transformations while also making things more generic over the coordinate system
I'd also like to try if we could fully support non-uniform scaling with stuff like shearing without making discretized approximations via meshes, I think technically GJK+EPA should work with it?
there's a reason I'm making peck, I want to experiment with these sorts of things :P (and get rid of Nalgebra / use bevy_math)
in the process of updating to 0.16 and using latest avian... did something change with the collision events? My EventReader<CollisionStarted> seems to not be reporting anything ๐ค
ah I should have searched
Yup collision events are now opt-in via the CollisionEventsEnabled component
sorry Jondolf lol
np haha
I'm once again working on a KCC slowly but surely, keep running into that annoying issue where a combined pass gravity and movement causes nasty ghost collisions but having gravity on a separate pass makes managing gravity properly painful
You have any thoughts Jondolf? How does avian internally deal with gravity? Do you join it in the velocity or is it kept separate?
The ghost collisions in particular are showing themselves as sort of trapping the player, not quite inside the mesh but they can't overcome gravity to continue moving along the plane.
Having a skin width doesn't really solve this issue, since I think it's a math problem I'm approaching in the wrong way. You're not inside the floor, but you're definitely failing to move because of rejecting gravity along the plane of collision
Gravity is just added during velocity integration in the substepping loop, same as external forces
Also wrt using linearvelocity for KCC (something you mentioned wanting a while back), it'd probably mean doing the KCC steps during the integration phase too
Since otherwise it's getting applied twice since Avian will still move a kinematic body according to linearvelocity causing you to clip through stuff
Avian is now a Serbian project, confirmed ๐ท๐ธ
where should i get the manifolds/collision normals from with the new CollisionStarted event stuff on main?
The Collisions system parameter
thanks
docs of course aren't on docs.rs yet, but... see docs here I guess lol
https://github.com/Jondolf/avian/blob/main/src/collision/contact_types/system_param.rs
A detailed look at how we made our custom raycast-based car physics in Unity for our game Very Very Valet - available for Nintendo Switch, PS5, and Steam.
BUY NOW!! https://toyful.games/vvv-buy
~ More from Toyful Games ~
- Physics Based Character Controller in Unity: https://youtu.be/qdskE8PJy6Q
- Instant "Game Feel" Tutorial: https://youtu.be/...
Update: a larger skin width was the answer
@fallow pike you may also want to look into bevy_tnua
Seems 0.125 resolves the issue mostly
Discovered it while investigating some other engines KCC impls
this is what I followed.. I keep feeling like it got me 85% of the way there and I keep finding scenarios that are weird and am unsure if it's that the video was missing some information
to be clear, it is an excellent video
describe your issues in detail then, it might not be a niche problem
one that's getting me right now is that at high speeds it seems like the steering forces cause the car to suddenly spin out and go flying (even without attempting to turn)
I think it's stuff like that though.. as I start pushing some limits, I need to add more logic to handle stuff.. like... something that scales turning at low speeds vs turning at high speeds.
what are you using for ground, and are your wheels ray or sphere casts?
wheels are ray, and the ground varies but most of the time it's a plane.
What joint i will need to use?
Soo manu joints
What to pick
I didn't use any joints
I will say that what I have right now works well enough at the speeds I'm running. I probably will dig into it more when I get further along with my game
plane as in trimesh collider?
yeah, I'm using trimesh_from_mesh
then that's probably the main culprit ๐
try box or half-space, i had a bug where instead of slowing down i sped up to mach-10 and it worked fine (on half-space collider)
ah, I'm creating a world mesh in blender and importing it and creating the collider from it.. does that work for concave meshes?
#1351602963352911963
convex meshes seem to be problematic in every physics engine
yeaaaah after I get 0.16 working I was going to start using that
how is this commonly handled? Like, a simplified collision "map" that is made of many non-trimesh colliders?
convex decomposition, or ideally using primitives
if you pay attention to it, you can easily notice convex decomposition in most games
modular kits are usually primitives where it's possible
like, where it feels like there's a bit of an invisible barrier around things?
just invisible barrier could be primitive, but generally yeah, e.g. bucket that you can't put anything into
Why mass not works?
I set like 10000 density and same results with 1
Mass, or bundles
Not working
@vestal minnow
Why is the crosshair a sensor collider? This looks like something I'd do with a ray cast
if you're just shooting at a target
i would use raycast if it was 3d
but i didnt think i can raycast for 2d
but
hm
yeah no, i have no idea how to raycast for this situation
you can use SpatialQuery::point_intersections
Can someone help? Only properties it have its rigid body dynamic and mass 10000000.0
but yeah that sensor problem still looks a bit strange, I'd maybe log CollisionStarted events to see when the intersection gets detected
(or CollidingEntities)
What components does your rigid body have?
Rigidbody::Dynamic and mass 100000
Oh sory i also forgot
It has collider
Rectangle 50 : 30
Make sure you have PhysicsPlugins added, and you might also want the body to have a Transform, though I think that's technically optional
Ehen i running its just ignores mass
And falls very very slowly
your dynamic body is 30 units tall but gravity is -9.81 by default
use .insert_resource(Gravity(Vec2::new(0.0, -98.1))) or whatever feels good
probably even higher
Is it normal?
Like i want more realistic physic
Or also why that happends
Any mass what i insert gravity eat
9.81 m/s^2 is the average magnitude of the gravitational acceleration near Earth's surface. This means that the linear velocity is increasing downwards by 9.81 m/s every second. In your case, the dynamic body is 30 units tall, which is like a 30 meter tall building, so an acceleration of 9.81 m/s^2 looks tiny for it when zoomed out like this.
Are Avian Sphere colliders filled or hollow?
filled
Is there a way to do a hollow sphere?
I want to make a gatcha ball with something inside
like this
Ah yes, the hollow sphere ... The non-trivial thing to implement that is somehow easy with SDF collisions #off-topic message
You can either scale down the shapes so that their sizes are closer to real-world values, e.g. a character might be 1 or 2 meters tall, and then change the scale of the 2D camera's projection to zoom it in a bit. Or if you want to use pixels as units like you're currently doing, you can scale the gravity and any other forces you might apply to match the scale of your objects
For "realistic physics" it's generally easier to work in SI units (meters, kilograms, Newtons)
In which case you'd scale the camera in 2D (since Bevy's 2D camera defaults to 1 px = 1 unit)
A trimesh, or some compound shape of convex shapes that approximately match the boundary of the sphere
Sounds complicated ๐ฌ
collision detection algorithms generally don't like concave shapes (excluding Nise's SDF colliders)
I haven't looked into those SDF colliders. Do they integrate with the rest of Avian?
No (or not yet at least :P) it's just something Nise has for their own game
Trimesh it is then ๐
It does integrate with avian, and this example lives outside of my game, but it is definitely not ready yet ๐
For one the new version is largely untested, so I'm pretty sure there are flipped normals and points everywhere ... But then also it's missing impls between types of colliders, and there are currently no spatial queries at all
you could use a spring/distance joint and limit distance ๐ค
That should work for my case
I tried increase gravity but mass still dont works
They fall at the same rate ... That's how gravity is supposed to work, right? right?????
yes
I also tried different forms
what are you expecting to happen here?
It sounds like you want air resistance (aka drag)
Thatโs how it works ๐ https://en.m.wikipedia.org/wiki/Galileo's_Leaning_Tower_of_Pisa_experiment
Between 1589 and 1592, the Italian scientist Galileo Galilei (then professor of mathematics at the University of Pisa) is said to have dropped "unequal weights of the same material" from the Leaning Tower of Pisa to demonstrate that their time of descent was independent of their mass, according to a biography by Galileo's pupil Vincenzo Viviani,...
Oh man, OBS exist, you don't need to film with your phone XD
Ok
But why
I think all OS now have a record function in their default screenshot app ๐ค
Because thatโs how real-life gravity works
You can have drag however, which is when air stops certain shapes from falling (e.g. a feather)
If you want a proof, then according to Newton's law of universal gravitation, the gravitational force acting between two objects is
F = G * (m1 * m2) / r^2
where m1 and m2 are masses, r is the distance between the centers of the masses, and G is the gravitational constant.
If m1 is the Earth and m2 is your object, based on Newton's second law we get
m2 * a2 = G * (m1 * m2) / r^2
Now we divide both sides by m2, and we get the acceleration caused by gravity for our object
a2 = G * m1 / r^2
Therefore the acceleration of the object only depends on the mass of the Earth and the distance between the center of mass of the object and the center of mass of the Earth. These are approximately constant for all objects near the surface of the Earth, and the mass of the object itself has no effect.
And yes the object also pulls the Earth towards itself, and this force is larger the greater the mass of the object is. But still the acceleration for that object is the same in that point in time, and unless you're doing orbit simulations or something, the force pulling Earth is insignificant enough that you don't need to take it into account
Did you just erase m2 left and m2 / r^2 right ?
both sides have m2 as a factor so we can just cancel those out
Ok I'm dumb, I was thinking like it was addition, so dumb of me
hi, interesting perf issue. What do you think? Or is it normal because of ton of debug gismos ?
I use ColliderConstructorHierarchy for my gltf model
that looks like way too much detail for the collider
probably I dont need to use ColliderConstructorHierarchy for original gltf model and I need to add some simpler layer to it
I mean CollisionLayers
you should have a simplified version of the mesh for the collider with waaay less triangles
can I do it inside the same gltf? Or I need to add a separate entity as a parent for real gltf one?
btw, even with such level of detail for the collider, its still 120fps w/o debug gismos hehe
what ColliderConstructorHierarchy mode are you using
ColliderConstructorHierarchy::new(ColliderConstructor::TrimeshFromMeshWithConfig(
TrimeshFlags::MERGE_DUPLICATE_VERTICES
| TrimeshFlags::DELETE_BAD_TOPOLOGY_TRIANGLES
| TrimeshFlags::DELETE_DEGENERATE_TRIANGLES,
)),
mesh detail doesn't matter if there's nothing in the aabb
you could try a convex hull instead of the trimesh unless your meshes in that glTF have a lot of concavity
The gizmo perf probably sucks since we're still using Bevy's immediate-mode gizmos, 0.16 got retained gizmos which should perform much better but we haven't switched yet
why? Whats the diff?
solid, fewer polys
Trimesh is the exact mesh, convex hull is like a simplified convex blanket around the mesh
You can use Blender to place an invisible simpler model in the gltf alongside the mesh
Then only provide a collider for that simple mesh
yeah I thought about it, Also I remember you used bevy_trenchbroom in Foxtrot game and probably did the same (invisible simpler model) there?
Nope, but good guess!
The level itself is already just cubes, so those are just convex hulls. For most props, convex hulls are enough as well. The chairs are heavily concave, so I use trimeshes for those.
The chair meshes as still fairly simple detail-wise, so I didnโt bother with creating simpler ones for performance. But if I noticed a dip in performance when placing too many chairs, I would have created those simpler proxies ๐
Has anyone seen something like this before? When viewing the rectangular collider on the player models left arm while the playeris running, the collider is lagging behind the arm's mesh (you can barely see the mesh it's like 0.4 alpha base material but that is in the correct position.) I'm wondering if it's just the physics debugger's visualization that's lagging or the actual collider?
Some sample code...
commands.entity(entity_leftarm_with_mesh).insert((
ColliderConstructor::ConvexHullFromMesh,
CollisionLayers::NONE,
Sensor,
));
Am I right that convex hulls works only for cuboid models?
And if I need any other, I have to add invisible simple model and use trimeshes?
this is convex hull for my ground model
Not very good solution)
From what I've been reading I thought you should use a Trimesh from Mesh for something like a static ground/terrain mesh.
@half ruin
yes, buy not for real model and for simpler invisible version?
@vestal minnow btw, just saw this issue, is it my mistakes in controller setup, right?
I don't think you need a simpler invisble version when you're working with a static body and trimesh collider. I mean it's still a little bit heavy but it's not a dynamic geometry which means it's a low cost compared to something that is recomputing new geometry on all the vertices every iteration of the engine.
I'm sure you would still see a little less load though if you were able to create an invisible version that has simpler geometry but I don't think it's necessary - atleast from how I've been understanding it.
It works for models that can afford the inaccuracy. For example, if you have a mug, you probably donโt need to have collisions inside of it. Or for a bookshelf, you probably donโt need to have collisions inside of for each book in detail.
Just decide what is and isnโt important to reflect in you collider ๐
Yeah there you will probably want a simpler proxy collider mesh
Though again, depends on your scene
For the group itself, trimesh is probably alright, doesnโt look like that many triangles
Itโs just that building really that is a problem
yes, there definitely needs to be a simplified proxy
ground with trimesh. I think its ok
The problem is mainly with dense geometry. Let's say you had a very detailed area with a hundred triangles under the player's feet; you'd be computing intersections with potentially all of those triangles and getting hundreds of contact points for the solver deal with, when really you only needed a few. A manifold reduction scheme could be used to group triangles with similar normals together and reduce the number of contact points (e.g. Jolt has this), but we don't have that yet.
Ah yes that looks nice ๐
@vestal minnow I feel like I'm dealing with something similar here in a way. i created a simplified geometry to add coliders to a players mesh for their arms for specific collision events there. The difference in that case is that the collider is moving around with the parent(/sibling?) every iteration and recomputing the whole whole player mesh as a physics object every iteration is highly expensive and not recommended.
There's just a lag issue in my case though it seems to be creating correctly.
That doesn't look like perf lag, more like either the collider itself or the gizmo is lagging behind
It's possible there's a one frame delay somewhere
This would apply to SDF collisions as well, which would correspond to solving a bunch of inequalities. In other words, an efficient solution to non-convex collisions would also solve a lot of other optimization problems.
what do you think about these repulsions?
Looks like my tnua builtin walk has a bad config?
controller.basis(TnuaBuiltinWalk {
// The `desired_velocity` determines how the character will move.
desired_velocity: direction * 1.2,
desired_forward: Dir3::try_from(direction).ok(),
// The `float_height` must be greater (even if by little) from the distance between the
// character's center and the lowest point of its collider.
float_height: PLAYER_FLOAT_HEIGHT,
// Restrict the max slope so that the player cannot walk up slightly angled chairs.
max_slope: TAU / 6.0,
acceleration: 50.0,
air_acceleration: 30.0,
spring_strength: 3000.0,
spring_dampening: 1.2,
..default()
});
@visual sparrow
hm, I changed spring_strength to 300 and now there is not repulsions issue
Yeah I believe some SDF collision algorithms use gradient descent to find intersection regions and to estimate contact points and normals
but now when i step off a low platform the collider very slowly flows down to the floor as if gravity is not 9.8 but 1.0
for example this paper
https://dlpf.github.io/sdf-collision.github.io/static/resouces/Real_Time_CD_between_SDFs.pdf
The function version actually just uses an octree that is only traversed for the nodes that have a possibility of being relevant contact points
Yeah, tweak that value for what feels correct ๐
@Jondolf would that just be visually for the gizmo?
What actually triggers ColliderOf to be added?
I have an entity that's missing those and I'm trying to figure out why
just fyi ColliderOf seems to only update when RigidBodys are added or removed or when children are added or removed, so adding a collider to an existing child entity doesn't trigger adding a ColliderOf to that entity
the comments in the hierarchy plugin make me think this is the intended behavior
but it was surprising to me
e.g.
/// Updates [`ColliderOf`] components for colliders when their ancestors change
/// or when a rigid body is added to the hierarchy.
I think it would make more sense to also trigger it when colliders are added to the hierarchy? if not, It would be nice to have a note somewhere in ColliderOf (or if there is a note, make it more prominent, I spent a while trying to figure out what was happening ๐ )
actually, the more I test stuff, the more I think this might be a bug. I think the behavior is inconsistent between whether the components are added in a system or in a hook?
Here's a main.rs with behavior that seems wrong to me. I'm using bevy 0.16 and the main branch of avian3d on git:
Let me know I've just done something incorrectly, or what. I think I'm done with this for the night
Yeah this should work, but it's possible there was a regression when I reworked some of the logic there to use relationships. I'll take a look when I have some time
I accidentally posted this in general and meant to post it here.. I'm running into this warning/error on main branch
Encountered an error in command
<bevy_ecs::system::commands::entity_command::remove<avian3d::sync::ancestor_marker::AncestorMarker<avian3d::collision::collider::backend::ColliderMarker>>::{{closure}} as bevy_ecs::error::command_handling::CommandWithEntity<core::result::Result<(), bevy_ecs::world::error::EntityMutableFetchError>>>::with_entity::{{closure}}: The entity with ID 727v1 was despawned by forks/bevy/crates/bevy_scene/src/scene.rs:112:46
it seems similar to this...
https://github.com/Jondolf/avian/pull/677
I actually just realized I was looking for the wrong component... this seems to be complaining about .remove<AncestorMarker<ColliderMarker>>
I also have one complaining about .remove<AncestorMarker<RigidBody>>
gonna look some more..
I'm guessing it's related to remove_ancestor_markers
guess I'll try try_remove here
Yeah that should be using try_remove... It does check if the entity exists there, but EntityCommands is also deferred so it could be despawned by the time it runs ๐
that fixed it. I suspect it's because it queues a command instantly
yeah
I can make an issue + pr if it's helpful
I sometimes get a little conflicted with tiny fixes like this.. the amount of overhead of an issue and PR vs just fixing it with another change. But, it might be worth having the error documented as an issue if someone else stumbles on it before it's fixed ๐ค
I made #714
is there a 0.16 compatible 3d build out yet?
Not a release yet, but the GitHub repo's main branch supports 0.16
Hey sup y'all I'm still testing this collider from yesterday a little bit and honestly I wasn't expecting this result. The collider on the arm is triggering before either the arm or gizmo are in contact with the wall ( the black wall is on the left.) Is this due to the predictive algos you were mentioning yesterday @vestal minnow ? the system I used for detecting the collision
.add_systems(Update, debug_collisons)
fn debug_collisons(mut collision_event_reader: EventReader<Collision>, names: Query<&Name>) {
for Collision(contacts) in collision_event_reader.read() {
let Ok(entity1) = names.get(contacts.entity1) else { return };
let Ok(entity2) = names.get(contacts.entity2) else { return; };
if (entity1.to_string() == "wall" || entity1.to_string() == "left-arm") && (entity2.to_string() == "wall" || entity2.to_string() == "left-arm") {
dbg!("wall and arm are in contact");
}
}
}
I was able to get the debug gizmo to appear correctly when adding:
app ...
.insert_resource(Time::<Fixed>::from_hz(240.0))
But I'm not really sure what other consequences this line has. Does it effect all the systems in the app?
I haven't gotten into configuring Time for my app until I saw this on an official bevy thread https://github.com/bevyengine/bevy/discussions/12005 where the gizmo was also having a 1 frame delay (not using avian) but they were able to add their gizmo system to PostUpdate schedule and that did the trick for them.
Adding the PhysicsDebugPlugin to the PostUpdate Schedule did not work just the Time snippet above was able to fix the display.
@vestal minnow thank you for these plugins and all the work you've put into this as well as the help from the other 65 or so contributors.
Here is a better video with .add_systems(FixedPostUpdate, debug_collisions)
@vestal minnow FYI, I'm porting Foxtrot to 0.16 and use Avian's main branch, and now I get a ton of these when going from the gameplay back to the menu, which despawns most entities
This could be my bad or a fault in one of my patched plugins, just letting you know
Sec, here is the same with track_location on
From just a cursory glance, it seems like a situation where remove should be replaced with try_remove
Try cargo update. There was pr recently that may solve the issue.
Indeed it did! Thanks!
wen

@vestal minnow I updated my code to 0.16 and avian main and EventReader<CollisionEnded> doesn't work anymore. collision_events.read() doesn't read any events. Is this a known issue?
Yea, there is a marker to enable events now
thanks for your reply. Could you point me to where I can understand more about the change and how to update the code?
See #1124043933886976171 message
I just came to a super important realization when it comes to the KCC. Gravity should be processed separately if you're not on a steep slope, but joined with the characters velocity if you're on one
Since I always do grounding checks before the collide and slide I have the floor angle already for this purpose
It's an obvious thing in hindsight but
So depending on floor angle you either have gravity as a move and collide on its own then add that result to the KCC's velocity, or put both in a single pass
did you build your own collide-slide-kcc? is it publicly available?
It's not good enough for use by games yet. Once I've it to a more stable and reliable implementation I'm probably going to form bevy-tnua to be the base of it
Actually hm... @vestal minnow couldn't I run my KCC processing during narrow phase and do collision events and such the same way Avian does internally?
I'm using the 0.16 branch and am running into this behavior and am curious if anyone else has seen it. It's like my frame rate just drops for a few frames with these long calls to "avian3d::sync::propagate_transforms_physics" even when I have physics time paused.
ah, realized I can't make a thread here so I made one here
#off-topic message
Is it possible to create a cone/pizza slice shaped collider? Or do I have to apply an angle filter on CollidingEntities?
I want to detect collision with defined radius and angle from object's X or Y.
Anyone knows good examples on adding custom colliders like doughnut shapes, ...?
doughnut is a torus, it's concave so not a very good collision shape
cone does have a primitive that you can convert to mesh, no idea about pizza slice, you'll probably need to hop into blender to make it
Encountered an error in system avian2d::picking::update_hits: Parameter Res<RayMap> failed validation: Resource does not exist
get this when trying to run with MinimalPlugins. i don't have the bevy_picking feature enabled for avian2d, since i'm trying to run headless. do i need to disable picking some otherway in headless mode?
on main btw
ah for some reason i was manually adding PhysicsPickingPlugin, that explains it..
could manually make one triangle
Oh huh box2d got some KCC related features
I might take a look at those
Wait hold on
This geometric solver (they're calling it) is very similar to the solution I was reaching on my own
Wait no this is... exactly what conclusion I reached in my latest impl attempt, just better executed.... hmm....
Lets see, CastMover appears to tell you how far you move along your velocity until you hit a collision? Returns the fraction, which I believe is 0->1 of how far you managed to move?
Omg I spend 5 hours and still cant setup my physics correctly with Avian and Tnua controller
-
Why a player slides down very slow from low profile box?
If I setspring_strengthto 3000, it slides fast (As I need, because its a normal fall down, not something special)
But with that 3000 option, there is another issue - the player begins to be pushed away strongly from inclined planes -
Why player jumps very high if I jump from inclined planes ?
-
Why player sinks a little into the ground and then sort of floats back up every time he lands after a jump?
-
Why player starts shaking if he trips over a corner
all the issues are in the videos
1 video - spring_strength is 3000
https://youtu.be/pD3N8p7I_zE
2 video - 400
https://youtu.be/Ho2w2seSvdk
I'm honestly not a fan of tnua for some of these reasons
it's great for a chaotic/arcadey game
to me that looks like the collider is way too big
I'm having a bit of trouble figuring out the best method for implementing RayCasters and child rigidbodies. I'm making a top-down 2D game, and the intent was that characters have independently-rotating child "head" entities that cast rays in the direction they're looking at.
I haven't been able to implement this at all though. If I just have minimal "head" child entities with nothing other than a transform and a raycaster component, it doesn't work. The rays don't rotate with the head.
If I add a Kinematic Rigidbody to the head child, when the main body moves the child just gets left behind.
How can I have a head attached to a body that can rotate with raycasts that spin with it? I really just want a head that can look around.
is there an easy way to visualize shape casts other than trying to construct a gizmo where you think the shape is?
doesn't the physicsdebugplugin place gizmos and such for you?
what do you use then instead? You write collide-and-slide algorythm for KCC from scratch?
what do you mean? Too big in comparison with what?
here is my settings:
collider: Collider::capsule(0.5, 0.7),
sensor_shape: TnuaAvian3dSensorShape(Collider::cylinder(0.49, 0.0)),
and walk basis:
desired_velocity: direction * 1.2,
desired_forward: Dir3::try_from(direction).ok(),
float_height: PLAYER_FLOAT_HEIGHT,
max_slope: TAU / 6.0,
acceleration: 50.0,
air_acceleration: 30.0,
spring_strength: 400.0,
coyote_time: 0.1,
i did something similar, with weapons that float in-place relative to the camera
ended up needing to just make them a separate body, then give them velocity to move them toward the target position
if you don't need the heads to have colliders, though, there's probably an easier way
my tnua: Capsule3d::new(0.5, 1.0), controllable::Walking { walk: 10.0, jump: 4.0, height: 1.5,}
and ```rust
fn apply(
intent: Single<&crate::player::Intent, With<Inhabitor>>,
mut habit_query: Query<(&mut TnuaController, &Walking), With<Inhabited>>,
forward: Single<&ForwardFromCamera, With<Inhabitor>>,
) {
let Ok((mut controller, opts)) = habit_query.get_single_mut() else {
return;
};
controller.basis(TnuaBuiltinWalk {
desired_velocity: intent.direction * opts.walk,
float_height: opts.height,
desired_forward: Some(forward.forward()),
..Default::default()
});
if intent.jump {
controller.action(TnuaBuiltinJump {
height: opts.jump,
..Default::default()
});
}
}```
oh and a TnuaAvian3dSensorShape(Collider::cylinder(0.49, 0.0))
and you dont have such issues?
there's a little adjustment when stepping on and off of ledges, but it seems natural enough for my purposes
i think Rule 1 of tnua is "don't touch the ground directly"
it does show colliders, but I don't think it was showing raycasts/shapecasts.. maybe there's a setting I missed
what does it mean?
it's an entire system designed to work around how incredibly inconvenient it is to slide a capsule around on the ground
so probably just, don't put the capsule on the ground
even on slopes
look at very very valet character controller tutorial to understand how tnua works
Was just working with a ShapeCaster in a new project and figured I'd check. Seems to visualize for me.
I'm guessing they're using SpatialQuery methods, not the component
(also I'm probably still busy today but I'll be back soon!)
yeah, like Jondolf said I was using the SpatialQuery, but that's good to know. Might use that instead for debugging purposes and then switch back
I don't need them to have colliders. I don't even need them to have rigidbodies, rigidbodies just seem to be needed for the raycasters to work.
oooh nice this is hype
https://github.com/dimforge/parry/pull/336
do you have triplanar mapping for your debug textures?
Are there any plans for an official kinematic character controller for Avian?
I've been trying to write one the last few weeks, and it's been a frustrating experience for a physics noob like me. There are still so many bugs in my implementation that I don't know how to fix, and information on this, to my knowledge, is pretty sparse.
It would be nice to have built-in adjustable/extendable character controller(s) with clear docs. It probably should not be included in Avian default plugin and should be added as separate plugin (like avian debug plugin).
There are a couple of floating character controllers compatible with Avian, like bevy_tnua (which is great), but there a couple of issues with the approach that would be circumvented by using collide and slide, but there aren't any solutions out there for Avian. Having a solid, well-tested (bare-bones) implementation of a kinematic character controller in Avian (which is also great) would be really awesome for prototyping and as a learning resource.
Yes
is that a separate crate or did you implement it yourself? been meaning to make something like that for my own test environment
I implemented it myself, I can publish it later if it's something you're interested in. Just afk right now.
Ya I'd be interested whenever you get around to it ๐
Hey, so I'm not sure how "official" worthy it is, but I have a pretty rock solid approach that has worked pretty well for me in the past, in other engines too. I did just notice a flaw with my Bevy version right now (moves a bit faster when sliding against walls) but I can fix that by comparing to my Godot version.
I took the idea from Quake 1. Essentially you loop up to 4 times, shape-casting each time. The moment you dont hit anything, you break out of the loop.
The reason you do up to 4 times is, you may hit a wall, slide along it, then penetrate another wall, so you need to check that next wall, and so on.
I've seen this question pop up a few times now and I'd love to build out a proper example. I've done one in the past but it had a bunch of multiplayer stuff in it too, can strip all that out and keep it scoped.
@green adder is also working on one, but I don't think he's open sourcing it, but maybe willing to share techniques, especially surrounding stairs.
And, this approach is solid for first/third person games, but I don't think you'd want to have thousands of units using it, so it wouldn't be good for an RTS. That's just gut feeling without trying it.
This approach is also great for multiplayer, because you can design it in such a way that you can rollback just the character you want, instead of needing to have full rollback. This is important because not every game needs full rollback.
What I can do is fix my Bevy implementation, and invite you to the repo (github) if you want
Or I just open it up I guess
I'd be curious to see this as well
ok actually so I'm looking at your code now, what are some of the problems you're getting? I see you're doing the looping thing too.
The big difference i see is you're using a par_iter. I think that may cause problems, you want it to be sequential
oh nvm
Ok you have the exact same issue as me, you're using remaining motion instead of remaining time
Hmm maybe its worth creating a temporary Discord server to figure this out?
Hey, is there a way for kinematic rigid bodies to opt out of automatically moving the entity using the LinearVelocity? I'm making a character controller and the movement is handled by me, I don't want to define my own velocity since then I would need to special case characters in systems. My solution for now is to just not have a RigidBody on my characters but that's biting me in my butt because now I don't get collision events for free anymore.
what issue is you having?
Oh I just mean for the general problem of having a rock solid character controller. I just feel like if we really dive into it, it would pollute this thread
oh yeah, I'd definetly join that.
there's like four or more people with KCCs for Avian at this point, could be nice to gather requirements and ideas in some way
at least UB, aceeri, BrianH, Philipp, Luk, kinda me as well...
Yeah, and part of the problem is once you get into things like how it climbs stairs and ledges, it starts to become a game-feel thing. Phillip for example has some different ideas than I for that
Hey there, yes I will be doing work in this area in the next few days/weeks. I would love to share thoughts etc.
It's been a bit but I did some high level planning for some features a while ago and I'm currently planning again.
A small example of the old work:
@crimson crest fyi ^
finally
@vestal minnow Will avian get a physx backend in the future?
I highly doubt it
No, Avian is a physics engine, if it used PhysX then it wouldn't really be Avian anymore. But a direction I'd like to explore for an official bevy_physics is to have it be mostly just an API layer, and then other crates can provide physics backends for that API, like Avian, Rapier, Box2D, Jolt, PhysX, and so on
forgive me for being annoying while I bump this ๐
Seems like I might've gotten it twisted. For ShapeCastConfig.target_distance, I assumed that the shape would travel Scalar units before detecting collisions. Am I wrong about this? just want to make sure it's my fault because I'm going a little crazy ๐
(implying in this picture, that the log distance would be >= 100). The other param settings compute_contact_on_penetration and ignore_origin_penetration appear to have no effect...ig I'll just need to cast the ray after recomputing the direction 200 units ahead haha
See the docs of the property
https://docs.rs/avian3d/latest/avian3d/spatial_query/struct.ShapeCastConfig.html#structfield.target_distance
The separation distance at which the shapes will be considered as impacting.
Meaning that in your case, when the distance between the cast shape and the other shape is 100.0, they will be considered as impacting and the shape cast will terminate at that distance
so if the distance is already less than or equal to 100.0, the distance traveled by the shape is 0.0
I totally misconstrued that. Makes sense! I interpreted it as minimum distance between cast shape and other shape.
mmm the determinism problem in #706 is so annoying
It's not really a determinism bug, since the behavior is consistent across runs. But the PR results in different behavior when restarting a scene without fully clearing the contact graph, because the free/vacant graph edges affect the contact pair insertion order
Now should we accept that behavior (if you don't clear the graph) for the perf win or not... I'm pretty sure it shouldn't be a problem for 99% of cases, it's mainly just weird for users that past contacts would affect a "fresh" scene, and it feels like something that people shouldn't need to worry about
How would this behave with rollback? Like let's say we got an update, roll back to what the state was the tick before (which was incorrect), then apply the updates from the server, and resimulate ... Would this result in different contacts than the server?
Similar cases would happen with things like reversible time more immediate rewinds, or even snapshot systems
If you roll back the contact graph too, including its vacant edges, then you should get the same behavior I think
But yeah I'm not 100% sure how it'd work for stuff like that
For now I think I'll just keep the current/old approach until optimizing this is more relevant
Box2D uses a contact ID pool that I believe would have the same problem of past contact pairs affecting the insertion order of new pairs (I tried an ID pool too), but I'd need to run some tests with it to double-check if it has the problem
Ultimately the order of IDs doesn't matter if it doesn't affect the outcome
Yay or nay? Rigid body entity in OnCollisionStart and OnCollisionEnd events
https://github.com/Jondolf/avian/pull/717
You can query for the rigid body entity via ColliderOf, but that is still an extra query and more verbose
Internally it needs to do a query here anyway to check if the entity has collision events enabled, so this doesn't really add any overhead beyond storing the extra entity
This is what I need in 99% of cases, so it seems like an ergonomics win
Bit unfortunate that it needs to be behind an Option
I think this is optimized for Entity and trigger.rigidbody.unwrap_or(trigger.entity()) or whatever should be fairly efficient ๐ค
So I still have the whole let Ok(rb) = trigger.rigid_body else { return; } song and dance