#Avian Physics

1 messages ยท Page 21 of 1

nova relic
#

yeah, I was gonna have a look at what the lightyear year code looked like since they already have it too

royal helm
#

just set your goal fps to 240fps and no one will notice

#

simple

#

lol

vestal minnow
prime turret
#

following up to myself: hard to say, attempting to apply the correction along the free axis of the revolute joint results in explosive behavior (do I need to rotate the free axis to the current rotation first? will try that next)

vestal minnow
#

You don't need to call that, it's intended to be internal

prime turret
#

OK!

cinder summit
prime turret
#

huh, ok, in that case, it's hard to tell if the anglelimit is doing anything ๐Ÿ˜ฆ

vestal minnow
#

What have you set it to?

prime turret
#

+/- 0.01 of a target value (default 0.0)

#

this is like the steering joint of a bicycle, the neck

vestal minnow
#

the repo's revolute joint examples work at least

prime turret
#

yeah

nova relic
royal helm
#

or just have the tickrate so high no one even knows until it crashes lmao

prime turret
#

OK, it is working, but the maximum angle_limit_torque isn't high enough to constrain it

vestal minnow
#

I definitely wouldn't make it the default strategy tho

peak timber
#

I tried to make a tiled floor where each tile was a separate entity with a static rigid body and a collider, where they perfectly touch but don't overlap

But I got an explosive overlap warning and when I try to walk over them, it's bumpy as if there was a gap between them

#

Is there a better way to do this?

#

basically trying to do simple procedural 2d platform generation

#

with a grid of rectangles

vestal minnow
#

Other things that might help if you're using a dynamic character, specify SpeculativeMargin::ZERO and maybe add a small CollisionMargin

peak timber
#

Thanks - I guess I could also try to join the colliders together to prevent anything static from touching
Might get complicated though since it's procedural

#

I guess only flat surfaces need to be joined, not perpendicular ones

fringe mango
#

if I want to detect whether or not a ray has hit Layer1 or Layer2, should i just do two raycasts?

peak timber
#

btw I still think there's a bug with CollidingEntities but I switched to ShapeCaster for ground detection and it works like a charm

#

combined with collision layers to prevent jumping on coins

vestal minnow
#

This issue?

peak timber
#

yeah

peak timber
#

in a list or bitwise union/or

vestal minnow
# peak timber yeah

Yeah I can see that being an issue currently ๐Ÿค” I think we could fix it in an unoptimal O(n) way already, but it'd probably be more efficient once we have a contact graph so we can look up the edges of the despawned entity

native stump
#

@vestal minnow Had a question about the intended mechanism for adding custom collider types in Avian.
Parry supports this typically through chaining their query dispatchers, which allows you to create totally custom collision handling, but by default Bevy colliders use a DefaultQueryDispatcher without allowing chaining of the dispatcher at all.

I assumed the intended mechanism was to instead implement our own AnyColliders, but that means we have to have this enum as a layer to interact with the avian plugins, as the default avian plugins only support avian Colliders:

#[derive(Component)]
pub enum ColliderWrapper {
    /// A default bevy collider
    AVIAN(Collider),

    /// A custom "foo" collider
    FOO(FooCollider)
}

// ...

 let builder = builder
            .add(ColliderBackendPlugin::<ColliderWrapper>::new(self.schedule))
            .add(NarrowPhasePlugin::<ColliderWrapper>::default());

// ...

impl AnyCollider for ColliderWrapper {
    fn aabb(&self, position: Vector, rotation: impl Into<Rotation>) -> ColliderAabb {
        match self {
            ColliderWrapper::AVIAN(collider) => collider.aabb(position, rotation),
            ColliderWrapper::FOO(collider) => collider.aabb(position, rotation),
        }
    }

    // ...
}
fringe mango
native stump
peak timber
peak timber
#

I opted for bitmasks though

fringe mango
peak timber
#

it's pretty neat

#

one thing I feel like could be a footgun though is if you forget to add collision layers to an entity it presumes it belongs to all layers and interacts with all layers

#

don't know of a better solution, but just something to keep in mind

vestal minnow
# native stump <@545959292281552928> Had a question about the intended mechanism for adding cus...

I'm not sure how easy it is to make fully custom collision logic, but there's a few custom shapes in the Avian repo which you could use for inspiration, like Ellipse and RegularPolygon (I'm using wrappers to overcome the orphan rule, but you could use your own shape directly if you own it). Basically you need to implement Parry's Shape trait and some other traits depending on the type of shape, and then you can create a SharedShape and Collider from it.

That might not be enough if you need a more complicated custom shape, and in that case you would indeed need to derive AnyCollider and use a fully custom collider type

fringe mango
peak timber
#

yeah, making your own bundles helps too

peak timber
vestal minnow
#

yes, but reaching feature parity will take time

native stump
wanton forge
#

I've been trying to get our project to run on WASM, but keep getting the time not implemented on this platform error. Our deps are bevy, bevy_ecs, avian2d, leafwing-input-manager, and bevy_asset_loader. I think avian2d is causing it, but I'm not 100% sure since I'm still not good with more complex rust project structures. Does the code in avian/src go into the 2d crate? I assume the tests/benchmarks/examples shouldn't be causing the error, but there are 2 instances of std::time::Duration in src that I'm not sure about. They are at src/schedule/mod.rs and src/schedule/time.rs.

vestal minnow
#

I have a project running on WASM with Avian so I kind of doubt that's the cause

#

It's actually using avian3d, LWIM, bevy_asset_loader, and ofc bevy

#

so the same crates pretty much

#

But yes src essentially goes into crates/avian2d

vestal minnow
#

std::time::Instant doesn't work on Wasm but iirc Duration does

peak timber
#

is there just no monotonic clock in browsers?

wanton forge
#

Hm, so it's just instant? I guess I have to keep digging then, thanks.

vestal minnow
#

or web-time now I guess thonk

peak timber
#

rip

wanton forge
#

Yeah, I've already replaced all the spots in our code with web-time.

vestal minnow
#

But if you used a custom component for the custom voxel collider (without using AnyCollider stuff), you'd need to handle everything you need for it manually, which might be kinda painful

native stump
#

Not an ideal layer to have but IG I'm using anycollider so better than from scratch

vestal minnow
#

I think I could get all (or most) geometric queries for Bevy's primitive shapes implemented relatively soon though

wanton forge
#

One other thing that you might want to know about, but also is probably just us being dumb, we ran into a race condition? with Collisions. Our setup was Crouching is started if player.grounded, player.grounded is if any of body.collider_ref's collisions have a negative manifold. When Crouching starts, it replaces the reference in body.collider_ref to a collider half the height and stores the old one for replacement on uncrouching. Very rarely, we would get cycles of crouch -> uncrouch -> nothing -> crouch -> .... As far as I can tell this was caused by body.collider_ref being "stale", so checking Collisions returns nothing since it doesn't exist/is set to CollisionLayers::NONE. It was fixed by checking both the current body.collider_ref and stored crouch ref, but was almost impossible to solve. Thoughts?

vestal minnow
#

I'm not sure if I understand exactly what's happening so it's hard to say

#

Is the crouched collider positioned at the "bottom" of the uncrouched collider so it's not in the air for a moment when starting to crouch?

#

Generally I'd also do ground detection with something like shape casts instead of actual contact data

wanton forge
#

It is a lot going on and probably not avian specific, but here the links:
broken ground check method
crouching plugin
fixed ground check method
As far as I could tell from all my testing with printing positions and shifting the colliders, it was always touching the ground, there wasn't any floating point nonsense happening, it was just something making the Collisions check in our method use the wrong entity reference.

#

I did try implementing the crouch by altering the scale of the player collider instead of replacing it, but I just could not get it working, probably because of how the systems were getting ordered.

fringe mango
#

is there any way to do something along the lines of this?

#[derive(PhysicsLayer, Clone, Copy)]
pub enum Layer {
    Camera,
    Ant,
    Pheromone,
    Obstacle,
    Colony,
    Ground,
}

impl Layer {
    fn interactions(&self) -> impl Into<LayerMask> {
        match self {
            Layer::Camera => [],
            Layer::Ant => [Layer::Pheromone, Layer::Obstacle, Layer::Colony],
            Layer::Pheromone => [Layer::Ant],
            Layer::Obstacle => [Layer::Ant],
            Layer::Colony => [],
            Layer::Ground => [],
        }
    }
}

this currently gives an error that the match arms each have different lengths, which makes sense, but i'm unsure how to work around it. in the end I basically want to do something like
commands.spawn(CollisionLayers::new(layer, layer.interactions()))

#

would I have to do something like mapping each variant to a specific CollisionLayers?

wanton forge
#

impl Trait has to be just one, or the match has to be just one return type, so either use a dyn or manually call .into() and make the function -> LayerMask. Or something else I missed.

fringe mango
#

seems like dyn requires the trait to be an "object" and Into<> isn't one, so it doesn't work :(. i'll probably just go witht he manual .into() approach for now

#

thanks for the help ๐Ÿ˜Š

junior flower
#

I wonder if anyone has any suggestions for what Iโ€™m doing wrong here.

Iโ€™ve got 4 spheres each with RigidBodies attached to another RigidBody (all Dynamic) via RevoluteJoints.

Although itโ€™s all stable, once the wheels reach an Angular Velocity of around 20 the whole thing lifts off the ground and flips over.

I'm using MassPropertiesBundle, with the body set to 10,000 density and the wheels are each set to 10. (No particular reason for any of these values; they were just guesses. With the body at a probably more realistic 1,000 density the problem persists).

Mass is showing as really really small value (~5) for the vehicleโ€™s parent, and its child collider is around ~50,000.
Each wheelโ€™s Mass is around 1.2.

The wheels are not children of the vehicle; they are separate entities entirely. The RevouteJoints are also separate entities.

Side note: In case it's relevant, the wheel colliders are ignoring the vehicle's body collider via PostProcessCollisions.

junior flower
lusty bison
#

Are there any implementations for modifying the local scale of a collider?

lusty bison
#

...

visual sparrow
# lusty bison ...

FYI the Bevy game jam is currently nearing its end, so you might get fewer answers than normally as people are busy finishing their entries ๐Ÿ™‚

vestal minnow
#

If you need to scale a collider and get the actual underlying shape, you could also call set_scale on it and get shape_scaled

#

(GlobalTransform scale will generally override this if the collider is on an entity with a transform)

prime turret
junior flower
# prime turret re collisions, you could also use `CollisionLayer`s and put the wheels and body ...

Thanks for the reply. CollisionLayers won't work because I want the wheels to collide with other vehicles' main colliders. I just don't want inter-collision. Once #364 gets merged I'll be able to use that instead.

I was indeed applying the torque in world space, thank you for that suggestion.
However, even with it corrected it still takes off ๐Ÿ˜ฆ

I did a bunch of playing around with it yesterday like adding suspension and giving it more realistic masses and I think I've managed to get it to a point where it's at least close to being stable. The wheels have to spin at 100rads/sec for it to take off, which is something like 80km/h with the current wheel radius. So I have a feeling it was just weight ratios.

It seems like a bug that a very light thing spinning quickly can move a very very heavy thing, though?

past escarp
#

Is there a way to attach a sensor collider as a child of a rigidbody without affecting the parent's centerpoint?

visual sparrow
errant laurel
#

Hey, how do I prevent/reduce things going with a relatively higher speed falling through the ground?

signal iron
#

@vestal minnow I managed to make quickhull work with robust for arbitrary 3d shapes, tested on 10000 different random point clouds.
More info here https://github.com/Jondolf/quickhull/issues/1

Was the tolerance value only needed for the robustness issues? If so, I can remove it and clean up my fork into a mergeable state.

There is also some low-hanging fruit in the form of the HashSets and HashMaps hogging ~15% of the performance which should be easy enough to fix with a faster hashing algorithm. I can take care of that too.

GitHub

heavy_sphere_test reliably produces concavity errors. Tried visualizing the offending face and it does indeed have several points above it that should belong to the hull, will investigate in this i...

past escarp
# visual sparrow I think this is already the behavior on `main`

thanks! that appears to have done the trick.

It also got me to upgrade from 0.1.0 -> 0.1.1, and I noticed what appeared to be a regression ๐Ÿค” unless I'm doing something really funky. first video is 0.1.0, 2nd is 0.1.1.

Possibly relevant system? Perhaps because I am directly modifying the velocity?

/// Apply input to the controllers
fn apply_controller_movement(
    mut characters: Query<
        (
            &Transform,
            &Craft,
            &mut Controller,
            &mut LinearVelocity,
            &mut AngularVelocity,
            &mut LinearDamping,
        ),
        Without<Destroyed>,
    >,
    time: Res<Time>,
) {
    let dt = time.delta_seconds();
    characters.iter_mut().for_each(
        |(transform, craft, controller, mut velocity, mut angular, mut damping)| {
            **velocity += controller.thrust * transform.forward() * dt * craft.acceleration;
            **velocity = velocity.clamp_length_max(craft.speed);
            **angular = controller.angular_thrust * -Vec3::Z * dt * craft.rotation;
            **damping = controller.brake * dt * craft.brake;
        },
    );
}
visual sparrow
past escarp
#

It feels like the set angular velocity is fighting with something else, and sometimes it just won't take at all (despite it appearing in the inspector that the velocity is set?) It's very possible I'm doing something weird though. I'm not sure if there are any guarentees with minor versions being compatible.

#

Ah, I think it might have something to do with LockedAxes restricting movement. Not sure what changed but I'm guessing I might just have the wrong axis or something, and something with transforms was changed/fixed in .1 and maybe i just have things set up wrong?

edit - yeah, when I remove .lock_rotation_y(), the issue resolves. (Note my project is top down aligned with the Z axis as up, though). It looks to work as expected in 1.0

vestal minnow
#

With robust it might not be needed

vestal minnow
hexed veldt
#

Does avian collision detection skip Visibility::Hidden entities?

visual sparrow
hexed veldt
#

@vestal minnow is this intentional? It seems to me if an entity is set to Hidden it would be nice if the collision process skip that?

ornate jetty
#

I'd bet it is intentional. You often want invisible walls / barriers, no?

#

Works the same in Rapier

hexed veldt
#

You are right. It is definitely useful for hidden objects to collide with other objects. A good use case I can think of is having a low poly mesh collider to represent a high ploy object in the collision process, and the collider should always be hidden

edgy light
#

you don't need to have a mesh displayable to add a collider to an entity, your invisible wall could be just the collider

ashen nest
#

I have a floating hand that can pass through objects connected to a rock with a joint the rock should be able to stop at walls while it's being held and stop everything in it's tracks but it just passes through them and applies a little spin on the thing that's being held as if it can feel it but can't stop it from going through not quite sure on how to solve this

ashen nest
fringe mango
#

is there any collider type that resembles an arc or should i just use a circle collider and check the angle?

vestal minnow
#

Unless you mean a circular sector or circular segment, those we could probably implement decently

fringe mango
vestal minnow
#

Yeah that's a circular sector. I think it should be relatively straightforward to implement as a collider shape, but it's not built-in yet

fringe mango
#

yup, im just checking the angle right now to see if its within a range, but it would also to have stuff like a debug gizmo ๐Ÿ‘

brave path
#

hey everyone! i'm getting an error when using SpatialQuery alongside another Query<[...]> that includes Collider:

spatial_query: SpatialQuery,
pub fn fps_controller_move(
    spatial_query: SpatialQuery, // ๐Ÿ‘ˆ
    mut query: Query<(
        Entity,
        &FpsControllerInput,
        &mut FpsController,
        &mut Collider, // ๐Ÿ‘ˆ
        &mut Transform,
        &mut LinearVelocity
    )>,
)
error[B0001]: Query<[...]> in system shooter::controller::fps_controller_move accesses component(s) avian3d::collision::collider::parry::Collider in a way that conflicts with a previous system parameter. Consider using `Without<T>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevyengine.org/learn/errors/#b0001

i hadn't much success using ParamSet (i get a cannot borrow set as mutable more than once at a time error when trying to acess the spatial_query and query from the set) and don't know how i could use Without<> here to fix this... any ideas?

vestal minnow
brave path
#

nice, tysm!!

wanton forge
#

Interesting, I've also run into this while trying to get CollisionLayers, Transform, and Collider (though not all at once). ParamSet has been working for my cases, basically doing ```rust
fn system(
mut params: ParamSet<(SpatialQuery, Query<&mut Collider>)>,
) {
let spatial_query = params.p0();
if spatial_query ...
// As long as spatial_query is not used past this point Rust should be smart enough to figure out the borrows.
let mut q_collider = params.p1();
// Do whatever mut query stuff.
}

boreal tendon
#

Hey folks, I run into

thread '<unnamed>' panicked at /Users/yatekii/.cargo/git/checkouts/avian-b0a258754c9e72b0/5c2188c/crates/avian2d/../../src/position.rs:252:9:
the given sine and cosine produce an invalid rotation

Just when I add a RigidBody::Static or a Collider::rectangle

Whole bundle is:

 commands.spawn((
            SpriteBundle {
                transform: Transform {
                    translation: Vec3::new(x, y + CIRCLE_OFFSET_Y, 0.0),
                    scale: TILE_SIZE * 0.99,
                    rotation: Quat::from_axis_angle(Vec3::new(0.0, 0.0, 1.0), phi),
                },
                sprite: Sprite {
                    color: TILE_COLOR,
                    ..default()
                },
                ..default()
            },
            // RigidBody::Static,
            // Collider::rectangle(TILE_SIZE.x, TILE_SIZE.y),
            Tile,
        ));

with phi being (0, 1)

visual sparrow
visual sparrow
wanton forge
#

It looks about right to me, I assume they mean 0..=1 since (0, 1) shouldn't compile, and while we haven't used SpriteBundles yet we do routinely have translations with 0 z. I couldn't find why it's panicking since it looks like a valid rotation to me, though isn't there a way to specify rotation from an angle so you can skip the quat?

boreal tendon
#

Ah sorry, (0, 1) is an exclusive range from 0 to 1 so indeed radians, but very low numbers, which I stated because there was some GH issues about big radian numbers

#

TILE_SIZE is 30

#

If I make Z=1 that does not change anything. Quat::from_rotation_z(phi) is very nice, thanks! I am using it now ๐Ÿ™‚ But still crashes ๐Ÿ˜ฆ

visual sparrow
visual sparrow
boreal tendon
#

ahhh that works!

#

are overlapping at spawn, which can result in explosive behavior. ihihihi

#

thanks a lot!

#

now i need some debug grid to find where my characer goes, lets see

alpine oak
#

hey, im wondering whether there's a reason that the PhysicsDebugPlugin doesn't use AnyCollider

#

and whether ShapeCasters work with AnyCollider

visual sparrow
#

Oh, I forgot to post it here, in case anyone is out of the loop.
The Bevy Game Jam has just concluded and @vestal minnow and me submitted a lovely little game about being yeeted by physics while trying to deliver stuff on your bike: https://janhohenheim.itch.io/bike-game cooltofu

itch.io

A hectic first-person game about delivering stuff on your bike in time. Try to abuse the janky physics!

formal galleon
#

I modified the kinematic character controller to meet the needs of my hedgehog game. The hedgehog should rotate according to the ground normal on uneven terrain to appear natural. Currently, Iโ€™m struggling with the rotation because the hedgehog needs to face the direction it is walking and combine the directional rotation with the surface rotation (from the ground normal). However, as soon as it stops walking, the hedgehog slowly rotates away from the direction it was walking (I assume due to the normal rotation). Any ideas on how to fix this?

Here is my code, I think the relevant parts are in update_surface_normal and update_rotation functions: https://pastebin.com/xW5yxbgV

boreal tendon
#

Hmm the colliders seem to scale with the transform. should I make the colliders all nominal size?

#

err normalized size

visual sparrow
boreal tendon
#

everything is completely manual atm. no textures, no blender, nothing

#

problem is that the colliders dont rotate with the tiles

#

or is there a way to make more accurate colliders?

visual sparrow
visual sparrow
vestal minnow
visual sparrow
boreal tendon
#

ah this is just the AABB

#

Thanks a lot folks! Now to map controls to the character and play a bit with the gravity, jumping etc ๐Ÿ™‚

#

Seems to work nicer than back in February when I tried the crate ๐Ÿ™‚

vestal minnow
#

Cool, that's nice to hear ๐Ÿ˜„

visual sparrow
boreal tendon
#

I had tunneling issues back then. Let's see what happens if I add lots of force ๐Ÿ˜„

#

Or acceleration

vestal minnow
vestal minnow
#

But I'm not sure how doable that is with Parry

#

The collider would likely have to implement some of Parry's traits, and at that point the value of a custom collider is smaller

alpine oak
#

so essentially thereโ€™s no way to do any raycast/shapecasts with custom colliders

boreal tendon
#

Ok, so the is_grounded bug seemingly still exists :/

vestal minnow
alpine oak
#

ah okay, do you have any pointers for that?

#

because i am lost

#

and kind of spent the last 3 hours trying to get my shapecast to work with custom colliders

vestal minnow
#

Depends a lot on what the shape is

alpine oak
#

essentially just a cube

molten mason
#

Hi!
I want to make a wheel go spin by dragging with the mouse.
I already thought about making a plane which does 3D raycast onto so I only have 2D world coordinates directly correlating to the wheel and the relative position change.
Now I wondern how I would "connect" a force at the start position to the wheel and "move" it to the newly dragged position such as that the wheel rotates there.

vestal minnow
# alpine oak ah okay, do you have any pointers for that?

Inigo Quilez has some ray casting implementations here, like a cube
https://iquilezles.org/articles/intersectors/
I also have code for a Rust adaptation using Glam (Bevy's math library) if that's all you need.

Then spatial queries like ray casts typically have a Bounding Volume Hierarchy (BVH) as an acceleration structure if you have a lot of colliders in your world. Parry has a Qbvh for this, but it uses Nalgebra.

If there aren't tons of colliders, then just iterating through them can be fine.

#

Is there a particular reason you need custom colliders?

alpine oak
#

it's a voxel mesh collider

visual sparrow
boreal tendon
#

this is considered not grounded ๐Ÿ˜ฆ

#

(I stole the character controller from the examples)

visual sparrow
boreal tendon
#

well, for now I just want to make it work

#

but so far that's not even possible with the examples

#

which is a bid :sadge:

alpine oak
visual sparrow
vestal minnow
alpine oak
#

scale of the world i'm guessing

#

i'm not really the physics guy in this project

#

so i'm not 100% sure on the decisions

visual sparrow
#

Alright. I assume the physics person has done benchmarks on that? Just trying to save you time here ๐Ÿ™‚

vestal minnow
#

I would probably start with built-in colliders and explore the custom collider route if performance is actually identified as an issue

visual sparrow
boreal tendon
visual sparrow
#

Keep in mind avian is not a character controller library and any example doing a character controller is just an example. Do not be surprised if it does not work for your use-case.

vestal minnow
boreal tendon
vestal minnow
molten mason
boreal tendon
#

(even though the collision seems to be working)

visual sparrow
boreal tendon
#

So I am not sure what's fudged

vestal minnow
visual sparrow
boreal tendon
#

it was already a bit weird because I have a bit of a weird world setup ๐Ÿ˜„

#

Hmm how are ShapeHits produced though ๐Ÿค”

vestal minnow
#

The example also has this warning :P yeah it's not a very good KCC and has some issues. Should be better when we eventually implement built-in collide-and-slide

boreal tendon
#

Ah, I am getting the hang of it I think

visual sparrow
boreal tendon
visual sparrow
#

Any implementation you will find as part of an example will have glaring issues quite quickly

alpine oak
#

and fitting cuboid colliders on the world can become kind of complex

visual sparrow
alpine oak
#

you cannot simple fit a single cuboid collider on the world

#

and giving each separate voxel it's own collider also isn't really possible

visual sparrow
#

Why not?

alpine oak
#

with the amount of voxels

#

voxels don't exist as entities

visual sparrow
alpine oak
#

we have ~262k voxels per chunk

#

and roughly the same amount of chunks on screen

visual sparrow
alpine oak
#

correct, but we want physics objects to be able to interact with them

#

and the easiest/best way to do that is to have a custom collider that uses our spatial acceleration structure to test for collisions i'm assuming

visual sparrow
#

Can't you give a cuboid collider only to surface voxels?

visual sparrow
alpine oak
#

i still think that would end up with an unholy amount of colliders

vestal minnow
#

If you have custom collisions, spatial queries, and acceleration structures, and heavily specialized performance needs, you might potentially be better off with custom physics tbh

alpine oak
#

oh boy don't say that too loud PauseDuck

#

perhaps yea, i've really been enjoying using avian so far

#

also wouldn't mind PR'ing support for AnyCollider or some other trait that adds support

vestal minnow
#

The majority of SpatialQueryPlugin is Parry-specific logic, so it probably wouldn't be that helpful. You could implement your own version with your own acceleration structures though

boreal tendon
#

Ok, I fixed it, jumps are working with more travel time

#

What I do not understand is how MaxSlopeAngle goes from degrees to radians

#

there is no conversion bit oO

#

omg I am blind like a goldfish

vestal minnow
#

mostly forwarding to Parry APIs

#

and then the plugin just calls update_pipeline

alpine oak
molten mason
#

Other question, is there a way for an idiot like me to help in avian?
Don't know that much stuff about physics yet but learning isn't impossible ๐Ÿ˜›

vestal minnow
boreal tendon
#

Yeah, so the max_time_of_impact is the problem. With 50 inead of 10 it works, but I really don't see how :/

#

Like the two colliders touch. I would expect the travel distance to be infinitesimal

vestal minnow
#

It could be because of this

#

and if you're using pixels for dimensions, 10 can be small

boreal tendon
#

I am just using the bevy units basically. But I got it

visual sparrow
boreal tendon
#

the cast origin is the center

#

might be that

visual sparrow
visual sparrow
molten mason
#

that seems like stuff I could try

molten mason
visual sparrow
boreal tendon
#

Yeah, the max_travel_distance needs to be bigger than the player diameter ๐Ÿ™‚ what I do not get is why. I mean for a raycast, yes. But apparently it's a shape cast?

vestal minnow
visual sparrow
visual sparrow
boreal tendon
#

Also, the player can go a biiiit into the terrain if I press hard enough. While I understand that the CC might not be optimal, wouldn't this be controlled by the underlying physics?

vestal minnow
visual sparrow
vestal minnow
visual sparrow
visual sparrow
molten mason
#

Something like a showcase where every single joint is explained and demonstrated might be nice, but I'm not sure if you would want every joint as another example instead of stashed together

vestal minnow
visual sparrow
#

Forgot to add it to the tracking issue for examples, fixing that

boreal tendon
#

When does the ShapeCaster do the intersection tests? I see where it's configured but not when it actually casts. is it a System as well?

vestal minnow
#

that is run near the end of the PhysicsSchedule

boreal tendon
#

Ah ok so it's a system ๐Ÿ™‚ thanks!

#

my spherical world is nearly working ๐Ÿ™‚

vestal minnow
boreal tendon
#

hmm, the arrow in the middle is the linear velocity. and it jumps around hard ... is that because of the colliders always giving some impulse?

boreal tendon
#

somehow it just falls in this one ๐Ÿ˜„ all the other ones don't seem to be a problem ๐Ÿ˜„

#

And I cannot use a ready made character controller I think because I need a polar coordinate system

edgy light
#

is it possible to project a shape on a plane and get its outline?

vestal minnow
edgy light
#

I'm using intersection_with_plane on TriMesh from parry... I guess I could do it every few units along an axis then union all the polygons ๐Ÿ˜„

#

that seems efficient

peak timber
#

My cat seems to be falling into the ground a bit ๐Ÿค”

#

I have Gravity(Vec2::new(0.0, -9.81 * 16.0)) since gravity is so slow in 2d (multiplying by 16 since I want it to be 16 pixels per meter)

errant laurel
#

It is all good unless the cat falls through the ground ๐Ÿ™ƒ. You could maybe try enabling SweptCcd on it, not sure if it will do anything.

astral smelt
#

Does using PhysicsPlugins::default().with_length_unit(16.0) instead of custom gravity help?

peak timber
#

and it does still fall in a little bit even with default gravity

#

I can open source my code if it helps

errant laurel
#

Sadly Avian is still pretty new and stuff, I used it in the recent jam and encountered a ton of issues with it, if you want to have perfect physics it is not the right tool yet.

peak timber
#

yeah bevy_xpbd was a lot more stable, I guess just some kinks to iron out with the refactor

#

I could use rapier in the meantime I guess

#

or try and make an Avian branch to fix this

vestal minnow
#

since your game is in pixels

#

oh mb bestRanar suggested it already

#

You need both that and the scaled gravity though. Gravity isn't scaled by the length unit, only internal tolerances are

#

Also xpbd was not more stable for the vast majority of cases, it had horrible stability issues and way more bugs (although ofc the refactor did cause a few new issues, but they should mostly be fixed). Most likely your situation just isn't configured correctly or there's some other issue

#

The examples in the repo do not have this sinking issue

peak timber
#

If I move the Collider into the parent (I have it in a child to offset it vertically), it doesn't sink into the ground

#

But it does re-introduce issues with colliding against the corners of overlapping squares (still haven't dug too deep into fixing that)

#

I tried removing the Restitution and Friction and neither seem to be causing it

#

then my ground is just a rectangle collider on a static body

visual sparrow
peak timber
#

I guess it used to be pretty explosive

#

I remember cubes flying apart at mach 10 when they collided sometimes lol

#

for whatever reason I never had collision issues like this in the 3d game I made with xpbd though

vestal minnow
#

In bevy_xpbd it wasn't as noticeable since collision detection was substepped (which was horrible for performance)

peak timber
vestal minnow
#

I'll look into it more tomorrow and try to fix it

quartz heart
#

Is it currently considered to add center and orientation parameters to the colliders (meaning you can have the collider on the main entity, but offset it by a cartain value and rotate it without needing to create a child entity and attach the collider there)?

vestal minnow
#

Not currently, that would add extra transformation operations everywhere where colliders are used since the engine now needs to take multiple different transforms into account

#

You can already use compound shapes to offset things though, they just have some more overhead

quartz heart
#

Maybe with relations it also become more convenient to use.

#

Currently working with unity ecs physics, and having those parameters is certainly very convenient.

#

And need to look into compound colliders for that indeed.

vestal minnow
#

I think the idea of a generic Translated<T> and Rotated<T> or similar wrapper for Bevy's shapes has been brought up in #math-dev at some point, it could maybe be possible to have opt-in offsets with something like that

#

APIs could use helpers so you could do e.g. Sphere::new(0.5).translated(foo) to get Translated<Sphere>

#

(might be tricky to support nicely with Parry, but I think I could support it decently in my own lib Peck if we plan on switching to it eventually)

quartz heart
#

How far along is Peck?

vestal minnow
#

It has ray casting, some point queries, support maps, GJK, EPA, and single contact computation, and then in bevy_heavy I have mass property computation, and in Quickhull a WIP convex hull computation algorithm. Peck doesn't currently have shape casting, contact manifolds, triangle meshes, heightfields, compound shapes, convex polyhedra, convex decomposition, and so on (although I do have issues with rough implementation outlines for these)

#

So pretty early stages, and reaching parity with Parry will take a lot of work and time

#

With GJK I can implement a bunch of geometric queries (shape casting, intersection tests, closest points...) really quickly and easily, but ideally a lot of shapes should have more optimized and robust analytic solutions

junior flower
fringe mango
#

if i want to temporarily "pause" an object so that it isn't affected by physics should I set its rigidbody to Rigidbody::Static?

visual sparrow
fringe mango
#

i guess it doesnt really depend becaues i want all objects to be paused

#

actually probably makes more sense to just set Time<Virtual> ๐Ÿค”

vestal minnow
#

use Time<Physics> and time.pause()

fringe mango
#

oh nice

#

thank you

fringe mango
# vestal minnow use `Time<Physics>` and `time.pause()`

for some reason it's giving me the error that there's no method named pause

fn set_time_scale(
    mut virtual_time: ResMut<Time<Virtual>>,
    mut physics_time: ResMut<Time<Physics>>,
    slider: Query<&Slider, (With<TimeScaleSlider>, Changed<Slider>)>,
) {
    if let Ok(slider) = slider.get_single() {
        virtual_time.set_relative_speed(slider.current);
        if slider.current == 0.0 {
            physics_time.pause();
        }
    }
}
vestal minnow
#

Are you not importing prelude::*? You might need to import PhysicsTime since 3rd party crates can only add methods to Time<Whatever> with extension traits

fringe mango
#

ah i was importing prelude::Physics, changing it to * fixed it ๐Ÿ‘

nova relic
#

Is there any prior art on combining avian with big_space? Doesn't have to be robust or anything (I suspect that would require at least simulation islands?). Just wondering if anyone's cobbled that together before

#

I guess one easy way could be f64 and a custom sync plugin, that might work well enough for now

#

or stick with f32 and copy paste the big_space GlobalTransform logic into a sync plugin if, avian doesn't mind the teleporting. I'm not simulating anything away from the camera anyway.

vestal minnow
#

relevant parts are recenter_position, the changes to position_to_transform, and probably something else

#

doesn't handle multiple floating origins though, and might have some other issues, but there was at least one project using this succesfully iirc

severe urchin
#

i fire a SelfDestruct event when an asteroid (2d poly) takes critical damage, and an observer calls commands.entity(asteroid_entity).despawn(). same observer triggers a bunch of SpawnAsteroid events to create smaller parts of the larger asteroid that was destroyed. (an observer for SpawnAsteroid calls commands.spawn(Asteroid...etc)).
I am getting warnings that the newly spawned smaller asteroids overlap at spawn, and i get explosive behaviour. I added a spatial query to the SpawnAsteroid observer, and it seems to be overlapping with the parent asteroid i despawned. i guess it's all happening in the same frame. those commands are sequential in the command queue. despawn happens first, but nothing is updated to that effect before the smaller asteroids get spawned. is this expected, and can someone suggest a better approach? thanks!

#

do i need to wait a tick before spawning the smaller parts, or is there a way to ensure the despawn is fully processed first

peak timber
#

for example (system_1, apply_deferred, system2).chain()

severe urchin
#

all the commands are in the queue though, since they are observers i'm not sure how i could use apply deferreed

vestal minnow
#

with auto sync points

peak timber
#

that must be new ๐Ÿค”

vestal minnow
#

since 0.13 at least

peak timber
#

ah I haven't used it since 0.11 I'm pretty sure

#

is there a way to opt out of it if you want the extra parallelization?

#

or does it only affect chain

vestal minnow
#

it doesn't affect parallelization, it's applied between systems that have commands and are ordered relative to each other, which implies opting out of parallelization between those systems anyway

peak timber
#

I see

#

that's pretty cool

vestal minnow
severe urchin
#

let me check

#

Fixed, since it's part of my client-prediction collision logic

#

in a FixedUpdate set that runs just before the physics sets

vestal minnow
#

hmmm

#

if you're getting an overlap warning then I'm pretty sure the entity must still exist at that point in time since the system that logs the warnings queries for the entities

severe urchin
#

yeah; i do a spatial query and it detects the original as an intersecting entity with where i want to spawn the new smaller one

severe urchin
vestal minnow
#

that one makes sense because the spatial query pipeline is updated after physics, so the despawn only registers the next frame

#

but for collisions there shouldn't be a delay

severe urchin
#

the flow is like this, all in fixedupdate:
system the processes collisions, and triggers TakeDamage events
observer on TakeDamage that issues SelfDestruct (on critical damage)
observer on SelfDestruct that calls commands.entity(e).despawn(), and then triggers a bunch of SpawnAsteroid events to create smaller asteroid parts
observer on SpawnAsteroid does a spatial query, sees it will overlap with original entity, if it calls commands.spawn anyway i see explosive behaviour and warning

#

i had this working pre 0.14 and pre observers, but it probably had a tick separation between despawn/spawn due to how it used systems and whatnot

vestal minnow
#

Just making sure, do the asteroids have child entities? If so, you'd probably want despawn_recursive (this probably isn't the issue though if it was working before)

severe urchin
#

no child entities

#

i could perhaps do the despawn in the same place as now, but move the "spawn a bunch of smaller ones" to after the physics sets. feels a bit inelegant though

#

that would mean 1 frame without anything at all existing though

vestal minnow
#

visually they would exist, but for physics, yeah

severe urchin
#

maybe i can use a collision filter of some sort so the small parts can't collide with the parent that's despawning, does that sound sane?

vestal minnow
#

hacky, but it could work

#

you could also remove the RigidBody, but that would probably have the same delay issue as despawning the entity

#

if it doesn't have the same issue, I'd be thoroughly confused lol

severe urchin
#

feels like there should be a way to remove a collider and place a different one at the same location all in one tick somehow, without any funny business. i'll experiement with some workarounds and see if i can provide any more useful feedback. i rather liked swapping over to observers and triggered events for this, but this has taken the wind out of my sails a bit

#

thanks ๐Ÿ™‚

vestal minnow
#

no problem ๐Ÿ™‚ lmk if you figure out the issue, I can't think of why the despawn would be delayed either on the Bevy or the Avian side

royal helm
#

Is there any way to include sensors in SpatialQueryFilter?

#

or do I just need to maintain a Sensors(HashSet<Entity>)

#

or is there a sensor layermask?

vestal minnow
#

you could have a collision layer for sensors and filter based on that, but there isn't a built-in sensor filter atm

royal helm
#

gotcha, just important for a kinematic controller

#

I'll just throw together a collision layer for it

#
pub const SENSOR: LayerMask = LayerMask(1 << 31);
pub fn add_sensor_mask(trigger: Trigger<OnAdd, (Sensor, CollisionLayers)>, mut layers: Query<&mut CollisionLayers>) {
    let Ok(mut layer) = layers.get_mut(trigger.entity()) else {return;};
    layer.memberships |= SENSOR;
}

pub fn remove_sensor_mask(trigger: Trigger<OnRemove, Sensor>, mut layers: Query<&mut CollisionLayers>) {
    let Ok(mut layer) = layers.get_mut(trigger.entity()) else {return;};
    layer.memberships &= !SENSOR;
}

observers ๐Ÿ™‚

#

@vestal minnow have you moved to using observers to add all of the other components? or is it slower

#

I've been havin a ball messing around with them

vestal minnow
royal helm
#

just a note: entity mapping is messed up with it, but I don't think any of the physics components use that except joints?

vestal minnow
#

Yeah I don't think other components use that currently

#

Good to know though, wasn't aware of that ๐Ÿค”

royal helm
#

yeah, they are working on it I believe, but it's just tricky

#

oh sensors dont get CollisionLayers added automatically

vestal minnow
#

nothing gets it automatically, the engine interprets entities without it as CollisionLayers::ALL

royal helm
#

oh never knew that

#

hmm

#

complicates this a little bit

#

I think I'd have to do this in reverse then

#

const NOT_SENSOR = LayerMask(1 << 31);

#

lol

#

or I just add/modify every body to have a collision layer

#

hmm, do other physics engines default to all layers for memberships?

#

just sounds weirdly backwards to me

vestal minnow
#

Rapier does

#

and iirc others do too

royal helm
#

the filter including every group makes sense but the membership is weird to me

#

"The default values are 0x0001 for categoryBits and 0xFFFF for maskBits"

#

for box2d

vestal minnow
#

I think that would make sense, yeah ๐Ÿค”

royal helm
#

I feel like it'd be more intuitive too

vestal minnow
#

I'm trying to think of why we wouldn't do that but can't come up with a good reason lol

royal helm
#

since otherwise you have to make sure every object has their layers set up correctly

#

since you'd get interactions you didn't expect between things

#

trying to find the defaults for unity right now and asked in the rapier discord about it

vestal minnow
#

Godot seems to default to just one layer (membership) and one mask (filter)

royal helm
#

yeah the filter defaulting to only 1 makes some sense too, but I think it's less important

#

not sure though

#

I think the filter one is just a tradeoff of default interactions vs special interactions

#

I am confused by unity's "collision matrix"

#

but seems like they default to all membership?

#

though idk if unity is the best source of good practices

#

I'm gonna throw together a PR for avian and rapier and just try to get some thoughts

#

I do feel pretty strongly about doing it the box2d/godot way though, I feel like that makes much more intuitive sense for the usecases of collision layers (plus it simplifies logic since otherwise it makes more sense to make memberships the opposite way like with the "NOT_SENSOR" thing I was talking about before)

#

just the filters part is iffy to me

#

this does mean we have to reserve 1 bit for a "DEFAULT" though

#

what's the point of all_bits? couldn't it just be a LayerMask(u32::MAX) instead of on a PhysicsLayer? I do see that it's derived to be all the bits in that specific physics layer though

royal helm
#

also ngl, filter seems backwards as a name as well

#

interacts or interactions makes more sense

royal helm
#

actually yeah no I can't even do the Sensor membership stuff currently I don't think

#

I'd have to instead of adding/removing the membership for sensor entities, modify every default object to not be a member of Sensor

#

otherwise I'd be excluding everything

sleek thicket
#

all my stuff has custom layers but gltf stuff was weird so it had to be default, everything broke because of it

#

@royal helm "31 layers" message should probably be something like 31 custom/additional layers

arctic fulcrum
#

Having a problem syncing state correctly - I have two chained FixedUpdate systems, control_player and control_camera. The control_player system sets the player (RigidBody::Dynamic) and the control_camera sets the camera's position to a fixed offset relative to the player. I explicitly set

app.add_systems(FixedUpdate, (control_player.after(avian3d::prelude::PhysicsSet::Sync), control_camera).chain()))

The control_camera script basically sets camera_transform.translation = player_transform.translation + CONST so the player should always be in the exact center of the screen. However, what happens is that most of the time, the player is "one frame ahead" of the center of the screen- so while moving right, they are slightly to the right of the center, etc. This would be just a minor hiccup, except that every few seconds, for a single frame, the player jumps to actually being in the right spot in the center of the screen, so there's a sudden and very visible jerk.

I'm not actually sure if this is avian-specific, but wanted to post here in case there were any insights/examples on properly syncing a camera to a rigidbody that don't have this problem.

arctic fulcrum
#

Ah, I see where I went wrong I think - avian3d seems to continue to run physics every frame, but my systems only run on Time::<Fixed>, so they usually lag behind

#

Hm, that doesn't actually help either, so I'm stumped

royal helm
#

I guess a real thing to think about with the filters including everything is why should they

#

but idk I'm still on the fence about it

vestal minnow
royal helm
#

I realized it also just makes certain things impossible with our current system without modifying everything else to not be the default anymore

#

I posted this in the rapier discord but:

since the default is ALL/ALL, the interaction will happen as long as any bit is set in my other membership/filter

e.g. I want to shapecast to find that CAR group right? how do I do that without also hitting every default object as well

since that collision group i pass to the cast_shape is membership: 0b0001, filter: 0b0001, when I shapecast and hit an object that is defaulted to ALL it does this: (0b0001 & 0b1111 = 0b0001) && (0b1111 & 0b0001 = 0b0001) and passes

vestal minnow
#

Also, while Unity does define which layers interact with each other with the collision matrix thing, it's not like objects belong to every layer by default. Objects can only be on one layer, and that is "Default", which essentially matches the "one membership, all filters" default, unless I'm misunderstanding what it does

royal helm
#

actually true I hadn't thought about that

#

going to go to sleep but I'll fix up the PRs more tomorrow

royal helm
#

idk I'm leaning towards maybe one member/one filter

harsh condor
#

Hi! I'm currently playing around with the kinematic_character3d example, potentially gonna try to implement the collide and slide algorithm. At the moment I have an issue with it that I'm not really sure how to approach.
My floor is made of tiles that each have a static body collider. My character has a capsule collider. When I walk from one tile to another, I sometimes get a large upwards impulse and fly into the air, even though the floor as a whole is a completely flat surface (just made of multiple colliders).
You can also see this in the official example - when you hug the wall facing the camera and walk towards the ramp, once you cross the edge between the wall's collider and the ramp's collider the player gets pushed away from the wall a bit.

I can sorta see why this may happen, but I don't know how other game engines / character controllers solve this.

#

At the moment of walking across the edge the collision vector does not point completely upwards. I don't know if this is a problem at the level of collision detection or at the level of collision response.

visual sparrow
royal helm
#

ok thinking about it more, 1 membership/all filter makes sense if using && for combining collision groups, 1 membership/1 filter makes sense if using ||, since the main thing we'd want from a user standpoint is custom groups that want to interact with the default should interact with it. If using && then the default needs to include all otherwise you miss those and don't have a way to interact with default objects

#

&& vs || however is another question

#

does it make more sense intuitively for a consensus between the two for the interaction to happen or allow either to decide whether the interaction should happen

royal helm
#

that essentially does the "overwrite defaults for everything" approach

visual sparrow
#

Not saying this outweighs the alternative, but this is a nice result of the current system that I want to highlight

visual sparrow
visual sparrow
#

One thing that is not working nice with the current bitmask approach is that editor support is basically nonexistent

#

To work with Blenvy, I still have to create this Preset struct, even if I was able to easily change the default layers

royal helm
#

you'd just have 2 layers, character, player right?

#

I guess hmm, yeah nvm I see what you mean

#

like a "player only" door that will collide with characters, but not players

#

or maybe im a bit confused

#

im a bit delirious right now, need to sleep

visual sparrow
cinder summit
#

Defaulting to ALL/ALL isn't particularly useful behavior at the very least

edgy nacelle
arctic fulcrum
# harsh condor Hi! I'm currently playing around with the kinematic_character3d example, potenti...

Although it doesn't really fix the problems you're seeing, you can use a floating character controller to mitigate most of these issues: https://youtube.com/watch?v=qdskE8PJy6Q

This is the approach Bevy-tnua takes

A detailed look at how we built our physics-based character controller 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 ~

โ–ถ Play video
gentle ridge
#

@vestal minnow hey qq, using avian right now for a basic character controller with 2d sprites

#

is there a way to have a pixel perfect collider (my game is pixel art, and the pixel art is small)

#

and have it change dynamically based on the current sprite that is being used (animation)?

#

like if a character is jumping and they do a flip, smaller collider for the flip and larger for idle etc

vestal minnow
# gentle ridge and have it change dynamically based on the current sprite that is being used (a...

No built-in functionality for that, but you can either just re-insert the Collider component or call collider.set_shape() to change the shape. For a character controller you'd typically want a capsule collider or maybe a (rounded) rectangle.

I think you could get the sprite's dimensions at run-time roughly like this

fn my_system(
    mut sprite_query: Query<(&Transform, &Handle<Image>), With<Sprite>>,
    assets: Res<Assets<Image>>,
) {
    for (transform, image_handle) in sprite_query.iter_mut() {
        let Some(image) = assets.get(image_handle) else {
            continue;
        };
        let scaled_image_dimension = image.size() * transform.scale.truncate();
        // Do something with sprite dimensions
    }
}

and update the collider based on that

gentle ridge
#

that is super useful thank you

#

is there a way to get the sprite shape for a pixel perfect collider?

#

like a polygon 2d in godot that automatically sets the shape?

vestal minnow
#

There's this 3rd party crate for generating colliders from images with transparency, and it has support for bevy_xpbd (Avian's predecessor), but it hasn't been updated for Bevy 0.14 or Avian
https://github.com/shnewto/bevy_collider_gen

#

Do you really need pixel-perfect colliders though? Generally they're not as great for performance or stability and the accuracy is rarely necessary

#

especially for something like a character controller, unless it's some really weird shape or something

gentle ridge
#

yeah it's not super needed i thought it would be interesting to test it out though

#

thank you @vestal minnow for your help!

nova relic
harsh condor
royal helm
#

I'm assuming the problem is just the KCC in the examples uses a naive/very simple collision response compared to the actual physics and tiles like that are a notorious problem with them

#

I'm making a simple KCC with collide & slide for my own game but I just don't really need a lot of features like auto-stepping

#

I have a collide & slide function you can use if you'd like, but just know you'd have to re-implement anything you'd want in a KCC still

harsh condor
#

Oh yeah that would be super helpful to take a look at, thanks!

royal helm
royal helm
#

I think that collision response stuff (flush colliders right next to eachother) is usually solved more with contact manifolds? I have no idea, jondolf would have a much better idea of how that stuff works

vestal minnow
#

the issue with bumping into tile edges is mostly a ghost collision issue, explained here
https://box2d.org/posts/2020/06/ghost-collisions/

royal helm
#

oooo box2d article ๐Ÿ˜ฎ

vestal minnow
#

it can be fixed for chain shapes or polyline colliders, and trimeshes (Parry can fix internal edges), but separate colliders don't have the knowledge of representing continuous surfaces like that, so the issue can't really be solved for them entirely

#

speculative collision can also make ghost collisions a bit more prevalent

#

the fixes are generally to use rounded colliders for e.g. the character controller (a capsule is good) and to maintain a slight margin/skin/offset around the character so it's slightly "floating"

#

disabling speculative collision for the character might help slightly as well, at the cost of potential tunneling issues (could use SweptCcd instead though)

#

In theory we could maybe make some tilemap collider that fixes the issue for them and has other optimizations, although I don't remember seeing prior art there

harsh condor
#

Thank you for the explanations! I'm not super familiar with game physics yet and have been having a hard time finding resources. Knowing the term ghost collisions will already help a lot

#

Does disabling speculative collisions mean setting the SpeculativeMargin to zero?

vestal minnow
#

Yup

royal helm
harsh condor
#

I promised myself not to look into networking until I've released at least one solid single player game haha. But will definitely check out more of box2d articles!

royal helm
#

thierryberger makes a good point of maybe the first layer should be the default, but also should still include that in the derive/let the user rename it normally, just with documentation about it

royal helm
#

@vestal minnow ty for the add function in avian, I've already built an entire virtual computer with it

vestal minnow
#

np, I'm glad you found it useful ๐Ÿ‘

royal helm
#

are shapecast results in avian accurate when penetrating?

visual sparrow
umbral verge
#

I wonder if the crate is already at a state where it can support most things a top-down 2d game needs, with respect to colliders with projectiles/swings which should affect physics (push back, pull, etc), and be kind of ergonomic with it compared to rapier/rolling my own thing

#

It looks promising but the v0.1 tag is scary haha

visual sparrow
umbral verge
#

Good to know
Iโ€™ll look further into it, thanks ๐Ÿ™‚

junior flower
royal helm
#

I need to start building a map and placing stuff by hand in files is rough

harsh condor
#

Hi, I have another question about the kinematic character example. Specifically this part:

for contact in manifold.contacts.iter() {
  if contact.penetration > 0.0 {
     position.0 += normal * contact.penetration;
  }
  deepest_penetration = deepest_penetration.max(contact.penetration);
}

If I understand correctly this is the code responsible for resolving overlap between colliders. But wouldn't this overshoot the goal if there are multiple contact points in the same manifold? E.g. when my capsule shaped character walks against a wall there would be multiple contacts each with the same penetration, but moving the body for each contact pushes it to a distance of three times the penetration depth. So would this perhaps be better?

for contact in manifold.contacts.iter() {
  deepest_penetration = deepest_penetration.max(contact.penetration);
}
if deepest_penetration > 0.0 {
  position.0 += normal * deepest_penetration;
}

With this code I can walk against walls without issues, whereas before I'd get bounced back in a strange way.

harsh condor
# royal helm

thanks again for the code! I've been playing around with it and have some questions if you don't mind. So if I understand correctly, with this approach you do not run a system using Res<Collisions> like in the kinematic controller example, and instead you manually cast the shape of the player in the direction of the velocity and compute the next position based on that. Is that right? With that approach I can now smoothly walk across the floor and and avoid ghost collisions. Second question is, how do you deal with multiple colliding objects? Not sure if I'm doing something wrong but when I walk against a wall at an angle I don't move at all. Also, since position is calculated manually, do you set LinearVelocity to zero to avoid the rigidbody being moved automatically by the physics engine? (Sorry if I'm asking too much ^^')

royal helm
#

but yeah, if the distance is too low it ends up not moving at all as well

#

I'm going to be working on that tomorrow though

royal helm
harsh condor
#

Btw if this works out the way I imagine then Bevy would enable much more precise character controls than are possible in Godot, since apparently it doesn't support sweep tests

vestal minnow
#

afaik you can also use the physics server, not sure tho

#

lmaoo code from Godot

harsh condor
#

I can't say I fully understand the problem (that's part of the reason I'm playing around with this in Bevy, to learn what goes into contact resolution) but a friend of mine has been fighting to get a decent character controller in Godot for years but has ultimately given up because Godot just is incapable of giving accurate collision information (in 3D at least). The project leaders have also admitted the physics is buggy and they can't find anyone to fix it

cinder summit
#

@vestal minnow Did you look at the compile errors without parry yet? If not I could make a PR if you let me know what solution is desired there ๐Ÿค”

vestal minnow
#

Not yet, but I can start working on it right now

vestal minnow
harsh condor
#

only if it interests you of course :) it's a bit of a long read

edgy nacelle
#

Quick assets processing question -- I'm trying to have a dynamic rigid body with colliders built from a gltf asset, and prevent physics from running on it until the asset is loaded & colliders built. I'm a bit confused which steps have to happen in which order:

  • I have a system that handles AssetEvent::Added for my gltf Scene, by inserting ColliderConstructorHierarchy on the scene asset's root entity
  • I spawn an entity with all the components I need, including Handle<Scene> (to load the scene from the previous step), but without RigidBody::Dynamic
  • I have another system that waits until the scene has been spawned as a child of the entity, then adds RigidBody::Dynamic to it
    But this results in the newly spawned object not colliding with anything at all? and I suspect I'm overcomplicating things.
visual sparrow
vestal minnow
#

*once CI is happy

edgy nacelle
visual sparrow
edgy nacelle
visual sparrow
edgy nacelle
#

I don't have blender in my workflow yet and it seems like overkill to start using it just so I can use gltf assets (which I already have) in bevy+avian

cinder summit
#

Everything seems to work except I get rollback issues ... Are there new components in avian to roll back compared to bevy_xpbd 0.5, or is there a determinism issue like @dreamy viper mentioned? ๐Ÿค”

dreamy viper
#

I only get rollback issues on collisions

cinder summit
#

Yea, that's what I get too. If I bump into a ball, the moment it touches another ball things will jump around

#

Occasionally it also happens on that initial collisions, so I guess it can happen for all collisions. So either a new component needs to be rolled back or collision responses aren't deterministic ๐Ÿค”

cinder summit
#

@vestal minnow what happened to not getting a lot of performance? There used to be multiple systems running as long as the green block at the end (generate_bvh) and even that got sped up by the 0.14 update (my last profile was on 0.13). You basically removed all the bottlenecks. The narrow phase especially. It runs 4x faster on top of not running in each of the 4 substeps

#

It is a bit funny how the longest running systems in the substeps are two mysterious closures inside the SolverPlugin tho ๐Ÿ˜‚

vestal minnow
#

Is there a nice way to pass an argument to a system instead of doing whatever this is?

peak timber
#

lol

#

a system.curry method would be nice

vestal minnow
#

I know there's In<T> but idk how to use it outside of one-shot system stuff

vestal minnow
vestal minnow
#

true, I guess that'd work

cinder summit
#

In<T> outside of one-shot systems normally involves system piping iirc

cinder summit
drifting marsh
vestal minnow
cinder summit
drifting marsh
#

I setup a system to record inputs to a file, play it back, and manually step frames to debug edgecases

vestal minnow
#

Hmm I don't suppose warm starting would be problematic? I.e. collision data from the previous frame is used to warm start the solver

cinder summit
vestal minnow
#

That can at least be disabled by setting SolverConfig.warm_start_coefficient to 0

#

to test if that's the issue

#

it'll just hurt stacking and overall solver convergence

#

pretty much all engines with an impulse-based solver do warm starting from what I know

cinder summit
#

Definitely not how the laws of physics work thonk

visual sparrow
visual sparrow
cinder summit
#

A swamp with explosive spheres bavy

vestal minnow
#

Ah wait, also try setting NarrowPhaseConfig.match_contacts to false ๐Ÿค”

#

I think there might be a bug where setting the warm start coefficient thing to zero still warm starts the impulses, but just doesn't apply them (but it affects the solver)

cinder summit
#

Ah, that behaves a lot better

#

Still seeing some minor jitters when walking into objects that aren't moving ... Do we have some form of sleeping that works now? ๐Ÿค”

vestal minnow
#

Objects can sleep when not in contact with other dynamic bodies

#

with islands we could make colliding bodies sleep too, as long as the energy for all bodies in that island is low enough

cinder summit
#

Yea that's the only situation where it goes wrong, I don't roll back any of the sleeping components so I guess that makes sense

#

They also only jitter for exactly 1 frame

vestal minnow
#

I think you'd need to roll back TimeSleeping and/or Sleeping

#

(or just disable sleeping)

#

TimeSleeping is a bad name ๐Ÿค”

cinder summit
#

Yea probably both ... I'll just disable it for now cause my rollback doesn't support adding/removing components

cinder summit
vestal minnow
#

Yep

#

SleepTimer or TimeInactive or something would probably be better

cinder summit
#

Like this right? .disable::<SleepingPlugin>();

vestal minnow
#

Yea that, or set a negative SleepThreshold

#

disabling the plugin makes more sense though

#

For the warm starting issue, is it viable to like... roll back Collisions? Or would that be too expensive / otherwise bad

#

I don't know networking stuff lol

cinder summit
#

A resource? Yea I guess that would be doable ... Yet another thing to add to my rollback thonk

#

Rollback isn't even really networking anymore, you just save the state every frame and load it when you rewind ... Similar to a time rewind system, but without being a really cool gameplay mechanic ferris_sob

#

No more mispredictions ๐Ÿฅณ

#

The physics are a bit explosive tho, I guess 4 substeps is a bit low without warm starting

vestal minnow
#

yeah warm starting is generally really important for proper stability with impulse-based methods

#

cc @dreamy viper: It's not really a determinism issue, the new solver just has "warm starting" based on the previous frame's contacts, which seems to be problematic for rollback. It should be fixed by either setting NarrowPhaseConfig.match_contacts to false (disables warm starting, can make physics less stable), or by rolling back the Collisions resource (haven't tried but should work?)

#

also roll back some sleeping components or disable sleeping

dreamy viper
#

What does warm starting mean?

cinder summit
#

Huh ... This bevy_xpbd -> avian port was surprisingly simple considering this change even includes updating my sdf collisions ๐Ÿค”

 22 files changed, 117 insertions(+), 108 deletions(-)
vestal minnow
# dreamy viper What does warm starting mean?

https://docs.rs/avian3d/latest/avian3d/dynamics/solver/struct.SolverConfig.html#structfield.warm_start_coefficient

Warm starting uses the impulses from the previous frame as the initial solution for the current frame. This helps the solver reach the desired state much faster, meaning that convergence is improved.

cinder summit
#

After disabling warm starting and sleeping, yes

#

And doubling the substeps ... Which is still a net performance improvement somehow ๐Ÿ˜‚

vestal minnow
#

magic โœจ

dreamy viper
#

and there was no warm start in xpbd?

cinder summit
dreamy viper
#

what is sleeping lol? i'll need to read more on the physics solver

cinder summit
#

Sleeping is a way to skip calculating for colliders that should not have been affected by physics and thus don't need to be updated

visual sparrow
dreamy viper
#

how come if you disable warm start, the object goes through walls? I assume it's becaues of sleeping?

vestal minnow
dreamy viper
#

I disabled sleeping and warm_starting; there's no rollback but the physics seem way worse. My ball still manages to go through walls

#

What would I need to do to rollback warm starting? Is that a component?

cinder summit
#

Probably the Collisions resource

#

And for sleeping it's Sleeping and TimeSleeping (which does not do what the name suggests)

vestal minnow
#

yeah roll back Collisions since that's where the contact impulses for warm starting are stored

dreamy viper
#

Is there a list of stateful resources/components? that could be useful to know for rollbacks

vestal minnow
#

Not currently, but I agree it'd be useful

#

I'll make an issue

dreamy viper
#

But also that would mean that my physics is less good and less efficient, because there's no sleeping and we don't use pre-cached results? And somehow my ball now goes through walls so I assume I need to increase the substep count

cinder summit
#

The list should probably also include conditions for when things should be rolled back or not. Like how you only need to roll back ExternalImpulse/ExternalForce if they're persistent

cinder summit
#

Rolling it back is definitely the more efficient option, especially since the settings need to match between client and server to be deterministic

#

And not having sleeping on the server sounds like a nightmare ๐Ÿ˜‚

dreamy viper
#

even with substep count 12 my objects cross walls; is the new algorithm better than xpbd?

vestal minnow
#

I'm not having issues with objects going through walls, even with warm starting disabled

cinder summit
#

Yea I don't have anything passing trough walls either, that's odd ๐Ÿค”

#

And I only have 6 substeps

#

Tho every collider in my game does behave solid unlike mesh colliders

edgy nacelle
vestal minnow
#

(one ball does tunnel through because it's pushed by another ball and there's contact softness)

dreamy viper
dreamy viper
vestal minnow
#

one thing you probably want is to set the length unit / physics scale if you're using pixels for object dimensions, similarly to what Rapier, Box2D, etc. have

#

PhysicsPlugins::default().with_length_unit(50.0) or something where 50.0 would essentially be 1 m = 50 px for internal tolerances and stuff

cinder summit
#

Does avian use the bevy_math's bounding anywhere? If so you'd also want to be on bevy 0.14.1, there's a few nasty NaNs that can pop up from bounding that got fixed in 0.14.1

vestal minnow
#

It doesn't iirc

#

(yet)

vestal minnow
vestal minnow
#

1.0

#

"1 unit = 1 meter" if we're assuming SI units

#

Ideally 2D games would scale the camera projection instead of using pixels for dimensions, at least for physics... but pixels can be useful for many games ig

dreamy viper
#

hm even with 50.0 or 100.0 i get weird physics

cinder summit
vestal minnow
#

yeah, true

vestal minnow
harsh condor
vestal minnow
vestal minnow
dreamy viper
#

but then we're still using warm starting?

vestal minnow
#

No, it disables it since contact matching is the thing that transfers the old impulses to the current/next frame. But yes setting the warm start coefficient should also work for this, there's just a bug there atm

dreamy viper
#

I just tried it, unfortunately i still have rollbacks

#

I'm actual doubtful that these are the issue. This is just a 1 player game where both client/server have exactly the same inputs

#

So there should be no rollbacks at all, so warm_start, Sleeping, etc. should have no impact

#

(disabling these might be important in case a rollback happens)

#

but there should be no rollbacks in the first place since client/server should basically be running the same simulation

#

so it has to be a determinism issue

#

let me remove all the networking stuff and turn it in to a determinism example for you

cinder summit
#

They don't always both start from the same default conditions right? Like the server usually starts first, then sends something to the client, and if that data isn't from frame 0 warm starting and sleeping could already have some impact

#

That said I can't actually test that specific thing, since I don't do conditional rollback. My game always rolls back when data comes in

dreamy viper
#

i can't reproduce the non-determinism in my test aha

vestal minnow
#

yep, I also haven't noticed non-determinism when testing in FixedUpdate before

dreamy viper
#

let me add more logs in the networked example, i definitely don't get the same values. Any ideas what I should log? Maybe Collisions?

vestal minnow
#

yes collision data in Collisions would probably be good

visual sparrow
vestal minnow
#

fixed

visual sparrow
#

that was fast ๐Ÿ˜„

vestal minnow
#

just used GitHub's UI :P

visual sparrow
#

Thanks, I was hoping to get that one in for some optimization in a project

vestal minnow
#

I've been holding off on merging so I could release a 0.1.2 patch without meaningful breaking changes without having to cherry-pick things

visual sparrow
#

I see, that makes sense!

dreamy viper
#

actually I have one

#

Server:

Collision detected event=Collision(Contacts { entity1: Entity { index: 16, generation: 1 }, entity2: Entity { index: 18, generation: 1 }, body_entity1: Some(Entity { index: 16, generation: 1 }), body_entity2: Some(Entity { index: 18, generation: 1 }), manifolds: [ContactManifold { contacts: [ContactData { point1: Vec2(0.34488943, -14.996035), point2: Vec2(13.712224, 20.0), normal1: Vec2(0.02299263, -0.99973565), normal2: Vec2(0.0, 1.0), penetration: -0.920166, normal_impulse: 1715.9131, tangent_impulse: 0.0,

Client:

Collision detected event=Collision(Contacts { entity1: Entity { index: 41, generation: 1 }, entity2: Entity { index: 43, generation: 1 }, body_entity1: Some(Entity { index: 41, generation: 1 }), body_entity2: Some(Entity { index: 43, generation: 1 }), manifolds: [ContactManifold { contacts: [ContactData { point1: Vec2(13.712223, 20.0), point2: Vec2(0.34488943, -14.996035), normal1: Vec2(0.0, 1.0), normal2: Vec2(0.02299263, -0.99973565), penetration: -0.920166, normal_impulse: 1715.9131, tangent_impulse: 0.0, 

The contact point is 13.712224 on the server, 13.712223 on the client

vestal minnow
#

okay I wonder if that's because the entities are flipped in the data

#

which maybe results in different computations somehow

#

Avian sorts entities in collision data based on the entity ID at the moment

#

I don't suppose there's a way for you to make that consistent across the server and client?

dreamy viper
#

Or another:
server: point1: Vec2(-9.58982, -11.534095), point2: Vec2(75.88797, 350.0)
client: point1: Vec2(75.88791, 350.0), point2: Vec2(-9.589782, -11.534127)

#

but even if the entities are flipped when reporting events, then the impulses sent to each entity should be roughly the same?

#

what are usually causes of non-determinism? order of additions/multiplications?

cinder summit
vestal minnow
#

hmm okay

dreamy viper
#

I guess we could try a branch where we have a CollisionPriority which we use to order entities

#

and check if I can reproduce it in those conditions

vestal minnow
#

Yeah that could be useful, to test if this could actually be the issue

dreamy viper
#

Could you point me to where avian does the sorting?

vestal minnow
#

src/collision/broad_phase.rs lines 240-244

#

We could technically remove that ordering, but the X-coordinate based ordering produced by sweep and prune is kinda weird and iirc it caused some collision event and warm starting issues

cinder summit
vestal minnow
#

yes

#

and the order changing also used to count as a separate collision event, even if the objects never actually stopped colliding, for example

cinder summit
#

Hmmm ... Might want to apply that ordering only to how they are fetched/stored and not to the calculations or something ๐Ÿค”

vestal minnow
#

To some extent I think this would also be fixed by just having a contact graph. Intersections between entities would just be edges on the graph, and it wouldn't overwrite edges with a different direction or anything

#

or I guess we could already kinda do that

#

would just need to check both (e1, e2) and (e2, e1) combinations every time you add a new collision since the order would no longer be guaranteed

#

But yeah I think the way this should eventually be handled is:

  • Broad phase collects all intersection pairs, no guarantees on order (other than determinism)
  • Narrow phase iterates over broad phase pairs, and adds undirected edges for each of them in a contact graph, unless an edge already exists
    Then the order of the entities for a given contact is essentially arbitrary, but stable
drifting marsh
dreamy viper
#

is there a tag for 0.1.1? main is broken for me

vestal minnow
#

How is it broken? ๐Ÿค”

dreamy viper
#

error[E0433]: failed to resolve: use of undeclared type Vector
--> /Users/cbournhonesque/Snapchat/dev/rust/.cargo/registry/src/index.crates.io-6f17d22bba15001f/avian2d-0.1.1/src/sync/mod.rs:233:46
|
233 | + accumulated_translation.map_or(Vector::ZERO, |t| {
| ^^^^^^ use of undeclared type Vector

#

hm it must because of a version issue

#

ah, it's because i wasn't using the same version in lightyear and in my example, sorry

vestal minnow
#

ah np

#

I was testing it and confused as well ๐Ÿ˜…

dreamy viper
#

happy to report

#

that without the entity sorting I get full determinism ๐Ÿ™‚

vestal minnow
#

Okay nice, that should be fixable

dreamy viper
#

how come sorting on aabb.min.x doesn't work? sounds like a good idea to me

vestal minnow
#

It's fine, just you can get both (e1, e2) and (e2, e1) and the collision code would need to be changed to not overwrite an existing collision between the entities if the order given by the broad phase changes

#

And to avoid duplicate events

cinder summit
#

I think it might be more efficient if the fetching logic sorts and swaps them for you ๐Ÿค”

dreamy viper
cinder summit
#

But yea I guess this source of error make sense, a - b probably errors in a different direction than b - a ๐Ÿค”

vestal minnow
cinder summit
cinder summit
dreamy viper
#

I don't get it lol

#

you're saying that we can have (e1, e2) once, and then (e2, e1) in a future FixedUpdate?

#

that's fine no?

vestal minnow
cinder summit
#

That's where the problems come from

#

If they flip the state isn't found and the event fires again despite the collision never ending

vestal minnow
#

and that order also determines which entity is entity1 and which is entity2 in collision data, which resulted in the issue of collision data being flipped between server and client in your case

dreamy viper
#

ah i see, because we want to keep some state to check when the collision ends, I see

#

Maybe we could also keep the entity-based sorting, but make sure that all the ops after that are still deterministic

cinder summit
#

Yea, so really we need storage to sort them, but everything else to keep the order based on position (because that's deterministic without relying on entity-order)

#

Importantly this would also need to include events, otherwise user systems will have the same determinism problem ๐Ÿ˜‚

#

bit perfect determinism really is all sorts of messed up

dreamy viper
#

btw what is the exact cause of the non-determinism due to the ordering?
What kind of floating-point ops depend on the order between e1 and e2?

dreamy viper
#

well at least i'm happy that we understand the problem

vestal minnow
#

Contact constraints also use the world-space contact normal on the first entity, so if the order was flipped, the normal would be the opposite. Not sure if this would affect results necessarily though

cinder summit
dreamy viper
#

It looks to me that this is possible:

  • keep storing (e1, e2) in aabb ordering in BroadCollisionPairs
  • this doesn't seem to be an issue because we're querying for both directions
  • the only problem seems to be in here (manifold matching), since the order of entities in the manifolds could be swapped. Just for manifold matching, we use the entity order, but the output of match_manifolds still uses the aabb order

Then the order of computations is always based on aabb, and we can successfully match on past data

GitHub

ECS-driven 2D and 3D physics engine for the Bevy game engine. - cBournhonesque/avian

vestal minnow
#

collision events still need to be handled as well

cinder summit
#

Oh right, @vestal minnow how similar would a 30 tickrate with 12 substep simulation be compared to 60 tickrate with 6?

vestal minnow
#

Probably fairly similar but I haven't tested much ๐Ÿค” Collisions would be checked less often with 30 Hz, so you'd be relying more on speculative collision or other CCD, and of course movement would be choppier without transform interpolation

#

Btw @cinder summit have you tested yet if speculative collision helps with the tunneling issues you were having at some point with dashes iirc?

cinder summit
#

I haven't tested that, tho I haven't recently had that issue even on bevy_xpbd 0.5 at 3 substeps

#

Maybe I lowered the dash speed after I ran into that or something

dreamy viper
cinder summit
vestal minnow
dreamy viper
#

the entities in Contact would be ordered based on aabb order

vestal minnow
#

The issue is that it will send CollisionStarted(entity1, entity2) or CollisionStarted(entity2, entity1) whenever the aabb order changes, even if the entities were already colliding

#

It iterates over Collisions

for ((entity1, entity2), contacts) in collisions.get_internal().iter() {
    // ...send collision events
}
#

and entity1 and entity2 would use the aabb order

#

again with a contact graph we would likely handle this differently and it'd probably be nicer

cinder summit
#

Wait ... Is Collisions used to generate those events? ๐Ÿค”

vestal minnow
#

Currently yes

cinder summit
#

I really should be rolling that back then I guess ๐Ÿ˜‚

dreamy viper
#

But those CollisionStarted and CollisionEnded events are purely for external use right?

vestal minnow
#

Yes

#

But getting collision events even when you haven't actually stopped or started colliding is weird and could cause bugs in user code

dreamy viper
#

do we have a unit test for this

dreamy viper
#

i think it's rather the during_previous_frame and during_current_frame, which seem to only depend on the manifold matching

vestal minnow
#

yes it's those during_ properties, but that's unrelated to contact matching

#

contact matching just transfers the impulses

dreamy viper
vestal minnow
#

yeah this breaks collision events like I suspected

dreamy viper
#

how do you know?

vestal minnow
#

you can try the sensor example and move the character in and out of the left side of the sensor

#

and get events every time

#

and break CollidingEntities as well I think

dreamy viper
#

hm that's weird, the code seems good to me though

#

i'll test it

#

you're right

#

my new version seems to work though ๐Ÿ™‚
although we'll want more thorough testing

vestal minnow
#

Does that still fix the rollback issue?

#

That looks like it's just moving the sorting from the broad phase to the narrow phase without removing the sorting issue ๐Ÿค”

dreamy viper
#

yep, works for me

#

No because the entities are sorted in aabb.min.x order inside Contact

#

just not in the key that is used for Collisions

#

as well as when computing the contact manifold

#

probably good to have @cinder summit test it as well

vestal minnow
#

mm I guess it could work, although I don't really love the inconsistency

#

or no it's probably fine...

#

methods like Collisions::get already don't care about which order users give entities in, from an API perspective

#

This would technically be a breaking change if anyone is relying on the entities being sorted by ID for whatever reason though

#

so I'm not sure if we could ship it in a patch without breaking semver

dreamy viper
#

it's ok it's not really an urgent patch imo

#

rollbacks don't really cause issues visually, they just lower the perf

vestal minnow
#

yeah, cool

#

I'll test the PR more tomorrow, I think it should be a decent fix for now

#

I'd like to "do it properly" once I rework the narrow phase to use a contact graph though

dreamy viper
#

In the contact graph solution, Contacts would still be sorted in order of aabb,
but Collisions would not be an IndexMap anymore, instead it would be a graph where each node is an entity?

vestal minnow
#

yes, each node is an entity, and each (undirected) edge is a collision

harsh condor
# drifting marsh I just uploaded my current code: <https://github.com/nezuo/avian-3d-kcc> Right n...

Nice! I've studied the code and played around with it a bit, looks more solid than what I have so far. Regarding the getting stuck on the ceiling, I may have found something that improves it? It's hard to tell because I don't know what the exact button inputs were in the replay, but what I did was change

if hit.time_of_impact >= SKIN_WIDTH {
  transform.translation += direction * (hit.time_of_impact - SKIN_WIDTH);
}

to just

transform.translation += direction * (hit.time_of_impact - SKIN_WIDTH);

i.e. drop the condition. The reasoning being that in the case when hit.time_of_impact is smaller than the skin we are in a situation that shouldn't happen (being too close to a an obstacle) and what we should do is move backwards by the necessary amount to be at exactly skin_width away from the collider. By dropping the condition hit.time_of_impact - SKIN_WIDTH can become negative and moves us by that required amount (I think, unless I got confused in the math somewhere). Maybe try it out and let me know if that fixes the issue you saw?

#

Ah but when I enable the floor I get stuck under the ceiling as well when trying to move sideways. I think to fix this the algorithm will have to be expanded to slide along multiple planes, like Freeman mentioned in his post. I'll try to figure out how that works from the Quake source code he linked
https://github.com/id-Software/Quake/blob/bf4ac424ce754894ac8f1dae6a3981954bc9852d/QW/client/pmove.c#L100

GitHub

Quake GPL Source Release. Contribute to id-Software/Quake development by creating an account on GitHub.

visual sparrow
vestal minnow
#

Got a very basic broad phase working with Griffin's OBVHS ๐Ÿ‘€ had to extend it to support proxies and arbitrary leaf data

#

pretty unoptimal atm and I don't have separate dynamic and static trees yet, but at least I seem to be getting intersections correctly

hoary finch
#

Avain specific newbie question I posted in #1019697973933899910 : #1269624819972964372 message

cinder summit
#

@vestal minnow I added resource rollback, added Collisions to it, and set my settings back and it seems to work ๐Ÿ‘€

harsh condor
# drifting marsh I just uploaded my current code: <https://github.com/nezuo/avian-3d-kcc> Right n...

I tried adapting Quake's movement logic. I can't say I 100% understand it, and there are some things I'm not happy with (sliding under the ceiling feels wrong somehow), but I have not gotten stuck anywhere using this code. Also made some random changes like adding the floor and some fake gravity. Let me know if you'd like me to make a PR, or you can just copy paste any parts you like manually.
https://github.com/tracefree/avian-3d-kcc

GitHub

Contribute to tracefree/avian-3d-kcc development by creating an account on GitHub.

#

Also do you mind if I show this to Freeman? He may have some more advice on how to make it stable and feel smooth

drifting marsh
#

Thanks for taking a look! You can definitely show it to him. As for the ceiling issue, your suggestion to remove the condition helps but the issue still exists. I did some work on this yesterday and I think this is the issue:

#

I'm still looking into a way to fix this though. I'll take a look at your quake-like code and see if I can understand it and learn from anything there.

#

@harsh condor

harsh condor
harsh condor
drifting marsh
#

I think I've seen the quake code with a fix for it, I'll have to look.

#

quake also has an "unstuck" algorithm that would help but I don't want to add that until the base movement code is good

harsh condor
#

Makes sense

drifting marsh
#

your code is based on quake 1?

harsh condor
#

Yeah, that's what I was linked to and what the paper above explains. Probably a good idea to compare to later versions, but think the basic idea behind the algorithm hasn't changed much

drifting marsh
#

so I noticed a difference with your implementation that was confusing me

#
let mut walk_along_crease = false;
                    'clip_planes: for i in 0..num_planes {
                        projected_velocity = extra_velocity.reject_from_normalized(planes[i]);
                        for j in 0..num_planes {
                            if j != i && projected_velocity.dot(planes[j]) < 0.0 {
                                walk_along_crease = true;
                                break 'clip_planes;
                            }
                        }
                    }
#

here, you project extra_velocity onto the planes but quake projects the first original_velocity

#

quake's makes sense because it's basically making all the projected velocities that were seen in the past

harsh condor
#

There were a few places where I didn't know what I was doing and kind of guessed to be honest :P I just tried changing it to original_velocity and that works too

#

(i.e. character_controller.velocity * time.delta_seconds())

vestal minnow
#

Got separate trees for active and sleeping/static bodies working, kinda cool to see it visually like this
white = internal node
cyan = active primitive
red = sleeping/static primitive

#

need to improve a bunch of update logic and maybe handle "fat AABBs" still

#

then I need to stress test this and compare against both the old SAP broad phase and Rapier

edgy light
#

nice to see you working on sleeping improvements! I piggy back on it to exclude some stuff from updates, works nice ๐Ÿ‘

vestal minnow
#

If I do full rebuilds anyway then I probably don't need it though

drifting marsh
#

This does fix the issue though. I'm just not sure what I should do about the y component.

severe urchin
#

i solved my weird explosive spawn issue btw, was caused by rotations on my player character, not overlapping spawns after despawning something. changing too many things at once ๐Ÿ˜ฌ

#

is it ok to have a child entity with a sensor collider, with a parent that has a normal collider? i just want a sensor to stick out in front and inherit the rotation

#

i recall that wasn't fully supported in bevy_xpbd a while back

severe urchin
#

great

vestal minnow
# vestal minnow Got separate trees for active and sleeping/static bodies working, kinda cool to ...

Not a very thorough benchmark yet, but I'm getting some interesting results in a basic stress test ๐Ÿ‘€

Setup is a grid of 100,000 bodies with a circle collider shot in random directions, and being slowly pulled back towards the center. The colliders have collision layers set up such that they do not interact, to focus on stress-testing the broad phase for tons of moving dynamic objects. Parallelism is enabled for all of these tests.

  • Old SAP broad phase: Starts at 6 fps, goes up to 15 fps as bodies spread out and move less relative to each other.
  • New BVH broad phase: Stable 20+ fps with Collider, and 38 fps with a custom collider. This implies that Parry's SharedShape might be a bottleneck?
  • bevy_rapier: Starts at 7 fps, and degrades over time all the way to below 2 fps. Slowly recovers to 7 fps as bodies get pulled closer again.
#

bevy_rapier seems very suspicious here, and it's interesting that the performance characteristics are opposite to my old SAP in that performance seems to get worse as objects spread out. Not sure what's going on there, although I know they have their own "Hierarchical-SAP" broad phase.

#

A better test would probably be to compare against Rapier directly, but it's interesting to see how bevy_rapier seems to struggle here

#

The collider type having an effect is also interesting, as there isn't much that operates on it with this setup other than computing the AABB and mass properties, and I think my custom collider type is doing basically what Parry does, just without dynamic dispatch

#

@grizzled depot You may also be interested ^

visual sparrow
vestal minnow
#

also add rand

#

One thing worth noting is that my broad phase can handle BVH traversal to collect the collision pairs in parallel, so it seems to scale decently; I'm not sure if Rapier's broad phase is parallelized, didn't look into how it works too deeply

#

(I also still haven't even properly optimized it lol)

cinder summit
vestal minnow
# cinder summit Also worth testing cases with low numbers of bodies. My raymarcher got a ton slo...

With 10,000 bodies:

  • Old, SAP: 1200-1400 fps
  • New, BVH: Stable 1400 fps
  • bevy_rapier: 130-140 fps
    With 1024 bodies:
  • Old, SAP: 1600-1700 fps
  • New, BVH: 1600-1700 fps
  • bevy_rapier: 900-1000 fps
    At very small scales the difference is of course smaller and the old SAP might even be faster in some cases if bodies are well spread out along the X-axis, but with such a high fps the difference probably doesn't really matter anyway
#

Also worth noting that the new BVH broad phase of course has separate dynamic and static trees, so it should generally perform better for scenes with a lot of static geometry. I need to benchmark that separately though

#

The new BVH might be a bit slower when single-threaded though atm

vestal minnow
#

the BVH building is the biggest bottleneck with this, even though this is using the Bvh2 with fastest_build, which is basically the fastest option based on tray_racing

cinder summit
#

The building is single threaded? thonk

vestal minnow
#

Hmm I do have parallel enabled for OBVHS ๐Ÿค”

cinder summit
#

Oh, maybe it just doesn't register things for tracing

vestal minnow
#

parallel only seems to give a few FPS more ๐Ÿค”

cinder summit
#

Just imagine how slow it would be with ploc-bvh ๐Ÿ˜‚

vestal minnow
#

the multithreaded build should be like four times faster

#

nvm

#

I was looking at vfb not tfb

#

apparently single-threaded fastest build is only slightly slower than multi-threaded fastest build

#

I feel like my numbers are still pretty low compared to a good dynamic BVH though, like what Box2D has

jade solstice
#

I don't know much about anything in this area but there's this library from Ralith and it may be of interest?

#

oh I see this library has already been talked about here a month ago

royal helm
#

@drifting marsh have you tried it with velocity instead of directly modifying position?

#

I'm having some issues of my character scaling walls

drifting marsh
#

tried what with velocity?

vestal minnow
#

the weird thing is that Box2D seems to have 3x faster BVH rebuilds even when doing full rebuilds with it

#

getting 5 ms full rebuilds for about 110,000 bodies with Box2D V3, and 18 ms in mine

royal helm
#

I guess you'd also not want physics to integrate that

#

or well hmm

vestal minnow
drifting marsh
royal helm
#

idk why but its broken a lot

#

trying to figure it out

drifting marsh
#

I can think of cases where that doesn't work

#

for example this

#

setting position manually calculates the red vectors, but start to end is blocked by an obstacle

royal helm
#

ya true

royal helm
#

I mean effectively it shouldn't matter

#

idk the issues are just weirder stuff like climbing walls

drifting marsh
#

do you mean if you walk into a wall it raises you slightly up or you are actually going to the top of the wall?

#

I'm working on adding gravity to my controller now and I have the first issue

royal helm
#

ya, it raises slightly up

#

I think the issue is there is a penetrating contact point on the cap of the capsules

#

but im not entirely sure

#

I don't see why else it would decide to go upwards

drifting marsh
#

well, this is the next issue I plan to work on so I'll let you know if I figure it out

royal helm
#

gotcha ty

grizzled depot
harsh condor
harsh condor
# drifting marsh setting position manually calculates the red vectors, but start to end is blocke...

Do you have collisions enabled in addition to the sweep testing? In my local copy I actually removed the collider of the character and spawn a capsule only for the collide and slide algorithm (not attached to any rigidbody). So the body does not get blocked by the corner if you set the velocity instead of the position. I tried it but have not found much benefit though, actually I'm concerned setting the velocity and letting the integration handle the actual movement leads to more floating point errors

#

Btw Freeman is preparing to send me the results of his research into KCC algorithms, I already received a great tip on how to choose a better direction to slide in when in contact with more than two planes

hoary finch
#

With CollidingEntities how can I get back the specific entity types that collided in the case where there are multiple colliders per entity? I'm not really sure how best to do this

visual sparrow
visual sparrow
hoary finch
vestal minnow
visual sparrow
vestal minnow
# hoary finch So not sure I have the ECS parlance/understanding right, but how do I get from C...

If you want to know what the player collided with, you could query for its CollidingEntities with something like player_query: Query<&CollidingEntities, With<Player>>.

Then if you want to know what those entities are, you could either:

  • Have CollisionLayers for your entities and check what layer(s) each of the colliding entities belongs to
  • Check if the colliding entities have some marker component using another query, for example checkpoint_query: Query<(), With<Checkpoint>>, and checkpoint_query.contains(entity)

And yeah if you have child colliders, then the rigid body entity can be found in the ColliderParent component

harsh condor
visual sparrow
visual sparrow
#

Also, do you think the collide-and-slide parts are upstreamable?

#

I imagine there's some on_ground check as well?

harsh condor
# visual sparrow I imagine there's some `on_ground` check as well?

Yeah but I'm not using it extensively yet, for now I just check for it before applying gravity. If the controller turns out general enough I think it would be really cool to include it in Avian eventually, but I've never upstreamed anything so I don't know how that works

visual sparrow
harsh condor
#

Makes sense

visual sparrow
#

It would be supremely nice if we could use your implementation as a starting point. If you need help upstreaming, let me know ๐Ÿ™‚

harsh condor
#

In that case I'll try to rewrite my version into a function instead of a system

#

@drifting marsh How would you like to continue collaboration? I'll likely play around a lot with different approaches in my local version, should we keep developing at our own pace in separate repos and exchange ideas/code sections occasionally, or would you rather have me make PRs to your repo? Also how would you feel about adding a dual MIT/Apache 2.0 license? (I have a local project that's not a fork of your repo but whose collision response is heavily based on yours plus the multi-plane-sliding, with your permission I'd like to publish that under MIT/Apache)

vestal minnow
visual sparrow
cinder summit
#

@vestal minnow How does CollidingEntities get updated? Should I be rolling that back too or is it just based on whatever touched in the last physics update? ๐Ÿค”

hoary finch
# vestal minnow If you want to know what the player collided with, you could query for its `Coll...

Thanks for the pointers, was able to get what I want working ๐Ÿ™‚ however I suspect there is a much more concise/correct way than what I ended up with:

fn interact(
    player_collisions: Query<&CollidingEntities, With<Player>>,
    cp: Query<&ColliderParent>,
    interactables: Query<(Entity, &Interactable)>,
) {
        for ce in &player_collisions {
            for cent in ce.iter() {
                let parent = cp.get(*cent).unwrap().get();
                if let Ok(interactable) = interactables.get(parent) {
                    println!("{:?}", interactable);
                }
            }
        }
}

vestal minnow
#

And that logic currently uses the during_current_frame and during_previous_frame properties iterating over Collisions

visual sparrow
cinder summit
vestal minnow
#

If I understood what you mean then yeah, I think so

cinder summit
#

Guess that's one more component for the list then ๐Ÿค”

visual sparrow
drifting marsh
drifting marsh
formal galleon
#

How can I enable SweptCcd for a Trimesh-Collider constructed by

ColliderConstructorHierarchy::new(ColliderConstructor::TrimeshFromMesh)

๐Ÿ˜Ÿ

vestal minnow
#

So I don't think there's really a good way to make that work. What are you trying to do?

formal galleon
# vestal minnow So I don't think there's really a good way to make that work. What are you tryin...

Thank you for your answer! Iโ€™m working on a game where the ground is a Trimesh Collider and the player is Kinematic. Whenever the player walks under an object, such as a rock, causing the player to be pushed from top to bottom, the player falls through the ground.

The game: https://x.com/m_morgenthum/status/1820098296976982103?s=46&t=QoSz6HTtQm3FeOZyydFPKQ

๐Ÿš€Wild Spikes progress!

  • Added main menu (with volumetric fog)๐Ÿ“œ
  • Pause menu (using substates)โธ๏ธ
  • Migrated from bevy_xpbd to avian3d ๐Ÿ› ๏ธ
  • Movement is a bit jittery (will fix) ๐Ÿ•น๏ธ
  • Introduced a few animations (not yet in sync) ๐ŸŽฅ

#gamedev #indiegame #BevyEngine

royal helm
#

hmm

#

It seems like when the normal of the hit object and the direction you are going are parallel the reject from becomes vertical

#

which makes sense I suppose?

#

actually maybe this is just floating point shenanigans

#

hmm, I'm not entirely sure how to solve this

peak timber
royal helm
#

I'm just going to add a buffer zone around that instability lol

#

if the length is < 0.05 just ignore, act like its completely flat

#

does no one actually solve this, just ignores it? I guess you could say that gravity would cancel it out for the most part, but still

royal helm
#

I guess really you need a basis

royal helm
#

idk still confused on how to solve this, I might just say fuck it and set y = 0 since I don't really care about sliding up

#

actually wait i solved this before

arctic fulcrum
#

Trying to debug more system-ordering issues - I have a system that sets:

  • my_entity.linear_velocity.0 = Vec3::new(20.0, 5.0, 0.0); // fling sideways
  • my_entity.collision_layers.filters = EXCLUDE_PLAYER
    so that you launch this sphere collider through the player. But what I'm finding is that if you start close enough, the projectiles seem to "bounce off" the player, even though the filter now excludes the player. It seems like a collision is happening with the new large velocity, but the collision filters haven't been updated yet. Is there a pattern I'm missing here that would make this just work?
#

Maybe I need to filter the collision during PostProcessCollisions?

severe urchin
#

i want a circular 2d arena, but i don't think there's a hollow 2d ring/donut shaped collider option available. should i just fake it with a bunch of rectangular colliders overlapping to make an inner circle? or is there another approach?

harsh condor
#

Do Sensors trigger an event on collision that can be observed using the observer pattern? If not, is that feature planned?

sleek thicket
#

and at least torus exists but you need to make it from primitive i think

vestal minnow
# harsh condor Do Sensors trigger an event on collision that can be observed using the observer...

Not yet, but I'd like to figure out an API for this, yes. One problem is that the collision events store both of the entities in the collision, but for observers the trigger already stores the observed entity so it's redundant to have both. Ideally the collision data would also be explicit about which contact point belongs to which entity. So we'd probably need separate events for observers and "normal" buffered events

#

As for sensors specifically, in the future we might also add a separate intersection graph and send intersection events instead of always computing contact data for sensors since it's more expensive and often unnecessary

harsh condor
#

I see, thanks! Looking forward to that then. In Godot I'm very used to connecting signals e.g. when the player enters an area around the goal, an intersection graph sounds useful since I don't need contact points in such cases

vestal minnow
#

But yeah a ring or donut shape would be pretty difficult to add without approximations like this since most collision detection algorithms rely on convexity

#

(unless you're NiseVoid and have SDF colliders)

severe urchin
#

alright thanks, i'll probably take the easier option for now and create a bunch of rectangles

sleek thicket
#

hm.. now i kinda want to make that dynamic ring just for fun...

visual sparrow
vestal minnow
#

You can still trigger them in parallel through ParallelCommands, right (although we currently send events serially)? So on Avian's side it shouldn't be a performance issue. The events also aren't used internally for anything, they're just for users.

Buffered events may also be valuable still, so they would probably continue to exist alongside observer events. Although I would like to reduce event spam and avoid sending events unless necessary. I think contact reporting is opt-in in most engines

visual sparrow
#

That way, you can run a one-shot system on collisions with that specific collider

vestal minnow
#

I would probably just do that with observers to avoid having to manually register systems, assuming there's a way to check whether a given entity is being observed before triggering the event

#

Another nice thing about observers is that we can bubble events from child colliders to the parent rigid body

#

(which may or may not be a good idea)