#Avian Physics
1 messages ยท Page 13 of 1
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
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.
Do we have determinism on the same machine/architecture/build config at least?
"The desire to determine indeterminism fills you with determination"
Not perfect determinism (afaik bevy_rapier doesn't either, although there's been a PR to fix it for a long time)
rapier is a harder case to fix yourself because it's just a wrapper though
tbh I'm not that interested in using rapier, it's not bevy*-y* enough
rapier is deterministic, bevy_rapier isn't
I'd much rather help xpbd get to a better place
you're filled with determination to help xpbd โจ
It's a much better API imo
it's probably not easy making a wrapper though
you know enough about physics engines or should i link you to how it started?
I wrote one when I was in high school haha
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_colliderexample shows this decently, as different runs can have different results
So I know enough basic concepts and I've kept my math up to scratch
xpbd is a bit different though
So I'll probably be able to start off alright, but I'll be back here when I inevitably run into problems
the second one is easier to set up
I've been following the xpbd article linked in... Johan Helsing's blog, I think?
sick, thanks
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
yeah Johan has that tutorial series which bevy_xpbd originated from, but the main XPBD paper for rigid body sim is this
https://matthias-research.github.io/pages/publications/PBDBodies.pdf
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
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
๐ค is peck not in yet? xpbd's still on parry?
in the process, there's also barry
What's barry?
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
parry moved from nalgebra to glam/bevy math
input + normalization + delta might also affect it
Yeah it's my parry fork that uses bevy_math
I'm probably prioritizing bevy_peck though
what's the ideal goal btw, using bevy collision detection or having everything of your own with peck?
Build up features for peck and incrementally upstream them to Bevy (to the extent possible)
I mean I get the feeling that most/all of xpbd will be upstreamed eventually
most likely
I'd be surprised if this crate didn't end up as the de facto bevy physics solution
probably not with the XPBD solver but maybe
i'm just not sure if the current bevy collision detection is good enough for testing
it's just bounding volumes so not really
no contact data
feature gated? or is there a better one to use generally?
good opportunity for a shameless blog plug
https://joonaa.dev/blog/05/bevy-xpbd-0-4-0#solver-experiments
The 0.4 version of Bevy XPBD has been released!
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
yeah Bevy would like something with a clearer IP status (this has been stated by e.g. Alice too, and I agree)
I'm actually in the middle of that blog post, I guess I haven't gotten that far haha
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
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)
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
yeah maybe, if Bevy gets good enough modding support
i mean you know how modders "fixed" watch dogs to be similar to E3 demo at some point?
probably not, here's the comparison of E3 demo vs how it shipped
https://www.youtube.com/watch?v=sX4HTUuCy3k
Subscribe for more console and PC tech analysis: http://www.youtube.com/subscription_center?add_user=DigitalFoundry
Read our full analysis: http://www.eurogamer.net/articles/digitalfoundry-2014-was-there-really-a-watch-dogs-graphics-downgrade
yeah I was like 9 when that video dropped so I didn't even know about watch dogs ๐
thanks for making me feel old af ๐
mb lol
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
regarding this; I'll probably have collisions working in bevy_peck pretty soon (just need to implement EPA), so I could test with that
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
Johan's own version of bevy_xpbd is/was at least locally deterministic iirc
it's a stripped down version
bevy_xpbd_lite
bevy_xpbd_heavy? :>
a feature flag is probably better though
deterministic core and opt-out the rest
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
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...
Yeah, I'm going to dig in and see if I can figure out where it's breaking
I just got distracted watching that Erin Catto vid, it's incredible
TGS soft is the mvp
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
XPBD can do "hard constraints" where the constraint stiffness is basically infinite, which can reduce stretch for things like cloth; but then again, TGS soft seemed to be better even for that in Erin Catto's test
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
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.
it's just a 2d water sim though, i'm not even sure if physics are actually needed there
does anyone have experience using heightfield colliders in xpbd? I'm having some issues ๐
qq: if i set an rigid entity's visibility to hidden, then would that disable/pause the collision detection on it?
ok, looks like using CollisionLayers to disable the collision is the right way to go
update: still not sure what xpbd is expecting for input ๐ค but I was able to use Collider::from(parry::SharedShape::heightfield) and it works really niceley!
You don't like collider shapes like this? https://www.shadertoy.com/view/MlcBDj
The input is pretty much what the docs say, a list of heights, and the final size for the collider .. Using the parry shape gets you the same end result tho
do you know of any examples out there? the second parameter, scale was just moving the heightfield up and down the y axis
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
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
Real is just f32 or f64 depending on if you use the f32 of f64, same thing for xpbd's Vec<Scalar>
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
You can think of xpbd's scale like a cube that contains the heightfield
Then the heightfield values are for the relative height
ack I didn't mention I'm trying to work with a 2d heightfield if that changes things
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
it's the absence of that Vec2 in xpbd heightfield that's causing me the confustion ๐
Oh
Yea this seems a bit weird, it just does Vec2::splat(scale) and passes that along ... Which seems ... Wrong 
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 ๐
heightfield is just a mesh or is there something special about it?
Parry handles them a bit differently, probably a bit more efficient
Haven't looked into the details yet
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)
If I want the speed of a rigid body in unit/second (m/s), should I simply get the length of the LinearVelocity vector?
Yep
Yea pretty sure they are a bit more efficient, my old height map system performed a lot better than the voxel system after it, despite that voxel system having a much lower resolution
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
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?
Using where?
The reason is most likely that the direction should already be normalized so we don't want to do unnecessary normalisations
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...
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
yes, but i'm currently getting crashes without debug mode!
you mean, the debug drawer right
No, building in debug mode
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?
That rotates the direction which internally uses new_unchecked
i see.
so the result could be not normalized, thus causing the crash?
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
i see, thanks a lot!
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.
The rotation is normalized in the integrator in 3D at least. I believe 2D rotations don't have as much issues since I think the unit complex number representation makes sure it remains normalized
We should also check if this fixes the issue
https://github.com/Jondolf/bevy_xpbd/pull/344
It could be related
Because I'm pretty sure adding quaternions can result in unnormalized rotations
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`!
annoyingly I can't repro the crash in my examples, on main or on that PR :P
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
that could be useful, thanks
I've tried making a cube stack with shape casters fall but it's not crashing :P
my demo, for reference
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
you can find the project here: https://github.com/zwazel/crash-repro-shape-casters
i'm glad it doesn't only happen on my end xD
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,
));
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
I remember checking the margin on is_normalized when I was reviewing this, it's already fairly lenient, but if you let a fairly high amount of floating point errors stack up that are biased in one direction it'll still get there in a few hunderd iterations
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
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 ๐
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
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 ๐ค
yep
I think @sleek thicket suggested that
and also have the length in the error message
Wait ... Checking length_squared against 1e-4 is a threshold of 1e-8 right? 
maybe? I need to do the math on that
i just did that, and it works for the first few frames, after that it still crashes!
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
my brain isn't braining rn, but if you have a length of 1.0 + 1e-6, which is exactly at the threshold the docs say, then the squared length is roughly 1.0 + 2e-6, which means that the actual threshold for the squared length should be 2e-6
just putting this in a calculator
length = 1 + 10^(-6)
length^2 = 1.000002000001
Ah yea, when we consider the total number the value changes ... But then the margin for is_normalized is actually huge right now 
Tho the implementations might vary too
I guess I should make an issue about the threshold being wrong
Used some beautiful LaTeX there
yeah I get this too
Wait where'd you get this? The docs for Vec2 and Vec3 say it's 1e-4 in the repo at least
https://github.com/bitshifter/glam-rs/blob/1ea8163d0907f1ac876d1ec1d213f6add59d9ec0/src/f32/vec2.rs#L475-L483
Vec4
i'm pretty sure the jumping around isn't causing any issues, but them dropping from high up is causing issues.
no crash when spawned close to the ground, immediate crash when falling down
Normalizing rotations in the solver here fixes the crash, and I think it should also fix #235.
It feels a bit annoying having to normalize rotations for every constraint at each substep like this, but I think it's worth it for stability. The XPBD paper doesn't normalize there, but I've seen other implementations that do, like this one (although they're questioning if it's necessary, like me).
I'll probably make a PR to add the normalization
awesome, thank you!
Here's the PR. When you have time, could you check if you still get crashes?
https://github.com/Jondolf/bevy_xpbd/pull/345
no more crashes!
nice, I'll merge :)
awesome!
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)
common where? angular is useful for physics engine itself but i never touch it
For my game I need to know the velocity at a specific point of my rigid body, and that requires angular velocity
It's also required to apply forces at a point. in bevy_xpbd it's fine though since ExternalForce has both linear & angular parts. But if I want to know the torques on my object I have to add ExternalForce::torque & ExternalTorque (okay, maybe a niche use case)
yeah, i never touched externalforce either, what does it actually do that isn't covered by linear/angular velocity?
apply constant force?
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
unity has rigidbody.addforce(value, mode) that coveres it, seems like a more elegant solution than a separate component
yeah but you can't take mass or time into account there
mode does that
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
also if you want to visualize the total force with a gizmo it's nice to have access to a force component, rather than something that is applied instantly
you could make functions that take them as parameters though
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
so, what do you have to do if you need to apply force just once? (e.g. punch)
attach component to target?
An external angular impulse applied instantly to a dynamic rigid body.
But yeah I'm still open to this if people prefer it... I'm not sure if I like ExternalForce having a force property though, having to do force.force feels weird, but I guess you could get around this with derefs and helpers
Forces can be configured to be reset every frame
Using .with_persistence(false)
Or use impulses
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?
I don't understand, isn't this already how it is currently?
remove the component at 0?
whatever you do when persistence is false
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
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
but if there are multiple then how would you know which one to change
there's just one force property, the total external force
i.e. the sum of all the forces you've applied
do you just reduce it by the same amount when exiting gravity field?
you could do that yeah
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
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
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
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
yeah
if i think about externalforce same as unity's rigidbody it makes sense, just that why not everything in one place then
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)
yeah unity has 0 concerns for safety so it does whatever it wants
you could probably cache delta before processing all forces though
Technically, we could also apply forces with commands, but then you'd need to give the Entity every time
isn't delta always the same in fixedupdate anyway
You can configure it but yeah it's the same every frame typically
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
Is it possible to get vertices and indices back to modify the collider?
I see that I can create it this way:
https://docs.rs/bevy_xpbd_3d/latest/bevy_xpbd_3d/plugins/collision/struct.Collider.html#method.trimesh
But can I "take" them back, modify and reinsert?
A collider used for detecting collisions and generating contacts.
I think you can get the vertices and indices, but not mutably...
You can get the underlying dynamic Parry shape and cast it to a reference to the trimesh shape (assuming you know it's a trimesh)
let trimesh = collider.shape_scaled().as_trimesh().unwrap();
// do something with vertices
Thanks for the info!
So I can't modify them, only copy and create a new collider?
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
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?
(this is what Rapier does as well)
Sure, I know that it's parry-specific.
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
Makes sense.
Colliders as assets sounds interesting!
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
That would be so great!
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
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.
I was running into this same crash issue in my game and this PR fixed it ๐
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
you want the force to be pointing from the object to the target position, so it should be (parent_transform.translation() - object_transform.translation()).xy()
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
thanks looks like it works, but how can I make it "stronger"?
multiply it
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);
adding this kind of grabbing with gravity would be nice in move-marbles example
mm could be fun
LMB for LV, RMB for force
and "randomize" the mass, changing color based on it
How do I make an entity not be able to collide with a different entity?
i want to ignore a specific entity tho
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 ๐ค
there might be a better way to do it but we don't know enough about the intention
im making a explosive projectile weapon in an fps, i want to spawn the projectile inside the player, but then it collides with the player and explodes
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
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?
if not colliders, then what?
The most common thing for projectiles would be ray/shapecasts, since it has features like excluding entities and ignoring origin penetrations built in
using a raycast would make it hitscan, not a projectile
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
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
i dont see where the performance gain is
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
BVH?
Bounding Volume Hierarchy, it's what the spatial queries use to find things in the world
wait, if i use the raycasts, doesn't that mean 2 projectiles can't collide with each other?
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
alright
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
i have that, i just do a short shapecast forward to before spawning projectiles, which should be the tip of the weapon anyway but i never bothered adding rotations ๐คทโโ๏ธ
also preventing if it'd spawn inside environment
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?
same thing as the usual spring
sorry but what is spring?
oh, thanks
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?
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()
is it possible to get some feedback on this? ๐
That's much simpler than I expected! Thank you ๐
Is this using trimesh colliders?
looks like it
yeah, the ground is trimesh and the trucks are convex hull ๐ค
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
it makes some sense it's like.. hitting an edge
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
Ah found it, but this is slightly different since this seems to have multiple separate colliders and not trimeshes
#1142165587620007976 message
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 ๐)
@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/
Dealing with ghost collisions is a challenging problem in game physics. The basic idea comes from motion across a flat surface. You may have several shapes joined together to make a flat surface, like a triangle mesh in 3D or a chain of edges in 2D. Convex shapes can hit the internal connections and have their motion blocked. This is undesirable...
thanks! I may be diving into a fun adventure here. Hopefully I'll come back with a solution
nah it doesn't help, i tried it a couple days ago with spherecast checking dot of slope, >0.995 and it was still tripping
switching to raycast worked
switching to raycast? Are you saying you ran into this ghost tripping too?
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
so you just have a collider that hovers above the ground?
yep
^ check these out
duuuuuude, this is excellent ๐
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?
it scales collider but no idea about the rest
when raycasting, what's the ideal way to skip hidden entities? add my own logic/visibility-query based on RayHitData?
probably layers
Lmao bro its fun to watch
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());
are the ColliderAabb coordinates (min & max) local or global?
global
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?
thank you for helping me, now everything works almost as expected
hell no
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?
fn get_point_velocity(linear_velocity: Vec3, angular_velocity: Vec3, point: Vec3) -> Vec3 {
linear_velocity + angular_velocity.cross(point)
}
dang, math is cool after all
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
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
I'm making good progress, but just curious have you tried implementing the vehicle one before?
it's really similar to what i have because of anti-gravity
I think the thing I'm missing is that I need to track the wheel points of the car separately from the visual representation of the wheels
just don't do the visual representation until controller feels good
a hovercar represents the whole thing much better
yeah, I think that's about where I'm at.. just want the wheels to stay above ground which would make it look like a real suspension.. but yeah, I might just continue to the next part
yeah don't rush it, it'll be simple to add afterwards
it looks like car is floating on water
lmao its cool
anyone know of a collider-aware way to compute shortest paths?
that's called pathfinding
but considering how fast stuff changes i'm not sure if there's a good one that just works
i can imagine a system that updates a nav mesh every frame but im hoping for a less imaginary version
it's definitely possible, just not sure if we have it ๐คทโโ๏ธ
actually seems like we do
with last update literally 3 hours ago
nice ty! will look into this
Sometimes this community is awesome
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?
i have no idea, check examples?
i'm used to unity baking navmesh for me ๐
I didn't see any 3d examples. I did see this discussion thread: https://github.com/vleue/polyanya/discussions/17. Nothing about how to get the 2d mesh from a 3d scene though..
Are these 3D or more 2.5D?
looks 3d, i never tried it
Yeah but if 3D then the paths would just go over the obstacles?
try it and see?
I think the documentation probably makes it clear enough. Looks like it expects a navmesh as input
The "Integration with a physics engine" one looks promising! Any idea where I might find the source code for these examples? They don't seem to match the examples in the repo.
nope but i'm interested too @edgy light
it's from the interactive branch, you can find it here https://github.com/vleue/vleue_navigator/tree/interactive/examples/physics_xpbd with Bevy 0.11, I updated to Bevy 0.13 yesterday there https://github.com/vleue/vleue_navigator/pull/24
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
overlapping zones like bridges?
bridge where the same unit can go over and under
yeah, if that's an issue then it's pretty much 2d though
if I have a rigid body representing a car... what should I set its mass to?
you can project as a 2d navmesh
Thanks for your help! In build_navmesh, it seems like you use TriMesh::intersect_with_plane to do the projection. Am I understanding it correctly? I wonder if this would make sense as a library, otherwise I would basically just take this example and copy it.
Iโm not looking at the API right now, but youโd want to do a projection and not an intersection
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?
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
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
If your level is โflatโ then that would probably work
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
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
@carmine sluice i think francois' nav deserves a thread in crate-help ๐
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 :)
or at least separate #game-ai as in behaviour and navigation from AI as in ML ๐คทโโ๏ธ
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
i'll just delete my messages later ๐
nav discussion in xpbd seems off-topic too though
although they're both involved
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
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? 
it sounds like a normal thing to do though
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)
why would it be any different from applying full velocity though
Applying full velocity would be even worse here ๐
actually yeah, my dash just sets velocity so if there's a problem i wouldn't notice it
Maybe you could limit the y-velocity for the duration of the dash? Or something similar
although that seems kinda hacky, idk
and even though my movement adds velocity, i have a spring that would mean i wouldn't notice it ๐ค
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 
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
in unity i had an animation curve for dash, i should probably re-add it
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..
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 ๐ค
xpbd's external force is closest thing to unity rb, but doing it like unity doesn't sound ECS'y
yeah, it's definitely simple (and now forever burned into my mind) but it makes me wonder how some specific logic like that can be stored in a user-friendly way
i think just using that formula directly might be the best way
yeah
it's short enough to just not need an abstraction
If it was a more complex formula maybe custom query types or systemparams would make sense ๐ค
yeah, I have just inlined it.. but it just makes me wonder
functions just don't feel as comfortable to use as in unity, and i'm not entirely sure it's a bad thing
I agree generally.. I think this is the first time I've actually run into something that made me think otherwise
I released it way too early while I was mostly toying with it, I'm cleaning up everything to take a fresh start, I'll do a thread once I'm happier with it. Sorry Jondolf for the off-topic here!
@deep ingot or @sleek thicket don't hesitate to DM me about it for now!
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
I see, thanks. fyi my use case is putting physics objects into DynamicScenes
can it not be newtyped?
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" ๐
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
TypePath would be easy to implement manually I'd imagine ๐ค
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)
i meant to manually impl reflect instead of deriving
yeah that could maybe be possible, but I haven't worked enough with reflection to know what it needs
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,
)
}
Mainly because I didn't know that's a thing... Bevy's derives for it also seem pretty inconsistent, some reflected types have it and some don't
Could definitely be added tho
Usually if the type derives serialize/deserialize, it has #[reflect(Serialize, Deserialize)], just like how you put Resource/Component in there if you derive those
I'm pretty sure xpbd types also don't have any #[reflect(Component)] or #[reflect(Resource)] ๐
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)]
oh yea they do, misremembered
yeah we can add Bevy's Serialize/Deserialize behind serialize too
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) ๐
Would this be good for making a basic 3d platformer?
I definitely recommend checking out the #1110648523558506597 for this ๐ It's a great base, and the community is very helpful
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
Yea they would overlap, splitting them up doesn't bring you anything besides confusion in this case
@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? ๐ค
Yeah XPBD with a Gauss-Seidel solve handles one contact at a time, pushing the bodies each time, so in a case where a body hits a corner like this and has e.g. two contacts, it could end up bouncing to the side because one contact would push the body before the other has done anything. I don't see why it'd necessarily push the body upwards here though
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)
I think there's 2 contact points on each of the arcs, the lowest part where the capsule touches the arc, the highest part where it touches the arc, and then the same thing mirrored on the other one
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
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
to elaborate on the issue:
when you drop down a ledge when not facing it directly (turned about 45 degrees away from it), the player acts as if they have collided with the face below them, and so their velocity is affected accordingly, making it feel like they're being "pulled" along the edge of the collider as they fall
here's my repo
I couldn't reproduce this in my own test with a cylinder player dropping down a ledge, but I also have rotation locked. I don't see why turning the player away 45 degrees would change anything if it's a cylinder ๐ค
I can try your repo though
tyy
What's sark_grids? It seems to be a local dep
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
yup I'll do that
@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)
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
bevy_tnua (has xpbd support) and bevy_mod_wanderlust (doesn't have xpbd support yet) are prior art. They're both largely based on Very Very Valet
I haven't implemented one myself though so I don't know all the details
np, happy to help :)
5: using voxel grid/cell collision system. but i think i've already pestered @brisk shale enough about it ๐ฅฒ
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.
man if i have to read "papers" then its just not worth the effort i think
like
you mean academic papers, right?
#general message
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 :)
it's super simple though, tnua overcomplicates it
over- how? how does it overcomplicate it? i got it set up in minutes?
if ray down hit ground
do the spring ๐คทโโ๏ธ
okay sure i guess
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)); } }
Yes, these papers aren't super complicated and I usually don't read papers. There aren't a lot of good resources on "collide and slide" that I could find
this is something on the topic i remember looking at before
I mean yea that's correct but there's a lot of stuff that can complicate character controllers ... A lot of simple things, like taking ground velocity into account (for moving platforms), but it still ends up making a character controller a fair bit of work ... At least floating character controllers bypass some of the more finnicky stuff like steps and ground snapping
Collide and slide is also fairly easy tho. This video explains it fairly well: https://www.youtube.com/watch?v=YR6Q7dUz2uk
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?
@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
It isn't that simple if you want it to be robust, what happens when your raycast is on a ledge? Now your capsule will fall and hit the ground despite arguably still being grounded
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
is there an existing api i can use to compute the intersection of two aabbs?
yeah, in unity i made it stick not just to moving but also rotating platform correctly, i never ended up making either the moving nor rotating platforms though ๐ฅฒ
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
Haven't done this yet, but I believe you can use SAT to generate a manifold in one shot for at least convex polyhedra, or accumulate contact points over multiple frames (since GJK/EPA only gives one point), rejecting points that have moved enough or are too close together.
Erin Catto has slides on this: https://box2d.org/files/ErinCatto_ContactManifolds_GDC2007.pdf
Parry has contact manifold implementations here, using SAT for things like cuboids and other polyhedra
https://github.com/dimforge/parry/tree/master/src%2Fquery%2Fcontact_manifolds
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 
is there an efficient way to query for the ColliderAabbs that totally contain a given ColliderAabb?
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
oh! does intersections include containment? i thought it was just for aabbs with boundary contacts
let me try...
The method Nise is referring to is this
https://docs.rs/bevy_xpbd_3d/latest/bevy_xpbd_3d/plugins/spatial_query/struct.SpatialQuery.html#method.aabb_intersections_with_aabb
It just gets the entities of the AABBs that overlap the given AABB, but they aren't necessarily fully contained
A system parameter for performing spatial queries.
But you could get those overlapping AABBs manually and check for containment
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
If only ColliderAabb was just Aabb2d/3d and had the contains method 
i actually implemented my own contains. it would be a nice thing to have in the lib but maybe not "physics related enough"
Yeah, that just wouldn't work as nicely for f64 (using Aabb2d/3d)
oh, interesting. it's actually an f64 issue?
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
it works! tyvm for the suggestion
@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 ๐ค
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
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? 
Oh is this because I don't set_if_neq? ...
@vestal minnow https://github.com/Jondolf/bevy_xpbd/blob/main/src/plugins/sleeping.rs#L28-L29 Is the intended order that things below the sleeping threshold start sleeping, then immediately wake up because their position/rotation/velocity changed from before they were sleeping?
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)
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
Hmm, maybe there was some regression that triggers component changes every frame
I've also noticed that sleeping seems even buggier than before
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
Wait ... I run SyncPlugin 10 times per frame 
I just need position_to_transform if I never touch Transform right?
yeah I think so
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 ๐ค
Previous* ones potentially?
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?
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
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?
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
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
The "at least some" is accurate yea, sometimes you get accurate ones and it works fine, other times they become bound ... I should look up if there's any info about what exactly causes bound SDFs in those cases ๐ค
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...
If collision detection was purely binary it would be easy "Oh it collides with cube but not sphere"
Yeah no collision algorithms like GJK and EPA rely on convexity, and a lot of shape pairs also have optimized custom implementations (like ball-ball collisions). I'm also not sure how the resulting collider would be represented, I guess some tree of operations and shapes
A tree of operations and shapes? Where have I heard that before? ... Oh right ... https://github.com/NiseVoid/bevy_prototype_sdf/blob/main/src/lib.rs#L93-L94
Right. So, yeah, I'll just use a couple of/three triangles to model the corner colliders for now
(I definitely didn't get the idea from there ๐)
(I certainly don't have that tab open)
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
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.
And even then, the most fancy usecases NVIDIA shows off aren't physx but some unspecified SDF physics simulation for proprietaryTM uses ๐
GPU physics and collisions are also much more prone to bugs. With graphics, a single NaN value likely won't show up at all, but with physics it can propagate to potentially break the entire simulation.
So with graphics it's "easier" to make GPU things work fine
Bepu has a great article on this here:
https://www.bepuentertainment.com/blog/2019/1/16/-but-gpus-arent-always-the-right-choice
In the last post , the fictional Toilet Toilers Interactive found themselves in a bit of a pickle with their GPU physics-and-everything-else pipeline. They might be regretting some of their technical choices, but itโs worth looking back at some of the things they might have considered during develop
Ah cool, Iโll look this over
i use the same thing but in 3d as trimesh, figuring out how UV should work is a bigger problem than collider though
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
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
Fair enough. That said, I really like bevy_xpbd's api
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
Fixing sleeping issues helps with performance
yeah that should definitely be fixed
With taa or any form of temporal denoising NaNs have become super obvious in rendering because you watch your screen get slowly taken over by the void
Anyone know if I can get the debug plugin to not make multiple arrows because of rollback?
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?
If you mean whether it generalizes to higher dimensions, I'm not sure... two vectors only yield a unique cross product (with orthogonality) in 3D and 7D, but you can technically compute cross products in higher dimensions too with determinants if you have n - 1 vectors, like 3 vectors in 4D. I don't see how that would apply to point velocity though
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
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?
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?
Should be the closest one
Yeah I just found there's a if self.max_hits == 1 { [...] traverse_best_first() [...] }, should be ok
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)
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.
Look at my contextually clearing gizmos pr
Should be getting merged soon
I don't think that would help since afaict debug gizmos run in PostUpdate, not in my simulation schedule ๐ค
Can you make sure this is in the 0.14 milestone please?
Sorry for procrastinating it lol
Ya! no worries, It isn't super urgent
You request the gizmos to be drawn in your simulation schedule though right?
They're xpbd's debug gizmos which run in PostUpdate by default, but the schedule can be changed
Nope, it runs in PostUpdate, it just draws all contacts that happened during the frame
Which is why I get 1 AABB, but 4 arrows (there's 3 resimulations + 1 new tick)
I see
Is it gathering contacts from multiple substeps or something?
I guess that wouldn't make too much sense since that'd duplicate
hmm
@cinder summit would need some way to clear the EventReader for collisions here I think https://github.com/Jondolf/bevy_xpbd/blob/c207fd4c8ebf7a68db6d72c26e7863761954a438/src/plugins/debug/mod.rs#L309
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
I already have performance issues, I doubt drawing gizmos only to discard them would make sense
I mean the xpbd debug gizmos plugin
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? 
Hmmm ... I guess I'll just insert a system that drains these events after the simulation runs for resimulations ๐ค
If you're running the entire physics schedule 4 times then it'll also run things like the broad phase 4 times
With 1 sim and 12 substeps it'd only run once per tick
The broad phase actually doesn't seem to make up a meaningful chunk of the time spent 
The bigger thing here is rebuilding the BVH ... I could probably do a whole extra simulation without it ๐
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
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?
If you just want the closest point on the nearest surface, you could use project_point
A system parameter for performing spatial queries.
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
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
Yep
Yea raycasts work very poorly, sphere shapecasts should be a relatively cheap improvement
How would I make the most simple possible platformer?
They have an example platformer but it is stuffed full of extra features.
define most simple
The most basic functionality.
Without extra features.
Purity much.
add dynamic rigidbody, linearvelocity and collider
add system to add/set linearvelocity .0 or y in your desired vector
The examples that I found have to much going on.
yeah i did suggest splitting it into multiple levels of complexity but idk what happened to that
I even want to use debug to see what is going on at the beginning.
PhysicsDebugPlugin::default(),
Are there docs for this?
for a suggestion? wat
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
Working on it.
@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
Like, move the input systems to some common module that examples can use?
yeah
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
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
Should I use dynamic or kinematic?
start with dynamic and decide if you need to switch to kinematic once you really know what you're doing
Hey guys, is there an easy way to visualize the colliders for debugging? ๐ค
PhysicsDebugPlugin::default(),
We use kinematic in Godot.
I'm also considering making the PhysicsDebugPlugin have more useful dev functionality like pause/unpause, step, change time scale, change gravity, etc. if/when Bevy adds the dev tool abstraction stuff
I think more physics debug tools could be useful for users too, not just examples (or me)
I don't think so
there are a lot of them
there are some samples here at least
https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/PhysicsSamples/README.md
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 ๐
Physics is fun to play with in Unity, but what about Physics AND Slow Motion?! Having the power to slow down time in a sandbox game is magnificent. In this particular video, we showcase how we can manipulate time in Unity using timeScale and how to modify it via code!
Watch longer training session & download the project:
https://on.unity.com/3g...
oh found it
it basically does most of the stuff you mentioned
it'd be a really cool example for collider shapes too
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
commands.spawn((RigidBody::Dynamic, Collider::circle(0.5)));```How does it know where to put the objects?
Hm do you guys know if there are there any special requirements for Collider::trimesh_from_mesh() ? ๐ค
They're at the origin by default, but you can position them with transforms just like meshes in Bevy. Add TransformBundle
iirc pbr/spritebundle has transform too
Yup, if you have that then you should change the transform property there
I don't think there are necessarily "requirements" other than that the mesh has vertices and indices
Hm cause this mesh doesn't seem to work as a whole
But as soon as I split it some more, it does work ๐ค
That looks like it doesn't have actual triangles? Idk
Or is that just blender showing the outline?
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_configmethod that allows some extra pre-processing if you want that
Doesn't necessarily relate to your issue tho
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
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
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
directly set it instead of using ExternalForce/Impulse?
like, vel += accel * time.delta_seconds()
right, that was mostly pseudocode
If you don't want to overwrite it you'd usually use external force/impulse
i kinda liked the impulse method because it takes the mass into account
Nope, but having one system add an impulse while another resets velocity would create system ordering issues
hmm, yeah, that could impact collision
No, but your code might reset it for whatever reason
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
As for External Impulse vs Force ... I'm not actually sure what the difference between them is ๐
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
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.
That's what it should do, that's not how these types work in xbpd tho ๐
yeah the persistence bit was causing infinite acceleration
Being able to make a persistent impulse feels kinda wrong tbh ๐
How do they behave in terms of substeps? ๐ค
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
Forces are applied over multiple substeps, impulses just once before the substepping loop
(currently)
IIRC I compared the results with PhysX/Unity to make sure it looks correct
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
yeah but just applying the same force/impulse for a body at the same position with the same mass
Hmmm ... I guess that means my movement probably needs to be a non-persistent force and not an impulse then
@cinder summit that's what i'm thinking too
You could make the force non-persistent and have a system apply the rocket force every frame
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 
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
i'm having a hard time picturing a oneshot force now for some reason. if i send a 1 frame oneshot force, what happens
yep
i can see it in the "throttle" case where you say "engines on, externalForce = accel", and then "engines off, externalForce = 0",
It just applies F newtons of force, causing acceleration for that frame, like irl
isnt that an impulse then, with variable frame timing?
functionally
not physically
Different unit so the same value will have a slightly different impact
that seems like more of a footgun then
or, it would need a bunch of docs about "when to choose which"
I mean we kind of already need those ๐
yeah this would just make it worse! ๐
We already have non-persistent forces tho ๐
Well impulses physically have a different unit than forces so it's kinda expected. Basically all physics engines have both non-persistent forces and impulses.
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
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
so a normal rocket uses persistent force, one of those mass-driver rockets where you detonate nukes behind a pusher plate uses impulses
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
arent you basically just clobbering it every time you write to externalforce anyway though?
Not sure if I want like 3 different force components
Ideally you can't "set" it because now you can't apply forces in any other systems
And that wouldn't be very ECSey ๐
Also forces can cause torque, which should account for all the external forces
(when applied offset relative to the center of mass)
hmm it looks like rapier doesn't even have non-persistent. Nothing about persistence, docs say the force is applied each timestep
In Rapier, force = persistent and impulse = non-persistent always (but different units ofc)
But non-persistent forces exist in Unity/PhysX and Godot, for example
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
actually I'm wrong, apply_force will basically combine all the force vectors of other systems, so it will work out
One example use-case: You have magnets that apply forces to bodies in a given range. There can be multiple magnets affecting the same body. You need to accumulate the forces, and clear them later.
MagnetConstraint 
wouldn't that be persistent, but call clear() when the magnets go away?
For magnets, the strength of the magnetic field depends on the distance
So you need to update it every frame anyway
ah
Same for orbit simulations
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"
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
Events and commands can also both perform a lot worse if you already need to access the entity in question anyway
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
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
You can use SpatialQuery directly
ah nice, perfect
Something like movement_event.send(MovementAction::Move(dir)) would be an action though, and then the reader of that can change the properties of the body to move it
A system parameter for performing spatial queries.
The more I use bevy the less I use events, they're pretty much only relevant for things that happen occasionally ... Like a player dying, the window getting resized, settings getting changed, etc
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
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
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
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
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
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
Seems to happen when 2 raycasters are in the same location.
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?
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 ๐ค
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
I don't really have high angular velocity. I'm going to start a thread in help so I don't spam here.
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.
If this is angular velocity related, I would be happy to clamp it under some acceptable value if I knew what it was. Do you know what values are acceptable?
No clue, I've only had it once myself and it was on a sphere that was spinning very fast ... If it's this bug you can probably just pull main and it would disappear ... If it's still there on main it would be unrelated
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.
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
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
Cause it's missing a &
Slaps his head sounds
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,
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.
```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.```
There's probably a constructor you can use. ExternalForce::new() or something similar
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)
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)
hmm docs say its updated automatically, does that mean it would get overwritten?
Did you only add Transform?
transformbundle yes
Yeah GlobalTransform is needed too, but TransformBundle should have that...
It should get updated using Transform/GlobalTransform, but if you don't have that on there I think it will just leave it unchanged
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)
ColliderTransfom should be added automatically
It might be a bug that's fixed in 0.4 ... There's a lot of commits between 0.3 and 0.4 after all ๐
but the transform bit works as expected if it has a rigidbody
and not if it doesnt
with no other changes
Could you show how you currently spawn the player and child collider?
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
yeah the code looks like it should be fine
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
Hmm, interesting
so is it not expected that a child collider without rigidbody would not respect its transform?
A child collider should work with local transforms yeah
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?
yeah the child should work without RigidBody
yeah it's working for me at least (right cube is child of left)
no rigidbody on the child?
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),
));
});
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 :(
Could technically be some scheduling issue too since you have a custom schedule, but I doubt it
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
Hehe, I guess there was a quick patch for that then! I somehow don't remember that myself ๐
@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
It was a cherry picked patch, not a specific commit
#crates message
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
could be this?
https://github.com/Jondolf/bevy_xpbd/pull/236
Objective
If user systems were added to any of the physics schedules (e.g. PostProcessCollisions) before PhysicsPlugins are added, the schedules would be replaced when adding PhysicsPlugins, effect...
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
didn't check if you have this already but the general way to fix camera stutter is here
https://docs.rs/bevy_xpbd_3d/latest/bevy_xpbd_3d/#why-does-my-camera-following-jitter
Bevy XPBD
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
@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
and maybe an example where shapes are randomly spawned and then get funneled into places where they are crushed or smashed?
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
Haven't found / looked for too many yet, but
- Erin Catto's slides https://box2d.org/files/ErinCatto_SequentialImpulses_GDC2006.pdf (and some other publications on the website)
- This tutorial series https://allenchou.net/2013/12/game-physics-resolution-contact-constraints/
- Existing engines, like Box2D, Rapier, and Bepu
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)
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
Yeah the contact impulses do have some issues with this currently, but generally it should work decently (e.g. the debug gizmos can render contact impulses). Weird if you're seeing so much 0.0; I'll look into it more tomorrow
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.
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.