#Avian Physics

1 messages Β· Page 38 of 1

cinder summit
#

-# Can we have query observers please πŸ₯Ί

vestal minnow
#

Maybe? Still not 100% sure how we want to handle that split, I think the most correct would be to have a DynamicBody/KinematicBody/StaticBody split, and have them all require a RigidBody marker component. We just need them to be mutually exclusive, so we'd need to do "archetype invariants at home" and have hooks to make sure you always have exactly one of the variants

cinder summit
#

Required components at home is what got us required components early right, so surely archetype invariants at home will get us archetype invariants bavy

#

But yea having a hook on say DynamicBody that removes KinematicBody and StaticBody OnInsert seems reasonable

#

Also should we replace normal1 and normal2 with a world_normal like in collisions? πŸ€”

vestal minnow
#

For shape casts?

cinder summit
#

Yep

#

Might be on intersections too

vestal minnow
#

For collisions the normal is the outward surface normal on shape 1, but for shape casts you might expect it to be the normal on the shape that was hit by the shape cast

cinder summit
#

Yea I'd expect it to be the normal on what was hit ... Having both normals is very easy to get wrong though since you're always just kinda guessing bavy

vestal minnow
#

But I guess since it's ShapeCastHitData it might already be implied that it's data related to the hit shape

cinder summit
#
+            &mut |hit| {
+                let slope_angle = hit.normal2.angle_between(Vec3::Y);
+                if slope_angle < best_angle {
+                    best_angle = slope_angle;
+                    ground.best_slope = Some(hit.normal2);
+                }
+                if slope_angle < MAX_SLOPE && hit.distance < distance {
+                    ground.closest = Some(hit.entity);
+                    distance = hit.distance;
+                }
+                true
+            },
         );
-        for hit in spatial_query.sphere_hits(ray_cast, ground_cast.radius, false, &filter) {
-            let slope_angle = hit.normal.angle_between(Vec3::Y);
-            if slope_angle < best_angle {
-                best_angle = slope_angle;
-                ground.best_slope = Some(hit.normal);
-            }
-            if slope_angle < MAX_SLOPE && hit.time_of_impact < distance {
-                ground.closest = Some(hit.entity);
-                distance = hit.time_of_impact;
-            }
-        }
```Actually had this diff which got it wrong πŸ™ƒ
#

(My old spatial queries only had the normal from the shape that was hit)

vestal minnow
cinder summit
#

I think ShapeHitData might be used in other places too, but if so that's easy enough to fix

vestal minnow
#

Also we should have a point in world space for collisions, ray casts, and shape casts, it's easy enough to compute but people keep asking about it and it's nice for convenience

cinder summit
#

Guess we should fit some API reworks into that BVH rework then

#

Cause it's gonna be breaking anyway bavy

civic wadi
#

Actually thats not too different. I missed that when I was looking over #770. Do you think some component to cap this for an entity would be a good idea in conjunction with this then?

vestal minnow
#

For example, contacts apply impulses to modify the body's velocity directly and resolve the contact, rather than computing some force and the acceleration caused by that force and then applying that acceleration.

#

Mathematically speaking, the theoretical contact force for a rigid body is infinite at the time of impact, as the collision would have to happen in zero time with zero deformation (not quite true with non-zero time steps though); if you were to limit the acceleration, high-speed collisions would lead to bodies sinking into each other, as the contact would not be solved instantly but over a longer time with a limit on the contact force.

#

So I guess to answer the question, you could control the acceleration caused by external forces (gravity, user-applied forces, etc.) but that is largely up to the user to control what external forces they're applying. But limiting the total acceleration, including stuff like contacts, doesn't make sense to me / I don't know what that would look like

civic wadi
#

I figured that was the case for this but wanted to check anyways, thanks!

vestal minnow
#

hah, PartialReflect has an is_dynamic method, so if we made RigidBody a ZST, this still compiles

rigid_body.is_dynamic()
#

that's a fun one

visual sparrow
cinder summit
#
  • a deprecate if you go that route πŸ€”
vestal minnow
#

I think we can work around this by queuing a custom command that only removes the component if there are other conflicting components left, so that

  1. DynamicBody::on_addruns -> command to try remove KinematicBody is queued
  2. KinematicBody::on_addruns -> command to try remove DynamicBody is queued
  3. KinematicBody is removed
  4. Oops, removing DynamicBody would leave no body variant left; skip this
  5. DynamicBody is left
    It's somewhat ambiguous which one you would expect to be left in this case, but I think it's better to leave the one listed first, as it's consistent with required component priority behavior
cinder summit
#

Probably emit a warning when that happens too πŸ€”

vestal minnow
cinder summit
#

But yea, I think that's just something we'll have to live with and use it as a reason to say "Archetype invariants pls" for the millionth time 🀣

#

Or we can not remove the other ones, and just emit a warning in the hook if the others are present

visual sparrow
cinder summit
#

Hmmm, though that warning needs to be delayed too, since you might .insert(DynamicBody).remove::<KinematicBody>() and that would fire the warning if it happens in a hook/observer

vestal minnow
#

Migrated pretty much everything and got collisions working like normal, though joints seem partially broken atm

#

haven't accounted for all the potential edge cases yet

runic tinsel
#

What's the purpose of this change?

vestal minnow
#

This is still very much open to changes and not finished, but mainly the motivations are:

  • Way less unnecesary data stored: static bodies don't need mass, velocity, force components, and so on, and kinematic bodies don't need mass either
  • Queries can filter by specific types of bodies directly rather than having to e.g. check rb.is_dynamic() in loops, which is both more ergonomic and performant
runic tinsel
#

I guess once we get the opposite of required components, whatever that is called, this would become a lot better too?

vestal minnow
#

If you mean archetype invariants (like an entity with X cannot have Y) then yes, for now I'm doing it manually with hooks

#

Currently with my implementation, if you .insert(DynamicBody) on a StaticBody, it should currently remove StaticBody automatically to replace it with DynamicBody

#

because both existing at the same time would be an invariant

#

From an ECS philosophy standpoint it also feels to me like the different types of rigid bodies should have their own components. They all share RigidBody behavior (non-deformable physics object) but behave in fundamentally different ways, and have different behaviors and systems acting on them based on the type of body

visual sparrow
#

Soooooo many

let Ok(rigid_body) = rigid_bodies.get(trigger.target()) else {
  return;
}
if !rigid_body.is_dynamic() {
  return;
}
vestal minnow
#

I will say that seeing RigidBody::Dynamic or whatever replaced with just DynamicBody in the diff feels strange after seeing RigidBody for so long, but I think it's just a matter of getting used to it

#

the shorter names are nice, just weird atm lol

visual sparrow
vestal minnow
#

The lack of the Rigid prefix feels mildly weird too, but if we look at engines like Box2D, Jolt, or Bepu, they actually just use names likeb2BodyDef or Body or whatever and a separate b2BodyType or EMotionType, the "rigid" prefix is largely redundant in type names

#

In this case the body is still a RigidBody but the body type is specified via compositional inheritance using the separate components like StaticBody, which feels more ECS-y I think

vestal minnow
visual sparrow
calm sundial
sweet sundial
#

kinematic softbody? static softbody?

#

depends on the actual api, but those both sound like a rigid body with a weird collider

vestal minnow
#

If it's kinematic or static then it isn't affected by forces so it just doesn't deform like a soft body would

spring loom
cinder summit
hoary turret
#

completely random question, can things "float" in Avian due to density diffenrence?

#

they can't right? at least not without putting in some work I guess

spring loom
#

Doesn't that require a Fluid Body/Simulation then?

runic tinsel
hoary turret
runic tinsel
little maple
#

if an entity has a ColliderDensity and a Mass component... does the ColliderDensity do anything?

runic tinsel
#

@vestal minnow Is there a way to get the volume of a collider/physics body?

vestal minnow
#

So yes it affects the mass properties computed for the collider itself, but when computing mass properties for the rigid body, the components like Mass will have higher priority in a sense

vestal minnow
vestal minnow
#

there's a few ways to do it depending on the level of realism desired

#

Jolt has built-in buoyancy

spring loom
runic tinsel
#

It's easy to simulate a body that is only ever in a single fluid, because you just add a bouyant force to it, based on the bodies volume and the fluids density

calm sundial
#

Reminder that OpenUsd and Gltf physics formats doesn't have explicit separation between static/kinematic/dynamic rigid body and contain bool "Is_kinematic" and static body is considered static if it only has collider without rigid body (IIUC). Doesn't mean we should follow this approach but Avian should be able to parse these formats properly.

#

At least Unity and Omniverse USD Composer have bool is_kinematic on Rigid body component and static rigid body only has collider without rigid body component in the same way as mentioned formats (IIUC).
https://www.youtube.com/watch?v=Y3xkgpCukow
https://youtu.be/RfD8-X0Zyoc?t=57

Here's what I learned about Rigidbody in Unity...
Unity's Physics Engine allows us to use the Rigidbody Component to let a GameObject be influenced by the physics.
In this video, we'll take a quick rundown of the component, and we'll discuss some important tips as well!

Support me on Buy Me a Coffee! β˜• Your support helps me create more in-dep...

β–Ά Play video

This tutorial will teach you how to set up the deformable body, a physics extension in NVIDIA Omniverse USD Composer (formerly Omniverse Create).

NVIDIA Omniverseβ„’ is an open platform built for virtual collaboration and real-time photorealistic simulation. Complex creator, designer, and engineering visual workflows are transformed as users a...

β–Ά Play video
vestal minnow
# runic tinsel Well yes, but then you would have to either deal with the transition between air...

Yeah the tricky part with buoyancy is figuring out the submerged volume when bodies are only partially submerged. One super simple approximation is to compute the whole volume of the object, uniformly sample some points inside of it, and use the ratio of how many points are submerged to estimate the submerged volume. Another more sophisticated approach that Jolt uses though is to actually figure out the exact submerged volume; for some shapes like spheres this is pretty trivial, but for general polyhedra it gets more complicated, the Game Programming Gems 6 book describes an algorithm for this

vestal minnow
#

It is worth considering that sort of split in Avian itself too though, where "statics" are separate from rigid bodies; Bepu actually does that too, though it's probably more for optimization reasons

#

Functionally a StaticBody marker doesn't really do anything and just adds some overhead since you need to attach colliders to that and manage those relationships rather than just making each collider act as its own static thing

#

The question is more what kind of mental model we want here and what "makes sense"

calm sundial
#

More reasons to have physics_dev channel where we can ask this question.

vestal minnow
#

If we were to copy the model of an "is_kinematic" bool exactly, with an IsKinematic marker component (or just Kinematic), one of the problems I have with that mental model is that turning a dynamic body into a kinematic body fundamentally removes and changes behavior. It effectively forces infinite mass so that it cannot react to any forces, it disables gravity, it should (but doesn't yet) disable collision checks against other non-dynamic bodies, and so on. Components in the ECS should generally be designed to be composable and additive instead, or otherwise they should be treated as mutually exclusive

#

i.e. adding a component should typically not disable the behavior of another component IMO

#

unless it is very explicitly for that purpose like Bevy's NoWireframe component, though even that is not overriding a component, it's overriding a global resource's setting for an entity

vestal minnow
# vestal minnow If we were to copy the model of an "is_kinematic" bool exactly, with an `IsKinem...

Worth noting that we do already sort of break this philosophy with Collider and Sensor. A Collider attached to a RigidBody acts as a solid shape that other bodies can bump into, but Sensor kind of "removes" that behavior and makes other bodies pass through it. This might be even weirder as we make sensors a more separate thing with their own intersection graph and broad phase tree and possibly their own events etc.

#

I've been kind of toying around with the idea of a theoretical split like this

  • PhysicsShape: An asset storing a shape used for physics.
  • Collider: A component for a Handle<PhysicsShape> that acts as a collision shape that dynamic bodies can collide with.
  • Sensor: A component for a Handle<PhysicsShape> that detects when other shapes intersect this one.
  • RigidBody: A component for a non-deformable physics object with optional Colliders and Sensors attached to it.
    • DynamicBody: A dynamic RigidBody with non-zero mass that can be moved by velocity and forces.
    • KinematicBody: A kinematic RigidBody with infinite mass that can be moved programmatically with velocity.
#

In this theoretical split, colliders and sensors would be fully separate concepts, but they would both store a PhysicsShape

#

Colliders would always be actual colliders, meaning dynamic bodies can collide with them, not pass through them if they're sensors

#

it feels weird to call something a collider if it doesn't have collisions

#

but yeah anyway this is all very hypothetical and needs to be thought through and designed properly

#

I probably won't merge the DynamicBody/KinematicBody/StaticBody split for this release since it feels a bit scary, people aren't sure about it, and IMO there are still some unknowns there

#

not sure yet

visual sparrow
vestal minnow
# visual sparrow

If Alice makes #physics-dev and I can first discuss it there πŸ˜‰

visual sparrow
vestal minnow
#

Also πŸ‘€ I think we're using slightly wrong contact points in the solver

#

Parry returns local_p1 and local_p2 on the surfaces of the two shapes, and then for the solver we just transform those to be in world space relative to the center of mass of each body, but we should be taking the midpoint of those two world space points and making that relative to the centers of mass

#

So right now the solver is using different two points in world space for the contact point while they should be using the same point, just relative to each body

little maple
#

oh I actually have a question that is probably suited for physics-dev more than here πŸ€” about advice on controlling dynamic objects that are flying around

bold garnet
#

#1397333422401392792

#

it's right there in the name

vestal minnow
#

let's just start refusing to discuss anything that is not directly related to Avian and then we can send a million examples of why we need #physics-dev to #1397333422401392792

vestal minnow
#

(I can rename it fyi lol)

little maple
#

a million examples would take forever

#

like at least a week

vestal minnow
#

true

little maple
#

just imagine how many times the avian api would change by then

#

||that's a joke pls don't stop improving avian 😭 ||

#

actually, maybe what I want is to post in #math-and-physics

vestal minnow
#

Does someone have a small body or 3D model that is jittery even when resting on the ground? I'm curious if the contact point bug is the reason for it

#

I guess I can just make a very small cuboid and maybe stack some of them

#

nope still seems jittery, hmm

#

happens with f64 too, which leads me to believe it's not a precision issue but some fundamental bug

visual sparrow
#

I also have an important question for #1397333422401392792

#

Why does TriMesh look so right, but tri_mesh looks so wrong hmm

vestal minnow
#

I have wondered the same thing

little maple
#

for what it's worth, I did notice just now having one of my items on the ground with high friction made it jittery

bold garnet
#

is it ThreadPool or Threadpool in code? what about threadpool or thread_pool? is it Thread-Pool, Thread-pool or Thread pool or Threadpool in pose?

vestal minnow
#

it has had some stability bugs in the past that should be fixed, but it's possible something is still wrong there

vestal minnow
#

hmm

#

Yeah okay Rapier is perfectly stable here with small cubes, so it's an Avian problem. I'm going to prioritize trying to fix this now

#

Also bevy_rapier seems to have a fun bug where transform scale doesn't seem to be working on the first frame so everything just overlaps and explodes lol

#

unless I set it up wrong

little maple
#

I'm using Collider::convex_hull_from_mesh for that one

vestal minnow
#

okay Rapier is... strange, how do I even set a fixed time step

#
  • Tries .in_fixed_schedule() -> warning that TimestepMode is set to Variable
  • Tries to insert TimestepMode manually (since it's a resource) -> nothing changes
  • Finds a with_custom_initialization method for plugin init -> RapierContextInitialization::InitializeDefaultRapierContext (what is this name?) has IntegrationParameters and RapierConfiguration, but neither of them have TimestepMode
#

Okay you need to insert the TimestepMode resource before you add the RapierPhysicsPlugin, otherwise you get the warning

#

that's... mildly questionable DX but whatever

#

I'm annoyed by so many API decisions in bevy_rapier that I kinda want to dedicate a week to fixing them lol

visual sparrow
little maple
visual sparrow
cerulean zephyr
gritty estuary
little maple
#

what have I done

vestal minnow
#

let's make this another "dont normalize twice for no reason" campaign

#

get 60 different people to keep the chain going

#

-# please no

sweet sundial
cinder summit
thorn solstice
#

lol I made the forwarding recursive

visual sparrow
thorn solstice
visual sparrow
#

Done

#

Yesss it works super_bevy

#

Take that, LLM scrapping bots >:D

#

(hope they get stuck lol)

thorn solstice
#

tbh this is another reason we need a #1397333422401392792, making a mess here surely has less visibly

summer acorn
#

why does ColliderBackendPlugin require ScalableCollider and not just AnyCollider

#

what even is a detail: u32

#

why is there a 0.4 here, thats curious. i wouldnt expect a 5^-1 factor in sphere related maths

impl ComputeMassProperties3d for Sphere {
    fn unit_principal_angular_inertia(&self) -> Vec3 {
        Vec3::splat(0.4 * self.radius.squared())
    }
}
#

lol why is Rotation in a module named position

sweet sundial
sweet sundial
sweet sundial
vestal minnow
# summer acorn what even is a detail: u32

I think I copied it from Rapier, some shapes like spheres or capsules don't support proper non-uniform scaling in Parry so you need to use a discretized mesh approximation in those cases

vestal minnow
visual sparrow
cinder summit
#

How does avian currently respond if Position and/or Rotation get removed from an entity? πŸ€”

#

(Note: there is no SyncPlugin)

summer acorn
#

if i wanted to have a custom transform type and not use Transform, how hard would it be to get avian to play with that

cinder summit
#

On the latest release, just disable SyncPlugin and make your own. On main? things changed so probably hard 🫠

past escarp
#

is there anything besides gravity acting as a force on a body in freefall with no linear damping?

I'm drawing a trajectory arc with the following, and doing a shape cast along each line to find the point of impact. I'm getting really really close, but it's always slightly off and I can't figure out why.

points[0] = point; // Initial firing position

for i in 1..STEPS { // loop through an arbitrary # of steps to draw a line
    velocity += gravity.0 * gravity_scale * TIME_STEP;
    point += velocity * TIME_STEP;
    points[i] = point;
}

// draw a line between each point, etc...
acoustic spoke
#

in this case 64 Hz / 6 assuming default settings i think

visual sparrow
past escarp
past escarp
#

alright, so I switched to ensuring Im updating with the same time step, and now using avian's integrators, but still running into the same issue with my shapecast being slightly innacurate πŸ€” maybe theres some collider margin im not including?

points[0] = initial_translation;
for i in 1..STEPS {
    points[i] = points[i - 1];
    integrate_velocity(
        &mut velocity,
        &mut angular_velocity,
        Vec2::ZERO,
        0f32,
        ComputedMass::new(1.0),
        &ComputedAngularInertia::new(0.0),
        LockedAxes::default(),
        ball_gravity,
        time_resolution,
    );
    integrate_position(
        &mut points[i],
        &mut rotation,
        velocity,
        0f32,
        LockedAxes::default(),
        time_resolution,
    );
}
torn hinge
#

Hi, I would like to integrate Avian into my project in a limited way where I expose just the basic collision detection functionality (and any logic which would help with calculating how to resolve collisions geometrically) but otherwise running all my own logic to resolve things in a kinematic manner for all colliding entities.

Are the any recommendations on how best to do this? I naively assumed I might get away with enabling only the parry-f32 feature and then adding the default plugins but this is not building.

Thanks :)

edit: Now building since I added the "2d" feature. Nonetheless the question stands. Would be interested to know if there are any particular architectural considerations here.

summer acorn
#

its really unfortunate i cant do type Context = Gizmos<'static, 'static>; in AnyCollider

#

no DerefMut

crystal cosmos
#

What's the best way to debug which colliders might be triggering this? It's happening here in avian2d 3.1

thread 'main' panicked at /Users/choc/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/avian2d-0.3.1/src/collision/collider/mod.rs:508:9:
assertion failed: b.min.cmple(b.max).all()
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
Encountered a panic in system `avian2d::collision::collider::backend::update_aabb<avian2d::collision::collider::parry::Collider>`!
Encountered a panic in system `avian2d::schedule::run_physics_schedule`!
Encountered a panic in system `bevy_app::main_schedule::FixedMain::run_fixed_main`!
Encountered a panic in system `bevy_time::fixed::run_fixed_main_schedule`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
sweet sundial
#

can you get more backtrace with the environment variable?

#

wait, this should only trigger if grow is given a negative vector

#

do you have a negative collision margin?

crystal cosmos
#

I'm not sure the circumstances that would cause a negative collision margin to exist. I have some colliders that are moving very fast which is the only physics thing happening at the moment. I don't understand the correlation between the speed of collider and collision margin

sweet sundial
#

i'm just looking in update_aabb for the word grow

crystal cosmos
#

well I worked around it by removing the Collider after I no longer need it. It was for picking up coins that moved towards the player mouse after being clicked, they speed up the longer it has been since the click. At high speeds they sometimes trigger that panic 🀷

So I remove the collider as soon as they're clicked and the problem stopped happening.

sweet sundial
crystal cosmos
#

They're all just Collider::circle(5.), and I don't touch the collider or scale after creation, only the translation

vestal minnow
echo parcel
#

Are there any video tutorials about avian physics?

lone glade
#

Is there any way to toggle debug rendering at runtime?

visual sparrow
#

(Can’t link well because I’m on the phone rn, but it’s in src/dev or something like that)

vestal minnow
#

the main learning material currently is the docs.rs documentation and the examples in the repo

#

game jam games that use Avian might also be a useful reference for "real-world use"

#

most of the core features and concepts also tend to be largely the same across different physics engines even outside of Rust, so looking at other engines' docs and resources can also be useful for understanding things

vestal minnow
# vestal minnow I don't think so

(as for why there are barely any video tutorials, I imagine that's because both Bevy and Avian have rapidly evolving APIs and features, and are quite young)

vestal minnow
#

FYI @visual sparrow, the normal_speed is another way to judge how "strong" a contact is, -normal_speed is equivalent to an "approach speed" indicating how fast the objects are approaching each other at that point

#

Unlike a normal_impulse, this is not dependent on mass or the time step since it's just a relative velocity

#

(also cc @cinder summit since you might need to adjust your SDF contacts a little for this lol, it shouldn't be too bad though)

#

the diff for the built-in Parry contact manifold computation is like this
(the old one might be a bit unclear but it's just passing local_point1 and local_point2 to ContactPoint::new)

willow elbow
#

Hello, I just came back from holidays and my app runs now at 60fps whereas it used to run at 120fps. It's not necessarily due to Avian but does anybody have a clue? I cargo updated the project but it was already bevy 0.16.1

visual sparrow
willow elbow
visual sparrow
willow elbow
# visual sparrow You could take a look at `tracy` to profile

the thing is that I didn't change a single line of code since. Also, I tried building in release mode and it's still at 60 fps. So I'm not sure tracing would be beneficial at all. Also, if it was about performance, it should probably go lower than 60, but it's like there's a cap that prevents from going up

vestal minnow
willow elbow
vestal minnow
#

@little maple @hoary turret I bet this fixes (or significantly reduces) the jitteriness and instability you were seeing

vestal minnow
# vestal minnow Before

Note that these are 10 cm cubes (i.e. sides have a length of 0.1) at a gravity of 9.81 m/sΒ² with 6 substeps

#

I can go below 1 cm and the cubes are still not jittery on the ground (though gravity is too high at that point to keep the stack from falling over)

#

yeah okay below 1 mm is fine too if you lower the gravity

#

rendering is scuffed though, I need to tweak the camera

vestal minnow
#

Merged already, but do let me know if it causes any new weirdness

hoary turret
#

I'm going to test it straight away

#

❀️

visual sparrow
#

Jokes aside, that's wayyyyyyyy better. Impressive!

visual sparrow
#

They were a bit jittery before haha

hoary turret
#

@vestal minnow I'm getting lots of compile errors after updating to the latest commit πŸ€”

#

but theoretically it's pointing to bevy 0.16

#

imma try cargocleaning just in case

#

(its over, 15 minutes compile time heh)

vestal minnow
hoary turret
#

Mostly related to what seems like a version missmatch with I think is glam?

#

it was complaining about Vec3s and Scalars

#

if it's still wrong after cargo clean I'll start giving it a thought

#

fuk

#

okay everything is bevy_math

#

I mean I've got nothing weird going on

vestal minnow
#

sync or position or prepare

#

Do you have two conflicting versions of Avian? One using main and one using 0.3

#

maybe through another dependency if you happen to have something else that uses it

#

also make sure the Cargo.lock is updated and not somehow broken

hoary turret
#

Uh wait, maybe this could be the problem?

#

I'm using bevy_trenchbroom which integrates with Avian

#
bevy_trenchbroom = { git = "https://github.com/Noxmore/bevy_trenchbroom.git", rev = "a8454bf28292158f5b843cacf44d3023c6260260", features = ["avian"] }
#

so it is probably pulling the latest release of avian and it cannot work together

#

this makes me sad big time because I truly want to test that out immediately πŸ₯²

#

I think Imma temporarily fork bevy_trenchbroom just to test this haha

oak vigil
#

Hey, I have a weird issue where if I raise the time scale (Time<Virtual>), I get really bad FPS, even if I have no rigid bodies in the scene. I've been debugging/profiling and it seems like because time delta is larger, it causes FixedPostUpdate to run more frequently, which increases the time delta, which causes FixedPostUpdate to run more... and so on! Until it stabilizes at an awful frame rate. Is this normal?

#

What's the correct way of controlling time with avian? I couldn't find any examples

#

Zoomed in:

#

I could get around this by using Time<Fixed>::set_timestep, but that makes the movements very choppy. So I'm not sure if that's the correct way

#

Also, it feels odd to me that Fixed time is derived from Virtual rather than Real time. πŸ€”
Cause then what's the point of Time<Physics>::set_relative_speed?
If I set Time<Virtual>::set_relative_speed to 2x it would cause physics to update twice. But if I set Time<Physics>::set_relative_speed to 2x as well, wouldn't that cause things to move 4 times as fast?

sweet sundial
#

would you rather Time<Virtual> not effect physics?

oak vigil
#

I'm not sure. I was assuming to control time scale, I would have to set virtual time relative speed and also physics time relative speed to "synchronize" them

#

But from what I see, that isn't correct

#

And if virtual time affects the number fixed steps, then also what's the point of SubstepCount?

sweet sundial
#

those are substeps

#

step count != substep count

bleak wadi
#

how do i increase the timestep hz?

sweet sundial
#

specifically, the physics simulation runs every FixedUpdate, and during that a shorter inner loop repeats SubstepCount times

bleak wadi
#

so i should increase fixedupdate?

bleak wadi
#

will that speed everything up so i would have to adjust movement values to match?

sweet sundial
#

no

oak vigil
#

For if I increase the virtual relative time speed, the Fixed update will be called more, which WOULD maintain the accuracy

#

So then why would I ever have SubstepCount not be 1?

sweet sundial
#

substeps are only a little bit of the overall simulation, they don't even do collisions iirc

oak vigil
#

Ah maybe I misunderstood the concept then

bleak wadi
#

oh this is great, thanks.

bleak wadi
#

is there any reason not to set the timestep to multiple hundreds

sweet sundial
#

of?

bleak wadi
#

physics

#

i guess performance depending on the type of game

sweet sundial
#

hundreds of*?

bleak wadi
#

ah sorry, hz

sweet sundial
#

yeah, performance

bleak wadi
#

for a metroidvania it shouldn't be too much of a bottleneck right? at least in the cpu frametime it seems to have very little effect

sweet sundial
#

i had mine at 144hz for a while, but it turned out to be expensive and unnecessary

#

currently at 72 hz, dropped it to 24 hz for a while to fix issues in my math that aren't obvious at high time resolutions

oak vigil
#

Doesn't raising it make movement choppy though?

sweet sundial
#

interpolation

visual sparrow
#

@vestal minnow something whacky is going on with the trimesh of a Plane3d hmm

bleak wadi
#

i had a lot of ghost collisions at the default 64hz, i've got it at 256 now and it's really smooth

#

i might turn it down though

visual sparrow
#
let shape = Plane3d::new(Vec3::Y, Vec2::splat(25.0));
let collider = Collider::from(shape);
let trimesh = collider.shape().as_trimesh().unwrap();
println!("trimesh: {:?}", trimesh.vertices());
sweet sundial
#

PhysicsInterpolationPlugin::interpolate_all + explicitly exclude camera + hermite easing on small objects

visual sparrow
#

Prints

trimesh: [[10000.0, 0.0, -10000.0], [-10000.0, 0.0, -10000.0], [-10000.0, 0.0, 10000.0], [10000.0, 0.0, 10000.0]]
#

Is it possible that the collider ignores the plane's half size?

#

Oh lol I see

#

Is that intentional?

#

That should be self.half_size instead imo

sweet sundial
#

probably copied from the unsized plane

visual sparrow
#

Lemme PR then

visual sparrow
sweet sundial
#

wow bevy_math's got weird names

visual sparrow
#

Simple as

#

thx for the hint @sweet sundial

#

Also added support for InfinitePlane3d using the old behavior while on it

visual sparrow
sweet sundial
#

if you need a punchline i have a bunch of (Collider, Mesh3d), most of which are just IntoCollider + Into<Mesh>, the lone exception being (Collider::half_space(..), Mesh3d(Mesh::from(Circle{..})))

visual sparrow
#

Also had to just give up for those haha

#

Hold up, why shouldn't InfinitePlane3d be a half space instead hmm

sweet sundial
#

because things can be on either side

visual sparrow
sweet sundial
#

could be modeled as two halfspaces with different collision layers i suppose

sweet sundial
#

by the way i made a really big sphere to try and have visible ground to match the atmosphere shader, but as soon as i made it a static body it started jittering constantly

vestal minnow
# oak vigil Also, it feels odd to me that `Fixed` time is derived from `Virtual` rather than...

Time::<Physics>::set_relative_speed scales the delta time used by physics, but it does not affect how often physics is updated. This means that with 2x speed, it would take 2x longer steps, unless you also reduce the time step from e.g. 64 Hz to 128 Hz or something. So changing the relative speed of physics affects behavior.

Time<Virtual> is meant to be kind of like a gameplay clock determining how fast the gameplay is. So it makes sense that it also affects schedules like FixedUpdate. However the difference for physics is that the relative speed of virtual time does not change the physics time step, it only affects how frequently physics runs. This keeps behavior consistent and deterministic even if you had some slow-mo effect, unlike when changing the relative speed of physics, at the cost of a lower update rate when in slow-mo (needs interpolation to look smooth) and a higher cost in fast-forward.

vestal minnow
#

there might be a few more 2D shapes like that

vestal minnow
#

Constraints such as contacts and joints are solved iteratively, and using substeps helps things converge on the solution better

#

Increasing the time step Hz can have the same (or better) effect, but you need to pay for the more frequent collision checks, which can be expensive

#

And oftentimes you might want your gameplay logic and physics to run at the same rate, and might not want a super high update rate for your own logic

#

So it's a balancing act of stability vs. perf

bleak wadi
#

@vestal minnow did you see my messages? after reading this it seems substeps could be good for my usecase?

vestal minnow
#

Using a higher tick rate (Hz) can be useful if you do need more frequent collision checks for some reason, like to reduce ghost collisions in your case

#

for ghost collisions you can also try to set the SpeculativeMargin to zero to disable speculative collisions (but you risk tunneling at high speeds or clipping into things slightly), try more rounded shapes, try to manually maintain a small separation from the ground, etc.

#

or if this is a 3D triangle mesh collider, use TrimeshFlags::FIX_INTERNAL_EDGES, but your game is 2D afaik?

cinder summit
oak vigil
vestal minnow
#

In general you should just use transform interpolation

#

The trade-offs are that interpolation can lag behind a bit since it's using old positions (usually not very noticeable), while extrapolation is more snappy but can cause jarring movement when the prediction is wrong, for example when your movement's trajectory suddenly changes

oak vigil
#

It's mostly useful if your fixed update rate is lower than the monitor's refresh rate
This is currently what I'm doing on higher time scales to help with performance:
fixed.set_timestep(Duration::from_micros(15625 /* 64 Hz */).mul_f32(ratio));

#

I tried using interpolation last night, but my entities (kinematic, velocity based) would over/under shoot their targets on higher scales

#

Interpolation seemed to help, but it's still a problem

vestal minnow
# cinder summit Now that this has been reworked, how do we want this to reflect in `ShapeHitData...

Hmm, maybe something like this? πŸ€”

pub struct ShapeCastHit {
    /// The entity of the collider that was hit.
    pub entity: Entity,

    /// How far the shape travelled before the initial hit.
    ///
    /// If negative, the shapes are intersecting, and this represents the penetration depth.
    #[doc(alias = "time_of_impact")]
    pub distance: Scalar,

    /// The hit point in world space.
    ///
    /// If the shapes are penetrating, this will be the midpoint between the closest points
    /// on the surfaces of the two shapes.
    pub point: Vector,

    /// The outward surface normal on the hit shape at the hit point in world space.
    pub normal: Vector,
}

I think it'd be waaayy less confusing and much easier to use than the existing setup

#

For penetrating cases you can also still figure out the points on the surfaces of the bodies based on the world-space point, penetration depth, and normal, if you needed that for whatever reason

#

The downside is that a world-space point is subject to precision-loss at large coordinates, but eh idk if it's really a problem. We could still additionally store the points relative to the shapes' positions if we wanted to

cinder summit
#

Yea, that would work πŸ‘

#

Should help with some of the footguns when using the API, and it makes implementing this trait a lot easier

vestal minnow
#

Yeah Parry's version is a bit less... user-friendly

cinder summit
#

Not that the API in avian 0.3 is particularly great either, especially since it's not consistent with collisions

vestal minnow
#

yeah imo it's nice if the different types of hit results are mostly consistent with each other, do what you'd expect, and are in world-space so you don't need to manually transform things from local space

#

I'm not sure when a typical user would need local-space values

little maple
#

it's definitely better though

little maple
visual sparrow
#

I believe I hacked around it by increasing their mass / density

little maple
vestal minnow
#

is that a Collider::cylinder or a mesh or convex hull?

visual sparrow
little maple
vestal minnow
#

a decent way to tell if it's an Avian thing is to try the same with Rapier

visual sparrow
vestal minnow
vestal minnow
#

I could implement it if y'all have a use for it

#

(Box2D has it too :P)

#

or just throw some AngularDamping on it

little maple
#

It's honestly not a big deal for me

#

for my use case

#

I mean, I get that "no, it has to be right!" perspective lol

vestal minnow
#

why does bevy_rapier wrap the hit points and normals in a separate ShapeCastHitDetails struct

#

is using them so unergonomic that they need to be hidden from the API thonk

#

oh it's if you don't compute the points and normals, right

visual sparrow
cinder summit
#

Okay, changed the API and this actually seems like it makes a lot more sense in my codebase, why did I not do this from the start thonk

#

And the shape intersection point/normal/penetration I internally have in the trait now actually gets returned ... I'll have to see if that's viable to keep when I add the parry impl though

#

Never made sense to me how shape intersections don't tell you what they hit, just a boolean

torn hinge
#

is this the correct way to pull per-frame avian logic into FixedUpdate and run my own stuff before/after?

pub struct AvianPlugin;

#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct PrePhysicsSet;

#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub struct PostPhysicsSet;

impl Plugin for AvianPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugins((
            PhysicsPlugins::new(FixedUpdate),
            avian2d::debug_render::PhysicsDebugPlugin::new(FixedUpdate),
        ))
        .add_systems(FixedUpdate, add_colliders.in_set(PrePhysicsSet))
        .configure_sets(
            FixedUpdate,
            (
                PrePhysicsSet,
                (
                    PhysicsSet::Prepare,
                    PhysicsSet::StepSimulation,
                    PhysicsSet::Sync,
                ),
                PostPhysicsSet,
            )
                .chain(),
        );
    }
}
little maple
#

I thought that... if I am setting the mass then the colliderdensity doesn't get used?

cinder summit
visual sparrow
#

I was asking about increasing the mass through any means, sorry for the confusing wording πŸ™‚

visual sparrow
cinder summit
#

Yep, if it needs to be after I'd suggest throwing them in FixedPostUpdate with a constraint or FixedLast

torn hinge
visual sparrow
#

Note that you don't need to schedule your pre-physics sets if you use them in FixedUpdate πŸ™‚

#

@vestal minnow what's your take on Vec3A vs Vec3?

vestal minnow
visual sparrow
visual sparrow
#

But when interacting with Bevy API, it consistently requires Vec3

#

So I have a ton of Vec3::from(some_vec3a) in the Bevy integration hmm

#

Of course the real answer is "profile and find out", but do you have some rule of thumb or experience to share before that?

#

Oh btw, the trimesh from mesh stuff was not the problem: #1364848195670114325 message
Thanks for helping me debug that πŸ™‚

vestal minnow
#

Right now Avian just uses Vec3 almost everywhere because we have f64 support and the feature-dependent Vector shenanigans, and I don't want to deal with special-casing f32 just for Vec3/Vec3A conversions everywhere, but if we yeet (or reduce) f64 stuff then we'll probably use Vec3A a bit more

visual sparrow
vestal minnow
#

I don't have a specific rule though, if you do a lot of SIMDfiable ops somewhere then it's good to try Vec3A and ideally profile if it's better

#

I generally wouldn't just default to using it everywhere, but idk I haven't benchmarked it much

vestal minnow
#

For the solver internals or velocity or material properties or anything like that it doesn't really make sense

vestal minnow
visual sparrow
vestal minnow
#

Yeah I would generally just use Vec3 for public APIs (and maybe like impl Into<Vec3A>) but use Vec3A for internals where performance matters and it has an actual benefit

visual sparrow
cinder summit
#

impl Into<Vec3A> ALL the things!

dreamy viper
#

Sync has been split into Prepare and WriteBack?

paper hamlet
#

Hello, sorry for the silly question. I think I am missing something conceptually and could use some help. I am making a simple scene where this cylinder is the ground, and generating a collider for it.

    // circular base
    commands.spawn((
        Mesh3d(meshes.add(Circle::new(20.0))),
        MeshMaterial3d(materials.add(Color::WHITE)),
        Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)),
        ColliderConstructor::Cylinder { radius: (20.0), height: (0.5) },
        RigidBody::Static,
    ));

Though when I am looking at it with the debug plugin, it appears to orient perpendicular like it isn't getting the Transform rotation for the mesh. What am I missing?
Thank you in advance!!

vestal minnow
#

You could make either the mesh or the collider a child entity and transform that separately

#

Or alternatively use a cylinder for the mesh too

paper hamlet
#

That is very good to know. Thank you!!

vestal minnow
paper hamlet
#

OOHHH! Ok that makes a lot of sense. Does that extend to squares and cubes/rectangular prisms, etc as well

vestal minnow
#

Yeah circles, ellipses, rectangles, polygons, etc. are on the XY plane, and cylinders, capsules, tori/toruses, cones, and so on are upright

paper hamlet
#

Ok great. This intuition I am sure will be useful many times in the future so thanks for that

viral goblet
#

I moved my avian logic to a different crate and now when I try to run the game I get:

#

I have no idea what changed

#

Has anybody ever had anything similar?

drifting marsh
#

would it be a good choice to rely on Avian's determinism for a p2p deterministic game? or should I roll my own physics?

visual sparrow
drifting marsh
#

I'm aware of the flag, my question is more about how well it works. I had some issues with determinism with Avian in the past.

visual sparrow
visual sparrow
drifting marsh
#

Does it also work cross platform?

echo parcel
#

Can I include somewhere in avian things like air resistance, drag coefficient etc?

vestal minnow
#

that feature should really be called cross-platform-determinism or math-determinism or something

#

Avian is locally deterministic even without that feature, it's just for cross-platform deterministic math via libm

vestal minnow
echo parcel
vestal minnow
#

and of course mass properties, but that's handled automatically unless you want to manually configure or compute them

echo parcel
vestal minnow
#

For aerodynamics stuff I would imagine you just compute a force and torque to apply to the body and then apply them in FixedUpdate like normal gameplay logic

#

Or you could schedule your own systems directly inside the PhysicsSchedule or even SubstepSchedule, but those are more prone to breakage and changes

echo parcel
vestal minnow
vestal minnow
#

but like it all depends on what you're trying to do, you need to figure out the scheduling and stuff from the system sets if you're trying to insert your own systems in Avian's internal schedules

#

I don't know any other engine where you can even insert your own logic like that (and I don't generally recommend it) beyond dedicated hooks for specific things like contact modification, which Avian does have too

cinder summit
#

-# (For parry, CastShape and Shape would probably be either Collider, a type like it without scale, or just SharedShape)

echo parcel
vestal minnow
#

the ones called custom_broad_phase and custom_constraint

echo parcel
#

Could've guessed xD

vestal minnow
# cinder summit <@545959292281552928> what's your opinion on this set of traits and types btw? <...
  1. We should probably make AnyCollider reuse the bounding trait instead of both having their own versions of AABB methods
  2. We can probably make ColliderAabb a wrapper over Aabb2d/Aabb3d if we only support f32 anyway for the BVH. Then we can return Aabb2d/Aabb3d from shape_aabb (I would maybe call this aabb_with_context)
  3. Does QueryCollider need to implement AnyCollider? Or could it be a fully separate thing with its own Context?
  4. ray_normal feels strange to me. If you have the normal, then you should typically also have the distance. I would just call these ray_distance and ray_cast or something, where ray_cast returns a QueryRayCastHit
  5. shape_hit should just be shape_cast IMO
  6. I would rename hits_point to contains_point
  7. I would maybe rename shape_intersection to contact? Though I think I would personally just have a method to query for AABB intersections with the BVH, and then users can further do their own contact computations for those shapes, whether that's with contact or contact_manifolds or something else
  8. FYI, the intent with the shape intersection methods that just return a bool is that they can be way faster than computing actual contact data. You never need EPA, and a lot of the analytic intersection tests are also more optimized than the contact computations
#

Also I wonder if there's a way to hide the Context stuff from the API with a ContextShape wrapper or something πŸ€”

visual sparrow
vestal minnow
#

Oh wait ray_normal takes a point and not a ray thonk

cinder summit
#

Yea, ray_normal just computes the remaining info when we know a hit actually needs it

#

So like, not one that is filtered out for not being the best hit

cinder summit
# vestal minnow 1. We should probably make `AnyCollider` reuse the bounding trait instead of bot...

1: That makes a lot of sense actually
2: Yea, ColliderAabb was getting a bit clunky too,
3: I think these are in theory seperate, so we could split them appart
4: see above
5 + 6: Makes sense
7 + 8: Yea, probably makes sense to change that API a bit, my SDF collider impl basically just wraps contact_manifolds, though in theory I could make a slightly faster one that just returns a bool (but ime that's often not enough data)

#

On 1 specifically .... The weird bounding trait that gets context was originally just a quick hack to get things to actually work, so I never considered the fact that colliders could use it too bavy

#

Would the non-manifold contact method still be on QueryCollider or just on AnyCollider with a default impl that just does the manifold but then yeets the manifold data?

cinder summit
#

If we get rid of that I think we can also just use Bounded2d/Bounded3d directly too ...

vestal minnow
#

AnyCollider should be scoped to what colliders need to function as colliders, meaning what they need for the broad phase and narrow phase and for rigid body sim

#

QueryCollider can be for additional geometric queries and spatial queries

cinder summit
vestal minnow
#

We already don't have a spatial query for contact computations, we only have shape_intersections which doesn't compute contact data and just returns intersecting entities

cinder summit
#

Also just curious, what data do you actually get if you try to get a boolean contact check, is it just a boolean, or is there something like the penetration depth and direction there? πŸ€”

vestal minnow
# cinder summit Also just curious, what data do you actually get if you try to get a boolean con...

Parry supports three levels here

  • Intersection test: Just does the minimal work to determine if two shapes intersect. For example, a ball-ball intersection test is literally just center_distance_squared <= sum_radius_squared.
  • Contact: Computes a single contact point between two shapes, with a penetration depth and normal, typically just running GJK+EPA for most shape pairs.
  • Contact manifold: Computes a whole contact manifold in one shot, often consisting of multiple contact points. Typically uses SAT and/or GJK+EPA and contact clipping.
#

The middle one with a single contact point is usually the least useful IME unless you're building contact manifolds incrementally or something

cinder summit
#

For a lot of gameplay things just getting that contact can be all you need, but for the actual physics it's not particularly useful πŸ€”

#

And of course sometimes intersection test is all you need too, like "Can I place this here or does it overlap anything?"

vestal minnow
#

Or even something like selecting all entities in some selection box or lasso selection tool or something

cinder summit
#

But for cases like "Did this AoE hit an enemy" you might start to care about where the hit was so you can put some vfx there

#

Gameplay logic gets so annoying when you start adding vfx bavy

weary hornet
#

Hey how do you recon a high detailed mesh would perform on the physics end? Like, instead of using a heightmap for terrain I'm thinking of sculpting it in something like Substance Modeler and converting to meshlet for the rendering side.

#

I guess I could run it through a decimator if I have to

cinder summit
#

Decimating it + using convex decomp can do a lot compared to using a high poly trimesh

#

A lot of terrain workflows rely on doing exactly that too

weary hornet
#

Do you have a good strategy on how I could better automate the convex decomposition process?

#

it would be pretty complex terrain like something out of Star Wars Pod Racer

vestal minnow
#

yeah highly detailed meshes can perform quite poorly for collisions since you can end up with shapes doing collision tests against a ton of triangles at once and have to compute contacts against each of them

#

this wouldn't be as bad if we had manifold reduction to prune contact points, but we don't have it yet

#

(neither does Rapier)

cinder summit
weary hornet
#

oh wow ok

#

And while I'm here, do you guys happen to know if a big meshlet would even work for terrain? Like, does it lower the detail of the entire mesh based on distance, or is it all localized?

cinder summit
#

Legend has it Jan made something for caching at least, but idk if that persists across reboots πŸ€”

vestal minnow
#

doesn't persist

#

it's just a hash map with mesh handles IIRC

weary hornet
#

ok so probably a pretty expensive operation eh? I could split the mesh tho

cinder summit
#

Probably worth splitting the mesh in general if it's big

weary hornet
#

ya

#

ya because the meshlet stuff would eat my ram

#

as its baking

cinder summit
#

Yea, plus if it's big enough, loading the terrain can be done in chunks that are relevant rather than all at once

weary hornet
#

yeah which may work quite well in my case because I'm making it very canyon-y

vestal minnow
#

hmm, it could be interesting to try and offload convex decomposition done at runtime to some async tasks to avoid blocking the main thread

weary hornet
#

well how involved is it from the user perspective? am I just passing some verts into a function?

#

if parry does it I could probably help with this if you want

#

I want to build up a whole terrain strategy/pipeline for bevy

cinder summit
weary hornet
#

ah wtf

#

so awesome

vestal minnow
#

or if you have a scene then you can use ColliderConstructorHierarchy to generate the colliders automatically

weary hornet
#

awesome

cinder summit
#

Benefit of making the terrain chunks too is that the convex decomp resolution starts to become consistent

vestal minnow
#

But again this can be very slow and expensive for anything remotely detailed

weary hornet
#

so this is the jist of my strategy atm:

  • sculpt in blender or whatever
  • export into a lossless format, whatever is the smallest
  • use meshopt (C++) or baby_shark (Rust) to decimate
  • split into regions
  • convex decomp
  • meshlet
#

ya I hear you

#

I can fix that though, happy to contrib

#

fix by running it async lol

vestal minnow
#

By slow I mean like up to several minutes depending on your PC and the size of the scene

cinder summit
#

Convex decomp being wildly slow, and trimeshes being wildly inefficient is literally how I ended up making SDF collisions after all 🀣

vestal minnow
#

For the Ferris crab model it's a few seconds in debug mode for me

weary hornet
#

it's really not too bad tbh. What matters for speed is being able to preview changes fast with a flycam. Then when it's time to walk or drive around it, you have to run it thru the various processing steps

vestal minnow
#

in release mode it's a little faster

weary hornet
#

Like, baking shit with Nanite can take like 30 minutes on a beast PC so its just the way she goes I guess

cinder summit
#

Yea, if we get an actual asset processing workflow for this one day (probably when we finally have scenes and can translate a gltf file to a set of assets among which a scene), then this would be very doable on premade geometry

weary hornet
#

i'm building a terrain editor 😈

#

it's in the 10s of millions of verts

#

...although I have an RTX 5080

cinder summit
#

On procgen games with slightly less detailed meshes it would probably be workable too as long as you tune the parameters and run things in the background

#

And then you have the cursed usecases like my game:

  • Procgen everything
  • Nothing is low poly
  • The server has a single thread
weary hornet
#

haha

#

ya.. the problem I'm running into is file sizes

#

shit is just a lot of data

#

as soon as you're moving away from heightmaps its like oh shit i have to store the verts

#

or something

vestal minnow
#

Typically I'm pretty sure static terrains in a lot of open world games just use low detail trimesh colliders

cinder summit
#

A lot of games crank the poly count waaaaaay down, yes

vestal minnow
#

example scene from Horizon Zero Dawn using Jolt

cinder summit
#

I'm sure we've all seen the collision vs visual mismatches πŸ‘€

vestal minnow
#

*Horizon Zero Dawn I mean

weary hornet
#

but ya

#

neat to see

visual sparrow
#

It’s split into submeshes, those are the titular meshlets. And those submeshes can change detail independently of each other

vestal minnow
#

(I'm moving the boxes here)

#

Next step is to wire up the sleeping and waking

cinder summit
#

[Places a little alarm clock in each simulation island]

runic tinsel
vestal minnow
#

i should take a vacation and go sleep on an island

#

lies down on a bed of cubes

cinder summit
#

[Hands Jondolf yet another little alarm clock]
For your island

echo parcel
#
commands.spawn((
        RigidBody::Dynamic,
        Transform::from_xyz(0.0, 100.0, 0.0),
        Mesh3d(mesh),
        MeshMaterial3d(material.clone()),
        Collider::cylinder(radius / 2., cylinder_height),
        Mass(100000.),
    ));

No matter how big mass I set the cylinder always behaves the same. Why?

vestal minnow
#

if it's just on static ground or all the other dynamic objects also have that same mass then it shouldn't really change behavior much

echo parcel
#

But shouldn't the object with the bigger mass fall faster?

vestal minnow
#

no, a 1 kg box will fall just as fast as a 10000 kg box, assuming they have the same shape

runic tinsel
#

Air resistance is not simulated in avian, is it?

vestal minnow
#

it's not

runic tinsel
#

Then any object, with any shape should fall the same speed right?

vestal minnow
#

yes, I just mean in real life the shape would affect things (unless you're in a vacuum)

runic tinsel
#

fair fair

echo parcel
vestal minnow
#

SI units are recommended, so meters for distance and length, kilograms for mass, seconds for time, and so on

#

But it doesn't really matter as long as they're dimensionally consistent, like speed is "distance units divided by time units"

#

This could be meters per second, or pixels per second, or however you want to interpret values

visual sparrow
echo parcel
#

So 1 unit is 1 meter?

visual sparrow
visual sparrow
vestal minnow
visual sparrow
vestal minnow
#

I think the renderer mostly assumes SI for lighting units, like intensity is in lumens and illuminance in lux (which is lumens per square meter)

#

not sure if it necessarily assumes units elsewhere

runic tinsel
#

Probably also for some of the pbr equations

vestal minnow
#

right

#

oh and the atmosphere stuff

runic tinsel
#

So takeaway is that renderer is SI, and 2d is whatever you want

visual sparrow
#

Volumetric lighting too I believe, due to the scattering coefficients

visual sparrow
#

I really hope I get to have a good reason to use that for a game at some point

vestal minnow
#

for even more unique visuals, consider rendering the world a few dozen kilometers from the origin

visual sparrow
#

StandardMaterial::depth_map is also very trippy when set to random data

runic tinsel
#

For even more unique visuals, consider wearing those drunk goggles

visual sparrow
#

For even more unique visuals, consider normalizing twice for no reason

runic tinsel
#

For even more unique visuals, consider also drinking funny water (If your at legal age of course!)

vestal minnow
#

For even more unique visuals, please give us #physics-dev

#

speaking of visuals, I kinda want to just slap an atmosphere on most of the 3D examples, I'm bored of all of our scenes looking like this lol

#

or at least change the color scheme

#

also have some camera controller and maybe the grabber plugin thingy

#

(maybe not for examples that focus on demonstrating some specific feature, but for more general samples)

runic tinsel
#

That just adds a camera, and object picking

visual sparrow
vestal minnow
#

We have an ExamplesCommonPlugin already, it just doesn't do that much atm

echo parcel
#

SubstepSolverSet runs during SolverSet::Substep, right?

vestal minnow
#

yes

#

but specifically inside the SubstepSchedule

#

SolverSet::Substep is where the SubstepSchedule is run

echo parcel
#

IntegrationSet::Velocity will be the best to apply drag/air resistance, right?

sweet sundial
#

there're drag components already, can either check their impls or use them directly

echo parcel
echo parcel
vestal minnow
#

LinearDamping and AngularDamping, they're just exponential decay

#

(or specifically the PadΓ© approximation of exponential decay)

vestal minnow
#

There might still be some small error in the island splitting logic since it sometimes takes a while for it to split things properly, but it's mostly functional now

little maple
vestal minnow
# little maple this looks neat but what does it mean

Simulation islands are like collections of bodies connected by constraints, where each island forms a graph-like structure. Islands are fully disjoint from each other and can be simulated independently. Their main purpose though is to allow sleeping and waking; if all bodies in a given island have a low enough velocity for some time, then that island can be set to sleep. And if any body in an island is woken up, the whole island must be woken up.

#

Here the red boxes are just visualizing which bodies belong to the same island. It's drawn around their combined bounds, but that doesn't really mean anything beyond that

#

The difference to our current scuffed sleeping is that we only have per-body sleeping, which doesn't allow bodies to sleep when they're interacting with other dynamic bodies, either via colisions or joints

#

Whereas with simulation islands we can handle sleeping and waking properly, as can be seen with that whole cube stack sleeping when it's resting for a bit

#

Some engines like Rapier also use islands for solver parallelism, but we use graph coloring, which supports parallelism within islands, not just between islands

#

So these islands are used only for sleeping and waking, and persisted across time steps, doing incremental updates to minimize overhead, and deferring splitting (the expensive part) so that only one island is split per time step, the sleepiest one

little maple
#

is this new? I thought you had some island-like thing implemented before? if not I think I maybe just heard about it here at some point

#

I mean, it looks great, especially that second one and I can see how useful it is

vestal minnow
#

It's new, I haven't had any island stuff before, though graph coloring has some conceptual similarities (a graph where bodies are nodes and constraints are edges)

#

I have been talking about wanting simulation islands for a very long time tho

sweet sundial
#

livin' the dream

little maple
#

that island life

vestal minnow
#

we're moving into the big boi league now with these simulation islands, graph coloring, the BVH broad phase (Soonβ„’) etc.

hard helm
#

I’ve had islands for a long time, because I needed to track them anyway for CSG. I didn’t run them in parallel though since Bevy makes that difficult. I also use a BVH for the broad phase. I’ll probably do graph coloring if I implement AVBD. I’m not sure any of this counts as the big leagues after seeing the latest SIGGRAPH demos.

#

One thing I use islands for is to force conservation of energy to help with stability.

#

Identifying islands is the union-find algorithm once you have an intersection graph.

vestal minnow
#

By "big leagues" (half-joking) I mean having implemented a lot of the fundamental optimizations and getting close to (or exceeding) the performance of existing popular game physics engines like Box2D, Jolt, or Rapier

#

I do not really consider any GPU-based implementation (that I have seen) for rigid body dynamics to be in the "big leagues" for game physics, as I consider that to be a totally different category. For a general-purpose game physics engine, running on the GPU tends to be a non-goal IME

little maple
#

every time I show my game off people tell me how great the physics are and I'm like "thank you Jondolf πŸ™ "

vestal minnow
#

As for AVBD specifically, I'm still fairly unconvinced based on the results I've seen or even replicated, but I'm interested to see how it develops

hard helm
hard helm
#

If AVBD doesn’t work right away, it might be worth fixing.

vestal minnow
#

Yeah it has some really nice characteristics, like handling both high stiffness ratios and high mass ratios well, and allowing vertex coloring. But from what I've seen and heard (both with my implementation and their own 2D demos) it's just way too unstable for collisions, requires a ton of tuning to behave well, breaks Newton's third law, and doesn't seem like it'd work as nicely with wide SIMD

#

They recently updated their 2D demo to use post-stabilization, which removes the need for tuning the alpha parameter, and should prevent adding extra energy to the system, but it made contacts even less stable and more jittery :/

hard helm
#

Like I said, we’re getting more CPU cores, but not wider SIMD. Physics laws are more like guidelines in games πŸ™‚ Stability is nice though.

drifting marsh
#

I'm really struggling to get avian to run on a custom schedule.

  app.add_plugins((
            avian2d::PhysicsPlugins::new(CustomPhysicsSchedule).with_length_unit(50.0),
            PhysicsDiagnosticsUiPlugin,
            PhysicsDiagnosticsPlugin,
        ))
        .add_schedule(Schedule::new(CustomPhysicsSchedule))
        .add_systems(GgrsSchedule, (move_players, step_physics).chain())
        .add_systems(CustomPhysicsSchedule, foo) // this prints "foo" and that shows up in the output

I modified avian/src/schedule/mod.rs a bit to debug:

 println!("schedule: {:?}", self.schedule); // this prints CustomPhysicsSchedule

        app.add_systems(
            schedule,
            run_physics_schedule.in_set(PhysicsSet::StepSimulation),
        );

        app.add_systems(schedule, foo2); // this system doesn't print anything??
#

I genuinely cannot figure out the difference between foo and foo2. It's the same schedule so why does only foo run?

regal parrot
#

Guys, I am migrating to the new Forces. I have modified my old projectile spawning command to look somewhat like this:

fn spawn_projectile(
    In(config): In<SpawnProjectile>,
    mut commands: Commands,
    mut force_query: Query<Forces>,
) {
    let entity_id = commands.spawn((
        Projectile { [...] },
        config.transform,
        RigidBody::Dynamic,
        // ExternalImpulse::new(config.force),
    )).id();

    if let Ok(mut forces) = force_query.get_mut(entity_id) {
        forces.apply_linear_impulse(config.force);
    } else {
        info!("NO FORCES");
    }
}

There is no Forces querydata ready for the entity when this runs. Do I need to add an observer here and then add the impulse in the observer after a sync point?

sweet sundial
#

can't you just have a Velocity in the bundle?

regal parrot
#

I'm reading the implementation of apply_linear_impulse & yep, it looks like I could just add the velocity on spawn. The new component is LinearVelocity for anyone who stumbles across this in future πŸ™‚

sweet sundial
#

if you really needed to use an impulse it'd have to be after mass is calculated, which is probably an observer; either queue it separately (Commands), put it after a sync point, or figure out observer ordering

#

if it's a schedule system rather than an observer then you'd need to do something persistent

echo parcel
vestal minnow
#

inside the solver you need to use SolverBody, it has linear and angular velocity

scenic violet
#

What is the best way to create a shockwave that will push rigidbodies along with it, a sensor that gets velocity and gives velocity upon collision, or is there a way to do it with some kind of spatialQuery?

vestal minnow
#

a sensor could also work if you want it to persist for several frames or to automatically move with some velocity

vestal minnow
echo parcel
#

I've came up with something like this rn, it compiles but I'm not sure if this is correct:

let substeps =  app.get_schedule_mut(SubstepSchedule).expect("add SubstepSchedule first");
        substeps.add_systems(
            air_resistance_substep.in_set(IntegrationSet::Velocity)
        );
vestal minnow
#

oh right you said that the first foo system still prints something, hmm

echo parcel
#

According to the example, I should rather work with some draits dedicated to the velocity, right?

https://github.com/Jondolf/avian/blob/main/crates/avian3d/examples/custom_constraint.rs

substeps.add_systems(
        solve_xpbd_joint::<CenterDistanceConstraint>.in_set(SubstepSolverSet::SolveUserConstraints),
    );

    // Run the app
    app.run();
}

/// A constraint that keeps the distance between the centers of two bodies at `rest_distance`.
#[derive(Component)]
struct CenterDistanceConstraint {
    entity1: Entity,
    entity2: Entity,
    rest_distance: Scalar,
    /// The relative dominance of the bodies.
    ///
    /// If the relative dominance is positive, the first body is dominant
    /// and is considered to have infinite mass.
    relative_dominance: i16,
    compliance: Scalar,
    /// Data stored from before the solver step.
    pre_step: PreStepData,
}
impl PositionConstraint for CenterDistanceConstraint {}
impl AngularConstraint for CenterDistanceConstraint {}

impl EntityConstraint<2> for CenterDistanceConstraint {
    fn entities(&self) -> [Entity; 2] {
        [self.entity1, self.entity2]
    }
}

impl XpbdConstraint<2> for CenterDistanceConstraint {
    fn solve(
        &mut self,
        bodies: [&mut SolverBody; 2],
        inertias: [&SolverBodyInertia; 2],
        dt: Scalar,
    ) {

Some kind of equivalent of this code

GitHub

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

vestal minnow
#

I'm not sure if I'd model air resistance as a constraint

#

You're just applying a force, no? I'm not sure if there's really a specific constraint that it'd need to satisfy

#

but I haven't looked much into how realistic air resistance tends to be implemented

#

I guess you could model drag as some sort of damping constraint that aims to dampen velocities rather than explicitly using forces, but idk seems more complicated

echo parcel
#

Some equivalent of this code for the velocity

#

AngularVelocity, PositionVelocity traits, I'm not sure if such things exists

echo parcel
oak vigil
#

Hey, is there a method to get a random position inside a collider?

summer acorn
#

iirc some bevy_math primitives have volume sampling methods

oak vigil
#

I see bevy primitives. Are you suggesting converting the collider into a bevy primitive and using that?

#

If that's the case, I might just implement the function to work directly on collider

summer acorn
#

i think theres a way to go from bevy primitive to collider

#

but that may be unreleased peck stuff

vestal minnow
#

Are you on 0.3? There you can just use LinearVelocity and AngularVelocity inside the solver, but on the main branch things are quite different

echo parcel
#

I'm at 0.3.1

vestal minnow
#

yep solver bodies don't exist there yet, they're new (or added like over a month ago, but not released on crates.io)

echo parcel
#

I've been bamboozled!

#

What can I do about it?

vestal minnow
#

or use the main branch or some specific commit

#

this is what I meant about the internal schedules being very prone to changes here, and (generally) recommending to just use the built-in stuff and running logic in FixedUpdate :p

echo parcel
vestal minnow
#

in Cargo.toml do

avian3d = { git = "https://github.com/Jondolf/avian" }
#

if you want to lock to a specific commit, you can use rev = something where you replace something with a commit hash or whatever it's called

echo parcel
vestal minnow
#

you need to update Rust, it's a feature that was stabilized in a new release a few weeks ago

cinder summit
#

Whoa, we can do that now? Neat

vestal minnow
#

Or I don't remember that specific syntax πŸ€” but let-chains were stabilized at least

#

with &&

cinder summit
#

let chains were stabilized???? πŸ‘€πŸ‘€πŸ‘€

mossy brook
vestal minnow
#

Or if we wanted to go further with this and allow simulating each world fully independently, like advancing one world but not others, we would need first-party query-by-value functionality in Bevy, or to rework our internals to rely on the ECS less

#

I had a prototype for multi-world support implemented already using bushrat's index query PR, but the work on that stalled on Bevy's side

echo parcel
vestal minnow
#

a hack to support two mutually exclusive dimensions in a single code base, same as what Rapier and Parry do

echo parcel
#

Do I have to add SolverBody manully into my entity? The breakpoint doesn't hit

vestal minnow
#

have you added MaxLinearSpeed to the entity?

echo parcel
#

No

vestal minnow
#

SolverBody is added automatically for dynamic and kinematic bodies, MaxLinearSpeed is not

#

(might change that though, we probably want to have some default bounds on linear velocity and especially angular velocity for stability reasons)

mossy brook
vestal minnow
#

Yeah it probably could be a relationship, I need to see what the performance of query.iter_many(entities) is compared to query.iter() though

#

With index queries we can split archetypes based on the world that each body is assigned to, and theoretically have ideal iteration perf that way, but idk how much worse iter_many is

mossy brook
#

This is interestingly a rare case where I think many-to-many is actually a bad fit too, I think as a design principle you only ever want a physics object in a single context. It saves on performance and you don't need to wait for the Bevy implementation of many-to-many.

mossy brook
vestal minnow
#

I'm not sure how I'd make it opt-in without duplicating the systems to have both a "contextful" and "contextless" variant

#

it'd need two different queries and to do the iteration in two different ways depending on whether you're simulating a specific context/world or not

drifting marsh
# vestal minnow oh right you said that the first `foo` system still prints something, hmm

I used bevy_mod_debugdump and foo is the only thing in the schedule. Is there any way I can check the schedule of the run_physics_schedule system?

digraph "" {
    "compound"="true";
    "splines"="spline";
    "rankdir"="LR";
    "bgcolor"="#0d1117";
    "fontname"="Helvetica";
    "nodesep"="0.15";
    edge ["penwidth"="2"];
    node ["shape"="box", "style"="filled"];
    "node_System(0)" ["label"="foo", "tooltip"="rounds::game::physics::foo"]
}
vestal minnow
#

I'm on mobile rn so I can't really read it :/

#

I'm not really sure why your case wouldn't work

#

run_physics_schedule should run in the schedule that you give to PhysicsPlugins::new

drifting marsh
#

my only guess is that Interned schedules don't work properly but I assume someone would have already come across that

mossy brook
drifting marsh
#

Well, and the default schedule is also interned so that wouldn't be the issue. I'm very lost

#

I didn't think this mattered but apparently I have to add the schedule before I add the avian plugin

#

Ah, add_schedule says it overwrites the previous schedule with that label

vestal minnow
#

yeah you might want edit_schedule instead

drifting marsh
#

I don't even need add_schedule lol. I just copy pasted that from an older project

vestal minnow
#

that's definitely a nasty footgun though

drifting marsh
#

The docs for with_length_unit make it sound like it I shouldn't have to adjust stuff like gravity. But the default gravity doesn't even move my character at all.

#

For reference, I set the length unit to 50.0 and my character is 50x50 pixels

vestal minnow
#

I mean it does say "Note that this is not used to scale forces or any other user-facing inputs or outputs." and that it only adjusts some internal tolerances and stuff for stability

drifting marsh
#

Hmm, it says "the physics engine will interpret 100 pixels as 1 meter for internal thresholds" so I guess I interpreted that as my character would count as 1 meter in size so the default gravity would be fine

#

but I guess I glossed over the "internal thresholds" part

echo parcel
#

When adding to solver_body.linear_velocity, should I include delta time into account?

vestal minnow
#

#physics-dev πŸŽ‰

sweet sundial
echo parcel
finite blaze
#

@echo parcel I'm also interested in creating a flight dynamics plugin for Avian, though I have barely looked at it besides reading some game dev books. The new changes in avian main sound promising.
I wonder if a thread on #physics-dev for general FDM approaches would be useful

marble cradle
#

in my editor how can i dynamically turn on and off this ?

.add_plugins(PhysicsDebugPlugin::default() )

#

it seems like i cant like .. enable or diasable that... ?

pulsar bone
runic tinsel
#

Using lambdas as systems... Why did I never think of that...

#

Rust is just cool like this I guess

marble cradle
#

love it !!!

#

thank you

#

yay now my editor shows physics colliders πŸ˜„

heady oasis
#

Hello, need some help with applying forces to already spawned rigidbodies

#

all the documentation shows how to spawn a rigidbody with a force aswell, but no way to add a force to something already spawned (unless it's hidden somewhere I haven't found yet)

#
let mut force = ExternalForce::default();
// calculate force
force.apply_force_at_point(calculated_force, cool_place, mass_center);
// typical example in docs
commands.spawn((Stuffs, force));

// but I wanna apply at runtime
item.apply_force(force)  //this sort of thing kinda
sweet sundial
#

required component or insert with commands

heady oasis
#

at runtime

sweet sundial
#

commands is runtime

heady oasis
#

so like add a lifting force for car

sweet sundial
#

you could also swap to main and use the new force api

heady oasis
sweet sundial
#

Query<Forces>

heady oasis
#

so I just query the force and then .apply_force onto it?

vestal minnow
#

You can also use the current/old API in 0.3 and query for ExternalForce and modify it, but that old API is a lot more limited and footgunny than the new one

#

With the old ExternalForce API, all forces are persisted across frames by default, so you need to manually clear them, or alternatively configure the forces to be non-persistent (and you couldn't apply both persistent and non-persistent forces at the same time)

#

With the new API you can just use Forces to apply forces or impulses that are cleared automatically, like what you'd see in most game engines, and there's a separate component-based API with components like ConstantForce if you want persistent forces

heady oasis
#

do you use unstable branch for it or?

#

so like avian3d = "unstable"

vestal minnow
#

It's on the main branch

#

you can also lock to a specific commit if you want

heady oasis
#

so I can just use normal 0.3.1?

#

or like how to query for "main" in toml file

#

do you just to avain3d = "main"

vestal minnow
#

If you want the new API then you need to use main

[dependencies]
# optionally also specify rev = "the SHA of some commit"
avian3d = { git = "https://github.com/Jondolf/avian", branch = "main" }
heady oasis
#

thx

#

kinda new to avian & bevy as a whole, but noticed lack of docs on avian3d

vestal minnow
#

Note that if you have other dependencies that also use Avian, you might get a version conflict and need to patch or fork things to get it working

heady oasis
#

I noticed that there are like no tutorials out there that show how to query for rigidbody

#

bcs you cant query rigidbody directly for some reason

vestal minnow
#

The docs.rs documentation should generally be alright, but some more "book-like" content and tutorials and better examples would be nice

heady oasis
#

owm to making a car game tutorial

#

w avian3d

#

using very very valet general car game (they coded it in unity) tutorial as basis

vestal minnow
heady oasis
#

specifically Angularvelocity and linearvelocity (i think) but querying them as is (as the tutorial did) works

sweet sundial
#

components don't directly impl QueryData, only references to them

heady oasis
#

but then you have to ang.0 +lin.cross(position) to find velocity_at_point

vestal minnow
heady oasis
#

that specific example is what throws erropr

#

when also getting transform

#

so
let rb = Query<stuff from there>
let car = Query<Transform, with car>

vestal minnow
heady oasis
#
mut car_stuff : Query< ( &Transform , &mut AngularVelocity , &mut LinearVelocity ) , With<car>
#

this is what ended up working

vestal minnow
#

since just the component by itself doesn't implement QueryData

#

that's more of a Bevy thing and not something that necessarily belongs in Avian docs

heady oasis
#
mut car_stuff : Query< &mut Transform  , With<car> >,
    mut rb : Query<RigidBodyQuery>,
#

here is old stuff

vestal minnow
#

that should work yeah

heady oasis
#

throws incomprehensive error

#

because they can be both

vestal minnow
#

what's the error?

#

(if you still have it)

heady oasis
#

1 sec

sweet sundial
#

probably aliasing between two &mut Transforms

heady oasis
#

it was a panic

vestal minnow
#

I don't think RigidBodyQuery has a Transform

heady oasis
heady oasis
vestal minnow
#

that's not a Transform

heady oasis
#

thread 'main' panicked at /home/gobbe/.cargo/registry/src/index.crates.io-1949cf8c6b5b557f/bevy_ecs-0.16.1/src/system/system_param.rs:409:5:
error[B0001]: Query<RigidBodyQuery, ()> in system brumm::bil::fjΓ€der accesses component(s) Position, Rotation in a way that conflicts with a previous system parameter. Consider using Without<T> to create disjoint Queries or merging conflicting Queries into a ParamSet. See: https://bevyengine.org/learn/errors/b0001
note: run with RUST_BACKTRACE=1 environment variable to display a backtrace
Encountered a panic in system bevy_app::main_schedule::FixedMain::run_fixed_main!
Encountered a panic in system bevy_time::fixed::run_fixed_main_schedule!
Encountered a panic in system bevy_app::main_schedule::Main::run_main!

#

got error

#

(that's the old error)

vestal minnow
#

do you have other queries in that system? beyond the two you showed

heady oasis
#

fn fjΓ€der(
    kΓΆ : SpatialQuery,
    mut bil : Query< &mut Transform  , With<brumm> >,
    mut rb : Query<RigidBodyQuery>,
    tid : Res<Time>
) {
    let HJULEN : Vec<Vec3> = vec![ Vec3::new(4.0 , 0.0 , 7.0) , Vec3::new(4.0 , 0.0 , -7.0) , Vec3::new(-4.0 , 0.0 , -7.0) , Vec3::new(-4.0 , 0.0 , 7.0) ];

    for dΓ€ck in HJULEN {
        let bilen = rb.single_mut().unwrap();

        let pos = **bilen.position + dΓ€ck; // dΓ€cken roterar inte, de sitter fast lΓ€ngs axlarna
        let hjulet : Transform = Transform::from_translation(pos);

        if let Some(trΓ€ff) = kΓΆ.cast_ray(pos , Dir3::NEG_Y , 100.0 , true , &SpatialQueryFilter::default() ) {
            ...
        }
    }
}
#

what I can tell its just that bil and rb are same

#

components of car:```
Transform::from_xyz(0.0 , -3.0 , 0.0),
//mesh stuff
//collider stuff
RigidBody::Dynamic,
brumm

sweet sundial
heady oasis
#

because it has both transform and rb

vestal minnow
#

Right SpatialQuery is currently internally querying for Position and Rotation (components for the physics transform, mostly intended for internals) and some other things, and RigidBodyQuery is also querying for them mutably. You can't have multiple queries mutably accessing the same components in the same system unless you explicitly make the queries disjoint using Without<T> filters

#

Here I would recommend just not using RigidBodyQuery

#

I'm probably going to remove it soon too since it's not really intended for users, it was originally more to clean up internal logic

heady oasis
#

oh

vestal minnow
#

(and it's big and slow and somewhat footgunny)

heady oasis
#

thought it was transform n rb on same object :P

visual sparrow
#

Is trimeshing a big world of colliders something expensive?

#

Obviously it becomes expensive if you have millions of colliders lol

vestal minnow
#

Like, rasterizing a lot of primitive shapes into trimeshes?

visual sparrow
#

But for something like Chainboom's level that is made of a bunch of convex hulls and convex decomps

#

My current design for rerecast doesn't neatly allow offloading that onto its own thread

#

And I'm worried about hiccups

#

But I think something like that shouldn't be too expensive, right?

vestal minnow
visual sparrow
#

thx

#

Hmm, I suppose I could turn the backend into an async task

#

then we just shift the problem from "rasterize everything this frame" to "copy all colliders into a separate task this frame"

#

would be so much easier if we had first-party colliders ;-;

visual sparrow
visual sparrow
vestal minnow
#

Every 3D convex hull is just a ConvexPolyhedron and a convex decomposition outputs a Compound of ConvexPolyhedron shapes

visual sparrow
bleak wadi
#

is there a good way to do one way collision platforms?

visual sparrow
#

@vestal minnow how come the feature is called debug-plugin and not debug_plugin?

#

Asking because I'm also doing a gizmo plugin for rerecast and checking prior art

#

Also, you don't use any retained gizmos, right?

vestal minnow
#

and I think I did that because I was originally copying Rapier for it bavy

visual sparrow
#

simply for the parity with bevy

vestal minnow
#

I would probably accept a PR renaming them to use _ consistently, though Bevy is also inconsistent

vestal minnow
vestal minnow
visual sparrow
echo parcel
#

I've noticed that ExternalForce is no longer available in the newest commits. What should I use instead to apply force to an entity

sweet sundial
#

Forces or ConstantForce

echo parcel
echo parcel
vestal minnow
echo parcel
#

I have such code. My problem is that the velocity goes up to the infinity in about 20 iterations. I'm not sure if I have a problem with calculations, or if I just misunderstand how forces in avian work

pub fn apply_air_resistance_forces(query: Query<(&SolverBody, &Transform, &mut ConstantLocalForce)>,) {
    for (solver_body, transform, mut local_force) in query {
        let rotation = transform.rotation;

        let tilt = tilt_angle(rotation);
        let area = calculate_reference_area(tilt, 2.0, 0.1);
        let drag_coefficient = get_drag_coefficient(tilt);

        let drag = calculate_air_resistance(drag_coefficient, 1.2, area, solver_body.linear_velocity.length().abs());

        local_force.y = -drag;

        println!("Drag: {}, Vel: {}", drag, solver_body.linear_velocity);
    }
}

fn calculate_air_resistance(drag_coefficient: f32, air_density: f32, area: f32, velocity: f32) -> f32 {
    let result = 0.5 * drag_coefficient * air_density * area * velocity.powi(2);

    result
}
foggy storm
#

Was just playing around with Foxtrot a bit and thought the physics was working perfectly but then I noticed objects don't always go to sleep. Is this because of the incline here or something else? Just curious why this happens.

vestal minnow
#

You can tune the SleepingThreshold to make it easier for bodies to fall asleep

foggy storm
#

I see, interesting. Have you looked into if this happens in other engines?

vestal minnow
#

I haven't yet, but I should try with Rapier at least since it also uses Parry

#

that should help confirm that the problem is what I think it is

foggy storm
#

I can see now it even happens on the flat ground. I would say that doesn't happen with other engines but it might be a different sleep threshold value as you said.

#

I'm guessing this degrades performance quite a lot in bigger scenes?

#

I find this seriously impressive πŸ˜† (sorry about bad recordings, have two screens with different resolutions and OBS doesn't seem to like that)

vestal minnow
golden python
#

Hello, sorry if this is a common question, but how would one have cumulative forces from different systems applied to a rigidbody ?
Is there a built-in way to do it, or should a query for an existing external force and if it exists, add to it or otherwise insert a new one ?

heady oasis
# golden python Hello, sorry if this is a common question, but how would one have cumulative for...

assuming that you are using avian, this might help

// using ExternalForce, avian 0.3.1 and below (main branch has a better force method)
fn setup (
  mut commands : Commands
) {
  commands.spawn((/*other stuff*/,ExternalForce::defualt.with_persistence(false); // set to true if you want the force to never stop
}
fn cumulative_stuffs (
  mut cumulative_force_query : Query<&mut ExternalForce>
  // query for some force here
) {
  let Ok((force)) = cumulative_force_query
  else {
    return // no force was found
  }  
  // handle the other force query
  force.apply_force_at_point(/*the force here*/ , /*point*/ , /*center of mass or pivot*/);
}
golden python
#

oh, forgot ExternalForce::apply_force is a thing, thanks a lot

heady oasis
#

no worries

golden python
sweet sundial
#

easier if you make it a required component for something

#

alternatively, commands.entity(e).entry().or_insert(_).and_modify(|_|{})

golden python
#

Thanks, i'm facing another issue now

impl Plugin for CharacterController3dPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Update, handle_hover);
    }
}

/*
Character controller is spawned with:
pub fn character_controller_bundle() -> (
    RigidBody,
    CharacterController3d,
    Collider,
    RayCaster,
    ExternalForce,
) {
    let capsule_height = 1.0;
    (
        RigidBody::Dynamic,
        CharacterController3d {
            hover_height: 1.0,
            move_speed: 1.0,
            drag_multiplier: 1.0,
        },
        Collider::capsule(0.1, capsule_height),
        RayCaster::new(
            Vec3::new(0.0, -capsule_height / 2.0, 0.0),
            Dir3::new(-Vec3::Y).unwrap(),
        ),
        ExternalForce::new(Vec3::ZERO).with_persistence(false),
    )
}
*/

fn handle_hover(
    time: Res<Time>,
    mut commands: Commands,
    mut controllers: Query<(
        Entity,
        &LinearVelocity,
        &RayHits,
        &CharacterController3d,
        Option<&mut ExternalForce>,
    )>,
) {    for (entity, linear_velocity, hits, controller, maybe_external_force) in controllers.iter_mut()
    {
        //stuff
        let total_force = (damp_force + bounce_force) * time.delta_secs();
        if let Some(mut external_force) = maybe_external_force {
            println!("external: {:?}", external_force);
            println!("total_force: {:?}", total_force);

            external_force.apply_force(total_force);
        }
    }
}

This logs:

external: Mut(ExternalForce { force: Vec3(0.0, 0.0, 0.0), persistent: false, torque: Vec3(0.0, 0.0, 0.0) })
total_force: Vec3(0.0, 66.86302, 0.0)
external: Mut(ExternalForce { force: Vec3(0.0, 66.86302, 0.0), persistent: false, torque: Vec3(0.0, 0.0, 0.0) })
total_force: Vec3(0.0, 48.842857, 0.0)

I'm very confused as to why there is still some external force on the second frame when the persistence is off ?
Can anyone help ?

vestal minnow
#

you're running that in Update instead of FixedUpdate, so if Time<Fixed> uses a lower rate than your refresh rate, you might apply the force multiple times per physics tick

heady oasis
#
#[derive(Resource)]
struct forces {
  // force 1
  // force 2
}
#

then you just query in the systems with a force you want to add to the sum

mut forces_query : ResMut<forces>
vestal minnow
#

note that on the main branch it's much nicer, and you can just use the Forces API without having to worry about components or configuring persistence or anything like that

heady oasis
#

yup

golden python
heady oasis
#

you could do

fn input_Update() {
  // handle input and store it
}
fn physics_stuff_FixedPostUpdate(){
  // fetch input from where you stored it, and act on it
}
vestal minnow
#

Yeah, wish we had input timestamps in Bevy so inputs in FixedUpdate would work more nicely :/

golden python
heady oasis
#

depends on type of game you are making, but an input que/buffer is still usually just a workaround :/

golden python
heady oasis
#

what are you making ? :P

golden python
#

A 3d character controller, why ?

heady oasis
#

so like fps or

golden python
#

yes

heady oasis
#

jump buffer is cool polish

#

coyote time and the other thing

golden python
#

yes, but it is an entirely different subject in my opinion, it should be implemented as a feature on top of a robust engine

heady oasis
golden python
heady oasis
#

force fields !??

#

cool

echo parcel
hoary turret
#

and I'm not seeing great improvements out of the box, I'm going to test it for a bit

#

first Imma replicate your test scene

#

with simple cubes stacked

bleak wadi
#

with my ldtk level i have thousands of staticbody squares, im looking into optimising that on the ldtk side (most of them are oob) but also none of those squares are actually asleep, possibly because they're all touching each other? if i could send them to sleep i think it would be a lot better

hoary turret
#

The reason you cannot put them to sleep is because they're in contact

#

with how things are right now if you want sleeping behavior you have to make them not be in contact or hack around it

#

Dynamic islands will fix that, or at least that's what Jondolf said couple weeks ago

#

the cubes on the first stack are lets call them 1x1, the towers on the right are 1x2, and the middle tower is 4x4

paper maple
#

I've read thru some stuff here regarding Disabled. I guess Avian RigidBodies don't respect Disabled due to some peculiarities of Observers or something ?

patent depot
#

Hello, I have a question related to future Avian development. You'll eventually replace parry by peck. What will be used for the BVH?

bleak wadi
#

@vestal minnow is there a reason why static bodies can collide with each other? it doesn't seem very useful

vestal minnow
#

How are your bodies set up?

#

Or there might currently be an edge case where if they are originally not RigidBody::Static when the contact pair is created, and you then change them to static bodies, the contact pair won't automatically be removed until they stop overlapping

bleak wadi
#
#[derive(Component, Default)]
#[require(
    CollisionLayers::new(
        PhysicsLayers::Ground,
        [
            PhysicsLayers::Enemy,
            PhysicsLayers::Player,
            PhysicsLayers::PlayerHitbox,
            PhysicsLayers::EnemyHitbox,
        ],
    ),
    RigidBody::Static,
    Collider::rectangle(128.0, 128.0),
)]
struct Wall;
#

idk if they're actually colliding; the issue is that they're not going to sleep

#

which i assume is because they are colliding

vestal minnow
#

Static bodies do not have sleeping because they can't move to begin with

#

They're not simulated anyway

#

Sleeping is for deactivating active bodies when they're resting

bleak wadi
#

i am having a performance hit, i guess i should just optimise it on the ldtk side to try and reduce the amount of entities it creates

vestal minnow
#

You could use the PhysicsDiagnosticsPlugin and PhysicsDiagnosticsUiPlugin to see where time is being spent

#

requires the diagnostic_ui feature

#

it will also show you if you do have collisions, and how many

bleak wadi
#

cool

vestal minnow
#

we're using it for the upcoming broad phase and spatial query rework too, even before peck

vestal minnow
#

Hmm, I'm thinking of doing a "joint rework lite" for 0.4

  • Support JointAnchor enum with Local, FromGlobal, and Auto variants for easier and less error-prone initialization of joint anchors
  • Expose way to set reference orientations or angles for FixedJoint, PrismaticJoint, RevoluteJoint, and SphericalJoint
  • Expose joint forces and torques with a unified JointForces component
  • Move all solver related data into separate types or components like RevoluteJointSolverData, making the user-facing joint components purely descriptions of joints and making them more solver-agnostic (or even engine-agnostic)
  • Make joint components immutable (useful for making simulation islands and the anchor stuff more robust)
#

I feel bad delaying it every release because the new joint solver stuff still isn't ready, but I could probably get a lot of the important API improvements done before that

scenic violet
#

Is it better to use LinearVelocity with LinearDamping or the new Forces api to move stuff in a system for a 2d game

past escarp
#

Depends on what you're looking for, but I think LV with damping is probably easier to control for something like a character since you can specify the exact speed, and forces would be useful for stuff like interacting with physics events (wind/explosions/etc.) but someone correct if this is inaccurate

scenic violet
#

The end result should be the same it’s just a matter of approach and ease of use no?

#

For my player I am using LV with damping rn, but wanted to try the new forces api for pushing enemies away and knockbacks

valid zenith
#

forces would make sense for any impulse based mechanics too, like air dashes, where you dont really want to override the velocity just nudge it

hoary turret
#

Increasing/decreasing Time<Physics> alter the speed of time in physics (On retrospective given the name I guess it makes sense lol). How can I increase the rate at which physics are simulated without altering the speed of them?

#

Because Increasing Time<Physics> and decreasing Time doesn't seem like a good idea hahah

sweet sundial
#

Time<Fixed>

hoary turret
#

that would also change the non-physics aspect of the app

#

is it inherently coupled?

sweet sundial
#

Time<Virtual> -> Time<Fixed> -> Time<Physics>

hoary turret
#

okay so that means Avian runs its simulation in sync with how many times bevy systems run

sweet sundial
#

there's an extension trait for Time<Physics>, but it's just relative speed & pausing

hoary turret
#

yeah

#

kk

sweet sundial
#

you can improve accuracy a little by increasing the SubstepCount

summer acorn
#

jondoooooooooolf

#

😭 why does returning f32::INFINITY from ComputeMassProperties3d::mass make a collider not collide with anything

#

this should make it immovable

#

or at the very least the mass should not be taken into account on RigidBody::Static colliders

visual sparrow
summer acorn
#

this is just standard physics engine stuff though

#

infinite mass means it cant move

visual sparrow
summer acorn
#

its usually specified in terms of inverse mass

visual sparrow
#

aaaaah that makes sense

summer acorn
#

so you can say 0 mass to mean immovable

visual sparrow
#

never thought of it that way, but makes total sense. Thanks!

#

Now do negative infinity next!

summer acorn
#

lmao

#

negative mass is a funny thing that is actually possible in real life theoretically

#

well, negative mass density

#

mass shouldnt be used in calculations when a rigidbody is static

#

im trying to figure out why avian does this

little maple
#

hmm, running into this when I despawn a sensor collider

thread 'Compute Task Pool (1)' panicked at forks/avian/crates/avian3d/../../src/dynamics/solver/mod.rs:478:21:
Contact pair not found in graph: ContactId(667)

I am despawning in PostUpdate after TransformSystem::TransformPropagate πŸ€”

little maple
#

oh, I think it's because the sensor was missing the Visibility component

#

nope, that's not it πŸ€”

summer acorn
#

is it reasonable to want a "wide simd" AnyCollider option

#

like i wanna be given 4 or more collider pairs at a time to process

#

preferrably lined up so that collider 1 is the same on all of them and the other 4 are different or smth like that

viral goblet
#

From what I understand, ShapeCaster updates every PhysicsSchedule which happens about every FixedUpdate, so once every few frames. Is there a way to make it check hits every frame instead?

viral goblet
# visual sparrow Why do you want that?

I have an entity that's being moved by a tween (it shouldn't react to physics things other than certain collisions) and I'm trying to clamp its movement to that collision

#

Since the clamping happens once every few frames, it jitters

#

I'm currently considering using regular raycast instead

visual sparrow
vestal minnow
#

I'm not sure how exactly it works in Bepu, but you need to batch by shape pairs and spit out wide contact manifolds

vestal minnow
sly badger
#

probably only meaningful for box/box tests

#

or other simple ones like spheres

#

anything using gjk or similar is not going to work

#

too much divergence

vestal minnow
#

no Bepu uses wide SIMD for pretty much all shape pairs, including convex hulls

sly badger
#

different number of vertices, different number of required iterations etc, different size of simplices

vestal minnow
#

it uses Tootbird search for its depth refiner to find the minimum depth between convex bodies

sly badger
#

not saying that its impossible, but seems like it might not be worth it

#

ok