#Avian Physics

1 messages ยท Page 13 of 1

sleek thicket
#

there was one but it's easy to make it yourself

vestal minnow
#

Johan has investigated the determinism issues a few times in the context of rollback networking, and we've fixed a few things but clearly not all

sleek thicket
#

just make a small boxed room and a ball with high restitution that you can control with wasd by applying force and a restart button
hold W+A to bounce off and restart. it's mostly deterministic but not always taking the same route.

zinc talon
#

Do we have determinism on the same machine/architecture/build config at least?

vestal minnow
#

"The desire to determine indeterminism fills you with determination"

vestal minnow
sleek thicket
#

rapier is a harder case to fix yourself because it's just a wrapper though

zinc talon
#

tbh I'm not that interested in using rapier, it's not bevy*-y* enough

vestal minnow
#

rapier is deterministic, bevy_rapier isn't

sleek thicket
#

replacing parry might fix it accidentally btw

#

you never know.

zinc talon
#

I'd much rather help xpbd get to a better place

sleek thicket
#

you're filled with determination to help xpbd โœจ

zinc talon
#

It's a much better API imo

sleek thicket
#

it's probably not easy making a wrapper though

zinc talon
#

true

#

Well someone grab me a razor. I've got a yak to shave

sleek thicket
#

you know enough about physics engines or should i link you to how it started?

zinc talon
#

I wrote one when I was in high school haha

vestal minnow
#

For repros

  • Run Johan's bevy_gaff with simulated lag or delay to see desyncs quicker
  • Just make an example where you can see different outcomes clearly. The existing custom_collider example shows this decently, as different runs can have different results
zinc talon
#

So I know enough basic concepts and I've kept my math up to scratch

sleek thicket
#

xpbd is a bit different though

zinc talon
#

So I'll probably be able to start off alright, but I'll be back here when I inevitably run into problems

vestal minnow
zinc talon
sleek thicket
#
Johan Helsing Studio

In a sudden and ambitious outburst of not-invented-here syndrome combined with hype-train, I decided there weren't enough physics engines out there and it would be a good idea to write one myself using all the latest buzzwords. In this tutorial series, I'll explain step-by-step how to build an extended position-based dynamics (XPBD) rigid-body p...

#

yeah i found it anyway

zinc talon
#

Yup that one

#

Saved me a search

vestal minnow
zinc talon
#

Yeah, I've seen that one. Super cool, kinda broke my brain the first time through

#

My engine from a few years ago was bog-standard dynamics

sleek thicket
#

oh yeah, now that bevy has basic collision checks, wouldn't it be possible to rewrite xpbd from scratch with just that to make sure it's deterministic at least when it's that simple?

#

cocporn's buggy stuff was using only 2d squares and circles so i think it should be easier to test if it's just that

zinc talon
#

๐Ÿค” is peck not in yet? xpbd's still on parry?

sleek thicket
#

in the process, there's also barry

zinc talon
#

What's barry?

vestal minnow
# zinc talon So I'll probably be able to start off alright, but I'll be back here when I inev...

For determinism specifically, the main things to look out for are

  • Make sure nothing that affects the core simulation is order-dependent
  • Use libm for "transcendental operations" like sin/cos/tan, otherwise different platforms get different results because of intrinsics
    • 2D rotation currently has one sine (that I'm aware of) that should be fixed to use libm iirc; this is only needed for cross-platform determinism though
  • Make sure scheduling has no ambiguities that could cause issues (the physics schedules already disallow ambiguities, although there are a few overrides)
    One thing to check could be to make sure that the delta time for the first few frames is expected, and doesn't use a variable time for any reason
sleek thicket
#

parry moved from nalgebra to glam/bevy math

#

input + normalization + delta might also affect it

vestal minnow
#

I'm probably prioritizing bevy_peck though

sleek thicket
#

what's the ideal goal btw, using bevy collision detection or having everything of your own with peck?

vestal minnow
#

Build up features for peck and incrementally upstream them to Bevy (to the extent possible)

zinc talon
#

I mean I get the feeling that most/all of xpbd will be upstreamed eventually

sleek thicket
#

most likely

zinc talon
#

I'd be surprised if this crate didn't end up as the de facto bevy physics solution

vestal minnow
#

probably not with the XPBD solver but maybe

sleek thicket
#

i'm just not sure if the current bevy collision detection is good enough for testing

vestal minnow
#

no contact data

zinc talon
vestal minnow
sleek thicket
#

xpbd license isn't 100% clear on whether it's open to upstream, but there's a potentially good replacement just in case

#

i kinda want xpbd to work out because fluid/cloth sim feels like it'd fit right in with theme of bevy

vestal minnow
zinc talon
#

I'm actually in the middle of that blog post, I guess I haven't gotten that far haha

sleek thicket
#

i agree too, having xpbd as "feel free to use it but we're not responsible for license" crate, and upstreamed optional but reliable alternative to switch to in case there's a problem is just the best solution

vestal minnow
#

yeah imo the ideal goal is to have the solver swappable and have the XPBD solver as a third-party plugin (at least unless we get an official blessing to use it)

sleek thicket
#

or let whoever uses it acquire the blessing :>

#

is it possible to ship the game with one but allow modding in the other?

#

that would cover all of the problems with 0 responsibility

vestal minnow
#

yeah maybe, if Bevy gets good enough modding support

sleek thicket
#

i mean you know how modders "fixed" watch dogs to be similar to E3 demo at some point?

vestal minnow
#

yeah I was like 9 when that video dropped so I didn't even know about watch dogs ๐Ÿ˜‚

sleek thicket
#

thanks for making me feel old af ๐Ÿ‘

vestal minnow
#

mb lol

sleek thicket
#

the biggest problem wasn't even that graphics downgrade though, the entire game felt like a downgrade.. but that's off-topic

#

modding is a nice loophole for everything

vestal minnow
sleek thicket
#

or let @zinc talon work on tests and debugging

#

the main point is that a side-project that fully focuses on determinism (at the cost of less features) would make it easier for the main crate

vestal minnow
#

Johan's own version of bevy_xpbd is/was at least locally deterministic iirc

#

it's a stripped down version

sleek thicket
#

bevy_xpbd_lite

#

bevy_xpbd_heavy? :>

#

a feature flag is probably better though

#

deterministic core and opt-out the rest

vestal minnow
#

But yeah a stripped down version of bevy_xpbd for investigating determinism should be pretty quick to make

#

Just copy the core stuff from the integrator, broad phase, narrow phase, solver, scheduling, and yeet everything else

sleek thicket
#

writing a step-by-step manual (as a continuation of johan's blog) along the way would be really great for getting more people to work on it too, but i think you already have enough stuff to deal with
there's also a bunch of stuff in blog that needs editing to get it up to date with bevy changes... and now there's also the stuff with transform2d and potentially separating scale...

zinc talon
#

I just got distracted watching that Erin Catto vid, it's incredible

#

TGS soft is the mvp

sleek thicket
#

yep, that's the fallback

#

xpbd is supposed to be better for liquid/cloth sim in combination with the usual, not sure what the reason is though

#

most of the xpbd problems aren't an issue for my game, but those 2 would be a really cool feature

vestal minnow
#

not entirely sure why position-based fluids and cloth are often considered better or how backed up that claim is though

#

also the XPBD impl in Solver2D wasn't optimal and had some issues so the stability can definitely be better, he has fixed some friction issues already and others have implemented things like block solvers and solving x/y/z separately for joints to improve stability

sleek thicket
#

for usual games accurate physics aren't really required, most of the stress-test scenarios should never happen to player (or anything at all actually),
and the floating sphere seems to be a clear winner for gameplay+IK over the sliding capsule, so that isn't an issue either...
so instead of accuracy, performance + interesting features are more important

on the other hand there are the deterministic games that don't need anything other than that, but they don't care about liquid/cloth accuracy if they have it at all

#

either way it's worth making both versions with only primitive colliders but with liquid and cloth for benchmarking

#

and i really want this kind of thing to be more common in games https://youtu.be/JxG5vJuS34s

This is just a quick non-commentary capture test I made of getting From Dust to run in 4K. I even managed to get sharper texture rendering using some additional tweaks via Nvidia Control Panel. Sadly the physics engine is locked to 30fps, but otherwise the game looks pretty good for its age.

โ–ถ Play video
#

it's just a 2d water sim though, i'm not even sure if physics are actually needed there

open helm
#

does anyone have experience using heightfield colliders in xpbd? I'm having some issues ๐Ÿ˜…

hexed veldt
#

qq: if i set an rigid entity's visibility to hidden, then would that disable/pause the collision detection on it?

hexed veldt
#

ok, looks like using CollisionLayers to disable the collision is the right way to go

open helm
cinder summit
cinder summit
open helm
cinder summit
#

I think it should work the exact same as the parry function, except it takes a different input, then turns that into the type parry expects

open helm
#

yeah that's what i was hoping to be able to work out, but the parry library takes a Vector<Real> and xpdb takes an f32. neither of the values I used in the parry vector worked as that xpbd f32 value

cinder summit
#

Real is just f32 or f64 depending on if you use the f32 of f64, same thing for xpbd's Vec<Scalar>

open helm
#

oh sorry yeah, i guess I just meant parry's scale param is really two values in a Vector, and xpbd's scale param is just one value

cinder summit
#

You can think of xpbd's scale like a cube that contains the heightfield

#

Then the heightfield values are for the relative height

open helm
#

ack I didn't mention I'm trying to work with a 2d heightfield if that changes things

cinder summit
#

The 2D version is definitely the simpler one ... Should be as simple as a Vec<f32> and a Vec2 ... In this case the scale is a recangle containing the collider

open helm
#

it's the absence of that Vec2 in xpbd heightfield that's causing me the confustion ๐Ÿ˜…

cinder summit
#

Oh

#

Yea this seems a bit weird, it just does Vec2::splat(scale) and passes that along ... Which seems ... Wrong thonk

open helm
#

๐Ÿ˜…

#

agree, I think I'll make an issue

vestal minnow
#

I'm not sure what my thought process for using a float for the scale was... I think I might've gotten confused about what the scale does because of Rapier's docs, which say that it specifically affects the size along the X axis in 2D and XZ in 3D

#

But the actual Rapier/Parry methods do use a vector for the scale, and the docs.rs docs for it are correct

#

No idea why I would've looked at Rapier's website for what the scale should be tho ๐Ÿ˜‚

sleek thicket
#

heightfield is just a mesh or is there something special about it?

vestal minnow
#

Parry handles them a bit differently, probably a bit more efficient

#

Haven't looked into the details yet

sleek thicket
#

if it's optimized for deformable terrain/water sim then it's interesting

#

but from the description it sounds like it just makes a mesh with 0 optimization (e.g. flat areas)

slim ledge
#

If I want the speed of a rigid body in unit/second (m/s), should I simply get the length of the LinearVelocity vector?

vestal minnow
#

Yep

cinder summit
#

Being able to find all triangles that could collide based on the collider's local XZ plane is probably more efficient than whatever mesh does to avoid checking collisions against every triangle

torn hedge
#

what is the reason we're using

pub fn new_unchecked(value: Vec3) -> Self {
    debug_assert!(value.is_normalized());

    Self(value)
}

instead of

pub fn new(value: Vec3) -> Result<Self, InvalidDirectionError> {
    Self::new_and_length(value).map(|(dir, _)| dir)
}

for creating Direction3d?

vestal minnow
#

Using where?

#

The reason is most likely that the direction should already be normalized so we don't want to do unnecessary normalisations

torn hedge
#

for example here:

impl core::ops::Mul<Dir> for Rotation {
    type Output = Dir;

    fn mul(self, direction: Dir) -> Self::Output {
        Dir::new_unchecked(self.rotate(direction.adjust_precision()).f32())
    }
}

as i get a crash here

#

wait, i might be mistaken, actually not sure where exactly the crash comes from

thread 'main' panicked at .cargo\registry\src\index.crates.io-6f17d22bba15001f\bevy_math-0.13.0\src\primitives\dim3.rs:40:9:
assertion failed: value.is_normalized()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_xpbd_3d::plugins::spatial_query::update_shape_caster_positions`!
Encountered a panic in exclusive system `bevy_xpbd_3d::plugins::setup::run_physics_schedule`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!

because in the update_shape_caster_positions i don't see anywhere Direction3d being created...

vestal minnow
#

Yeah it can sometimes panic in debug mode if there's enough numerical error, we should probably make the panic threshold more lenient and/or make sure the rotation remains normalized

torn hedge
#

yes, but i'm currently getting crashes without debug mode!

#

you mean, the debug drawer right

vestal minnow
#

No, building in debug mode

torn hedge
#

ah

#

my bad

#

yea

#

is the assert also triggered when doing something like

let global_direction = global_rotation * shape_caster.direction;

so like, when not caling the new_unchecked?

vestal minnow
#

That rotates the direction which internally uses new_unchecked

torn hedge
#

i see.
so the result could be not normalized, thus causing the crash?

vestal minnow
#

Yeah, it can happen if (1) the rotation is not normalized, or (2) you do a ton of successive rotations, which accumulates numerical error

#

In this case the rotation is most likely not perfectly normalized

torn hedge
#

i see, thanks a lot!

torn hedge
#

I'd love to contribute and help fixing this.
But i'm unsure on how to begin with.

how are we currently normalizing it?
i tried to just check with "is_normalized" but ran into the issue that in 2d feature it's not a quaternion and thus doesn't have this.

vestal minnow
#

It could be related

#

Because I'm pretty sure adding quaternions can result in unnormalized rotations

torn hedge
#

i'll run my game on that pull request, see if it still crashes

#

still crashes

thread 'main' panicked at .cargo\registry\src\index.crates.io-6f17d22bba15001f\bevy_math-0.13.0\src\primitives\dim3.rs:40:9:
assertion failed: value.is_normalized()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_xpbd_3d::plugins::spatial_query::update_shape_caster_positions`!
Encountered a panic in exclusive system `bevy_xpbd_3d::plugins::setup::run_physics_schedule`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
vestal minnow
#

annoyingly I can't repro the crash in my examples, on main or on that PR :P

torn hedge
#

basically, i currently have those cubes jumping towards me.
now i wanted to make sure that they only jump when on ground, so my first instinct was to do the same as i did with the player, add a shape_caster and check if its grounded.
but as soon as i added the shapecaster to the cubes, it started crashing immediatly

#

as the cubes rotate a lot, i suspect that causes some issues?

#

i could try and build a minimal project that reproduces it, if you'd want

vestal minnow
#

I've tried making a cube stack with shape casters fall but it's not crashing :P

torn hedge
#

hm interesting

#

then lemme make one where they jump at you or something lol

vestal minnow
torn hedge
#

hm, let's see if i'll be able to reproduce it

#

ye, could reproduce it

#

but interestingly the cubes aren't even moving yet

#

i mean other than the physics stuff

vestal minnow
#

thanks, I'll test

#

indeed it do be crashing

torn hedge
#

i'm glad it doesn't only happen on my end xD

vestal minnow
#

okay so

#

@torn hedge the issue in that repro seems to be that the ground is clipping the cubes which f's up their rotation
If you move the plane down, it works

    // Spawn ground and generate a collider for the mesh using AsyncCollider
    commands.spawn((
        PbrBundle {
            mesh: meshes.add(Plane3d::default().mesh().size(8.0, 8.0)),
            material: materials.add(Color::rgb(0.3, 0.5, 0.3)),
            // This transform
            transform: Transform::from_xyz(0.0, -2.0, 0.0),
            ..default()
        },
        AsyncCollider(ComputedCollider::TriMesh),
        RigidBody::Static,
    ));
torn hedge
#

I just ate lunch and litteraly got that idea too

#

But that can't be the issue with the original one, so i'll try to repro that again

cinder summit
vestal minnow
#

Rotations are normalized at every substep but before the solver

#

It could be the solver making them unnormalized

#

I don't think there are tons of successive rotations, the update_shape_caster_positions system just rotates the local direction so there's only one rotation

cinder summit
#

Meanwhile the glam code:

    /// Returns whether `self` is length `1.0` or not.
    ///
    /// Uses a precision threshold of `1e-6`.
    #[inline]
    #[must_use]
    pub fn is_normalized(self) -> bool {
        // TODO: do something with epsilon
        math::abs(self.length_squared() - 1.0) <= 1e-4
    }
#

This todo is ... Interesting ๐Ÿ‘€

vestal minnow
#

We could also change the panic to a warning

#

Doesn't fix it, but at least makes things usable

#

And you still see that it has issues

cinder summit
#

We could make our own check that warns when it's just a bit unnormalized, and panics when it gets so extreme normal behavior can't be expected ๐Ÿค”

vestal minnow
#

yep

#

I think @sleek thicket suggested that

#

and also have the length in the error message

cinder summit
#

Wait ... Checking length_squared against 1e-4 is a threshold of 1e-8 right? thonk

vestal minnow
#

maybe? I need to do the math on that

torn hedge
#

i made the ground bigger, preventing the cubes from falling down. now it doesnt crash

#

hm, it still crashes when i make the cubes fall from higher up

#

maybe because they jump around more thus more rotation happens?

#

try changing the transform of the floor to -5.0 or more, it crashes immediatly once the cubes touch the ground for me

vestal minnow
#

just putting this in a calculator

length = 1 + 10^(-6)
length^2 = 1.000002000001
cinder summit
#

Ah yea, when we consider the total number the value changes ... But then the margin for is_normalized is actually huge right now thonk

#

Tho the implementations might vary too

vestal minnow
#

Used some beautiful LaTeX there

vestal minnow
#

(but that's still slightly wrong)

#

okay, hmm

cinder summit
#

So it differs per implementation? What is this? thonk

vestal minnow
#

or was it "fixed" on main? (but still wrong)

torn hedge
vestal minnow
#

I'll probably make a PR to add the normalization

torn hedge
#

awesome, thank you!

vestal minnow
vestal minnow
#

nice, I'll merge :)

torn hedge
#

awesome!

quick saffron
#

Sorry for the necrobump ๐Ÿ˜… just wanted to voice that I'm in favor of a single component for linear & angular velocities (& same thing for external forces). It's common to think of them as a single thing (e.g. screw theory)

sleek thicket
quick saffron
sleek thicket
#

yeah, i never touched externalforce either, what does it actually do that isn't covered by linear/angular velocity?

#

apply constant force?

vestal minnow
#

takes mass into account (because it's a force) and causes acceleration (because it's a force)

#

and yeah you can apply a constant force if you want to

sleek thicket
#

unity has rigidbody.addforce(value, mode) that coveres it, seems like a more elegant solution than a separate component

vestal minnow
#

yeah but you can't take mass or time into account there

sleek thicket
#

mode does that

vestal minnow
#

unless you use a custom worldquery

#

you can't just access RigidBody and apply forces, you'd need access to several components

#

and the time resource

quick saffron
sleek thicket
#

you could make functions that take them as parameters though

vestal minnow
#

those functions would need access to the ECS world

#

or a function on which component/type?

#

also it wouldn't work because of substepping

#

forces are applied over substeps

#

and not just by instantly changing the velocity by some amount

sleek thicket
#

so, what do you have to do if you need to apply force just once? (e.g. punch)

#

attach component to target?

vestal minnow
vestal minnow
#

Using .with_persistence(false)

#

Or use impulses

sleek thicket
#

it makes sense how it works but adding it as a component feels weird to me

#

and couldn't you change from bool to int and just reduce by 1 every time it's applied, and remove at 0?

quick saffron
vestal minnow
#

oh yeah it is

#

lmao

#

brain malfunctioned

sleek thicket
#

whatever you do when persistence is false

vestal minnow
#

If persistence is false, it just means that the external force gets reset to 0 once it has been applied during integration

#

so you can apply many forces, but they only count for that frame

sleek thicket
#

and with persistence true it just never gets reset?

#

so e.g. a rocket?

vestal minnow
#

yeah it's a constant force, but you can of course set or reset it yourself

#

like you could have some gravity field or something

sleek thicket
#

but if there are multiple then how would you know which one to change

vestal minnow
#

there's just one force property, the total external force

#

i.e. the sum of all the forces you've applied

sleek thicket
#

do you just reduce it by the same amount when exiting gravity field?

vestal minnow
#

you could do that yeah

sleek thicket
#

i think i'm just stuck in unity mode in that regard, thinking about forcefield as the thing responsible for applying force to others over the duration

vestal minnow
#

another approach would be to have .with_persistence(false) and make each gravity field apply a force every frame to bodies inside of them

#

kinda like what you described

sleek thicket
#

so it's like half of unity's rigidbody.addforce, without the 2 modes that change velocity

#
ForceMode.Force: Interprets the input as force (measured in Newtons), and changes the velocity by the value of force * DT / mass. The effect depends on the simulation step length and the mass of the body.
ForceMode.Impulse: Interprets the parameter as an impulse (measured in Newtons per second), and changes the velocity by the value of force / mass. The effect depends on the mass of the body but doesn't depend on the simulation step length.

ForceMode.Acceleration: Interprets the parameter as acceleration (measured in meters per second squared), and changes the velocity by the value of force * DT. The effect depends on the simulation step length but doesn't depend on the mass of the body.
ForceMode.VelocityChange: Interprets the parameter as a direct velocity change (measured in meters per second), and changes the velocity by the value of force. The effect doesn't depend on the mass of the body or the simulation step length.

force is externalforce with persistence
impulse is externalforce without persistence

acceleration is velocity += value * delta
velocitychange is velocity += value

vestal minnow
#

yeah you can do impulses and change velocity too of course, but with different components

#

we could technically have a single Force component with a ForceMode enum too

#

but that'd limit the component to only that force mode

#

and again, the components themselves don't have access to mass or the delta time, so we can't just make force.apply_force(...) instantly change velocity, unless we make people give them to it as arguments

#

which wouldn't be ideal

sleek thicket
#

yeah

#

if i think about externalforce same as unity's rigidbody it makes sense, just that why not everything in one place then

vestal minnow
#

Unity can probably access delta time inside the method since your code is running in the context of Update or FixedUpdate, and the rigid body iirc is just a big object so the properties are all accessible

#

(idk about DOTS physics tho)

sleek thicket
#

yeah unity has 0 concerns for safety so it does whatever it wants

#

you could probably cache delta before processing all forces though

vestal minnow
#

Technically, we could also apply forces with commands, but then you'd need to give the Entity every time

sleek thicket
#

isn't delta always the same in fixedupdate anyway

vestal minnow
#

You can configure it but yeah it's the same every frame typically

sleek thicket
#

i think that's kinda what unity does since it always recommends putting continuous physics-related stuff into fixedupdate

#

i always thought it's because of framerate-independence though

frail robin
#

Is it possible to get vertices and indices back to modify the collider?

vestal minnow
frail robin
vestal minnow
#

Yep

#

Collider contains a SharedShape which is an Arc with a dynamic shape, and you can't get a mutable reference to the contents afaik

frail robin
#

Got it.
I saw that you are working on bevy_peck. Will it be possible with the new collision library?

#

Or the new collision library will be very close to parry for easier maintenance?

vestal minnow
frail robin
#

Sure, I know that it's parry-specific.

vestal minnow
# frail robin Got it. I saw that you are working on `bevy_peck`. Will it be possible with the ...

I haven't decided on how colliders will be represented yet. I believe the point of SharedShape is that you could share the same shape for a bunch of colliders, which would reduce memory usage. One thing I want to try is to just make colliders enums (like Parry's TypedShape) and store them as standard Bevy assets. The main question there is whether getting the colliders in collision detection systems would have more overhead

frail robin
#

Makes sense.
Colliders as assets sounds interesting!

vestal minnow
#

Yeah API-wise you'd just do e.g. colliders.add(Cuboid::default()), which is pretty nice. I've also been wanting to do convex decomposition for static colliders as an asset preprocessing step since it can take so long at runtime

frail robin
#

That would be so great!

vestal minnow
#

Again, the main issue is the potential cost of having to get the collider assets like colliders.get(collider_handle) every time, but we'll just have to benchmark

frail robin
#

Colliders as assets will also unlock the mentioned workflow of changing colliders dynamically without reallocation.
Right now I edit meshes, but create a new collider each time.

vestal minnow
#

Yep

#

Definitely something I'll test

little maple
merry gulch
#

How can I apply a force to an object so it will be pulled to a point? I wanna make a kind of gravity for my objects. They are follows the cursor, I move them using LinearVelocity such that: linear_velocity.0 = parent_transform.translation().xy(); where linear_velocity is the velocity of the object and parent_transform is the position where object should be moved. It doesnt work really well because object goes in the same direction and wont stop. That's why I wanna add a force that will pull all objects to the target position

#

btw I tried this: force.apply_force(parent_transform.translation().xy()) and it made no change

vestal minnow
sleek thicket
#

do you need mass?

#

because this sounds like a case where you do

vestal minnow
#

if you just use parent_transform.translation() and e.g. its y coordinate was positive, it'd always apply a force upwards regardless of the position of the object

merry gulch
#

thanks looks like it works, but how can I make it "stronger"?

sleek thicket
#

multiply it

vestal minnow
#

it's just a vector so you can multiply by a number

#

If you don't want the distance between the objects to affect the strength of the force, you can also "normalize" the direction to make its length 1, and then you can specify the strength by multiplying the force direction

let direction =
    (parent_transform.translation() - object_transform.translation()).xy().normalize();
force.apply_force(strength * direction);
sleek thicket
#

adding this kind of grabbing with gravity would be nice in move-marbles example

vestal minnow
#

mm could be fun

sleek thicket
#

LMB for LV, RMB for force
and "randomize" the mass, changing color based on it

wraith aspen
#

How do I make an entity not be able to collide with a different entity?

wraith aspen
cinder summit
#

I think the only option there would be making a component that removes contacts with that specific entity, probably not worth the effort to actually make a generic solution for that tho ๐Ÿค”

sleek thicket
#

there might be a better way to do it but we don't know enough about the intention

wraith aspen
cinder summit
#

You could just make the collision behavior exclude the player (and probably all the player's allies, if there are any) ... Tho I generally wouldn't recommend spawning projectiles as colliders, since they'll just end up tunneling trough basically everything

little maple
#

I'm running into this "tripping" behavior where my colliders with dynamic bodies seem to trip over relatively flat edges. Is there something specific causing this or is it literally the collider encountering an edge? Is there a way to reduce the effects of this?

cinder summit
wraith aspen
cinder summit
#

If you spawn an entity that moves forward by however far the raycast went, with velocity * delta as max distance it would be a projectile

wraith aspen
#

oh

#

why is that better than colliders?

cinder summit
#

Because you don't need to mess with things like CCD (which xpbd also doesn't have iirc) and it tends to perform better because you bypass a lot of steps

#

In godot there's this funny thing where making a projectile system that doesn't spawn things with colliders but instead just handles it with raycasts you can do about 10x as many projectiles :')

#

I'd imagine it would be less extreme with xpbd tho

wraith aspen
#

i dont see where the performance gain is

cinder summit
#

There's a few I can think of with xpbd, mostly that raycasts/shapecasts could be done once per frame instead of per substep, and looking something up in the BVH is more efficient than adding a bunch of extra colliders to the broad and narrow phase

wraith aspen
#

BVH?

cinder summit
#

Bounding Volume Hierarchy, it's what the spatial queries use to find things in the world

wraith aspen
#

wait, if i use the raycasts, doesn't that mean 2 projectiles can't collide with each other?

cinder summit
#

Yea, if you do need them to collide you'd definitely need them to be regular physics objects, in which case adding such exceptions to your collision logic is the way to go

wraith aspen
#

alright

cinder summit
#

I've also seen some games do both, the projectiles that can collide being fairly slow so they don't have any issues with tunneling, and the faster ones can collide with those, but not other fast projectiles

sleek thicket
merry gulch
#

I wanna make my object rotate around another. That's what i'm doing now:

let direction = (parent_transform.translation() - transform.translation)
                .xy()
                .normalize();
linear_velocity.0 = direction.perp() * 100.0;

And it works, in some way. I also wanna pull all the object so they will be rotating on the same radius. How can I do this?

sleek thicket
merry gulch
edgy nacelle
#

Hi everyone! New to bevy & this crate -- what's the canonical way to have buttons to pause the physics and step a frame at a time?

vestal minnow
# edgy nacelle Hi everyone! New to bevy & this crate -- what's the canonical way to have button...

You can pause/resume and advance physics using the Time<Physics> resource, with e.g. a system like this:

fn control_physics_time(mut time: ResMut<Time<Physics>>, keys: Res<ButtonInput<KeyCode>>) {
    if keys.just_pressed(KeyCode::KeyP) {
        time.pause();
    }
    if keys.just_pressed(KeyCode::KeyR) {
        time.unpause();
    }
    // Step one frame (60 Hz)
    if keys.just_pressed(KeyCode::Enter) {
        time.advance_by(Duration::from_secs_f64(1.0 / 60.0));
    }
}
#

You can also make a toggle for pause/unpause by checking time.is_paused()

little maple
edgy nacelle
#

That's much simpler than I expected! Thank you ๐Ÿ™

vestal minnow
#

looks like it

little maple
#

yeah, the ground is trimesh and the trucks are convex hull ๐Ÿค”

vestal minnow
#

I'm guessing it's an "internal edge" problem where it thinks it's hitting the side of a triangle in the ground... It feels more like a Parry issue than a physics issue, although I'm pretty sure Parry has some internal edge fixer thing

#

I vaguely recall seeing someone having a similar issue with a conveyor belt in rapier

little maple
#

it makes some sense it's like.. hitting an edge

vestal minnow
#

And I've also seen this in other engines fwiw

#

(like Godot iirc, could be misremembering though)

#

One thing that could help is having the edges of the vehicles rounded

#

It would maybe also be possible to filter collisions based on some criteria, like if the contact point is at the bottom of the truck but the contact normal is pointing in some weird direction, ignore the contact

#

That doesn't feel very robust tho

vestal minnow
little maple
#

ah, I do recall there being an offset thing in the character controller in rapier. It does seem like a general problem.. I really just wanted to see if I was doing something really incorrect or not. Gonna try beveling the edges of the collider a bit to see if that helps. Thanks @vestal minnow (and good luck with the rebrand ๐Ÿ‘)

edgy nacelle
#

@little maple I don't know if this is the cause of what you're seeing, but the symptoms look similar, so maybe it helps: https://box2d.org/posts/2020/06/ghost-collisions/

little maple
sleek thicket
#

switching to raycast worked

little maple
sleek thicket
#

i have a hovering sphere controller that switches gravity to match ground normals

#

and it was really easy to notice that every edge was fucking everything up

#

even if it was center of a flat plane

little maple
sleek thicket
#

yep

little maple
edgy nacelle
#

When a RigidBody's Transform component has a scale that is not 1, does xpbd also scale the Collider (and thus the mass, if ColliderDensity was given)? Do any other components also get scaled?

sleek thicket
deep ingot
#

when raycasting, what's the ideal way to skip hidden entities? add my own logic/visibility-query based on RayHitData?

slim ledge
#

Please correct me if I'm wrong; since the linear and angular velocities are expressed in world space, if I want to get the point velocity of the child of a parent, I must use its GlobalTransform:

let point_velocity = parent_linvel.0 + parent_angvel.0.cross(child_global_transform.translation());
deep ingot
#

are the ColliderAabb coordinates (min & max) local or global?

merry gulch
# sleek thicket https://www.youtube.com/watch?v=CdPYlj5uZeI https://www.youtube.com/watch?v=bFOA...

Watched this videos. I did this, but looks like it works in the wrong way. Objects starts accelerating, but they shouldn't.

fn particle_movement(
    cursors: Query<&GlobalTransform, With<Cursor>>,
    mut particles: Query<(
        &LinearVelocity,
        &mut ExternalForce,
        &Transform,
        &CursorParticle,
    )>,
) {
    for (linear_velocity, mut force, transform, particle) in particles.iter_mut() {
        if let Ok(parent_transform) = cursors.get(particle.parent) {
            let vel = linear_velocity.0;
            let direction = (parent_transform.translation() - transform.translation)
                .xy()
                .normalize();

            let other_vel = Vec2::ZERO;

            let dir_vel = direction.dot(vel);
            let other_dir_vel = direction.dot(other_vel);

            let rel_vel = dir_vel - other_dir_vel;
            let x = transform
                .translation
                .xy()
                .distance(parent_transform.translation().xy());

            let spring_force = (x * 10.0) - (rel_vel * 10.0);

            force.apply_force(direction * spring_force);
        }
    }
}
#

removed it, now they are instantly going to infinity

#

Am I missing something?

merry gulch
#

thank you for helping me, now everything works almost as expected

merry gulch
#

hell no

little maple
#

might be a long shot but is there an equivalent to Unity's GetPointVelocity to get the velocity of a specific point on a rigid body?

slim ledge
surreal dock
#

I think I've stumbled on a case where CollidingEntities is left with dead entries when a collider is removed immediately after a collision is reported

#

not the Collisions resource though

surreal dock
#

I believe I've found the cause

#

contact_reporting::report_contacts only sends CollisionEnded events and changes CollidingEntities if the contacts' during_previous_frame flag is true, but it's never set to true if one of the colliders is removed in the frame after the collision starts

little maple
sleek thicket
little maple
sleek thicket
#

a hovercar represents the whole thing much better

little maple
sleek thicket
abstract tendon
sleek thicket
#

that's literally what suspension does

#

except instead of water it's gel

abstract tendon
#

lmao its cool

abstract tendon
#

that is some nice information

#

i like it

#

thank you

deep ingot
#

anyone know of a collider-aware way to compute shortest paths?

sleek thicket
#

but considering how fast stuff changes i'm not sure if there's a good one that just works

deep ingot
sleek thicket
#

it's definitely possible, just not sure if we have it ๐Ÿคทโ€โ™‚๏ธ

#

actually seems like we do

#

with last update literally 3 hours ago

deep ingot
#

nice ty! will look into this

dusty knot
#

Sometimes this community is awesome

deep ingot
# sleek thicket https://github.com/vleue/vleue_navigator

It needs a 2d mesh as input. I'm wondering if I can get one by intersecting a plane with the rest of my scene at some height (with the assumption that all navigation happens in that plane) then using the ContactManifolds to populate the 2d mesh. Does that sound reasonable?

sleek thicket
#

i'm used to unity baking navmesh for me ๐Ÿ˜…

deep ingot
trail sparrow
sleek thicket
#

looks 3d, i never tried it

trail sparrow
#

Yeah but if 3D then the paths would just go over the obstacles?

sleek thicket
#

try it and see?

trail sparrow
#

I think the documentation probably makes it clear enough. Looks like it expects a navmesh as input

deep ingot
sleek thicket
#

nope but i'm interested too @edgy light

edgy light
#

it's not on main because I use dependencies that have not been released yet with some bug fixes, and they don't seem very active... I'll probably end up releasing my forks

#

3d doesn't actually matter in most cases for a navmesh, unless you want to use the slope as a cost function, or there are overlapping zones

#

otherwise you can project as a 2d navmesh, if the slope is too steep it's an obstacle, then find your path in 2d space and then re-add the height based on your actual 3d space when moving

sleek thicket
#

overlapping zones like bridges?

edgy light
#

bridge where the same unit can go over and under

sleek thicket
#

yeah, if that's an issue then it's pretty much 2d though

little maple
#

if I have a rigid body representing a car... what should I set its mass to?

deep ingot
trail sparrow
deep ingot
#

hmm, there's something i don't get. if i do a projection (basically drop the y-component, i guess?) wouldn't that cause things that are above or below the agent to act as obstacles even though they shouldn't?

trail sparrow
#

Yeah, but an intersection will just be across a single plane? If you have a 3D surface then youโ€™d have to find a single plane that cuts all your obstacles

deep ingot
#

yeah i'm thinking of getting the y-coordinate of the center of the npc collider and using that as the y-value of my nav plane

trail sparrow
#

If your level is โ€œflatโ€ then that would probably work

deep ingot
#

yeah, it's flat, but as the agent moves up and down so would the nav plane. slopes will be challenging though

#

so will "jumping over" stuff

#

it's fine in my case though

trail sparrow
#

Yeah, so in the general case Iโ€™d think youโ€™d cull the floor and ceiling, maybe by looking at the normal and use a projection

sleek thicket
#

@carmine sluice i think francois' nav deserves a thread in crate-help ๐Ÿ‘€

vestal minnow
#

It's up to the crate author (@edgy light in this case) if they want a #1034543904478998539 thread or not

#

Also I'm pretty sure Franรงois can make threads there too since he's a maintainer and moderator

#

But yeah a thread could be useful of course if he wants one for it :)

sleek thicket
#

or at least separate #game-ai as in behaviour and navigation from AI as in ML ๐Ÿคทโ€โ™‚๏ธ

vestal minnow
#

Yeah maybe, although I'm not exactly sure what the names should be, and people might confuse them either way... That's off-topic for a bevy_xpbd thread tho

sleek thicket
#

i'll just delete my messages later ๐Ÿ‘

#

nav discussion in xpbd seems off-topic too though

#

although they're both involved

vestal minnow
#

if it's related to an xpbd integration then that's fine, but if it's completely separate then that's probably a bit off-topic

cinder summit
#

Hmmm ... How bad would it be if I repeatedly applied 50% of the difference between current velocity (on the XZ plane) and desired velocity while there is a wall with 0 friction in front of that object? thonk

sleek thicket
#

it sounds like a normal thing to do though

cinder summit
#

Cause looking at this code this seems extremely sus and might just be the reason why the dash I implemented in the character controller makes things the player fly in weird direction (especially up, if anything changes any of the velocity upward)

sleek thicket
#

why would it be any different from applying full velocity though

cinder summit
#

Applying full velocity would be even worse here ๐Ÿ˜‚

sleek thicket
#

actually yeah, my dash just sets velocity so if there's a problem i wouldn't notice it

vestal minnow
#

Maybe you could limit the y-velocity for the duration of the dash? Or something similar

#

although that seems kinda hacky, idk

sleek thicket
#

and even though my movement adds velocity, i have a spring that would mean i wouldn't notice it ๐Ÿค”

cinder summit
#

Setting the velocity or resetting the Y velocity to whatever it was when it started might actually be the reasonable thing to do while adding forces ๐Ÿค”

#

And here I was thinking this was a mystery SDF or XPBD bug thonk

#

I also probably don't need to keep accelerating for 9 ticks when it lerps 50% of the way between current and desired every tick ๐Ÿ˜‚

#

Wait it's even worse it's 2/3 of the way for 1 tick, then 1/3rd for 9 more ticks

sleek thicket
little maple
# slim ledge ```rust fn get_point_velocity(linear_velocity: Vec3, angular_velocity: Vec3, poi...

I used this and stuff was working pretty OK and then everything would go wild..

I was looking for getting the velocity of a point on a rigid body that isn't the center of the rigid body.. I tweaked this to subtract the origin of the rigid body from the point, effectively this

fn get_point_velocity(linear_velocity: Vec3, angular_velocity: Vec3, point: Vec3, origin: Vec3) -> Vec3 {
    linear_velocity + angular_velocity.cross(point - origin)
}

and now everything is way more stable

#

it does make me wonder from like.. a Bevy ECS perspective.. where would be the best place for a function like that to "live"... in Unity it's just a function on the rigid body... but here we'd need values from 4 different components. It's admittedly a bit off topic for this channel..

cinder summit
#

I mean you only really need a function to convert an angular velocity and a local point into linear velocity, the other part is simple ๐Ÿค”

sleek thicket
little maple
sleek thicket
#

i think just using that formula directly might be the best way

little maple
#

yeah

sleek thicket
#

it's short enough to just not need an abstraction

cinder summit
#

If it was a more complex formula maybe custom query types or systemparams would make sense ๐Ÿค”

little maple
#

yeah, I have just inlined it.. but it just makes me wonder

sleek thicket
#

functions just don't feel as comfortable to use as in unity, and i'm not entirely sure it's a bad thing

little maple
edgy light
blazing sluice
#

RigidBody is Reflect, Collider is not. Is this by design?

vestal minnow
# blazing sluice RigidBody is Reflect, Collider is not. Is this by design?

I don't think we can nicely Reflect colliders yet because the underlying shape type SharedShape doesn't implement Reflect and we don't own the type (it's from Parry) so we can't conveniently implement it ourselves afaik. There might also be issues since it's an Arc<dyn Shape>, not 100% sure if that can even be reflected? (I assume probably yes?)
Before Bevy 0.13, another blocker was that reflection didn't support self-referential types, which is required for compound colliders, but I think at least that should now be supported.

#

I'm slowly working on my own collision detection library in the background though and that should support reflection

blazing sluice
#

I see, thanks. fyi my use case is putting physics objects into DynamicScenes

glad abyss
#

a wrapper struct is usually an easy way to "convert a type you dont own into a type you do own, so you can impl traits on it" ๐Ÿ˜„

vestal minnow
# glad abyss can it not be newtyped?

We do own the actual Collider component which wraps SharedShape, but to derive Reflect for it, the properties need to implement TypePath (and Reflect itself I believe)

#

And newtyping SharedShape and trying to derive TypePath for it also doesn't seem to work, idk if some manual implementation would be possible though

cinder summit
#

TypePath would be easy to implement manually I'd imagine ๐Ÿค”

vestal minnow
#

or TypePath itself does work but the compiler screams about other missing traits if I add it

#

I have also tried adding #[reflect(from_reflect = false)] and other similar clauses, but they don't fix all of the issues

#

(also I know very little about reflection stuff so I'm just arbitrarily testing things)

glad abyss
vestal minnow
#

yeah that could maybe be possible, but I haven't worked enough with reflection to know what it needs

cinder summit
#

Speaking of reflect ... Why do types not register ReflectSerialize/ReflectDeserialize when the serialize feature is enabled?

#

Also yes, I'm experimenting with reflect ... And yes it's really cursed ...
After manually registering some ReflectDeserializes myself I can load a collider with some properties correctly from a file like this (I mean it works without the deserialize too but it makes logging noisy because they're all dynamic values)

{
    "terrain::Object": (),
    "sdf_peck::SdfCollider": ((shapes: [Sphere(Sphere(radius: 0.3))], operations: [])),
    "bevy_xpbd_3d::components::layers::CollisionLayers": (memberships: (2), filters: (4294967295)),
    "bevy_xpbd_3d::components::mass_properties::ColliderDensity": (10.),
    "bevy_xpbd_3d::components::RigidBody": Dynamic,
    "bevy_xpbd_3d::components::Friction": (
        dynamic_coefficient: 0.5,
        static_coefficient: 0.5,
        combine_rule: Max,
    )
}
vestal minnow
#

Could definitely be added tho

cinder summit
vestal minnow
#

I'm pretty sure xpbd types also don't have any #[reflect(Component)] or #[reflect(Resource)] ๐Ÿ‘€

cinder summit
#

They do have #[reflect(Component)]

#

The only reason Serialize/Deserialize aren't in there is because serialize is a feature ...
This seems to be the standard on most components in xpbd:

#[derive(...)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[reflect(Component)]
vestal minnow
vestal minnow
cinder summit
#

I feel like this is a bit of an extreme amount of force for a bit of overlap from increasing the size of spheres (It's also with restitution 1 and friction 0 tho) ๐Ÿ˜‚

ionic gale
#

Would this be good for making a basic 3d platformer?

carmine sluice
next rose
#

Enums that derive PhysicsLayer are just convenient way to use bitmasks, so if I have two enums that derive this trait, they will overlap?
Like, one enum for actual physics stuff, and other one is for hitboxes

cinder summit
#

Yea they would overlap, splitting them up doesn't bring you anything besides confusion in this case

cinder summit
#

@vestal minnow After fixing some SDF collision issues and extremely high float forces my character controller no longer explodes ... But when I dash into one of those corners where two arcs meet (the border around the spheres in the video above), I somehow still go over them ... Is this related to what you described some time ago about XPBD behaving weirdly here and needing sequential impulses to fix it? ๐Ÿค”

vestal minnow
#

Also do you have one or more contact points? If it's just one, then I don't think the solver kind (Gauss-Seidel vs. Jacobi) would make a real difference in this case

#

since it doesn't matter if you accumulate corrections or apply them individually if there's only one constraint (per collision)

cinder summit
#

Also it might be less that it pushes it up and more that it gets pushed in, which would cause it to get pushed up because that's how the normals work out then

brisk shale
#

gonna post this here too:
hmm...
does anyone else have a strange issue with xpbd where when their collider drops down from a ledge, they sorta get pulled as if they're colliding with the collider they're dropping down from?
i dont have it when i use a capsule instead of a cylinder, but i prefer the way the cylinder feels

brisk shale
#

here's my repo

vestal minnow
#

I can try your repo though

brisk shale
#

tyy

vestal minnow
#

What's sark_grids? It seems to be a local dep

brisk shale
#

ah

#

im not sure if im actually using it, hold on

#

uh
i forked it because it didnt have reflect on its grids
but like,

#

im not sure if using the fork is necessary in this project? i kinda copied a lot of stuff over from my other project to have a baseline to work off of

#

yeah i think you can comment/delete the dep and then remove the "use" from map.rs

vestal minnow
#

yup I'll do that

vestal minnow
#

@brisk shale Sorry I had a convo going on at #math-dev at the same time so this took a while. Tested it now though and yeah, I see the "pulling".

My initial guess would be that the player is essentially hitting the sides of adjacent blocks. They're individual cuboid colliders and not combined into larger flat surfaces (kinda like "greedy meshing"), and because of numeric issues / solver reasons the player can be slightly "inside" the ground, which makes it register hits against the sides of blocks. For a capsule collider it's not really noticeable because it's rounded and not an abrupt bump into an edge.

This is just a relatively common physics engine issue because of the way collisions are typically handled, and for example rapier has it too (see #1142165587620007976 message). I've also seen it in Godot.

A few potential solutions I can come up with, if this is in fact the issue:

  • Use a capsule :(
  • Make a "floating character controller" where the player is kept slightly above the ground to avoid bumping into unwanted edges.
  • Implement some collider merging system similar to greedy meshing. Probably quite complex and might still have issues.
  • Maybe use trimesh colliders? I think this would still need some merging logic though, and it would probably be less stable and more prone to tunneling issues (fast-moving bodies clip through)
brisk shale
#

i was planning on doing some collider optimization at some point but ive just been focusing on feature development before i work on optimizations

#

could you go more into the "floating character controller" solution and how i'd implement that? :o

vestal minnow
#

I haven't implemented one myself though so I don't know all the details

brisk shale
#

oooh interesting, ty lots for the links :o

#

appreciate ur help :3

vestal minnow
#

np, happy to help :)

sleek thicket
drifting marsh
#

I've tried (and still want to) make a classic "collide and slide" character controller nut numerical precision issues are really hard to get right.

#

I've seen some approaches that don't make sense, the papers that have been written on it don't account for all the issues you can run into either.

brisk shale
#

man if i have to read "papers" then its just not worth the effort i think

#

like
you mean academic papers, right?

brisk shale
#

yeah ive got it set up with tnua

#

i need to play with the settings a bit more to make it feel right, but the annoying problem that was bothering me is gone now so :)

sleek thicket
#

it's super simple though, tnua overcomplicates it

brisk shale
#

over- how? how does it overcomplicate it? i got it set up in minutes?

sleek thicket
#

it's just 2 lines of code

#

meanwhile tnua is the whole char controller

brisk shale
#

okay

#

can you like
what do you mean "its just 2 lines of code"

sleek thicket
#

if ray down hit ground
do the spring ๐Ÿคทโ€โ™‚๏ธ

brisk shale
#

okay sure i guess

sleek thicket
#
if let Some(hit) = physics.cast_ray(pT.translation, -up, groundCheckDistance, false, SpatialQueryFilter::from_mask(layer::GROUNDMASK)) {
        fallDur = 0.0; // same as grounded = true; but allows coyote time
        if hit.normal.dot(up) > 0.95 { // keep if you care about steep slopes
            LV.0 += up * (((groundRestDistance - hit.time_of_impact) * strength) - (LV.0.dot(up) * damping)); } }
drifting marsh
cinder summit
brisk shale
#

okay, neat experiment, ty for sharing the code .โงฒ.

#

i think im probably going to stick with tnua, though, since it has helpers for anims

#

or like... helpers is not the right way to put it probably but like

#

awa

#

like
since im planning on adding multiplayer eventually, i think it makes sense to get used to how tnua works

#

damn yeah, that took me about an hour to play with
whereas tnua took like... 5? 15? minutes?

royal helm
#

@vestal minnow do you know any good resources on generating contact manifolds from gjk for example?

#

I'm not sure I fully understand the generating and usage of it

royal helm
#

Fixed by a shapecast but shapecasts also cause issues related to normals

#

e.g. what should be the normal on an edge of a polygon, which would be used for slipping? I think ideally it's the most "upright" face related to that edge or vertex but currently there isn't a way to get that in parry

deep ingot
#

is there an existing api i can use to compute the intersection of two aabbs?

sleek thicket
sleek thicket
# royal helm It isn't that simple if you want it to be robust, what happens when your raycast...

yeah i was concerned about the tiny bumps and gaps but haven't actually encountered it, and i had to set it to ignore the layer with junk because it'd mess with anti-gravity anyway so that probably helped
there was an anti-gravity ledge jitter which was solved fairly easily, but it's not even a problem here

there's 1 real problem i actually had so far is floating over the railings, i still have to fix that and i'm assuming it'd be a problem for a minecraft clone since it'd essentially turn 1-unit blocks into stairs

vestal minnow
cinder summit
#

One of these days I'm also going to need to figure out contact manifolds for SDFs ... Maybe having only 1 contact point is the reason why my spheres never go to sleep thonk

deep ingot
#

is there an efficient way to query for the ColliderAabbs that totally contain a given ColliderAabb?

cinder summit
#

You could use SpatialQuery to get all aabb intersections, then check if they contain your given aabb fully, tho it's not as efficient as if this were a method on SpatialQuery

deep ingot
#

oh! does intersections include containment? i thought it was just for aabbs with boundary contacts

#

let me try...

vestal minnow
#

But you could get those overlapping AABBs manually and check for containment

deep ingot
#

ok, i thought i tried this before and didn't get totally-contained in the result set, but maybe there was a bug. let me try again

cinder summit
deep ingot
#

i actually implemented my own contains. it would be a nice thing to have in the lib but maybe not "physics related enough"

vestal minnow
#

Yeah, that just wouldn't work as nicely for f64 (using Aabb2d/3d)

deep ingot
#

oh, interesting. it's actually an f64 issue?

vestal minnow
#

I meant that if we used Bevy's own Aabb2d/Aabb3d types (which use f32), they wouldn't work for far-from-origin cases as well as xpbd's own AABB which uses f64 when the f64 feature is enabled

#

But if Bevy had f64 versions, we could use them

#

We can also just add contains to ColliderAabb

deep ingot
cinder summit
#

@vestal minnow what exactly is ran in parallel with the parallel feature enabled? I'm only seeing the narrow phase speed up slightly, but penetration_constraint and solve_vel run at basically the same speed ๐Ÿค”

vestal minnow
#

The narrow phase is currently the only thing since that is very trivial to run in parallel. Ideally we'll also run the solver in parallel if/when we implement some kind of parallel island architecture

#

But currently the solver is fully serial because for multithreading it'd need to partition the constraints into parallelizable chunks to avoid conflicting accesses, which isn't as trivial

#

And multithreading a solver can also cause determinism issues

cinder summit
#

I'm asking because even with parallel my app runs about this well ๐Ÿ˜‚

#

The fact that FixedeUpdate contains 4 runs probably says enough ๐Ÿ‘€

#

For now I'll just limit it to 2 rollback frames and use 4 substeps ๐Ÿ˜‚

#

Also why the hell does sleeping not work? thonk

#

Oh is this because I don't set_if_neq? ...

cinder summit
vestal minnow
#

The sleeping logic is cursed and pretty broken, but I think so

#

Usually sleeping is done in islands afaik (requires the previously mentioned island architecture)

cinder summit
#

These spheres don't seem to move, but they always get marked changed, so they never start sleeping ๐Ÿค”

#

They just drop from the sky and land there, and then stay there unmoving

#

They didn't really rotate either, tho there are forces on them from the ground

vestal minnow
#

Hmm, maybe there was some regression that triggers component changes every frame

#

I've also noticed that sleeping seems even buggier than before

cinder summit
#

Interestingly AngularVelocity rarely ever changes on these spheres, except the tick they "wake up" (when they get marked sleeping and immediately unmarked for sleeping)

#

position and linear velocity are always changed and rotation is frequently changed

#

It might just be that the checks being == 0 are too strict, maybe if there's 1 ULP in there it would still change the value

cinder summit
#

I just need position_to_transform if I never touch Transform right?

vestal minnow
#

yeah I think so

cinder summit
#

Is there an up-to-date list of components that I'd need to network and rollback to get reasonably deterministic results? Position, Rotation, LinearVelocity, AngularVelocity, TimeSleeping, Sleeping are the obvious ones, but it's not quite deterministic yet ๐Ÿค”

royal helm
#

You'll at least need to roll them back

#

Impulses and forces too need to be rolled back if anything uses those

#

AccumulatedTranslation too maybe?

cinder summit
#

I don't use any constant forces, and store the state after physics, so impulses and forces shouldn't be an issue (since they're added to Velocity already) ... Not sure about the Previous and AccumulatedTranslation components ... Those feel like temporary internal stuff for xpbd but I'm not sure ๐Ÿค”

#

With the list above my character controller works fine (well without the sleeping ones, cause it doesn't actually go to sleep anyway because of sleeping bugs) ... But dynamic rigid bodies without direct forces applied and partially constrained rotation doesn't seem to rollback as nicely

trail sparrow
#

So, I'm toying with an idea and wondering if Bevy XPBD supports combined collider intersections, e.g.:

Collider::rectangle(1.0, 2.0) - Collider::sphere(0.5)
#

For example: I want a collider shaped like this

#

I should probably just make it from triangles, right?

vestal minnow
# trail sparrow So, I'm toying with an idea and wondering if Bevy XPBD supports combined collide...

These kinds of boolean ops are basically impossible for normal colliders because colliders are not allowed to have concavity. The only practical way that I can think of in 2D would be to approximate the shapes as polygons and to perform the subtraction using something like geo's boolean ops, hopefully giving you multiple convex polygons that you can use to build a compound collider. (idk if geo's boolean ops are guaranteed to produce convex polygons though)

#

You can also do (at least some) boolean ops on SDF colliders like the ones @cinder summit has

#

because they don't strictly have to be convex

#

the SDF collision lib isn't public yet tho

trail sparrow
#

Ok. I basically just want a couple of collider types that are corners for a 8-grid (up, down, left, right, + diagonals)

#

I was just intuitively thinking collisions could be modeled by subtracting the circle collision from the rectangle collision waves hands

cinder summit
trail sparrow
#

Also, something that might inspire: https://www.youtube.com/watch?v=rSKMYc1CQHE this guy uses a compute shader to calculate collisions. He's explicitly not trying to model reality though

Let's try to convince a bunch of particles to behave (at least somewhat) like water.
Written in C# and HLSL, and running inside the Unity engine.

Source code:
https://github.com/SebLague/Fluid-Sim

If you'd like to support me in creating more videos like this, you can do so here:
https://www.patreon.com/SebastianLague
https://ko-fi.com/sebastia...

โ–ถ Play video
cinder summit
vestal minnow
cinder summit
trail sparrow
#

Right. So, yeah, I'll just use a couple of/three triangles to model the corner colliders for now

vestal minnow
#

(I certainly don't have that tab open)

cinder summit
#

Someone actually sent me a video of another approach that's more of a list of operations+shapes ... I might try that at some point, sounds like it could make for better DX and model to an actual userfriendly UI

#

Also I'm actually going to optimize my SDF collisions soon, which has been the blocker to opensourcing it ever since we got the collider feature ... Because it went from 80micros per step to 140, because I had to remove some alloc reuses to get other things to work ๐Ÿ˜‚

#

That's with 200-300 spheres colliding with one arbitrary SDF

vestal minnow
# trail sparrow Also, something that might inspire: https://www.youtube.com/watch?v=rSKMYc1CQHE ...

Collision detection on the GPU can be really useful for massively speeding up particle simulations like this, but it's much more complex for general-purpose collision detection.

To see any parallelism benefits, you'd need to batch collisions based on the shape type, like one worker would handle ball-ball collisions, another one would handle ball-capsule collisions, and so on. There is a ton of complexity involved in the memory handling and collision batching here, and can often have more overhead than what it is worth. GPU simulations also have other issues, like the cost of data transfer between the CPU and GPU, and even issues with reliability across hardware.

GPU physics and collisions are generally only feasible for e.g. NVIDIA, which have tons of resources and expertise and are even the ones making a lot of the graphics cards. There's a reason PhysX is basically the only proper physics engine with GPU-based simulation.

cinder summit
#

And even then, the most fancy usecases NVIDIA shows off aren't physx but some unspecified SDF physics simulation for proprietaryTM uses ๐Ÿ˜‚

vestal minnow
#

So with graphics it's "easier" to make GPU things work fine

#
trail sparrow
sleek thicket
zinc talon
#

Just saw the rebrand notice, I'm stoked to see how things work out with the new solver! And starting to unblock upstreaming the crate is a big bonus as well

vestal minnow
#

Thanks, I'm excited to properly start working on it too once I'm done with exams... just a bit over a week left :)

#

Also to be clear, it'd be a step towards unblocking potential upstreaming... Rapier is still a worthy option too, especially as they're trying to improve the Bevy integration by e.g. supporting Glam in Parry and Rapier, like seb said here #math-and-physics message

zinc talon
#

Fair enough. That said, I really like bevy_xpbd's api

vestal minnow
#

Yeah I think bevy_xpbd's benefits over Rapier will continue to be:

  • ECS integration
  • Modularity
  • Nicer API in some places
  • Better docs.rs documentation
  • Active effort to be as "Bevy native" as possible (at the cost of not being very usable outside of Bevy)
  • My activity according to people :)
    Rapier can improve on a lot of these and even do things like reduce the number of wrappers and use Glam instead of Nalgebra more, but I don't see them being able to do things like completely remove Nalgebra, use Bevy's primitives and bounding volumes for collisions, or fully embrace the ECS and plugin system anytime soon. It could be theoretically possible to some extent, but I feel like it'd have trade-offs for other consumers of the core Rapier
#

Some of Rapier's pros on the other hand would definitely be performance and having more features, but hopefully the rebrand stuff will help on that front a bit

cinder summit
#

Fixing sleeping issues helps with performance

vestal minnow
#

yeah that should definitely be fixed

shell ermine
cinder summit
#

Anyone know if I can get the debug plugin to not make multiple arrows because of rollback?

zinc talon
#

Is there a general solution for velocity at a point on a rotating body? It's ang_vel * r.perp() for 2d and ang_vel.cross(r) for 3d, but is there a way to generalize that?

vestal minnow
zinc talon
#

Not to higher dimensions, just whether there's a way to generalize over 2d and 3d

#

Just like, most dynamics equations work for 3d and 2d, like moments of inertia

#

For 2d moment of inertia is a scalar and torque is a scalar, so Iฯ„ works, and in 3d it's a 3x3 matrix and a vector, so Iฯ„ still works

deep ingot
#

How do i get ray_caster.direction to point to a coordinate in the global reference frame if my ray_caster.origin is non-zero?

slim ledge
#

When we set RayCaster.with_max_hits(1) , will it return the nearest hit from the origin, or a random one from origin to max time to impact?

slim ledge
deep ingot
#

I'm trying to point a RayCaster (with a parent entity) at a coordinate in the global reference frame (dst). When I use
ray_caster.direction = dst - origin , it works, but as soon as the RayCaster's parent entity moves, the direction gets thrown off. Any idea what I'm missing?

#

I feel like I need to account for the rotation of the parent entity, but I'm not sure how to do that (all of my attempts have failed)

deep ingot
# deep ingot I'm trying to point a RayCaster (with a parent entity) at a coordinate in the gl...

After playing around a bit and looking at some code, I learned that the transform_point functions actually do the inverse of what I expected (and it seems like the docs are misleading?). I ultimately came up with this, which seems to work:

let (scale, rotation, translation) = ray_transform.to_scale_rotation_translation();
ray_caster.direction = rotation.conjugate().mul_vec3((dst - translation) / scale);

Not sure why this isn't an API on the GlobalTransform or RayCaster. Probably there's a good reason not to be doing inverse transforms in user code like this, but I couldn't find another way.

royal helm
#

Should be getting merged soon

cinder summit
#

I don't think that would help since afaict debug gizmos run in PostUpdate, not in my simulation schedule ๐Ÿค”

carmine sluice
#

Sorry for procrastinating it lol

royal helm
royal helm
vestal minnow
#

They're xpbd's debug gizmos which run in PostUpdate by default, but the schedule can be changed

cinder summit
#

Which is why I get 1 AABB, but 4 arrows (there's 3 resimulations + 1 new tick)

royal helm
#

I see

royal helm
#

I guess that wouldn't make too much sense since that'd duplicate

#

hmm

#

or some way to distinguish them by tick

#

or alternatively just have the debug gizmos run in your simulation schedule once that PR is merged

cinder summit
royal helm
#

I mean the xpbd debug gizmos plugin

cinder summit
#

Also, thinking about it ... @vestal minnow I run 4 simulations, with 3 substeps each ... It barely maintains 60FPS ... This is the same as 12 substeps and 1 tick no? thonk

cinder summit
vestal minnow
#

With 1 sim and 12 substeps it'd only run once per tick

cinder summit
#

The bigger thing here is rebuilding the BVH ... I could probably do a whole extra simulation without it ๐Ÿ˜‚

vestal minnow
#

Speaking of BVHs, I found a pretty juicy bug in Parry's ray casting when implementing my own... For non-solid ray casts where the ray starts in the inside of the collider, it seems like the normal is opposite to what it should be for all support mapped ray casts, like for cylinders, cones, capsules, convex polyhedra, and convex polygons

#

So it seems to just be wrong for like half of the shapes, which could probably cause some pretty nasty bugs ๐Ÿ™ƒ

#

It's a super easy 1-line fix tho

lavish orbit
#

So I want to make a customizable third person camera controller as my first bevy crate, with things like ensuring the camera doesnt go inside of colliders, what would a good way be to find the distance to the nearest surface (to find a "safe" distance for the camera to be from the player) would a raycast be good enough?

vestal minnow
#

and then get the distance to that point

#

So something like

if let Some(projection) = spatial_query.project_point(player_position, true, filter) {
    let min_distance = player_position.distance(projection.point);
    // ...
}
#

But if you need the closest point in a direction, you probably want a ray cast or shape cast

lavish orbit
#

thinking about, it probably should be a shape cast (like giving the camera a small sphere collider)
and checking how far I can move it back

vestal minnow
#

Yep

cinder summit
ionic gale
#

How would I make the most simple possible platformer?

#

They have an example platformer but it is stuffed full of extra features.

sleek thicket
ionic gale
sleek thicket
#

define most basic functionality.

#

move and jump without anything else at all?

ionic gale
ionic gale
sleek thicket
#

add dynamic rigidbody, linearvelocity and collider
add system to add/set linearvelocity .0 or y in your desired vector

ionic gale
#

The examples that I found have to much going on.

sleek thicket
#

yeah i did suggest splitting it into multiple levels of complexity but idk what happened to that

ionic gale
#

I even want to use debug to see what is going on at the beginning.

sleek thicket
#

PhysicsDebugPlugin::default(),

sleek thicket
#

for a suggestion? wat

ionic gale
sleek thicket
#

???

vestal minnow
# ionic gale Where are the docs?

Are you asking if there are docs for the basic movement? As in, this:

add dynamic rigidbody, linearvelocity and collider
add system to add/set linearvelocity .0 or y in your desired vector

sleek thicket
#

@vestal minnow i think you can actually simplify the example a bit by moving input outside of the example, it doesn't even matter if it's 2d or 3d

vestal minnow
#

Like, move the input systems to some common module that examples can use?

sleek thicket
#

yeah

vestal minnow
#

And then just listen to the action events

#

Yeah that could be fine

#

And maybe have one example that also shows how to handle input for movement, but generally use the common one

#

Hmm, or if examples can export things then we could just import from the input example

#

Leafwing input could also be a valid option I guess

sleek thicket
#

i remember i suggested adding all that complexity because of that really neat pause button in common examples

#

just needs a little bit of cleaning up and linearity for introducing all the common things you'd need

ionic gale
#

Should I use dynamic or kinematic?

sleek thicket
#

start with dynamic and decide if you need to switch to kinematic once you really know what you're doing

cosmic dagger
#

Hey guys, is there an easy way to visualize the colliders for debugging? ๐Ÿค”

sleek thicket
#

PhysicsDebugPlugin::default(),

sleek thicket
#

ok.

#

so?

#

kinematic is a footgun for beginners

vestal minnow
#

I think more physics debug tools could be useful for users too, not just examples (or me)

sleek thicket
#

mmm

#

you know unity's physics example?

vestal minnow
#

I don't think so

#

there are a lot of them

sleek thicket
#

i'm trying to find it but man they bury their stuff so much

#

i found a video that uses the example but not the example itself ๐Ÿ˜‚

#

oh found it

#

it basically does most of the stuff you mentioned

#

it'd be a really cool example for collider shapes too

vestal minnow
#

I think it'd be nice to have stuff like

  • Pause, unpause, step
  • Modify global simulation parameters (time scale, gravity, substep count, etc.)
  • Toggle debug rendering
  • Show number of collisions, sleeping bodies, etc.
  • Grab and drag around dynamic objects
    Of course GUI stuff would be optional
ionic gale
#
commands.spawn((RigidBody::Dynamic, Collider::circle(0.5)));```How does it know where to put the objects?
cosmic dagger
#

Hm do you guys know if there are there any special requirements for Collider::trimesh_from_mesh() ? ๐Ÿค”

vestal minnow
sleek thicket
#

iirc pbr/spritebundle has transform too

vestal minnow
#

Yup, if you have that then you should change the transform property there

vestal minnow
cosmic dagger
#

Hm cause this mesh doesn't seem to work as a whole

#

But as soon as I split it some more, it does work ๐Ÿค”

vestal minnow
#

Or is that just blender showing the outline?

cosmic dagger
#

yeah just a quick blender pic, sorry

vestal minnow
# cosmic dagger Hm do you guys know if there are there any special requirements for Collider::tr...

General trimesh tips

  • Make sure you do Ctrl+A and "Apply scale" in Blender, iirc Bevy doesn't love importing meshes with scaling (or at least colliders don't)
  • Very thin "needle-like" triangles aren't great for collisions since they're more prone to numerical issues (this can also apply to rendering in extreme cases)
  • There's a trimesh_from_mesh_with_config method that allows some extra pre-processing if you want that
    Doesn't necessarily relate to your issue tho
cosmic dagger
#

Hm ok thanks, will forward this to my modeler ๐Ÿ˜…
Will also try to tinker around some more. Maybe I can find out why the fn likes one simple mesh over another lol

peak schooner
#

Hello, beginner question here. I wanted to create a system that checks collisions involving entities tagged with a custom marker-component, and if a collision with said entity is greater than some threshold, it would trigger something (in my case, dynamically removing a joint attached to that entity).
I'm looking at Contacts, both via collision events and/or the collisions resource (just experimenting with both approaches). For now I'm just using simple print statements to see what total_normal_impulse and total_tangent_impulse look like - but I'm getting unexpected results - a lot of 0.0's where I would expect something else. Feels inconsistent w/ some collisions registering impulses while many do not.
I suspect that perhaps the issue is the timing of the system - maybe it's running in the wrong schedule? Or I'm misunderstanding something. Thank you for any help w this, still new to Bevy

novel spruce
#

this is more a general game physics question, but whats the right way to approach to handle player input in an asteroids-like game where you maintain momentum when you let off the throttle? ExternalForce or ExternalImpulse?

#

I've tried both but i can't quite get either to work just the way I want with a max object velocity

novel spruce
#

directly set it instead of using ExternalForce/Impulse?

#

like, vel += accel * time.delta_seconds()

#

right, that was mostly pseudocode

cinder summit
#

If you don't want to overwrite it you'd usually use external force/impulse

novel spruce
#

i kinda liked the impulse method because it takes the mass into account

cinder summit
#

Nope, but having one system add an impulse while another resets velocity would create system ordering issues

novel spruce
#

hmm, yeah, that could impact collision

cinder summit
#

No, but your code might reset it for whatever reason

novel spruce
#

setting it directly conflicts with externalforce/impulse and physics restitution, wouldnt it?

#

like it works if you want to give an initial velocity to something, and then let physics fall where it may

cinder summit
#

As for External Impulse vs Force ... I'm not actually sure what the difference between them is ๐Ÿ˜‚

novel spruce
#

one is acceleration, one is delta-v, i think

#

i cant keep them straight however

#

let me look at the docs again to remember which was which

#

oh Force is just "velocity", it persists across frames

#

impulse is a push

#

oh that makes sense why my Force code did wonky things then, i think i was accelerating at ^2 instead of linear, leading to unintentional hyperspace jumps

vestal minnow
# novel spruce one is acceleration, one is delta-v, i think

F = ma, unit N = kgm/s^2
I = pm, unit Ns = kgm/s

By default forces persist, causing constant acceleration (like gravity) assuming no other forces act on the body.

By default impulses are "instantaneous" and don't persist, which can be good for things like explosions or jumps.

cinder summit
novel spruce
#

yeah the persistence bit was causing infinite acceleration

cinder summit
#

Being able to make a persistent impulse feels kinda wrong tbh ๐Ÿ˜‚

cinder summit
novel spruce
#

so ExternalForce is basically persistent acceleration in a direction, ExternalImpulse is a push. So if i use externalForce up to a max speed and then set externalForce to 0 i'll still just float around right? Gravity is 0 globally

vestal minnow
#

(currently)

#

IIRC I compared the results with PhysX/Unity to make sure it looks correct

novel spruce
#

i've basically got impulse = vector * accel * time.delta_seconds() but i think i'll redo it as a force, i'm pretty sure that version has a bunch of lurking gremlins

#

in an Update system

vestal minnow
#

yeah but just applying the same force/impulse for a body at the same position with the same mass

cinder summit
novel spruce
#

@cinder summit that's what i'm thinking too

vestal minnow
#

You could make the force non-persistent and have a system apply the rocket force every frame

cinder summit
#

Kind of wondering if it doesn't make more sense to have separate persistant and non-persistent forces ... That way if you have a persistent force, then apply a non-persistent one for a while, it doesn't break things

#

Like ExternalForce.add_persistent_force() vs ExternalForce.add_oneshot_force() or something thonk

vestal minnow
#

Or apply_force and set_constant_force/apply_constant_force

#

Godot has that

#

I think that probably makes way more sense than a weird persistence flag

novel spruce
#

i'm having a hard time picturing a oneshot force now for some reason. if i send a 1 frame oneshot force, what happens

novel spruce
#

i can see it in the "throttle" case where you say "engines on, externalForce = accel", and then "engines off, externalForce = 0",

vestal minnow
novel spruce
#

isnt that an impulse then, with variable frame timing?

#

functionally

#

not physically

vestal minnow
novel spruce
#

that seems like more of a footgun then

#

or, it would need a bunch of docs about "when to choose which"

cinder summit
#

I mean we kind of already need those ๐Ÿ˜‚

novel spruce
#

yeah this would just make it worse! ๐Ÿ˜„

cinder summit
#

We already have non-persistent forces tho ๐Ÿ‘€

vestal minnow
novel spruce
#

yeah i'm now having trouble coming up with when you'd use a non-persistent force vs an impulse

#

yeah that falls out as a result of the simulation

cinder summit
#

Anything that needs to accelerate over time would use a force

#

Anything that's instant would be an impulse

#

The non-persistent thing is mostly just to make it easier to use

novel spruce
#

so a normal rocket uses persistent force, one of those mass-driver rockets where you detonate nukes behind a pusher plate uses impulses

cinder summit
#

It would be annoying if you had to remember the previous force you applied for movement, remove that, then apply the new one

#

Of course not all movement is based on acceleration, so sometimes impulses or even setting velocity directly are the way to go

novel spruce
#

arent you basically just clobbering it every time you write to externalforce anyway though?

vestal minnow
#

Not sure if I want like 3 different force components

cinder summit
#

And that wouldn't be very ECSey ๐Ÿ˜‚

vestal minnow
#

Also forces can cause torque, which should account for all the external forces

#

(when applied offset relative to the center of mass)

novel spruce
#

hmm it looks like rapier doesn't even have non-persistent. Nothing about persistence, docs say the force is applied each timestep

vestal minnow
vestal minnow
novel spruce
#

yeah i'm just having a hard time intuiting a reason why they should exist

#

doesn't help i'm sick and have a headache though

novel spruce
vestal minnow
cinder summit
#

MagnetConstraint thonk

novel spruce
#

wouldn't that be persistent, but call clear() when the magnets go away?

vestal minnow
#

For magnets, the strength of the magnetic field depends on the distance

#

So you need to update it every frame anyway

novel spruce
#

ah

vestal minnow
#

Same for orbit simulations

novel spruce
#

i think in rapier that's what you'd do, there's no apply_force to accumulate, you just overwrite the force and should probably properly take into account whether other systems have already messed with it

#

where theres no "oneshot"

vestal minnow
#

Yeah events or commands could work here in theory, not sure how nice it'd be in terms of DX

#

the main annoyance is that you need the entity here

#

and this would have potential issues with substepping stuff

#

if we want to still apply forces over multiple substeps and not in a single burst

#

Where is the force stored and how do you clear it?

#

The component would just be close to the current ExternalForce

#

And people would probably end up using that directly

#

Events also don't seem very idiomatic to me for this kind of thing, commands would be more semantically correct

cinder summit
#

Events and commands can also both perform a lot worse if you already need to access the entity in question anyway

vestal minnow
#

yup

#

Like I don't use a VelocityEvent to move bodies; to me, events signal an "action", and their readers handle the response. I don't consider vel_event.send(VelocityEvent(Vec3::X)) to really be an action

novel spruce
#

is there a way to do one-off raycasts? I'm trying to figure out camera positioning and doing it via RayCaster/ShapeCaster seems more difficult than the way i'm doing it in rapier

cinder summit
novel spruce
#

ah nice, perfect

vestal minnow
cinder summit
vestal minnow
#

Temporary forces need the same data as constant forces, and using commands/events would be less efficient anyway

#

We could technically have separate local/global components I guess

#

Forces become velocity updates anyway, the main difference behavior-wise (assuming the total change in velocity is the same) is that forces are substepped so the change is more gradual

novel spruce
#

hmm, my only problem now is that I don't know how to actually implement a max speed if I'm using ExternalForce. It is much smoother though

cinder summit
#

There's a few options:

  • You can limit speed in each physics step, that way it's perfectly accurate
  • Or you can calulate what the speed would be after your force, then limit it so it doesn't become too high
#

Well or you can do it entirely physics based, have the max speed be a function of some drag and acceleration

#

That dot introduces more behavior than just limiting speed, idk of that's actually desired here

novel spruce
#

i'm trying to translate that to an ExternalForce application

#

thanks, will look

#

i'm trying out the LV version now

#

in the above, input is the facing vector times forward or backward, right?

#

i don't have a Vec2 of input, you have thrust and rotation, no strafing

#

its Asteroids physics

#

k that works but then it doesnt have any sort of limiter on max speed

silk mauve
#

Periodically crashing with the only trigger I can think of being having a lot of characters (which use raycasters) instantiated at once:

assertion failed: value.is_normalized()
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_xpbd_3d::plugins::spatial_query::update_ray_caster_positions`!
Encountered a panic in exclusive system `bevy_xpbd_3d::plugins::setup::run_physics_schedule`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
#

It might be when characters are intersecting as well but it's hard to say

novel spruce
#

where's acceleration then?

#

none of this is making sense or working for me, I'm going to watch that video and play with ExternalForce solutions

#

thanks for the help

silk mauve
silk mauve
#

Now I'm reading back through and seeing that something similar was fixed almost a month ago. I'm currently on 0.4.2, which is the latest version... I assume those changes made it into the latest version by now, now?

cinder summit
#

There's a fix from a few weeks ago for rotations becoming unnormalized which might help, but iirc that only happens when things have a high angular velocity ๐Ÿค”

novel spruce
#

got it figured out (with oneshot, no less :P). That video was a great help, the key slide is at 21:46 in there. Implementing that as "force = whatever we calculated when the throttle is pressed, 0 on every other frame" seems to work pretty well

silk mauve
silk mauve
#

Ok, I was able to reproduce the bug in a smaller project:

use bevy::prelude::*;
use bevy_xpbd_3d::prelude::*;
use rand::Rng;

fn main() {
    App::new().add_plugins((
        DefaultPlugins,
        PhysicsPlugins::default().build(),
    )).add_systems(Startup, (
        setup,
    )).add_systems(Update, (
        update_jumper_system,
        spawn_jumper_system,
    )).run();
}

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>, 
) {
    // Spawn a platform and a fixed camera
    let base_size = 32.0;
    commands.spawn((
        bevy_xpbd_3d::components::RigidBody::Static,
        Collider::cuboid(base_size, 0.002, base_size),
        PbrBundle {
            mesh: meshes.add(Plane3d::default().mesh().size(base_size, base_size)),
            material: materials.add(Color::GREEN),
            ..default()
        },
    ));

    commands.spawn((
        Camera3dBundle {
            transform: Transform::from_xyz(30.0, 30.0, 30.0).looking_at(Vec3::ZERO, Vec3::Y),
            ..default()
        },
    ));
}

#[derive(Component)]
struct Jumper;

fn update_jumper_system(
    mut query: Query<(Entity, &mut LinearVelocity, &RayHits, &Transform), With<Jumper>>,
    mut commands: Commands,
) {
    for (entity, mut linear_velocity, ray_hits, transform) in query.iter_mut() {
        if ray_hits.len() > 0 {
            // Apply an upward force if there's a ground hit
            linear_velocity.0 += Vec3::Y; // Adjust the boost as necessary
        } else {
            let direction = (Vec3::ZERO - transform.translation).normalize();
            let dir = Vec3::new(direction.x, 0.0, direction.z);
            linear_velocity.0 += dir * 0.01;
        }

        if Vec3::ZERO.distance(transform.translation) < 1.0 {
            commands.entity(entity).despawn_recursive();
        }
    }
}

fn spawn_jumper_system(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    time: Res<Time>,
) {
    let mut rng = rand::thread_rng();
    let position = Vec3::new(rng.gen_range(-15.0..15.0), 10.0, rng.gen_range(-15.0..15.0));

    // Spawn a jumper every second
    if time.elapsed_seconds_f64().trunc() as i64 % 2 == 0 {
        commands.spawn((
            RigidBody::Dynamic,
            Collider::capsule(0.5, 0.4),
            PbrBundle {
                mesh: meshes.add(Mesh::from(Capsule3d::default())),
                material: materials.add(Color::rgb_u8(124, 144, 255)),
                transform: Transform::from_translation(position),
                ..default()
            },
            Jumper,
            RayCaster::new(Vec3::default(), Direction3d::NEG_Y)
                .with_ignore_self(true)
                .with_max_hits(1)
                .with_max_time_of_impact(1.5),
            RayHits::default(),
            Friction::ZERO.with_combine_rule(CoefficientCombine::Min),
            LinearVelocity::default(),
            AngularVelocity::default(),
        ));
    }
}

Start that, wait a little bit, and it will panic.

silk mauve
cinder summit
silk mauve
#

Using main seems to have worked

#

Just started doing it again.

#

Turns out I was occasionally feeding Vec3(NaN NaN NaN) as the linear velocity lol now main is working great.

cinder summit
#

Ah yes, if you NaN velocity I think angular velocity immediately NaNs too, and you hit the is_normalized error before anything else panics on the NaN

ionic gale
#

Why does players: Query<RigidBody, With<Player>> not work?the trait bound `bevy_xpbd_2d::components::RigidBody: QueryData` is not satisfied the following other types implement trait `QueryData`: DebugName bevy::prelude::Ref<'__w, T> Has<T> AnyOf<()> AnyOf<(F0,)> AnyOf<(F0, F1)> AnyOf<(F0, F1, F2)> AnyOf<(F0, F1, F2, F3)> and 43 othersrustcClick for full compiler diagnostic query.rs(328, 37): required by a bound in `bevy::prelude::Query

cinder summit
#

Cause it's missing a &

ionic gale
#

Thanks.

#
    persistent: true,
    ..default()
},```Should this work?
#

field `force` of struct `bevy_xpbd_2d::components::ExternalForce` is private field `force` is privaterustcClick for full compiler diagnostic field `torque` of struct `bevy_xpbd_2d::components::ExternalForce` is private field `torque` is privaterustcClick for full compiler diagnostic bevy_utils::default pub fn default<T>() -> T where T: Default,

peak schooner
#

Re-asking a question I asked last night to be a bit more specific. What is the proper way of accessing/using Contacts::total_normal/tangent_impulse?

I've experimented with both the Collisions resource and with collision events to access Contacts data. I can see which entities are colliding (as expected) - and I'm printing total_normal_impulse and total_tangent_impulse to console to get a feeling for typical values. However, 99% of what I see is 0.0 for impulse values, with the occasional non-zero impulse periodically appearing.

I think this has to do with the caveat I saw in the ContactData docs (see image). I'm hitting a knowledge ceiling here - could my 0.0's be because my system is running in the wrong schedule? I've tried a few different things (like running in PostProcessCollisions), but same result. Or maybe it's because the impulses are a single substep and not a physics frame (honestly uncertain what the ramifications of this are)? If anyone has any thoughts on accomplishing this behavior, I'd really appreciate the help. Thanks.

ionic gale
#

```error[E0451]: field force of struct bevy_xpbd_2d::components::ExternalForce is private
--> src\main.rs:36:15
|
36 | ..default()
| ^^^^^^^^^ field force is private

error[E0451]: field torque of struct bevy_xpbd_2d::components::ExternalForce is private
--> src\main.rs:36:15
|
36 | ..default()
| ^^^^^^^^^ field torque is private

For more information about this error, try rustc --explain E0451.```

silk mauve
#

There's probably a constructor you can use. ExternalForce::new() or something similar

patent vigil
#

I have a setup where I am attempting to spawn a child entity for my player entity with a collider for an attack hitbox. I at first expected to be able to spawn only the collider and have it offset with its local transform, but once collider was added as a child the transform was no longer respected. To work around this I added a rigidbody to the child entity, which causes the collider/child entity to respect the transform but then then i lose the behavior I want of the attack hitbox moving along with its parent the player. Is there a way to have a child collider entity without a rigidbody that respects local transform? (im on bevy 0.12 and xpbd_2d 0.3.3)

cinder summit
#

Hmmm ... You might be able to manually add a ColliderTransform to that child entity, it would be relative to the parent (if that has RigidBody, not sure about Sensor or just Collider however)

patent vigil
#

hmm docs say its updated automatically, does that mean it would get overwritten?

patent vigil
#

transformbundle yes

vestal minnow
#

Yeah GlobalTransform is needed too, but TransformBundle should have that...

cinder summit
patent vigil
#

it works as "expected" aside from the child not following if it has its own rigidbody, (but the not following is expected since then its position is managed by physics engine)

vestal minnow
#

ColliderTransfom should be added automatically

cinder summit
patent vigil
#

but the transform bit works as expected if it has a rigidbody

#

and not if it doesnt

#

with no other changes

vestal minnow
#

Could you show how you currently spawn the player and child collider?

patent vigil
#

lets see one let me check if i already pushed it to gh

#

player spawn

#

attack spawn

#

i notice if i spawn my player without its own rigidbody the child entity does not need a rigidbody for its transform to be respected

vestal minnow
patent vigil
#

but i need the rigidbody on player too, I guess i could make the player have its collider/rigidbody also a child so the attack would be a sibling, but that introduces more hierarchy traversal stuff

patent vigil
#

so is it not expected that a child collider without rigidbody would not respect its transform?

vestal minnow
#

A child collider should work with local transforms yeah

patent vigil
#

oh the code there is post applying rigidbody to child workaround

#

i guess imagine in the attack spawn just removing the RigidBody::Kinematic and Sensor components

#

would you still expect transform to work then?

vestal minnow
#

yeah the child should work without RigidBody

patent vigil
#

okay

#

I guess im running into some kind of bug then

vestal minnow
patent vigil
#

no rigidbody on the child?

vestal minnow
#
commands
    .spawn((
        PbrBundle {
            mesh: cube_mesh.clone(),
            material: materials.add(Color::rgb(0.2, 0.7, 0.9)),
            transform: Transform::from_scale(Vec3::splat(cube_size as f32))
                .with_translation(Vec3::Y * 5.0),
            ..default()
        },
        RigidBody::Dynamic,
        Collider::cuboid(1.0, 1.0, 1.0),
    ))
    .with_children(|commands| {
        commands.spawn((
            PbrBundle {
                mesh: cube_mesh.clone(),
                material: materials.add(Color::rgb(0.2, 0.7, 0.9)),
                transform: Transform::from_translation(Vec3::X * 3.0),
                ..default()
            },
            Collider::cuboid(1.0, 1.0, 1.0),
        ));
    });
patent vigil
#

hmm okay

#

is that 0.3 or 0.4?

vestal minnow
#

0.4 but I'm pretty sure this logic shouldn't have changed from 0.3

#

And child colliders definitely should work since colliders loaded from glTF scenes rely on them (like in the async_colliders example)

#

I can try to debug your issue tomorrow but I don't really have time today unfortunately :(

patent vigil
#

okay thanks for your help

#

its good just to know what was expected or not

vestal minnow
#

Could technically be some scheduling issue too since you have a custom schedule, but I doubt it

patent vigil
#

hmm you know what

#

i was pinned to 0.3.2

#

and it works in 0.3.3

#

๐Ÿ˜†

#

sorry bout the time waste but it was helpful just to talk through it

vestal minnow
#

Hehe, I guess there was a quick patch for that then! I somehow don't remember that myself ๐Ÿ˜…

patent vigil
#

@vestal minnow do you have any idea what commit 0.3.3 was released from? Or any idea how I could figure it out? I cant find a tag for it or even a commit where the version was bumped to 0.3.3

vestal minnow
#

It was a cherry picked patch, not a specific commit
#crates message

patent vigil
#

hmm okay thank you

#

i think the way i was scheduling things in 0.3.2 might have introduced some problem because although the other issue was fixed i get a camera stutter and bumping on my player now

#

ill see if i can find the scheduling commit, thats the only thing that looks relevant on that release

vestal minnow
patent vigil
#

I thought maybe but reading the description makes me think its not because i dont think im adding any systems before the xpbd plugin.. actually let me check

#

it might actually be

vestal minnow
patent vigil
#

due to my plugin ordering

#

yeah i did notice that, will look into that also thank you

#

okay i dont think its the overwrite schedules thing, im adding the xpbd plugin before camera or any of the player stuff. so maybe two unrelated issues. Will look into it further

peak schooner
#

@vestal minnow sry for the @, but i was hoping you (or anyone else) could elaborate on the 0.4 release blog- specifically the Access Contact Impulses part. If I wanted to use these impulses to trigger some game mechanic (destructible objects, etc), how should I do that? I have a system that prints these impulses to console (just to test - to see typical values), but 99% of the impulses I see are 0.0, even when I'd expect non-zero (when a collision correctly registers between two colliders). It happens regardless of whether I use the Collisions resource or collision events to access Contacts.
I've noticed the caveat in the ContactData docs: "This will initially be zero after collision detection and will only be computed after constraint solving. It is recommended to access this before or after physics." I also see "The impulse is from a single substep. Each physics frame has SubstepCount substeps. Impulses in contact events like Collision currently use the impulse from the last substep."
I assume one of these two factors is the cause of my 0.0's - either my system has bad scheduling/run criteria, or maybe the 0.0 is only from the last substep? (Or neither - just bad implementation on my end - which is possible lol) I'll be honest - I don't really understand the consequences of the above caveats - like what schedule the system should use, or how I need to handle the substeps. I apologize if the answer is already posted somewhere - I couldn't find it. Likewise, it's possible the answer is complicated and not straight-forward. Don't need a perfect answer, just a bit of discussion. Thank you.

#

I also promise I won't post the question again lol

sleek thicket
#

and maybe an example where shapes are randomly spawned and then get funneled into places where they are crushed or smashed?

last panther
#

Hey @vestal minnow , do you know any good resources for impulse-based solvers? I checked the original thesis but it kinda got a bit too much into weird math and derivatives and stuff and didn't get around to actually saying how to solve the thing in the time I was seeing
I'm taking a look at the pgs and solver2d things; if there's any things about like optimizing that'd also be nice to know

vestal minnow
#

And then some papers, like substepping was introduced here (this uses XPBD but can be applied to impulse-based, like the TGS methods in Solver2D)

last panther
#

alright thanks for the second link

There's no real point in me doing substepping, and I don't have constraints, which helps a lot

vestal minnow
zenith tiger
#

When I add a collider to an entity, the entity's z translation drops from 0.0 to -4.0, putting it behind the rest of my world. Any idea what causes this and how to prevent it? Right now I'm just running a system to put the z back to 0.0, but that seems like a bandaid.

peak schooner
# vestal minnow Yeah the contact impulses do have some issues with this currently, but generall...

I appreciate the help - there's no rush.
Things I've noticed: if all I do is spawn/drop a (RigidBody::Dynamic) collider down onto flat, static surface, it will quickly give consistent, expected values for total_normal_impulse in Contacts with that entity.
But if instead, that entity has a GravityScale(0.0) and I bonk into it with another (GravityScale(0.0)) collider, that's where I sometimes only see 0.0s - very obvious collisions never showing a non-zero impulse. Sometimes I'll get non-zero values, but it's inconsistent.
Likewise, I also tested this by colliding into RigidBody::Static colliders - and again saw a lot of 0.0s with occasional non-zero impulses popping up. It's just really inconsistent.
Again, the problem could be with my code - I usually trust other people's code more than my own. So if I'm the only one w/ this issue, I'll assume the error is on my end. I also still believe it could be incorrect system scheduling or substep handling on my part.
Like I said, the caveats were placed in the ContactData docs for a reason, they seem important. I just need someone to explain it like I'm 5 or something. I am not a smart man.