#Avian Physics

1 messages Β· Page 37 of 1

summer acorn
#

how can i help?

#

i looked more into the nesterov stuff not being faster and i think its just a matter of initial conditions and test case

#

its correctly implemented

#

it probably only helps on complicated convex hulls

#

but we should just do the gauss map traversal thing for that anyways

visual sparrow
past cargo
#

Perry the Platypus ?

#

I agree

#

Jondolf making a great job

summer acorn
#

unless theres something I specifically would be more of a help than others on, im inclined to not

summer acorn
#

ive got a renderer to fix lmao

past cargo
little maple
#

I definitely know a lot more about physics than I did before using avian πŸ€”

vestal minnow
#

Collision detection stuff for Peck (or otherwise) is one thing you'd probably be great for, but you're already kinda doing that with datura :P

#

Other than the GJK+EPA stuff, some things that I still need for Peck that are related to collisions and you could maybe be interested are

#

For large or complicated Avian work like the joint rework or solver optimizations, I tend to be quite wary of delegating work to others since I have ideas of how I would like to try and implement those, and I don't want others to spend a lot of time working on something just to have me turn it down or rework it again

#

I think one thing that I could definitely delegate more to others (anyone!) is to have more/better examples for Avian. We have a lot of features that don't really have their own examples, some examples could be merged (like a lot of the joint examples), we should have more examples demonstrating how to implement common but challenging physics-y things (buoyancy, fractures, vehicles), and so on

#

For this I think it would be a good idea to first make a list of examples that would be useful, and how they would be structured in the repo, rather than just adding examples for whatever randomly comes to mind

past cargo
#

I Just want see Avian merged into bevy, jondolf is goat

summer acorn
#

not really sure how you're going to handle that translation

#

the exploratory no-EPA gauss map optimization thing would be cool to bench against datura

#

i wonder if the extra bookkeepin ends up being worth it

#

maybe for complex shapes its worth it but not simpler ones

vestal minnow
#

It works πŸ‘€ I might've just cooked

#

Before:

fn apply_forces(query: Query<Entity, With<RigidBody>>, forces: ForceHelper) {
    for entity in &query {
        // Apply a force of 10 N in the positive Y direction.
        forces.entity(entity).apply_force(Vec3::new(0.0, 10.0, 0.0));
    }
}

After:

fn apply_forces(mut query: Query<Forces>) {
    for mut forces in &mut query {
        // Apply a force of 10 N in the positive Y direction.
        forces.apply_force(Vec3::new(0.0, 10.0, 0.0));
    }
}
#

@little maple This at least works properly with parallel iteration, you can just use par_iter_mut like normal

fn apply_forces(mut query: Query<Forces>) {
    query.par_iter_mut().for_each(|mut forces| {
        todo!()
    });
}
#

Screw it, merging now πŸ˜› I really like the API, and it's definitely a huge improvement over 0.3

#

yolo

little maple
#

lol I am only slightly dreading re-doing my vehicle controller to use this

visual sparrow
#

Impulses can no longer be persistent. Use persistent forces instead.
Thank you this sliiiightly annoyed me haha

#

Big fan of the removal of the External prefix too πŸ™‚

cinder summit
vestal minnow
#

ConstantForce is persistent, forces applied via the Forces API are not

cinder summit
#

Ah, neat

vestal minnow
#

Forces is essentially like Unity's Rigidbody.AddForce, Rigidbody.AddForceAtPosition, Rigidbody.AddRelativeForce, Rigidbody.AddTorque, and Rigidbody.AddRelativeTorque packaged under one dedicated type, using separate methods like apply_force and apply_linear_impulse rather than differentiating "force modes" via a ForceMode enum

#

And the components like ConstantForce are for persistent forces like the ConstantForce component also found in Unity's ECS physics

#

I was also considering calling ConstantForce like PersistentForce since it might be more accurate, but "constant" is cleaner/shorter, used by other engines (Godot, Unity) and maybe more commonly used as a term in actual real-world physics too

#

even though it's not truly constant since users can modify it

little maple
vestal minnow
#

At least it seemed like I was getting correct results, e.g. with a gravity of 9.81 m/s^2, a 1 kg cube stays floating when applying a 9.81 N upward force, or an upward linear acceleration of 9.81 m/s^2, or when applying an upward impulse of 9.81/64 kgm/s every frame (with a time step of 1/64 s)

#

and increasing/decreasing mass seemed to affect things correctly

#

but testing would be appreciated πŸ™‚ it could be that I still missed something

#

if you do see that values are different, let me know and I'll double-check

#

One important difference is that the point for methods like apply_force_at_point is now a point in the world, not a point relative to the body

visual sparrow
vestal minnow
#

No but it should be

#

Mm yeah I'll work on adding some unit tests for it now

little maple
vestal minnow
#

718 lines of tests πŸ™ƒ

#

mostly just the same thing duplicated for different APIs though

visual sparrow
sweet sundial
#

looking at docs on main, there's a double bracket in the new force docs at dynamics/rigid_body/forces/plugin.rs:103

vestal minnow
#

Thanks, I'll fix

bleak wadi
#

one of my hitboxes is hitting twice and i have no idea why
the exact same collision event happens twice, same entity and everything so it's not that i've made two hitboxes or something

vestal minnow
#

Maybe it bounces slightly so they're not colliding for a frame in between the events? Not sure why it'd trigger twice otherwice

vestal minnow
#

Unrelated, but currently we store raw geometric contact points local_point1 and local_point2 for ContactPoint:

// In 3D
pub struct ContactPoint {
    pub local_point1: Vec3,
    pub local_point2: Vec3,
    // ...other stuff
}

However, for internal physics purposes, I nowadays only really need two world-space anchors anchor1 and anchor2 that are relative to the center of mass, so I would like to store those instead. But for users, that'd be more annoying to work with, and quite often people specifically want access to global contact points.

#

I think we could get the best of both worlds by having anchor1, anchor2, and also a global point that is the average of the two points in world space:

// In 3D
pub struct ContactPoint {
    pub anchor1: Vec3,
    pub anchor2: Vec3,
    pub point: Vec3,
    // ...other stuff
}

point would be purely a user convenience for debugging and for gameplay logic that needs to figure out the infamous "where did these two shapes hit?" without having to manually transform points and do the math yourself

#

(also surprise surprise, Box2D does exactly this lol)

#

Unless someone complains, I'll make a PR for this tomorrow along with optimizing some constraint preparation logic that is related to this

#

(which in turn is related to the wide SIMD stuff :P)

#

Also I might finally change penetration to separation or distance since it's expressed that way in literally every other physics engine, but not 100% sure yet

sweet sundial
#

i feel like i've already asked, but is there a good way to get the force exerted by a collision? the kind of value you can use to play a sound or deal damage that scales with how "hard" something hits something else

visual sparrow
vestal minnow
# sweet sundial i feel like i've already asked, but is there a good way to get the force exerted...

The normal impulse is available, but I think it's not actually the value user code would want, since it's a clamped accumulated impulse for solver purposes, not necessarily the full collision impulse across substeps with restitution and everything added on. Contact constraints already have a max_normal_impulse (bad name, should be more like total_normal_impulse) which I think is closer to what you'd want, we just need to expose it in user-facing contact data properly

acoustic spoke
#

hi, i think there's a bug in main now; kinematic bodies are affected by gravity

vestal minnow
#

I can try to do that tomorrow as well

acoustic spoke
#

i had to add GravityScale(0.) to forcefully disable it

vestal minnow
#

hah whoops, I swear I tested that before merging the force rework stuff πŸ˜„ I'll try to fix it asap and then head to bed

#

should be an easy fix

acoustic spoke
#

haha okay, sorry for troubling and thanks for your amazing work πŸ˜„

vestal minnow
#

I even had a TODO for this

// TODO: Do we want to skip kinematic bodies here?
#

we should really add marker components for dynamic/kinematic/static, it'd make these filters more efficient and easy

acoustic spoke
#

ah so like splitting RigidBody into ZST components?

visual sparrow
vestal minnow
#

probably just the ZSTs and no enum though

acoustic spoke
#

(somehow i mixed up DSTs and ZSTs)

vestal minnow
#

but some shared component would still be good so you can iterate over all rigid bodies without caring about the kind of body, like a RigidBodyMarker or something

#

or just RigidBody but we'd want a panic or warning if you only have that without DynamicBody/KinematicBody/StaticBody specified

acoustic spoke
#

i wonder when Query-by-value is gonna land, it'll be cool to see this kind of pattern supported first-class

vestal minnow
#

I think we want to split RigidBody even ignoring query reasons, we want to have different required components for different types of bodies

#

Like static bodies don't need mass properties, forces, or velocity

#

But dynamic bodies do

vestal minnow
past cargo
#

@vestal minnow cmon jondolf, Its time to optimize It

#

So bevy can merge xd

#

Avian Will be the official one

bleak wadi
#

when using the normal despawn method, i actually get a warning because it tries to despawn it twice

visual sparrow
#

Not urgent or anything, I just want to keep it in the back of my head

bleak wadi
#

nvm, i tried deleting it instantly and it still has two events

sweet sundial
#

which event? reading them via EventReader?

bleak wadi
# sweet sundial which event? reading them via EventReader?

ok so i had a pretty weird setup where i had a trigger getting the hits, then that would trigger another event. i just refactored that into a single function (which is pretty long but anyway), but it turns out the real problem was that i added the trigger observer twice. but now i've got another problem, for some reason if i despawn the projectile on contact, knockback doesn't get applied. i have no idea why, but i suspect adding a frame delay will fix it since thats the setup i used to have

sweet sundial
#

it takes a few steps to actually apply force, my projectiles despawn when their velocity changes from initial + gravity

bleak wadi
#

is there an easy way to apply a frame delay?

#

i think that might be the easiest option, and if it doesn't work i can try something more complex

#

idk what it does but i'll try commands.queue()

#

oh thats only for spawning

sweet sundial
#

it's for commands that aren't the premade methods

#

there's actually a delayed command thing someone's trying to get into 0.17, i think?

bleak wadi
#

yeah, i saw that issue actually

#

are there any current solutions

#

if nothing else i could make an event for it but that feels like overkill

sweet sundial
#

a Local with a counter

bleak wadi
#

whats a local

bleak wadi
#

so what would i do with this?

sweet sundial
#

set it at the end of your system and check it at the beginning

bleak wadi
#

the system should only be running once though?

sweet sundial
#

do you have run_if()s on it? or is it not in a schedule at all

bleak wadi
#

no, it's triggered

sweet sundial
#

oh, observer

#

might be better in the schedule, but you can spawn an entity with a struct (Duration, Entity) on it that you check for in a schedule system

bleak wadi
#

that feels like overkill

#

i guess i could use a system though

sweet sundial
#

can put it in an event, but then you need to make sure the event reader doesn't run until the next frame

#

i don't think you want to delay it by exactly one frame anyway

bleak wadi
#

collision isn't working again what

#

*knockback

acoustic spoke
#

might be related, but Avian crashes when i insert Disabled to an entity that observes OnCollisionStart...

bleak wadi
# bleak wadi *knockback

i went back to the old version (before reworking stuff), deleted the one actual line that matters and now it's working ferris_sob

#

i didn't like how it used a separate event but it looks like i've got to anyway

#

its annoying i wasted so long but at least it's working

rough nebula
#

hello, so i split a collider into 3 smaller colliders (as children of the main rigidbody) and now whenever i apply torque it rotates much faster than earlier,
anyone know what causes this?

past cargo
#

@rough nebula you are applying the force on the 3 colliders

#

You need apply Just in one colliders that need be the center of the mass If you want it to go straight

rough nebula
#

hmm i am applying it to the parent object

past cargo
#

Show

#

The query

rough nebula
#

mut query: Query<(
&mut Transform,
&mut ExternalImpulse,
&mut ExternalAngularImpulse,
&LinearVelocity,
&mut Ship,
)>,
Ship is the parent object

#

the one with the rigidbody

past cargo
#

You are querying anything with externa impulse

rough nebula
#

no, im querying anything with an external impulse and ship

past cargo
#

Iam pretty sure

rough nebula
#

thats not how it works

past cargo
#

Oke so try make the others colliders Mass 0

#

Also make they dont collide with each other

maiden epoch
rough nebula
maiden epoch
#

AngularInertia and Mass

maiden epoch
vestal minnow
# maiden epoch I hated external forces, and this is so much better. Though for nonlinear, cheap...

In general I mostly treat the SubstepSchedule as an internal detail that users shouldn't need to worry about. It's prone to heavy changes and has limitations in what you can do, and most engines don't even allow you to have logic that modifies body state there. For your example, on the main branch, you can't even modify LinearVelocity directly, you would need to use the SolverBody since that is used for the solver

#

Also impulses are traditionally not something you apply over several substeps, forces are used for that

tribal hazel
#

anyone know if there's a significant performance difference between raycasts and shapecasts?

vestal minnow
maiden epoch
maiden epoch
vestal minnow
vestal minnow
maiden epoch
#

The Avian may not be the most performant engine due to reliance on ECS performance, but it definitely can be the most customizable one.

acoustic spoke
#

is there a way to create a very minimal avian project (preferably headless) to test things out as a minimum reproducible example?

vestal minnow
#

Just a basic Bevy app with DefaultPlugins is probably the easiest

#

You can set up a MinimalPlugins config too but IIRC there are some additional plugins you'd have to cherrypick currently, at least in 3D

#

for like scene stuff and whatnot, though we should make minimal setups easier

acoustic spoke
#

that's interesting... bevy with default-features = false has this amount of crates

#

and then it pulls this amount of crates when i add avian2d?

vestal minnow
#

oof

acoustic spoke
#

-# yeah there is no escaping year-long compile times is there...

vestal minnow
#

Is this Avian with default features?

acoustic spoke
#

yea- oohhh i see avian depends on bevy_scene by default

vestal minnow
#
avian2d = { version = "0.3", default-features = false, features = ["2d", "f32", "parry-f32"] }
#

(or the main branch, though I don't think we've changed much collider stuff there)

acoustic spoke
#

okay that works

#

no more year-long compile times, only month-long ones!

acoustic spoke
#

and it crashes with root entities too -- should i open an issue report?

vestal minnow
# acoustic spoke

Yeah I can reproduce this with both observers and EventReader, though it only seems to happen with Disabled, not with ColliderDisabled or when despawning

acoustic spoke
#

yeah i think the crash on despawning was on my part--although i wasn't trying to despawn it anyway in real life scenarios

vestal minnow
#

Oh I think I know why this happens lol

#

lmaoo

#

okay yeah the fix is to change this

mut query: Query<&mut CollidingEntities>,
collider_of: Query<&ColliderOf>,

to this bavy

mut query: Query<&mut CollidingEntities, Or<(With<Disabled>, Without<Disabled>)>>,
collider_of: Query<&ColliderOf, Or<(With<Disabled>, Without<Disabled>)>>,

waiting eagerly for Allows<T> πŸ™

visual sparrow
acoustic spoke
vestal minnow
#

yeah Disabled needs to appear in the query

acoustic spoke
visual sparrow
acoustic spoke
vestal minnow
visual sparrow
visual sparrow
#

I would have expected it to just ignore everything that is disabled

#

(Asking mainly because I wonder if I should be considering it somewhere as well)

vestal minnow
#

I mean it's not too bad but mostly just a bunch of OnAdd and OnRemove observers need to also consider Disabled to add/remove colliders from various data structures and to remove contact pairs etc. when entities are enabled/removed

#

And in those observers I sometimes need to be careful with queries to make sure they include disabled entities

#

For example this specific case was this

// Remove collision pairs when colliders are disabled or removed.
app.add_observer(remove_collider_on::<OnAdd, (Disabled, ColliderDisabled)>);
app.add_observer(remove_collider_on::<OnRemove, ColliderMarker>);

and remove_collider_on had a query that incorrectly didn't include disabled entities

visual sparrow
acoustic spoke
#

meanwhile i came up with this crazy hack to remove all components reflectively instead of adding Disabled, and it doesn't even work cleanly because i still need to reset several things like linear velocities and sprite states

visual sparrow
#

That means they all crash

#

Since I unwrap

#

Or I early return, which would mean that the components were not initialized properly

#

This is quite the footgun πŸ‘€

vestal minnow
#

yuuup

visual sparrow
#

Thanks for bringing this to my attention

little maple
#

my morning coffee still hasn't hit, I'm not understanding... is the problem that you were accidentally ignoring disabled colliders?

little maple
#

ah that's good to be aware of

#

I need to check my observers

vestal minnow
rough nebula
#

While the mass i used was still used for forces because linear and angular mass is different? πŸ€”

vestal minnow
little maple
#

I can see the utility of having a common Disabled component but yeah, that seems like a source of tricky scenarios that are hard to reason about πŸ€”

vestal minnow
#

Mass is resistance to linear acceleration, AngularInertia (or "moment of inertia") is resistance to angular acceleration

#

Rigid bodies use ComputedMass and ComputedAngularInertia for the actual values used by physics. By default, they are computed automatically based on colliders, but can be overridden with Mass and AngularInertia

#

If you specify Mass, it also scales the automatically computed angular inertia, unless you explicitly set it with AngularInertia

vestal minnow
#

how do I make this function not so horrible thonk

pub fn contact_manifolds(
    collider1: &Collider,
    position1: impl Into<Position>,
    rotation1: impl Into<Rotation>,
    local_com1: impl Into<CenterOfMass>,
    collider_transform1: &ColliderTransform,
    collider2: &Collider,
    position2: impl Into<Position>,
    rotation2: impl Into<Rotation>,
    local_com2: impl Into<CenterOfMass>,
    collider_transform2: &ColliderTransform,
    prediction_distance: Scalar,
    manifolds: &mut Vec<ContactManifold>,
) {
#

I could maybe have it be something like

pub fn contact_manifolds(
    collider1: &Collider,
    position1: impl Into<Position>,
    rotation1: impl Into<Rotation>,
    collider2: &Collider,
    position2: impl Into<Position>,
    rotation2: impl Into<Rotation>,
    prediction_distance: Scalar,
    manifolds: &mut Vec<ContactManifold>,
    manifold_builder: Fn(impl Iterator<Item = LocalContactPoint>, &mut ContactManifold)
) {
#

so then the caller (NarrowPhase::update_contacts in this case) can handle all the transformations and stuff to build the manifold from the given points

#

but it's kinda weird

maiden epoch
little maple
#

this might not be that avian-specific but I'm kinda curious because most of my transform changes are occurring due to avian

how many runs within a frame should I expect there to be of propagate_parent_transforms? (this is all within one update frame and the flags show where avian physics schedule starts and stops)

vestal minnow
# little maple this _might_ not be _that_ avian-specific but I'm kinda curious because most of ...

So this stuff is kinda messy but

  • once before physics to make sure child collider positions are up-to-date
  • twice right after physics
    1. right before transform-to-position sync to account for user Transform changes that happened during the physics step
    2. right after position-to-transform sync to make sure child transforms are up-to-date
      However I think we should axe the transform-to-position sync that happens right after physics and just disallow using Transform in the PhysicsSchedule in favor of Position and Rotation. And also remove all of the propagation that we do after physics since it shouldn't affect actual physics behavior, and Bevy runs its own propagation later anyway, so visually it should look correct
#

This would cut the number of propagation passes from 4 to 2, once right before physics and once at the end of the frame with Bevy's own propagation

visual sparrow
visual sparrow
#

Less then the GPU stuff though πŸ™‚

vestal minnow
#

Actually I think we could/should also axe the propagation before physics since it's only useful if people manually modify transforms of parent rigid bodies, which is not recommended anyway

little maple
vestal minnow
#

So then Avian wouldn't do any propagation, it'd be all Bevy

little maple
vestal minnow
little maple
#

yeah, I have a pretty smooth teleport thing working at the moment but it's like one-off teleports, not continuously doing it

vestal minnow
#

Lemme try this, it'd remove like half of the SyncPlugin πŸ˜‚

little maple
#

I'm sorry I nerd sniped you into doing something crazy

vestal minnow
#

nah this is good

#

I might finally remove PreparePlugin and rename SyncPlugin to PhysicsTransformPlugin

#

mm also we need to rename our system sets from FooSet to follow the FooSystems convention (that I myself added for Bevy lol)

visual sparrow
little maple
#

I'd be surprised if the answer to my question is actually "oh, we can just remove all that"

vestal minnow
#

"oh these systems are taking half of your frame time? k remove them then"

little maple
#

"it's actually faster if you remove the avian plugin πŸ€“ "

vestal minnow
#

"why not turn off your computer?"

visual sparrow
#

If your physics are so deterministic, why don’t you just precompute all frames of the game??
Checkmate Avian fans

vestal minnow
#

it appears to work, with the caveat that sleeping is broken

#

I'm guessing it breaks the current hack of using PreviousGlobalTransform to avoid unnecessarily changing transforms every frame

#

wait

#

hah no it did not break sleeping

#

it's already broken on main πŸ˜‚

#

yeah it's just the force stuff waking bodies up when it shouldn't... I wonder what we actually want to do with sleeping and forces

#

Specifically, should applying a force or impulse wake up a sleeping body?

#

Historically for Avian it has, because I wanted things to "just work" and that sleeping is purely an internal optimization

little maple
vestal minnow
#

However, overwhelmingly the default is actually no in other physics engines (Rapier, Box2D, Jolt) and you need to explicitly specify that you want to wake up the body

#

In general you want to avoid any cases where you unnecessarily wake up bodies, like let's say you have custom planet gravity via forces and a body is resting on the surface of a planet; it should be sleeping

#

But I do think we probably want to default to waking up bodies

little maple
#

I can see how it'd be desirable to control that. That does seem kinda annoying at the same time though

vestal minnow
#

Similarly, a lot of engines don't automatically wake up bodies when gravity changes, or when you remove a surface from under a body

#

I think I'm still of the opinion that sleeping should be fully transparent to the user by default, but there are ways to avoid waking up bodies when you need it

maiden epoch
#

I think impulses should wake up bodies, and forces should not

vestal minnow
#

Imo it should be configurable for both, but the defaults should be consistent between different types of forces

#

So wake up by default for both but have a way to change it

little maple
#

that makes sense to me

vestal minnow
#

Rapier has a wake_up boolean argument in all of its force APIs

rigid_body.add_force(force, wake_up);

Box2D has the same

#

I'm not sure if I like having it in all the APIs like that though

#

or bevy_rapier has no way to configure this, it just never wakes up bodies when applying forces

little maple
#

that's a tough choice

vestal minnow
#

I think we could do something like this

forces.apply_force(force).wake_up(false);
#

where it defaults to true

#

but it does make the default more implicit, for better and for worse

#

and for the constant force components it'd be awkward, but I think for those it's fine if we don't wake up since they're "constant"

#

It's interesting since physics engines tend to expose more control here and prefer the solution that is best for performance, but game engines focus on providing user-friendly defaults for their APIs that wrap those physics engines

#

And Avian is kind of in the middle where it's both the implementation and end-user API

vestal minnow
#

Or maybe call it no_wake_up() to better signal that the default is to wake up

little maple
vestal minnow
#

I'm not sure we want it to be globally configurable though

little maple
#

I guess if it's not globally configurable then it doesn't make sense to have a boolean parameter, right?

vestal minnow
#

yeah

#

mm this sort of API does feel kinda weird though because of cases like this

forces.apply_force(force).no_wake_up();
forces.apply_torque(torque); // should this wake up?
little maple
#

that second line should wake it up, right?

vestal minnow
#

yeah I think so, but we need methods like apply_force to return a sort of builder to make it work like that

#

and wake up / not wake up on Drop

#

it'd be really nice if we had argument defaults... πŸ™ƒ

pub fn apply_force(&mut self, force: Vector, wake_up: bool = true) { ... }
#

Or even this

pub fn apply_force<const WAKE_UP: bool = true>(&mut self, force: Vector) { ... }
#

Hmm or we actually already don't allow chaining for the force API right now, so we could make it like this

forces.apply_force(force); // this wakes up

forces.disable_waking();
forces.apply_force(force); // this would not have woken up
#

that seems fine

#

and then on Drop it is reset

little maple
#

that seems reasonable

vestal minnow
#

I don't think I can store local data on QueryData so naturally I'm making a separate private component with bitflags just to control this waking behavior :P

bitflags::bitflags! {
    impl ForceFlags: u8 {
        /// If set, applying forces, impulses, or acceleration will wake the rigid body.
        const WAKING_ENABLED = 1 << 0;
        /// If set, the rigid body is queued for waking by a force, impulse, or acceleration.
        const WAKING_QUEUED = 1 << 1;
    }
}
vestal minnow
little maple
#

I fear Alice is going to point to this as evidence that we have plenty of people who actually would review but don't or something

hoary turret
#

Is there a default unit of measure for the engine, I'd assume it would be 1 unit = 1 meter.

little maple
#

(I did approve)

hoary turret
#

and if there is, is it configurable somehow?

hoary turret
#

thanks ❀️

#

yeah so it's in fact meters by default

#

nice, Imma test scaling it down a bit

#

as I want to simulate a pachinko/pinball kind of thing

#

hmm

#

hmm

#

I set it up to 1000:1 and rigidbodies are freezing πŸ€”

sweet sundial
#

maximum sleep velocity is scaled

hoary turret
#

yeah I assumed that would be involved

#

but I thought this was one of the things that the WorldScale parameter is for

halcyon dew
#

it does say "It is recommended to configure the length unit to match the approximate length of the average dynamic object in the world to get the best simulation results."

#

so i think instead of using it as a way to get objects to feel larger/smaller you should scale it to the world-size of your pachinko ball and then just tweak the other numbers accordingly?

sweet sundial
vestal minnow
#

Oh I thought of a pretty nice way to handle the force waking thing, we can just have a ForceWaking component

#[derive(Component, Default)]
pub enum ForceWaking {
    #[default]
    Wake,
    NoWake,
}

This can be a required component for rigid bodies, and then Forces would just have a way to set it

// Prevent forces from waking up the body
// until the waking mode is set to `Wake`.
forces.set_waking(ForceWaking::NoWake);
#

This makes the default documented via required components, and also allows users to set it per-entity if desired

little maple
#

I'm trying to think of scenarios where that would be less friendly like.. if you had a force that wanted to apply to everything regardless like an explosion but you don't want to alter all the components πŸ€”

slim ledge
#

Or you know... a boolean tuple struct struct ForceWaking(boolean) πŸ™‚

vestal minnow
#

I renamed it to ForceWakingMode since ForceWaking sounds like "this forces bodies to wake up" rather than "this configures whether forces wake up bodies"

#

In Jolt there is a similar EActivation enum with Activate and DontActivate variants, which is passed as an argument to methods like AddForce, defaulting to Activate

#

(I don't like DontActivate because it's "don't", not "dont", I'm nitpicky like that)

cinder summit
#

Just typo the Wake a bit and then the other variant shows up by itself

#

Woke and Broke thonk

vestal minnow
# slim ledge Or you know... a boolean tuple struct `struct ForceWaking(boolean)` πŸ™‚

I made this an enum because I like that when you're calling set_waking_mode, you see the ForceWakingMode component in the method call instead of a random bool. This is self-documenting in the sense that it makes it clearer that it is directly connected to that component, and it is not some independent waking configuration that is somehow local to Forces in that system

cinder summit
#

Actually Wake or Break could work, because if you don't Wake the entity, it will Break the expected behavior of your forces 🀣

#

But does setting the waking mode actually work? If system A sets it to no wake, then B applies forces and does expect it to just wake but doesn't set it since it's the implicit default behavior, will it wake or not?

vestal minnow
#

It will not since you've set the force mode to not wake

#

But you could reset it after applying the force if you wanted to

#

but yeah that is probably the main downside with this approach

silk mauve
cinder summit
#

I mean it's written for bevy, which has probably the highest % of LGBTQ people of any game engine community, so objectively it is the wokest physics engine

#

Even if Jondolf is afaik not part of the LGBTQ+ community yet

silk mauve
#

Hack commedian: "Avian is so woke, when Jondolf implemented the pronouns component, it just wrapped a string!" Audience proceeds to burn down the venue

cinder summit
silk mauve
#

Sorry I'm done

vestal minnow
#

Really the ideal approach would be default argument values

fn apply_force(&mut self, force: Vector, wake_up: bool = true) { ... }

but we can't have that because of Rust. And I have not figured out a nice way to make the chaining approach work in any logical and intuitive way, and it has a lot of weird cases like this

// does the first or second force here wake? or neither?
forces.apply_force(force).no_wake().apply_force(force);
// does the previous no_wake still apply here or not?
forces.apply_force(force);
cinder summit
#

Can we do like

#

forces.non_waking().apply_force(force)?

#

Everything from .non_waking() doesn't wake, until you drop the retrun value from it and use force directly again

vestal minnow
cinder summit
#

Ofc these cases shouldn't actually happen, since you either want all forces to be waking, or none of them, or the waking force is conditioninal (and thus in a seperate codeblock, or sometimes zero)

#

I guess that's also worth considering: A waking force of zero shouldn't wake

vestal minnow
#

yeah I have that

cinder summit
#

Alternatively, don't allow chaining

vestal minnow
#

mm we can probably do forces.non_waking().apply_force(force) and disallow chaining for the actual force methods

#

(we already don't allow chaining atm)

#

the question is just how we do it cleanly and efficiently, we might need non_waking to return a wrapper type or something

rough nebula
#

aaaaaa
why is the field of RigidBodyColliders private??

cinder summit
rough nebula
#

i should be able to access all child colliders of a parent rigidbody....

cinder summit
#

Might even have both implement a trait so they have identical methods and could be passed to APIs in a way that's waking agnostic

vestal minnow
#

We can't allow direct mutable access to the field since it would let you break the relationship if you added or removed colliders through it

#

Children is the same way

#

but we can add read-only access

sweet sundial
#

honestly i feel like the simplest solution for the waking thing is forces.apply_force(_); forces.wake();, but that leaves the default off
there could probably be a Forces::reborrow, so making a wrapper struct for non-waking forces could mean also implementing QueryData for it & letting the fns to swap between them consume

vestal minnow
#

I did get non_waking working now

forces.non_waking().apply_force(force);
#

There's a ForcesItem which is what the Forces QueryData returns, and a wrapper NonWakingForcesItem which is returned by ForcesItem::non_waking

#

The two types of force items share a RigidBodyForces trait, and an associated WAKE_UP constant is used to determine whether it should wake up bodies or not

vestal minnow
vestal minnow
#

It's some internal boilerplate but I think I like this

bleak wadi
#

i recently found out about the Rotation component, whats the benefit over just using transform.rotation?

vestal minnow
#

For user code you should typically just use Transform

#

(FYI @rough nebula)

hoary turret
#

How would you guys go about having stacked structures be more stable? I'm building an angry-birds-esque type of game and I'm mainly doing towers of bricks like in Jenga.

#

I know simulating all the time and expecting physics to be stable and not crumble is not acceptable due to it being... well... the main bottleneck of physic engines...

vestal minnow
#

but my PR provides some easier access

hoary turret
#

so I'm okay with workarounds, that's mainly what I'm asking for

#

is there a way I can make a group of colliders "disabled" until an strong force is applied?

#

so that I could start the world with the entities in place but "frozen" (as I know the should be stable) and as soon as a "big hit" happens they unfreeze and start simulating again

#

Because this "isn't working" and I know it won't get anywhere near perfect, given that I'm probably going to stack way more rigidbodies than these

vestal minnow
#

You can increase the SubstepCount, though that amount of jittering seems a bit abnormal with such a small stack. Once they're mostly settled, sleeping would deactivate them and remove any remaining movement, but it currently doesn't work for piles or stacks of dynamic bodies because we don't have simulation islands yet

#

What colliders are those?

#

Cuboids would probably have the best results

hoary turret
#

Yeah, already tried increasing substeps but the framerate tanks way too much and it doesn't really get that much better

#

These are unfortunately generated trimesh colliders

#

from the bevy_trenchbroom plugin

#

didn't know that would have an effect on simulation accuracy

vestal minnow
#

I think you should be able to set a different generated shape for it, lemme check how we handled it in Chainboom

hoary turret
#

are simulation islands coming any time soon? because I would probably greatly benefit from it if it puts them to sleep

hoary turret
#

hahah

#

a jam game?

vestal minnow
hoary turret
#

gotta check it out

vestal minnow
#

The setup module has the collider setup stuff

#

Which can use any ColliderConstructor

vestal minnow
bold garnet
#

I watched that thread pool talk. It's interesting that he gets so much power out of spinning. In general, spinning instead of sleeping performs worse on most of my benchmarks. It might be because the tasks are so truly tiny.

#

I'd love to get graph coloring set up as a benchmark.

#

Does avian have an implementation of that?

#

It's probably because spinning puts the lock under contention for me. He uses lockless stuff, but that can still be contested, especally in a really hot loop.

hoary turret
#

but it uses mainly ConvexDecomposition and ConvexHull, how do those defer from what I'm already doing?

vestal minnow
# bold garnet Does avian have an implementation of that?

Yeah so we do have graph coloring, but it is done incrementally with a greedy algorithm whenever constraints are added or removed, rather than running some global graph coloring algorithm as its own step. It's the same approach described in Erin's SIMD Matters article
https://box2d.org/posts/2024/08/simd-matters/

hoary turret
#

I thought about checking the mesh I'm importing from trenchbroom, and if it has 8 points and they're a cuboid I just generate a cuboid from the points

vestal minnow
bold garnet
#

I might have a go at writing a graph-coloring step as well, we'll see.

vestal minnow
#

Ideally you would construct an actual cuboid collider if you can get its dimensions, but a convex hull is second best

hoary turret
#

fuck I gaslighted you, I missremembered from trying out bevy_skein past week

#

It's actually a convexhull

#

so I think Im gotta have to go for cuboids

#

it shouldn't be neither too hard to do nor too expensive, so lets see

#

given that mostly my shapes will be in fact cuboids

vestal minnow
#

Mm that still feels weirdly jittery if it is a convex hull, but I guess I have seen them sometimes have some stability issues, not entirely sure if it's the fault of Parry (the collision detection lib) or Avian

vestal minnow
little maple
#

and the transform propagation? πŸ‘€

vestal minnow
#

yeah I'm doing that now

little maple
#

oh snap

vestal minnow
#

since I got the sleeping thing fixed

bold garnet
little maple
#

this is the motivation I need to update to the new forces

#

I am super curious how that'll affect benchmarks

vestal minnow
#

or Griffin's par_map and par_chunks_mut from pool_racing

#

or something else?

hoary turret
#

I'm using a unit length of 0.2

#

and they're 0.2x0.2x0.4 in length

vestal minnow
#

Oh that could be another reason it's unstable, I think we currently have some problems with small shapes

#

though those aren't too small

hoary turret
hoary turret
#

I wanted to make them way smaller

#

buuut... they were even worse

bold garnet
hoary turret
#

at 0.002 units of length πŸ˜…

vague pebble
#

@vestal minnow funny story jon, i made shotgun bullets and I decided to be a smartied and made them have rotation onto themselfes u know like that movie , turns oujt i made my bullets make too many barrel rolls, which made them go straight into the floor anyways this is my podcast thank you for listening

vestal minnow
#

I'm just yeeting so much stuff

#

and it seems to be working like normal still πŸ˜‚

little maple
hoary turret
#

I mean

#

The custom cube colliders are in fact generating correctly hahaha

#

got it guys hah

#

just gotta find why the transform is fucked

#

and pray it solves some of my problems

little maple
#

seems like things might not be parented correctly?

hoary turret
#

nah, I think I just totally forgot about the transform

#

it is what you get when you're retarded

#

everything under control 😎

vestal minnow
#

TLDR:

  • Yeeted like most of the SyncPlugin, and renamed it to PhysicsTransformPlugin
  • Yeeted the entire PreparePlugin
  • Cut down from a total of 4 propagation passes to 2 (including Bevy's), with an option to also disable the one before physics
  • Shuffled some modules around
  • Renamed PhysicsSet::Sync to PhysicsSet::Writeback
  • Added some new convenience system sets like PhysicsSet::First and PhysicsSet::Last, because why not
  • Probably something else idk look at the diff
#

(cc @visual sparrow if you're interested)

summer acorn
#

Changelog: look at the diff

vestal minnow
#

the best changelog

little maple
#

I almost didn't ask that question about the propagations lol

vestal minnow
#

This cuts the total number of transform propagation passes from 4 to 2 (including Bevy's own). I kept the one before physics since it can still be important if you do modify transforms before physics, and bevy_rapier also has it. However I made this configurable via PhysicsTransformConfig::propagate_before_physics, so you can remove that too if you want

#

...except I didn't add the actual run condition πŸ˜‚ lemme add that real quick

hoary turret
#

anyway I think this could be a good contribution to bevy_trenchbroom, so the effort wasn't in vane

#

maybe I'm doing something wrong? you said this amount of jitter isn't common, so now I'm not sure

hoary turret
#

πŸ₯² making gravity lower solves most of the jitter problems, but it isn't something I can afford

little maple
hoary turret
#

yeah, I tried scaling it up but had no luck

#

If I scale it up and scale the gravity up with it it only gets ever-so-slightly better

hoary turret
# hoary turret

This is the system scaled x10, but the gravity stays at x1

#

so the jitter is less noticeable just because there's 10 times less force being applied to the boxes

#

best I have for now is to just have all colliders be asleep until something interacts

#

not ideal but will do at least while I prototype

sweet sundial
#

they're less jittery if you offset every other row

hoary turret
#

what do you mean by offset?

#

like in a brick-wall pattern?

#

they're already offset if that's what you mean πŸ₯²

sweet sundial
#

hard to see, i suppose

visual sparrow
vestal minnow
#

Merging the physics transform cleanup PR, it seems to work based on what I've tested

#

do let me know if it breaks things though
(edit: CI is still failing πŸ™ƒ merging once that's fixed)

little maple
#

does it have an impact on those crazy performance metrics you do?

vestal minnow
#

(also I fixed the remaining CI problems so it's merged now)

#

I'm trying to run Tracy now to profile the solver, but I'm getting some weeird traces

#

This is one iteration of the solver

#

It's definitely multi-threaded since it's way slower if I disable parallel, but the trace doesn't display it properly, or something else is horribly wrong

little maple
#

hmm I'm gonna update and check it out

visual sparrow
vestal minnow
#

same when running with bevy/trace_chrome

little maple
vestal minnow
#

Yeah

#

One frame looks like this for me

little maple
#

I haven't used tracy before, I don't think they have pre-compiled linux binaries

vestal minnow
vestal minnow
little maple
#

hmm, the force changes took a lot less time to update than I thought

#

ah, lol, forgot Forces has LinearVelocity/AngularVelocity in it

vestal minnow
#

Is it normal that intra-system parallelism is shown like this with unlabeled par_for_each spans

vestal minnow
little maple
#

yeah

little maple
#

||it actually does work lol, I need to adjust their spawn heights or something||

visual sparrow
cinder summit
vestal minnow
#

Mm I think par_chunk_map_mut doesn't add spans which is why it's not showing up in Tracy

#

(we currently use that for parallel iteration since Bevy doesn't have par_iter over slices πŸ™ƒ)

#

I want something closer to this

#

meanwhile ours looks like this lol

summer acorn
#

schaduler

#

is that with forte? or bevy tasks

vestal minnow
#

bevy tasks but it doesn't seem to output spans unless you're specifically using the parallel iteration methods on Query, which is pretty rare for us

summer acorn
#

bevy tasks is incredibly bad lmao

vestal minnow
#

most parallel iteration is over slices/vectors

#

does rayon output spans properly? I didn't see any tracing features on it or find anything related

#

or do you need to manually add spans somehow

bold garnet
#

forte kinda has tracing info. I mangled it a bit during the optimization process.

#

If you'd like I can add them back.

zinc talon
#

Is there an idiomatic way to handle collisions through Portal-style portals? Firstly to somehow disable collisions with the wall the portal is on, but only where the portal is, but then second to somehow detect collisions between objects that are far apart but still touching through a portal. Some kind of collision proxy or something?

vestal minnow
#

I'm not sure how I'm meant to look at what kind of gaps I have between the different tasks when I can't even see the tasks properly πŸ€”

bold garnet
#

for rayon specifically

#

You can get the information about what threads are scheduled on which cores during which time-slices directly from the OS.

vestal minnow
#

Also I'm trying rayon now but it's literally doing nothing faster even though it should have 24 threads and I tried to set the ComputeTaskPool's threads to 1 thonk

#

Like it's basically as fast as single-threaded

bold garnet
vestal minnow
#

With bevy tasks I have roughly 3x perf over single-threaded but with rayon there's barely any improvement, something has to be wrong

bold garnet
#

That's odd. Rayon is usually pretty good about setting stuff up automatically.

#

But it's also fairly high overhead.

#

It's possible your workload is latency-sensitive?

vestal minnow
#

Could be

bold garnet
#

It doesn't look latency sensitive

#

Rayon should be doing it's thing at timescales of a few ms

#

oh, are you using briged iterators or parallel ierators?

vestal minnow
#

Just par_iter_mut

bold garnet
#

odd.

#

that should be working.

#

you should maybe just disable multithreading for bevy, go fully single-threaded.

#

could be thread contention.

vestal minnow
#

I've tried that too

bold garnet
#

and rayon is doing nothing

#

can you push your benchmark today? I can profile it and figure out if rayon is going wide or not.

#

Later tonight.

mossy burrow
#

Quick question, I have a dynamic rigid body as character controller and want to attach a child sensor collider that will move with the parent rigid body. but when i apply impulses to the parent the child does not move it stays in the same global position, but if i edit the transform of the parent the child body moves. How can i make the child collider always relative the parent?

bold garnet
bold garnet
#

oof

vestal minnow
#

this is without

#

also rayon tanks Warm Starting lol

vestal minnow
bold garnet
vestal minnow
#

With bevy tasks, for reference

bold garnet
#

I doubt rayon-forte-compat will make too much of a difference until I publish my current set of changes, but I'd be interested to see it.

vestal minnow
#

I should still change it to ignore colors with no constraints though, and to move constraints to a serial overflow set if there are very few constraints in a color, like under 32 or something

bold garnet
#

how large is each list of constraints typically

vestal minnow
#

The number of constraints just depends on how many collisions you have, typically anywhere from 2 to 8 colors are occupied with a large number of constraints for heavier scenes, and they tend to be spread out fairly evenly

bold garnet
#

Ok, so it's about 200 ns per item, more or less? (5.8 ms / 12 / 2500). I can see how rayon's latency would be significant in those profiles.

vestal minnow
bold garnet
#

200 ns per item is long enough to make bevy_tasks performant, and when it works it does have comparatively low overhead.

vestal minnow
#

This is just a large 2D pyramid

bold garnet
#

Wait, and you do six iterations? Do the 4 systems run in parallel or sequentally?

#

Oh yeah, I can totally see how rayon wouldn't work here. That's super interesting.

#

(as a case-study, for me, that's great news)

little maple
#

I think... I am seeing something weird where my angular velocity randomly jumps up by a lot

vestal minnow
# bold garnet Wait, and you do six iterations? Do the 4 systems run in parallel or sequentally...

An outline of the simulation step looks roughly like this

broad_phase();
narrow_phase(); // par-for-each over contact pairs

// we do this incrementally as part of the narrow phase,
// not as its own step
graph_coloring();

prepare_constraints();

for _ in 0..substeps {
    integrate_velocities();           // par-for-each over bodies
    warm_start();                     // uses graph coloring
    solve_constraints_with_bias();    // uses graph coloring
    integrate_positions();            // par-for-each over bodies
    solve_constraints_without_bias(); // uses graph coloring
}

apply_restitution(); // uses graph coloring
store_contact_impulses();
#

By "iterations" I really meant substeps

#

The parts I've marked with "uses graph coloring" iterate over the colors serially and par-for-each over constraints in a given color

#

This is the general simulation structure used by most engines, excluding details like whether restitution is added directly to contact impulses or applied as a post-solve phase like we do, and whether graph coloring or just inter-island parallelism is used

#

This is pretty much exactly the simulation structure used by Box2D though, which uses graph coloring and wide SIMD

#

And yes each of these steps must run sequentially one after each other

bold garnet
#

The way to think about this is:

  • bevy_tasks has a low per-call cost, and a high per-item cost. the costs amortize primarily as the amount of the work done per item increases.
  • rayon has a higher per-call cost (caused by aggressive stealing and work starvation) but low per-item cost. the costs amortize primarily as the number of items being operated on increases.
  • forte has low per-call and per-item costs, but has lower max-throughput throughput than rayon. In the current form, it's especially sensitive to the amount of work per item.

Here, the 6 iterations and 6 filled colors means 36 distinct calls. so the per-call overhead shows up strongly. The longer each item takes, the better I'd expect bevy_tasks to perform. The more items in each color (imagine you had a million in each, not a few thousand) the better I'd expect rayon to do.

hallow goblet
#

Is it possible to match the mask layer with a specific physics layer in some way?

vestal minnow
#

Or explicitly convert it to a LayerMask if it can't infer the correct type

#

I'm not 100% sure if it works like that with matching, I haven't tried

hallow goblet
#

Expressions are not allowed on patterns
So I have to make crutches

vestal minnow
#

I think you can also do layers.memberships.has_all(GameLayer::Player) actually

#

the name is a bit weird, maybe contains would be better

vestal minnow
# bold garnet The way to think about this is: + `bevy_tasks` has a low per-call cost, and a hi...

I'm trying to get forte working but it's refusing to find rayon-compat

[patch.crates-io]
rayon-core = { git = "https://github.com/NthTensor/Forte", package = "rayon-compat" }
error: failed to resolve patches for `https://github.com/rust-lang/crates.io-index`

Caused by:
  patch for `rayon-compat` in `https://github.com/rust-lang/crates.io-index` failed to resolve

Caused by:
  The patch location `https://github.com/NthTensor/Forte` does not appear to contain any packages matching the name `rayon-compat`.
bold garnet
#

it's called forte-rayon-compat technically

#

there's also a version on cargo you can use.

#

I think I need to update the readme

vestal minnow
#

cool, yeah the README is a bit wrong

#

(also see path but it's given a git url)

bold garnet
#

things are still slightly messy and unstable.

#

also, I'd hold judgement until I can publish alpha-5. Work-stealing and idling has been significantly improved.

zinc talon
#

Suggestion: new channel #physics-dev to help avoid burying questions. This channel is probably the all-time highest traffic #1034543904478998539 channel, partially because of how much dev discussion goes on. We have the #ecs /#ecs-dev channel divide for exactly that reason. It's not first-party bevy development, but given the community-perceived high likelihood of upstreaming this crate, I think you could probably make a really good argument for the exception. Food for thought πŸ™‚

vestal minnow
#

We also have over a third of all the messages of all ecosystem crate channels combined :P

#

And often even more activity than #math-and-physics

bold garnet
#

If you want to split the parallelism discussion into it's own thread, we can do that too.

zinc talon
#

Idt you can make a thread in posts unfortunately

vestal minnow
zinc talon
vestal minnow
#

But yeah it would be nice to have a split for "avian development" and "avian help and questions"

#

People have asked me to make a separate Discord server for Avian in the past, but I would really like to not split away from the core community Discord just because we don't have a dedicated channel for Avian development

zinc talon
#

Agreed. That'd be a painful divide

vestal minnow
#

Also more broadly I think it would be good to have a place to discuss physics development, since it would also be a place where people could freely discuss character controllers, collision detection, BVHs (for collisions or spatial queries), etc.

#

Imo these don't really fit that well under #math-dev

#

Right now I would discuss those sorts of things here in #1124043933886976171 because they're still somewhat related to Avian and I don't think there is really a better existing dev-oriented channel

#

But it doesn't feel like it necessarily should be the place for that :P

paper hamlet
#

I don't mean to change the topic so feel free to respond to this when this topic is done!
I am trying to implement the idea of using transform interpolation for smooth and continuous rendering in Update schedule when the physics is in fixed step (such as in this example: https://github.com/bevyengine/bevy/blob/main/examples/movement/physics_in_fixed_timestep.rs) This example does its own physics, but I am trying to instead do this with Avian. I am a little confused right now because I currently understand that avian does physics on the "official" Transform component but the concepts from the example suggests I should have physics operating on its own decoupled component (in the example it is a current and previous translation) and then I would use those to interpolate it into the entity's "official" Transform component. I would appreciate any guidance!

zinc talon
#

Imo it's done enough for me to forward the convo to Alice and beg

vestal minnow
#

TLDR, just add TransformInterpolation to an entity and it should get interpolated

vestal minnow
paper hamlet
visual sparrow
zinc talon
visual sparrow
#

This channel is of course relevant, but not quite on topic for "How does HL2 implement pickup and how do I translate that to Bevy?"

#

And it’s wayy too niche for an ecosystem crate channel

zinc talon
visual sparrow
#

Also not quite sure where development of my navmesh stuff I want to eventually upstream should live

visual sparrow
vestal minnow
#

I think in the past I've also asked if it'd be a good idea to have an #1034543904478998539-dev channel with topics for crates that want their own dev channel, but it might get confusing so idk if I like that, I think a #physics-dev would still be better for what I would want

vestal minnow
visual sparrow
#

#math-dev feels too abstract imo

#

I currently just use #1364848195670114325 to discuss development, which is definitely not the correct channel lol

zinc talon
vestal minnow
#

Yeah I wouldn't want the channel to be just #avian-dev in disguise (even though it'd be that too :P), it'd be good for navmeshes, collision detection, character controllers, a potential VHACD port from Parry into a standalone Glam crate, or any other important physics development discussions

#

and you can create threads as needed, which you can't do here

visual sparrow
#

Also for bugging nth into helping with parallelism in physics stuff

#

I also need that for the navmesh

zinc talon
vestal minnow
#

(brb gone for 10-15 min)

little maple
#

ok, on the new forces stuff.. I'm having a weird thing (basically that video clip I posted before) and am having trouble tracking down what it could be...

I thought it was that the cars were spawning slightly in the ground but that doesn't seem to be the case. It's like.. somehow in the first couple frames of them being constructed, a large force gets applied to them. But, if I have physics paused while they spawn and then unpause everything is fine

not sure if there's something weird like.. if I have an entity with LinearVelocity that gets a rigid body and center of mass added later rather than all together and if that causes some weirdness?

vestal minnow
little maple
#

I think I'm using apply_linear_impulse_at_point everywhere now

#

I'm trying something, I think... it might be sorta what I said

vestal minnow
#

I'm guessing the GlobalCenterOfMass hasn't yet been computed before the first run of physics, so then there's a crazy torque for bodies that is larger the farther the bodies are from the origin

#

Also note that the point is a point in the world unlike in 0.3 where it was relative to the given center of mass

little maple
vestal minnow
#

If it's at the world origin but the body isn't then it's wrong

little maple
#

I did notice that.. this happens for all my vehicles except one whose center of mass I have configured to be Vec3::ZERO

#

let me try that

visual sparrow
#

@vestal minnow btw did you happen to implement the thing we discussed regarding collision strength for deciding whether to break glass?

little maple
#

yeah, looks like the first frame it's still world origin

#

Vec3(-684.1957, -24.869493, 668.8615) GlobalCenterOfMass(Vec3(0.0, 0.0, 0.0))

also, I think GlobalCenterOfMass is private. Which is fine. I'm unsure though if I should add something to check for this in my code

vestal minnow
#

I can try to repro and make a PR later

vestal minnow
#

IIRC there was some 2D physics engine that had some cool fracturing example, could be fun to replicate that and use the collision force or impulse to determine when it should break

#

I haven't run that though so I don't know what it looks like :P but the implementation is quite short and simple

#

though I think most shattering algorithms I've seen use some Voronoi approach

#

oh wait this is a Voronoi approach too I think

#

right Worley noise is an extension of the Voronoi diagram

little maple
#

similar thing happens when I teleport, gonna look into that now

vestal minnow
#

ffs has anyone ever managed to correctly patch dependencies in Avian's workspace? I put the patch in the crate's Cargo.toml, it tells me that it must be specified at the workspace root, I put it at the workspace root, it tells me it's ignored because it was not found in the crate graph

#

to this day I think the only way I've managed to patch deps for Avian is to fork every dependency that uses the crate I'm patching but I would really prefer not to do that with rayon

#

with other crates I have gotten patches working, just not with Avian

little maple
#

I patch bevy and have all the crates forked

cinder summit
vestal minnow
#

I'm trying to do this

# in workspace root
[patch.crates-io]
rayon = { path = "../rayon" }
rayon-core = { path = "../Forte/rayon-compat", package = "forte-rayon-compat" }
visual sparrow
vestal minnow
#
warning: Patch `rayon-core v1.12.0-dev (/home/joona/Programming/Forte/rayon-compat)` was not used in the crate graph.
Check that the patched package version and available features are compatible
with the dependency requirements. If the patch has a different version from
what is locked in the Cargo.lock file, run `cargo update` to use the new
version. This may also occur with an optional dependency that is not enabled.
#

I do have rayon-core as a dependency

bold garnet
vestal minnow
#

I did but then it conflicts with Parry and some other crates

bold garnet
#

ah

vestal minnow
#

so I'd have to fork those too since just the patch isn't working

bold garnet
#

:/

#

it is kind of a hack, sorry about that. hope it ends up being worth the struggle.

vestal minnow
#

actually hmm I think I can just disable parallelism for Parry, I don't think I'm benefitting from it anyway here

#

@bold garnet Hmm I'm getting these sorts of results

#

The old rayon profile for comparison

bold garnet
#

not encouraging

#

publish this branch somewhere and I'll have a look.

#

There are some practical problems with the current published version, I want to compare with my local work.

vestal minnow
#

yeah I'll push this and the rayon fork, sec

bold garnet
#

I suspect it's just failing to go wide, which I think is an issue I've mostly fixed.

#

Here, actually let me jush push my WIP stuff and you can try it.

#

perhaps give this a shot?

#

pay no attention to the // SAFETY: TODO comments.

vestal minnow
#

I'm running cargo run --release --example pyramid_2d in crate root workspace root

vestal minnow
bold garnet
vestal minnow
#

I wonder if there's something deeper going wrong πŸ€” it feels weird that bevy_tasks would be so much faster here

bold garnet
#

I will have to do some profiling.

vestal minnow
#

Honestly I think we should officially enforce a rule that you cannot have dynamic rigid bodies as children of entities with Transforms

#

This way, the Transform is always the global transform, and we don't have to worry about any issues like this

#

Shit big_space uses GlobalTransform for BigSpace roots mmmmmmm

sweet sundial
#

can't use local forces?

vestal minnow
#

having to handle hierarchies for rigid bodies is just such a nightmare lol

sweet sundial
#

could have a component that just stores the body's parent's GlobalTransform, maybe

vestal minnow
#

but what if the parent of that parent moves

#

you need to go up the whole tree

#

This specific issue we could "fix" by making apply_force_at_point take an offset from the center of mass rather than a world point, but this would make a lot of gamey patterns more annoying

sweet sundial
#

is there a version that uses local coords

vestal minnow
vestal minnow
#

I looked at other engines and they generally don't have it either

#

For example Unity has AddForce and AddForceAtPosition, and AddRelativeForce but no AddRelativeForceAtRelativePosition or whatever

visual sparrow
#

Editors (Blender and TrenchBroom and I think LDtk) spawn a scene hierarchy

#

And the rigid body happens to be a child in that hierarchy

vestal minnow
#

right the scene root has a transform too mm

visual sparrow
#

In the simplest case, the scene has an identity transform

#

So the rigid body's transform is still the global transform

#

But it’s not uncommon to have a group object of e.g. 5 barrels

#

And then you place that group 10 times on your map

#

In that scenario, the barrel rigid body's transform is the offset from the group's transform

#

Bevy does have a command for removing the parent in place

#

But I would find it very unintuitive to have to do that when working with a level design software @vestal minnow

vestal minnow
#

I wish Transform was an immutable component so we can run change detection hooks on it lol

little maple
visual sparrow
#

Though that would very controversial to upstream :p

vestal minnow
#

This feels like an actually impossible problem πŸ€”

  • We can't rely on Transform in case this is a child entity
  • We can't immediately detect Transform changes to update the GlobalTransform before users do something that requires it
  • We can't recompute the GlobalTransform inside Forces based on the hierarchy
visual sparrow
#

(Other than performance)

vestal minnow
#
  1. It would be expensive to do that every time you apply a force or impulse at a point
  2. Forces is a QueryData so it can only contain components
little maple
#

can't you argue that you can't apply forces on an entity that isn't fully initialized?

vestal minnow
#

Initialization isn't the problem, that we can easily fix. The problem is just that if a dynamic body is a child entity, and you teleport it by changing its Transform, we don't know the new global transform yet, so any applied forces will be wrong for that frame since the global center of mass is outdated

#

We could probably detect if Transform was changed by the user and not physics, and if yes, ignore the force, but (1) that adds more cost, and (2) it'd break scenarios like y-sorting or anything else that modifies transforms, even for purely visual effects

#

Gameplay-wise, it could be alright to take a point that is an offset from the body origin, this is also what Godot does. It just has the mild weirdness that applying a force at (0, 0, 0) will apply a torque if the center of mass isn't aligned with the body origin, but that's probably fine

#

We would however still need to compute the world-space center of mass relative to the body origin, and this requires the global rotation, which would have the same problem that we don't necessarily know the global rotation. But in general this is way less problematic than the wrong position

sweet sundial
#

could just store 'previous transform' and apply deltas to something

vestal minnow
#

I don't think that necessarily says anything about the global transform

#

the parent determines what the child's local Transform is relative to

#

if the parent was rotated upside down, left and right would be flipped for the child

#

or otherwise transformed

sweet sundial
#

presumably the thing that started this wouldn't be teleporting rigidbodies by just transforming the parent
besides, last time i tried moving the parent of a rigidbody on stable the rigidbody stayed in place

vestal minnow
#

last time i tried moving the parent of a rigidbody on stable the rigidbody stayed in place
That's because we have a rather cursed system that updates the local Transform such that the GlobalTransform will match the physics Position and Rotation

#

But the Transform is still relative to the parent

#

Checked what other engines take as the point or offset

  • Box2D: world point
  • Jolt: world point
  • Rapier: world point
  • Unity: world point
  • Bepu: world-space offset from body origin
  • Godot: world-space offset from body origin
#

IMO we do want a world point ideally

vestal minnow
#

I think we need to either

  1. Live with the teleport problem, but expose APIs for users to update physics positions after Transform changes; maybe a PhysicsTransformHelper?
  2. Change the _at_point methods to take a world-space offset from the center of mass.
  3. Disallow moving bodies using Transform, use Position and Rotation instead.
  4. Disallow dynamic bodies as children of entities with Transform.
  5. Implement a way to bypass Transform propagation for the translation and rotation of dynamic bodies, making those properties always global.
#

For now I would do 1

#

There's no shot I'm doing 3 lol

#

2 is nasty for actual usage

cinder summit
#

3 sounds totally fine to me :^)

vestal minnow
#

and 4 seems non-viable

#

and 5, ehh seems sketchy and would ideally be done on Bevy's side, not hacked on to work around it and do extra work

vestal minnow
cinder summit
#

I don't think cart would want first party physics to have Position/Rotation at all, and Alice would probably agree 🀣

vestal minnow
#

whether we should is another question

#

the biggest thing would be the lack of a 2D global transform

cinder summit
#

And weird things like skew in 3D global transforms

vestal minnow
#

and no f64 support but Bevy's global transforms don't support it anyway

#

The whole solver only touches Position and Rotation when preparing constraints and when writing back the results of the solver

#

The substepped part or the actual constraint solving doesn't use them at all

#

Collision detection and spatial queries are the other thing but affines should be alright there (if Parry supported them properly)

bleak wadi
#

@vestal minnow is a new release coming soon when you've finished this?

little maple
#

what's the downside with 1 exactly assuming that allows a teleport? is it just the increasing the API "footprint" aspect of it?

bleak wadi
#

btw is there a good way of fixing ghost collisions without tunneling? i'm using ldtk so the hitboxes are small squares next to each other

visual sparrow
#

@vestal minnow @hoary turret does that mean static colliders that are touching or intersecting never sleep?

pulsar bone
#

Sleep only applies to dynamic bodies afaik

visual sparrow
vestal minnow
#

yeah only dynamic bodies sleep, but currently only if they're not touching other dynamic bodies, because we don't have simulation islands and per-body sleeping is bad

visual sparrow
vestal minnow
vestal minnow
#

I'm going with that approach for now since it's the least intrusive and has less uncertainty than the other options IMO

visual sparrow
#

At least, I can’t think of any

vestal minnow
#

nope

vestal minnow
visual sparrow
#

And of course chaotic physics interactions

#

So at least in my case, errors in this case would not be entirely unexpected. I think it’s fine it it’s well documented and there’s a nice API

little maple
hoary turret
#

the stability of the towers might be a problem, but holy shit the destructibility would be the opposite of a problem

#

hahah

little maple
hoary turret
#

yup

#

although the artifacts/ghosting don't come from motion blur, they come from TAA

#

or... I guess a combination of both

#

it looks more cool than buggy tho

little maple
clever quail
#
fn cull_travel_ports(world: &mut World) {
    info!("cull");
    let mut travel_lane_query = world.query::<(Entity, &TravelLane)>();

    let mut lanes_to_add = Vec::new();
    for (entity, lane) in travel_lane_query.iter(world) {
        lanes_to_add.push((entity, lane.distance));
        // c!(world.get_entity_mut(entity)).insert(Collider::cylinder(0.01, lane.distance));
    }

    for (entity, distance) in lanes_to_add {
        world
            .entity_mut(entity)
            .insert((Collider::cylinder(0.01, distance), CollisionMargin(1.0)));
    }

    for _ in 0..10 {
        world
            .resource_mut::<Time<Physics>>()
            .advance_by(Duration::from_secs_f64(1.0 / 120.0));
        world.run_schedule(PhysicsSchedule);
    }

    let mut collider_entities = world.query::<(Entity, &CollidingEntities)>();
    for (entity, colliding) in collider_entities.iter(world) {
        info!("{entity:?}, {colliding:?}");
    }
}

Am I missing something for collisions. I am trying to cull these cylinders so there is no criss crossing (will delete longest).

however I am getting no collisions I have attached the debug view of the screenshot, these orange lines are not my mesh, but the debug view

#

Zooming in on a star I notice multiple cylinders per star (connecting the same stars) I am sure that I only have one, even if I duplicated by a bug it would be in exact place

marble cradle
#

yo i think im being affected by a nasty bug in Avian3d 0.3

#

so im using these packages

 bevy-tnua = "0.24"
 bevy-tnua-avian3d = "0.5.0"  
  

avian3d = { version="0.3", features = ["3d", "debug-plugin", "parallel", "parry-f32","serialize","collider-from-mesh"] }

and basically .. if i do NOT put a 'transformInterpolation' component on my character, the bug doesnt happen. I can teleport my character (mutate its Transform in the Update loop) and it works just fine. but if I DO add a 'TransformInterpolation' component to my character, [which i need to do to make walking look smooth w the camera] then my teleport is broken.

#

the docs claim this


Note that changing Transform manually in any schedule that doesn’t use a fixed timestep is also supported, but it is equivalent to teleporting, and disables interpolation for the entity for the remainder of that fixed timestep.

but this is not properly happening for me

#

one thing that is odd (not sure iff this is OK?) but my character has a TranslationEasingState whose start and end are always Some . and by manually setting the 'end' prop i can get my char to teleport properly. But mutating my Transform WILL NOT properly teleport my character. And making matters worse, that is a private component so i cant just mutate it in code .

#

😦

#

so for the time being i guess im going to have to disable the interpolation on my character. sad

#

now its super jittery compared to teh camera

visual sparrow
hoary turret
#

without interpolation physic objects appear pretty jittery, iirc the phyisics timestep is 30 but and he's probably running the game at 60, even more noticeable at 120

#

literally half or a quarter of the smoothness

#

interpolation hides it well

visual sparrow
vestal minnow
vestal minnow
#

IIRC it worked for me when I last tried, so I'm not sure what's going on there πŸ€”

visual sparrow
#

Remove the interpolation component, teleport, then add it again?

#

Or @vestal minnow adds API in general for "teleport this physics object so that everything works out" :p

vestal minnow
#

Really it should maybe be a TransformInterpolationBundle but that doesn't work as nicely with required components

visual sparrow
vestal minnow
#

Yeah, agreed

#

Hmm it could also be worth reconsidering whether it's even worth it to support interpolating individual transform properties, I imagine in the vast majority of cases you want to either interpolate the whole transform or nothing

#

Then we could have just TransformInterpolation, TransformExtrapolation, and a TransformEasingState, and not separate structs and systems for each individual property

#

Might need benchmarking to see what ends up being faster for the general case of interpolating the whole transform

#

With the current setup with each property being separate, some of the easing systems can run in parallel with each other

#

Nvm only the very cheap ones where it doesn't matter

vestal minnow
bleak wadi
#

@vestal minnow is turning up the timestep hz a way to fix ghost collisions and tunnelling?

vestal minnow
#

It doesn't really fix the core problem, but it does make tunneling less common since objects will be advanced in time in smaller steps

#

and results in more frequent collision checks

#

but like if you had an object travelling at a million units per second at a wall, it'd probably tunnel through at any reasonable time step unless you're using speculative collisions or swept CCD

bleak wadi
#

ofc

visual sparrow
#

And if people need it after all, I can imagine it's easy adding them back (with all current limitations)

vestal minnow
vestal minnow
#

still need to add more docs for the force methods and test that it actually works

little maple
#

I did run into a panic last night and then my cat immediately made a big mess so I didn't get to dig into it

thread 'main' panicked at forks/avian/crates/avian3d/../../src/dynamics/solver/constraint_graph.rs:168:9:
assertion failed: !is_static1 || !is_static2

marble cradle
vague pebble
#

Has anyone ever ran into a bug, where once spawning a dynamic body with a specific linear velocity, it only applies the y axis ? In avian 3d

little maple
vague pebble
#

0.3

little maple
# vague pebble 0.3

hmm, what you're describing is similar to a thing I'm seeing on main but that's related to the global center of mass talk above. I haven't really had problems with setting linearvelocity on spawn unless the entity I'm spawning is colliding with something else when it spawns

vague pebble
#

it is a sensor

#

ah this one is truly a headscratcher

little maple
#

oh I haven't made a sensor that moves before, that's interesting

vague pebble
#

yeah check this out

little maple
# vague pebble

that clip is a little hard to follow.. are you saying the first run has Vec3::Z but the bullets always go upward?

vague pebble
#

it seens to be a bug related to networking

#

not avian precisely

vestal minnow
#

On main I was seeing that applying an impulse in FixedUpdate for newly spawned bodies did nothing since their mass properties were zero because the mass property update ran before the collider had been properly attached to the body, but now it seems to work

#

Would y'all be fine with me changing Position and Rotation into a PhysicsTransform? I think this would more clearly indicate what they represent, and it would likely be better for both performance and internal stuff

#

API-wise it would mostly mirror Isometry2d/Isometry3d

#

I'm probably going to do that next unless someone complains :P

summer acorn
#

im here to complain, what needs complaining about?

#

whatever api decision you just took is annoying and not user friendly, but also whatever you changed it from is too. also my spacebar heating isnt working anymore

little maple
visual sparrow
marble cradle
#

yeah its weird -- my teleport (mutate transform) used to work even with the interpolation but now it doesnt anymore . not sure why

#

I am definitely mutating transform during Update (not fixed schedule)

#

so that sentence in teh avian docs seems incorrect

visual sparrow
vestal minnow
#

We also need f64 versions of the isometry types

visual sparrow
#

Makes sense πŸ™‚

vestal minnow
sweet sundial
#

yippee

vestal minnow
#

You can get the largest contact impulse in a collision with contact_pair.max_normal_impulse(), and divide by the time step (i.e. Time::<Fixed>::delta_secs()) if you need the corresponding force

#

Or for a specific contact point, just contact_point.normal_impulse

sweet sundial
#

i'm probably just going to use the first impulse over a threshold per collision

vestal minnow
#

Getting a stable 9.81 N for a 1 kg cube resting on the ground with 9.81 m/sΒ² gravity

visual sparrow
#

Thanks!

#

So many things I wanted to implement with this πŸ˜„

#

Glass shattering, playing different hit sounds, dealing damage, spawning a puff of smoke on enough impact, etc.

#

I tried normal_impulse for that in the past and found out that that was not at all what I needed haha

#

huh, specifically a Windows-only determinism issue?!

vestal minnow
visual sparrow
vestal minnow
#

I think I thought it was fine since if you divide it by the Time<Substeps> delta time, it is closer to the total contact impulse sometimes since you'd basically be taking the impulse from the last substep and extrapolating it as if that same impulse was applied at each substep, if I'm thinking about it correctly

#

but really you need to just add the impulses from each individual substep and the restitution pass into a separate value to get what you actually want

vestal minnow
#

but so far it's just Windows and only this local determinism test, the cross platform determinism test is fine bavy

sweet sundial
vestal minnow
#

It should be computed right after the shapes have been found to be touching

vestal minnow
#

(or in FixedPostUpdate and order relative to physics systems)

#

or in an observer for OnCollisionStart

#

an observer works too for me at least, and that is definitely guaranteed to be right after the solver has applied and computed the impulses

#

One caveat with this however is that speculative collision can affect what the initial impulse is

#

but so does the time step

halcyon dew
little maple
#

switched to main. That did fix the spawning problem I had (the frame where global center of mass wasn't calculated.. obviously since now it doesn't exist, right?)

but yeah, how would someone teleport? I think there's something I need to reset

#

oh oh lol PhysicsTransformHelper

little maple
#

cool that works. I didn't fully get why it returns a mutable position/rotation because... my first thought was "oh, I update the entity's transform and then call update_physics_transform" but then I saw it returns the mutable position/rotation so then I thought "oh, maybe I modify these directly"

but it's actually the first one. And I had to use a ParamSet so that I can modify the Transform first and then use the PhysicsTransformHelper.

#

it's not terrible for supporting this kind of thing, but it did confuse me for a minute

vestal minnow
#

We should probably add a teleport and maybe a teleport_local helper to it as well

visual sparrow
#

That would help @marble cradle as well, if the helper also deals with interpolation

little maple
#

I am occasionally getting this

thread 'main' panicked at forks/avian/crates/avian3d/../../src/dynamics/solver/constraint_graph.rs:168:9:
assertion failed: !is_static1 || !is_static2

#

I think it happens when I enter sensor colliders

#

it might be a specific sensor which changes the rigidy body and does some other things

vestal minnow
little maple
#

"surely he's not doing this"

vestal minnow
#

Contact pairs cannot be created between static-static pairs since they're skipped in the broad phase, but if you're changing the body type while the contact pair already exists, I guess it currently doesn't remove the pair and handle it correctly

little maple
#

hm, but I should be OK if I change the body type before the physics stuff happens?

vestal minnow
#

That should be fine yeah

#

Assuming its AABB isn't overlapping anything

little maple
#

hmm... I switch the rigidbody while OnEnter'ing into a new State... I would think that'd happen prior to physics, right?

marble cradle
#

yeah . making 'teleport' be a first class citizen in Avian would be really nice im o

#

bc just having us mutate transform no doubt is bound to create lots of undefined behavior and crazy edgecases

hushed river
#

ub? dang how much unsafe is in here 😭

visual sparrow
sweet sundial
#

poorly defined

clever quail
#

I attempted to place cylinders at origin but I still cannot detect examples, this is roughly a minimum reproducable example, only crates used are bevy and avian3d

vestal minnow
#

(I'm running this on main)

clever quail
# vestal minnow Sorry, what's the expected result here? They do collide at the start
2025-07-22T12:00:59.596653Z  INFO bevy_diagnostic::system_information_diagnostics_plugin::internal: SystemInfo { os: "Linux (EndeavourOS rolling)", kernel: "6.15.7-arch1-1", cpu: "AMD Ryzen 7 7800X3D 8-Core Processor", core_count: "8", memory: "30.5 GiB" }    
WARNING: radv is not a conformant Vulkan implementation, testing use only.
2025-07-22T12:00:59.641256Z  INFO bevy_render::renderer: AdapterInfo { name: "AMD Radeon RX 9070 XT (RADV GFX1201)", vendor: 4098, device: 30032, device_type: DiscreteGpu, driver: "radv", driver_info: "Mesa 25.1.6-arch1.1", backend: Vulkan }
2025-07-22T12:01:00.066338Z  INFO bevy_render::batching::gpu_preprocessing: GPU preprocessing is fully supported on this device.
2025-07-22T12:01:00.098764Z  INFO bevy_winit::system: Creating new window App (0v1)
2025-07-22T12:01:00.098829Z  INFO winit::platform_impl::linux::x11::window: Guessed window scale factor: 1.6979166666666667
2025-07-22T12:01:00.100215Z  INFO cylinders: cull
2025-07-22T12:01:00.100922Z  INFO cylinders: loop
2025-07-22T12:01:00.108594Z  INFO cylinders: collisions
2025-07-22T12:01:00.111357Z  INFO cylinders: collide set
2025-07-22T12:01:00.111368Z  INFO cylinders: after
2025-07-22T12:01:04.545192Z  INFO bevy_window::system: No windows are open, exiting    
2025-07-22T12:01:04.546151Z  INFO bevy_winit::system: Closing window 0v1

Hmm I am not getting a collision

#

will try main

clever quail
clever quail
vestal minnow
#

the Windows local determinism thing is killing me, I don't understand what it could be

#

I've checked and there shouldn't be any scheduling ambiguities, and if there was, then the Linux and MacOS tests should also fail sometimes

#

the only thing I can think of is if I somehow introduced some math operation that is non-deterministic across calls but I don't think I did?

#

or maybe like something where there's a dependence on how long a frame takes and the Windows runner in CI is slower than the others, but the test advances time in fixed steps

visual sparrow
vestal minnow
#

The run order of observers and hooks is deterministic right? That's the only ambiguity that isn't/can't be checked by CI, the physics schedules already error if there are ambiguities

#

but again even if that wasn't deterministic, I don't see why only Windows would be the problem

vestal minnow
#

wait surely it's not this lol

#

The transform sync refactoring PR uses Rotation::angle_between to determine if the old and new transform are equal within an epsilon

#

Quat::angle_between internally uses a custom acos_approx_f32 function for std math, which is fully deterministic

#

However DQuat::angle_between uses f64::acos for std math, which is documented as

The precision of this function is non-deterministic. This means it varies by platform, Rust version, and can even differ within the same execution from one invocation to the next. This function currently corresponds to the atan2 from libc on Unix and Windows.

visual sparrow
#

that’s subtle haha

#

Good thing you have those different platforms in the test matrix!

vestal minnow
#

But CI should be using enhanced-determinism, which uses libm, so I'm not sure why it breaks there πŸ€”

#

i guess note to self, never use DVec3::angle_between or DQuat::angle_between

#

or DVec2::angle_to

visual sparrow
#

Or DVec happy

vestal minnow
#

Nope that's not it I don't think, Windows still fails with the f32 version πŸ™ƒ

vestal minnow
#

well I booted up Windows and can at least actually reproduce it locally now instead of spamming CI

#

it's only with f64 but I'm not sure if that's just a coincidence or not

vestal minnow
#

Update: It seems like it wasn't the transform sync refactor PR, nor is it a math determinism issue

#

Instead we appear to have UB in the solver bavy

#

why the test only started failing on Windows and after that PR, no idea

#

oh lol yeah we currently par-for-each over the overflow constraints too, even though that should be serial

little maple
vestal minnow
little maple
#

hmm... I'm switching between kinematic and dynamic πŸ€”

#

actually, I guess I am switching the rigid body while inside of a static sensor

vestal minnow
#

the check that triggers that panic is

let is_static1 = contact_pair.flags.contains(ContactPairFlags::STATIC1);
let is_static2 = contact_pair.flags.contains(ContactPairFlags::STATIC2);
debug_assert!(!is_static1 || !is_static2);

and the static flags are set in NarrowPhase::update_contacts like

contacts.flags.set(ContactPairFlags::STATIC1, is_static1);
contacts.flags.set(ContactPairFlags::STATIC2, is_static2);

where is_static1 and is_static2 are body.rb.is_static()

#

(where body.rb is the RigidBody)

#

so as far as I can see, the only way the panic can happen is if both rigid bodies are static

little maple
#

hmm.. did this area change recently?

#

I guess it's part of the solver stuff

vestal minnow
#

as part of the graph coloring yeah

little maple
#

ok you're not going to believe this.

turns out I was switching a pile of dynamic rigid bodies all into static

vestal minnow
little maple
#

I'm running into an issue where... it seems like if I add a ColliderDisabled and then remove it... the collider still behaves like it has ColliderDisabled

vestal minnow
#

I'll take a look at that later, I'm opening the #physics-dev channel discussion in #community now :)

#

cc @zinc talon

vestal minnow
#

the broad phase has this

app.add_observer(
    |trigger: Trigger<OnRemove, (Disabled, ColliderDisabled)>,
     query: Query<AabbIntervalQueryData, Without<ColliderDisabled>>,
     // ...

It is supposed to react to re-enabling colliders. Two problems:

  1. Disabled doesn't work because, again, we're not explicitly including it in the query
  2. ColliderDisabled doesn't work because we have a Without<ColliderDisabled> filter, and OnRemove is triggered before the component has actually been removed
vestal minnow
#

I'll try to fix the static-static contact panic tomorrow, I'll probably make RigidBody an immutable component so I can react to changes via observers

little maple
civic wadi
#

I'm curious, is there a reason that something like acceleration structs don't exist?

As in, subtracting LinearVelocity from a different LinearVelocity to get a LinearAcceleration. I can't seem to find other physics engines that have it either which makes me think its just not common or necessary

sweet sundial
#

if you add or subtract two velocities you get a velocity, that's dimensionally consistent

#

and actual systems of measurement are probably out of scope anyway

civic wadi
#

I guess my question is more aimed at something like a MaxLinearAcceleration component or otherwise and getting that from said dv/dt

vestal minnow
#

Probably different from what you're asking for though?

cinder summit
#

BTW will 0.4 fix those TODOs on the requires of RigidBody that give ExternalForces/ExternalImpulse/etc to static bodies? πŸ€”

cinder summit
#

Bonus points if you can't figure out if your app is crashing because the query failed because the entity was disabled or because it was despawned after the trigger was fired but before it ran bavy