#Avian Physics
1 messages Β· Page 5 of 1
π
I think there's a theory here that makes a lot of sense tho
What if ... They patented it to stop patent trolls? 
NVIDIA gets hit by patent trolls pretty often, they always win but I'd imagine it's still a net cost to them because it wastes a lot of time
Also who the hell are these patent trolls that think it's a good idea to go after multi-billion dollar companies?
the bigger the company, the bigger the potential bank you can make - and the further you can go into debt if it fails, like it probably will
also aren't big lawsuits just a USA thing?
Not just the USA, I see it happen on korean companies from time to time too
yeah but in the EU you just can't sue someone for 10 million euro randomly
They also improved things in the USA, for copyright you now need to have a solid case before starting a case about fair use or you're forced to have to compensate the other side when you lose immediately
Those changes haven't happened on patents yet tho I think ... Patent law in the USA is a fucking joke
I mean patents generally don't even serve an actual purpose so it's not surprising the law is a joke
I'm going to patent ECS-based game engines made in Rust, surely that'll work π
You'd probably get the patent granted at least
But if you try to sue anyone you'd lose
Actually I think "made in Rust" might make it impossible to patent
But yea a patent for ECS-based physics is probably possible, even if unity already has it in their engine
"ECS game engine using a novel parallel executor"
I mean now we're getting close to something that actually sounds like a new idea π
"ECS-based physics integrated into a game engine"
ECS-based physics with modular collision detection, written on top of a novel parallel executor
Patent a BVH that becomes corrupted when you update it, then sue seb 
"ECS-based SDF physics"
Then sue nvidia because their GPU SDF physics uses arrays to store data and that's just ECS
- Sue nvidia
- Seize all their assets
- Take ownership of the company
- Opensource the XPBD patent and anything related to SDFs
- Sell the shares back to the original owners

Hostile sdf physics takeover
Watch them announce their plans to stop supporting SDF physics tomorrow π
Sure would be a setback to my plans of making SDFs dominate the world 
also how do they distinguish simulation methods? like the patent mentions using a Gauss-Seidel solver, but what if I made a minor tweak and called it a Gauss-Seigal solver
I mean they describe XPBD as a "small addition to PBD"
And now it's a different simulation method
If you change that small addition partially because there's mistakes in the paper you could call it JondolfPBD 
Especially in that it still has the PBD part that's easy to mix up
Meanwhile NVIDIA: "Initials are JA, interesting" takes notes π
||It is public on my GitHub, commit history and website though||
I'm having some weird behaviour with the trimesh colliders. I have four walls which each are a trapezoidal trimesh. It seems the wall on the left and bottom allow my player object to phase through the inner edge on only half of one the triangle edges. Could it just be a CW vs CCW thing?
I don't think I had thi issue using rapier
I also had some trimesh collider issues before switching to SDF collisions, some change on main might've introduced some issues with 0 thickness colliders
What do you mean by 0 thickness? The collider for the walls have width.
Trimesh colliders have no volume, it's just the outside surface
Oh ok
It's hard to say, but you could maybe try using trimesh flags for preprocessing them, like this
Collider::trimesh_with_config(Vec<...>, Vec<...>, TriMeshFlags::ALL),
I haven't really seen them do much though
It definitely could be a CW/CCW thing too, I believe Parry requires CCW for triangles
(Parry is the collision detection library used by both Rapier and bevy_xpbd)
Yeah, that's probably it, since it's only affecting the left and bottom walls
Also what's the scale here? How big are the walls and the player? (roughly)
I set the camera's orthographic projection to baically set a square -1 to 1 scale in the window
Which I assume is why the debug renderer is going weird
yeah that's what I was thinking, the debug renderer assumes pixels in 2D currently
logic
ah I bumped something and that typed out for some reason
I haven't really tested the engine in this kind of small 2D scale before so I don't know if it could also have numerical issues, the examples just use default cameras and normal pixels (in the future, something like rapier's physics scale will be added though)
although generally numerical precision should be better near 1
so I don't think it should be an issue in your case
I tested it and it most certainly is because of it needing to be CCW, annoyingly trying to apply a negative scale to flip the object also trips up the CCW direction. I guess I just have to remake the collider when flipping it though which isn't too bad.
I'm walking into the middle of a discussion so I'm probably going to say something dumb, but could you rotate it on the y-axis to turn it around? I guess in bevy 2d maybe that's not an option?
I've definitely done that in other game engines instead of using a flip
But in those, you did 2d as a subset of 3d
yeah you can't really do that in pure 2d
since rotation is just an angle in radians
you'd have to simulate 2D with bevy_xpbd_3d, which might be possible using LockedAxes, but inconvenient
bevy 3d apparently won't render sprites
You'd have to do your own quad + texture solution
Sorry, typo there.
it looks like trimeshes have a reverse method that seems to flip the orientation, not a 100% sure what it does exactly though
you could do collider.shape_scaled().as_trimesh().unwrap().reverse() maybe
The shaped_scaled and as_trimesh work with immutable values though
reverse() mutates the trimesh in place
hmm, I could've sworn I added a mutable version π€ doesn't look like it though
you can get a copy of the shape, mutate that, and create a new collider
using Collider::from(my_shiny_new_shape)
Ok I'll try that, but do I need to use shape_scaled instead of just shape though? I'm applying the transform via the component not through the shape itself.
yeah just shape
Wait, the SharedShape stores the trimesh with an Arc, so I think you're supposed to downcast to a trimesh Arc then grab mutability from the Arc?
I don't know, when I try to clone the trimesh, it's throwing me a different generic type, it's too confusing.
yeah the Arcs and generics in Parry are quite annoying
I guess you can just create a new collider from the vertices and indices, but reverse it
Parry's reverse for 2D is just this apparently
self.indices.iter_mut().for_each(|idx| idx.swap(0, 1));
Yeah, since the triangle has 3 points just swapping two indices is sufficient to change the CW/CCW direction
I think you can do the reverse() thing if you had a shape_mut method since you could downcast_mut::<TriMesh> from there
yeah I think I had shape_mut but it's gone for some reason now, I'll add it back soon though
I'm not really sure how to detect if the triangles in my trimesh are CW or CCW because I'm just generating the mesh from the two points the wall is supposed to span across and the inset normal.
I'm curious on whether kinematic or dynamic body based controllers are faster
my intuition says dynamic, but I'm not sure
Depends on what you're doing with either. Dynamic bodies are pretty likely to be faster tho, since you can benefit from the physics engine's optimizations for collision response stuff
what optimizations :p
Yeah that is what I'm thinking, also a fully featured kinematic will probably have to reimplement most responses themselves
Oh, I can probably just check the direction of the corners then the inset normal coming off the center and depending on whether those are CW or CCW use different indices.
kinematic bodies don't require a velocity solve unless done manually
(friction + restitution)
I suppose my thing with the controllers would be it'd be fully robust in each
Yea and they're pretty likely to all be systems that do this for a very small number of entities, so the relative overhead is huge. And it gets worse if you do something like rapier's KCC with tons of shapecasts
Idk if there is a non shapecast kcc that is robust
Unless it's like
Dot colliders
maybe I'm wrong though
the kcc example in the repo just does naive collision response without shapecasts
probably not super robust tho
and doesn't handle stairs etc.
You can make a fairly robust one with a small number of shapecasts
But it's still more shapecasts than a floating dynamic controller for example
You can also just replace those shapecasts with sphere casts on SDFs and reduce the worst case cost of it by a lot 
Why were you wondering about that? You running into any character controller performance issues? π€
Naw just a curiousity
I'm making a moba with xpbd probably and going to do a kinematics one this time
mostly for complete control
As long as you don't have trimesh colliders you're probably going to be fine
And if you do you can always switch to sdf physics later π
I was able to fix my trimesh collider issues by ensuring the vertice were CCW
Nice :)
I wonder if rapier does something to fix them automatically if it was working there... last I checked, I don't think it did, but I don't remember
Great now I have one more reason to hate trimesh colliders
lmao
Right after not being SDFs and having garbage performance 
Well, even with xpbd there was only phasing issues on half of one of the triangle's edges, so it's entirely possible I just didn't happen to notice when using rapier.
Sleep before I make you (not a threat, unless you make it one ;)
I believe it's a political science XD
Well I guess macro is more political science and micro is more just social science?
in the US damages are trebled if you knowingly violated the patent
which is why most companies discourage you from looking at patents
and if the paper/code was MIT then it didn't include any patent grants
which is why the rust ecosystem generally does mit+apache2 for foss stuff
and it doesn't matter if you're right or wrong, because I'm 99% sure you don't have enough money to fight it in court
Why are you randomly talking about licensing and patents?
Was an earlier topic
NVIDIA has patents for something they opensourced about 2 years before they patented it, which makes absolutely no sense
can't really patent something if it's effectively in the public domain
That 2 years things makes the patent invalid, and opensourcing things with patent rights is generally a hard to win fight that's mostly just used for patent trolling
yeah
you're probably fine, but I don't think it could be upstreamed without an explicit approval from nvidia
can't use some of their rendering stuff cuz of bad licenses/patents
Especially since cart (and thus the bevy organization) isn in the USA and not the EU
Fun thing is when AMD copies their patented tech and opensources it
software patents are generally a lot more tightly scoped
in theory
and amd has lawyers and money to fight bad patents
Yea I'm pretty sure AMD makes sure it won't get them in trouble first
NVIDIA never releases good info on the stuff either so AMD has to tank almost the full R&D costs for it too π€
Yeah this is something that would have to be eventually verified somehow
*if we were to upstream some day far in the future
I'll have to go in the lab and invent something novel then
then get an internship at nvidia and publish it through them, and end up with it patented by nvidia
π
feel free to banish me from the community if I do that
But if jondolf betrays the community, who will make our physics?
Where are we gonna find another highschooler than knows physics and rust
I'm not some physics genius, just read a few papers and generally value high quality docs, presentation, modularity etc.
I feel like a good readme goes a long way lmao
I'm a highschool graduate that knows rudementary physics and rust, I could take over with my qualifications from reddit
I mean we have like 3 people in the bevy community that value docs this much π
Alice ofc, who's the 3rd one?
That's a secret, can't reveal the results of the documentation competition yet π
Actually I think no one besides you and alice would do the cfg docs thing
I excelled a lot as a teen, that's where most of my passion for it came from
I'm 24 now
At first I was surprised, but once I started working on the SDF collisions it seemed a lot more normal to me
You just start working on something that's an infinite rabbit hole and you never get out
bevy_sdf and bevy_physics will surely be the next two bevy crates 
We need to at least beat bevy_editor right
bevy_geometry for the shape primitives too
Eh, sdfs are good enough for primitives
Use them for rendering
Would be cool if we could mix SDFs and mesh colliders with primitives
Both can interact with primitives, and most of the primitives are the same
Tho some primitives might be easier with one over the other
Then have unified spatial queries that work with the same API against meshes, colliders and SDFs
I'm plotting to make torus-arbitrary sdf collisions work 
If all spatial queries are done with primitives it would be fairly doable actually
I mean I don't think there's any valid cases for shapecasting those
Shapecasts run poor enough without that π
Ah yea, you could just use regular polygon collisions between primitives and trimeshes and convex hulls
And sdf collisions for primitives on sdfs
But yeah definitely before the editor, surely
I'm a beast on summer vacation, and next year it'll be extended since I won't have pretty much any school after March
until fall
can you have a crate depend on a previous version of itself
just make each new release of xpbd have only 1 feature
and depend on the previous versions for old features
for the most nightmarish cargo update experience
Hmm, apparently Query<&mut Collider> and SpatialQuery don't play ball in the same system, which makes sense, but I guess if I'm just setting it to a new one I might be able to use commands.insert for the time being
I can already imagine someone linking a rust blog post about it and being confused π
Why would you use SpatialQuery in a system to reverse the triangles? π€
Because I want to apply a negative scale when the object is clicked
And the negative scale means I have to reverse the orientation to keep the points ccw
Ah, yea commands is probably gonna be the easiest there. Or maybe you can do some tricks with a SystemParam
Uh, so I think a new CollisionStarted event is being created when moving an object within a sensor despite the object never leaving the sensor, is that a bug? π
I think Jondolf mentioned there was a big like that earlier
Well, that kind of sucks, I guess I can hack around it for now
Unless it ends up spamming CollisionEnded events too
Oh damn, I didn't realise this guy made Yew too, impressive
Oh no, it's just a ite that use yew, I'm stupid and can't read
Oh does it
I guess just screw sensors then
honestly don't even know why that other guy was even die harding this library at this point
Can't really have another collision start if it never considered it to have ended right? π€
yeah
Kind of a weird bug though
I always use CollidingEntities so I never ran into this issue, tho I have had some issues with it not getting cleared before, tho it works fine atm
I mean like, logically it would have to be considered interesecting and not intersecting at the same time for it to happen right?
I think it might be related to the substeps, if there's say 12 substeps it might be considered touching for 10 steps then not for 2, and then it would give you both
Oh, good point
With sensors that wouldn't happen as much, but with regular collisions the whole goal is to stop them from colliding
That can't be true, I'm looking at the code and the collision reporting is based on whether the collision started/ended in a frame rather than a substep.
That does sound like a bug.
Huh, apparently my bevy_xpbd version is behind as of 7 hours ago, I guess I could pull the new version just to see if that fixes anything
Well, upgrading the package made my application completely unusable
It could be related the scale I'm using, so I'll try changing that
Ok so I had an issue with collision events being spammed when dealing with sensors
Then I updated from 0.3.0 to 0.3.1 and immediately the scale I was working at stopped being stable, so I just multiplied all the numbers by one thousand, became stable again, and now the collision event spam seems even worse.
pain
#1124043933886976171 message
I think it's this issue
For now you could just work around it by storing the entities that are colliding with the sensor in a component, then when CollidingEntities changes seeing what got added/remove and doing something on those π€
Yeah my guess for the event spam is that the scale doesn't work nicely. The narrow phase prediction depth assumes you're using unscaled pixels by default, and it acts kinda like a padding around your colliders for making sure it doesn't miss collisions, but in your case that padding was way too big because of the scale.
I would've assumed that multiplying the scale of everything expect the prediction depth by 100 would work, but weird if it doesn't
I got the server ghost stuff to work. Seems like a simple thing, it was a little finicky doing the JavaScript -> WASM communication. But now you can post your time and decide if you want to race a different player. This is coming along relatively nicely.
The ghost replay stuff is super naive and sometimes the ghost is a lot faster. This is not related to the physics engine, this is all on me.
Sorry, what I was trying to say is that the update went well. Only thing that doesn't seem to work is the asset server in Bevy 0.12 for web.
I multiplied all the scalar values I was working with and it still has issues resending events when moving during contact with a sensor
It seems it specifically resends the CollisionStart event when the entity starts to move again while contacting the sensor
Hmm, yeah when entity stopped moving it sent a CollisionEnd event and when it started moving again got a CollisionStart event
Is it sending them constantly, or only when you've been still for a while and then start moving?
It seems to be when you immediately stop and start moving it sends the respective end and start event
Which I guess might be why it's only an issue with sensors, because otherwise the contact forces would ensure movement until the collision is over.
@vestal minnow Could the entity overlap warning print the Name of the entity in addition to the id? That'd make debugging a lot easier!
I can probably work on a patch to add that this evening....
This seems weird
// Reset collision states if either of the bodies is active (not static or sleeping)
// Otherwise, the bodies are still in contact.
if active1 || active2 {
println!("test");
contacts.during_previous_frame = true;
contacts.during_current_frame = false;
contacts.during_current_substep = false;
} else {
contacts.during_previous_frame = true;
contacts.during_current_frame = true;
}
start
test
test
test
test
test
test
test
test
test
end
It seems like it's making more than one "contact" for the collision, is this supposed to happen?
It seems to increase the number of contacts as I move the entity during the collision
When you're collecting the collisions I notice you're doing this
collisions.extend(new_collisions);
I think it may be possible you're just not flushing the contacts properly?
This is just what I'm gathering after skimming through things, could be wrong
Depending on the shapes of the colliders you could have multiple contacts, is the event code not handling that properly?
Would be easy enough to test by changing the collider I guess π€
Well, the contacts are stored in the Res<Collisions> which the contact reporter iterates over to create the events, so if there is supposed to be multiple contacts per collision then I don't think so, but I could test it
Multiple contacts being possible is new since 0.3, right @vestal minnow? Maybe the event code wasn't updated at that time
I'm not sure when manifolds got added, but multiple contacts were always possible I think. But that code has been changed a few times, I've seen issues with CollidingEntities not being correct at least twice, and I think that uses similar logic
Hmm, yeah I think this hypothesis was wrong, it seems like it only has one "contact" object for the collision
Ok so, the contacts were reset, got 12 substeps, then the contacts were reset again with no new contacts generated
start
reset
contact generated
contact generated
contact generated
contact generated
contact generated
contact generated
contact generated
contact generated
contact generated
contact generated
contact generated
contact generated
reset
end
Since it sends the end event when the entity stops moving it seems it has to be related to the sleep condition? Perhaps it's going to sleep too late?
multiple contact points per collision is new yeah, but the events aren't based on single contacts but rather the whole Contacts struct which contains all contacts for a given collision pair
this is why I was wondering about if you were still for a long time and then started moving, the bodies go to sleep if they're still for long enough
which could maybe cause buggy collision events
although I did test it some time ago and it worked... maybe something broke it again
you could try with SleepingDisabled component to see if it's sleeping related
and yeah the collision state logic is kinda weird currently, that function has a todo for that lmao
I struggled quite a lot to even get it working as well as it does
I plan on reworking it though, could at least have a CollisionStatus enum or something instead of the 3 separate bools
I added it to both entities involved and it still had the issue, which is weird since it is directly correlated with when the entity stops/starts moving
Thanks, that'd be useful
I think I found the issue! in the broad phase you're setting the AABBs as "inactive" when the position and rotation hasn't changed, then because of that when you're creating the broad collision pairs you're ignoring all of the AABBs that haven't moved. This doesn't involve the sleeping component at all. So when at the narrow phase you're going through the broad collision pairs you're not inserting the new Contact after the reset saying the collision is still hapenning.
start
inactive
inactive
inactive
inactive
inactive
end
I hope this is right
Ah, thanks for looking into it! There was some reason it uses the changed status for position and rotation, but I can see why that could cause issues
it can probably be changed back to use Sleeping, just need to verify it doesn't break other things
do you happen to have a simple repro of the issue? I could use that for testing things
if not, I can make one too
Not currently, but it should be simple enough to make a minimal example, just need to check collision events with a sensor.
I'm getting a lot less explody behavior with 0.3.x, but still some weirdness. This is in 3D, and I'm finding that if I insert space between my joints (that is, attach the rigid bodies not at their nominal surfaces, but a tiny bit apart), I get pretty good behavior, but if I make the joints actually exactly aligned, I get weirdness.
I haven't tested exactly, but it seems like a space of 1/64 keeps the different parts from colliding. With 1/128 or smaller, I still get good behavior -- and I also see collisions (cyan debug is on).
If I go to 1/1024, though, I get occasional explosions.
Is this floating point precision issues, or something else?
could be
I wonder if switching around the constraint order would help though π€ handle joints first, then collisions
I can test if I can repro
which joint is this?
They're all revolute joints
one of them was supposed to be a spherical joint but that didn't work right for some reason
and actually I couldn't get fixed joints to behave either, but I need to revisit
revolute joints are working with 0 distance between surfaces for me
tried different rotations too
They work, but then sometimes all of the sudden there's an explosion (as I'm moving the composite character around)
or also (not investigated yet) it seems like angular force gets compounded (force without persistence -- haven't switched to impulse) and the thing starts spinning like a top and then eventually vanishes. but this only happens when they're touching or close
spinning works too
I'll have to double-check that I haven't got some logic error, but it also seems that I have to start the rigidbodies with a separation of at least 0.01 to avoid having them considered overlapping
I've gotta go get lunch but I'll poke at it more and send examples later this evening or this week
I have to fix my camera, too -- I never got that ported from rapier properly π
this is related to this #1124043933886976171 message, prediction distance is 0.01 by default in 3D
and yes they are dynamic, I just disabled gravity
there was no overlap warning prior to 0.3
but I assume it's visible otherwise
yeah
Here's what I'm seeing. My "robot" is connected by revolute joints, with the "foot" sphere aligned to the X axis and with .with_angle_limits(-PI / 32., PI / 32.) -- I had used a fixed joint here and that was totally not working for some reason I've forgotten. The head is attached to the body aligned to the X axis, so it can turn (with limits at Β± pi/2). If the D key is pressed on any frame, it sets torque to -- well, I think it's pi, for some reason, but whatever, "some smallish number". When the D key is released, it sets force to 0.
With a space of 1/256 added between the joints, I get what I expect (and roughly what I had with rapier). (This is me just holding down the D key for 20 seconds or so)
for me it's working even if I apply a ricochet type velocity
if raycaster has max_hits = 1, then yes they should be
(Oh also note that in all of my examples I am starting with everything pushed away by .0101 so they aren't immediately overlapping. Physics is off at the beginning, and when I enable it, the joints pull everything together
Isn't there some ordered vs unordered thing here?
Also whats with people getting explosions with things overlapping? I spawn enemies in my walls and they just stay there π
max_hits = 1 uses best-first search and finds closest hit, others use depth-first search and can be unordered yeah
and cast_ray is basically max_hits = 1
Ah ... gotta love them edge cases
My SdfSpatialQuery just has ray_hits, it's never ordered, so if you want 1 thing you just store the best result π
It's honestly not even that annoying, since very often you need to do some extra checks because the collision layer is a bit too broad for the logic (like a combat layer instead of a Player and Enemy layer)
Distinguishing between those would be bad practice anyway, cause there's also PvP 
I also noticed that the overlap warnings are also wrong since they rely on the prediction distance too
so it's triggered unnecessarily
I can fix that very easily tho
yeah probably, but it fixes the overlap warnings for me at least so it's still worth doing
can also verify that it is in fact an overlap collision in your case and not something else weird
(although it probably is a collision)
okay, so in mine, that extra start distance at least is unnecessary
the spawn overlap warning should be fixed on main now
(also merged the log PRs @mellow orbit)
they're not vanishing for me, but it does give the overlap warning yeah
the debug rendering shows they're there, they just don't have a mesh
or texture
Update
here's the file I'm using
I changed the radius to 10.0 but same with the original 1.0
result
(but does print overlap warnings for some reason)
oh I think I've been misunderstanding your issue lmao, I thought the issue was that they "disappear" because the overlap causes NaN values or something, but by disappear you mean that you're specifically trying to despawn them, but not because of the wall that they're ricocheting off of
yeah well the CollisionStarted issue is this again #1124043933886976171 message
you can get slightly better behavior with NarrowPhaseConfig prediction_distance = 0.0 but that'll probably cause collision stability issues
but yeah you could also just spawn the ball about 1.0 px (or a bit more) before the toi
or rather move 1px in the direction of the normal I think
yeah
technically you can have a negative prediction distance π then every collision will just be detected a bit late
If you do a shapecast and then spawn a same size collider at that point they should be colliding at least π€
yeah I made an issue yesterday too https://github.com/Jondolf/bevy_xpbd/issues/224
It just needs to be a small amount away from the toi there
the toi is the point where it hits, so you'd be relying on floating point errors to have it not consider it colliding at that exact point, or you'd need to make the rules for what is colliding different
Like "it's only colliding if it's penetrating enough or moving against the other collider"
*toi is time of impact when a point is moving along a ray with some specified velocity
Yea, you need origin + direction * toi to get the point
At which point you already have some floating point error probably but whatever π
I remember it behaving the same if direction isn't normalized
Despite the docs saying it normalizes it either way
parry docs don't say it's normalized I'm pretty sure
Yea I think it's rapier saying that
and anyway seb verified #math-and-physics message
I don't like how it's called dir in parry
but shapecasts use vel
But yea what seb says there confirms my formula works
yeah it does
You just shouldn't put in unnormalized vectors because it'll make your brain melt π
My BVH and SdfSpatialQuery have the same behavior, but I plan to put in the docs that you should pass in a normalized vector. People can ignore that if they want tbut then it's their fault at least
My BVH also misbehaves if direction is very small, because the workaround for costs more cycles per aabb check
yeah in 0.4 I'll probably normalize it automatically and then have distance instead of time_of_impact
which is what most engines have afaik
with bevy_geometry we could also use Ray2d and Ray3d which are automatically normalized
You do want to be careful with it, putting in extra normalizes on things that are normalized already can add up to a lot of extra calculations
Yea there's various solutions, just something to keep in mind
"Future possibilities"
"SDF rendering"
It was in the plans all along? 
not SDF physics π’
It says collisions
SDF collisions are surely the only glam collisions out there right? 
Yea my SDF collisions are only accessible to like 5 people π
I still haven't even checked them out, I probably should
Just beware of really big enums and impl blocks
I should probably rewrite it using traits and use enum-dispatch or something for the main type π€
lmao there's actually an sdf_peck module
It's a crate even ... The repo has a lot of crates that need to be split out π
It looks really nice honestly
Is there an example of DIstanceJoint anywhere? I seem to have discovered a fun new way to yeet things into infinity π
you have way more tests than I do π
I don't even have that many tests π
as soon as I turn on physics, zoom!
let leash = DistanceJoint::new(target_id, globe_id).with_limits(0.01, 1000.0);
although I tried it .with_rest_length of various values too
without the "leash" the ball just drops to the ground and bounces, of course
you could try just DistanceJoint::new(target_id, globe_id).with_rest_length(target_pos.distance_to(globe_pos))
or whatever you want the leash length to be
but it should be the same as the distance between the anchor points
I'll try that, but ... does with_limits not do what I'd hoped?
I'd like this to act like a rope, not a stick...
I'm pretty sure it should work as long as the rest length is within the specified limits
but it's 0.0 by default iirc
testing that...
nope set it to 2.0 and zoooooom π
but let me use the exact right value...
not for me π limits work as expected
okay if I set the rest length close to whatever is correct at first, that seems better
I have zero issues with just this
commands.spawn(
DistanceJoint::new(static_cube, dynamic_cube)
.with_rest_length(2.5)
.with_limits(0.75, 3.5),
);
(static_cube can also be dynamic, no difference)
I've got ```
let leash = DistanceJoint::new(target_id, globe_id)
.with_rest_length(target_transform.translation.distance(Vec3::new(2.0, 3.0, -2.0)))
.with_limits(0.5, 500.0);
and that gets me:
(I'm moving the robot -- both dynamic)
ah, hmmm. setting "compliance" reaallly low might help
oh yeah π
hmmm still very rigid at 0.01.
0.1 works
Where can I see the progress on this? π
Cause I may want to refactor my SDF logic to use bevy shapes where possible π
10.0 is even better for what I'm looking for π
ahem
...
soonβ’
after I begin
Ah so it's like a bring your own bevy_primitives and then get it merged in bevy before you start kind of thing? 
I feel like I already have a bunch of things in this RFC
joint motors and other joint things? constraint optimization? spatial query API improvements? bevy_geometry?
Raycasting on bounding volumes? I already implemented that ... I also have a bunch of primitives π
If you're looking for raycasting stuff you can find it in the bvh crate π
wtf is morton_encode
It's a uh ...
maps coords into bit form somehow
space filling curve
oh
What does that mean? Idk I just followed the blog Griffin linked π
that explains everything, definitely
https://madmann91.github.io/2020/12/28/bvhs-part-1.html
Look for morton and it explains some of it
This site is a collection of posts on the topics of Computer Graphics, Programming Language Design, or Compilers. Opinions are mine and may not reflect my employerβs.
ah yeah this tutorial series thingy
it looked nice but haven't read it properly
yet
It seems pretty decent, but it starts out very complex, there's actually a later post that is a simpler introduction
And it's hard to translate to Rust because the C++ code is just really cursed
// TODO: dim4?
π
I mean if I make my BVH have 2D support, why not 4D support too π
Keeps the door open for 4D SDFs 
4D cloth and soft bodies in the horizon
oh god, delauney pentachoronization for 4D meshes
triangulation and tetrahedralization are already bad
(and no, I didn't know what a pentachoron was prior to this)
I got my topology thing kind of working, don't have rotation or scaling implemented yet though, and there seems to be some issue with how I'm deleting the projections when the player stops intersecting an edge because I'm getting warns about double despawns.
But as it is now, torus physics should work perfectly fine in theory
doughnut 
I'm wondering how I am going to work out how to "clip" the rendering of the meshes and the colliders though.
Torus where? π
The image is the fundamental polygon of a torus, because the opposing edges are connected
Oh hey the SDF for a torus is really simple ... I should implement it
Just look at this simplicity:
vec2 q = vec2(length(p.xz)-t.x,p.y);
return length(q)-t.y;
So, this is working pretty well!
let leash = DistanceJoint::new(target_id, camera_id)
.with_rest_length(10.0)
.with_limits(0.25, 20.0)
.with_compliance(1.0);
And next I should implement raymarching over arcs so I can make torus-torus physics ... Donut simulator 
The first part is just moving the character around. In the second half, moving the camera.
I really don't know what this SDF thing is you keep going on about, but if I can do topology shenanigans I'm interested
The camera is Dominance -127, and there's a system to slerp it to look at the character
and the input is enabling ExternalForce.
Placeholder ground needs to be fixed, obviously
And I need motors to keep the head looking forward π
SDF stands for signed distance function, they are functions that define shapes ... And I implemented collisions using SDFs ... Main benefit is that you can make relatively cheap collisions for concave colliders ... Also better for cloth physics, which I'm sure Jondolf will abuse at some point 
Or something like rest_limit for revolute joints.
unrelated, but this could be a pretty cool platformer idea; having to drag an object around, and having the player and object impact each other
Oh, but does that help for performing physics on the manifold of a torus?
could do some puzzle things where you need to swing the object in some way to e.g. get around objects, climb along the ceiling etc.
maybe it is an electromagnet
Maybe it's a donut and you can hook it onto things
SDF donut that can be molded into different shapes smoothly
Not sure if we can do collisions while modling between different shapes ... I can't imagine that wouldn't make it bound 
Oooo yeah if the shape is defined by a function you can just change the coeffecient for shape blending
Yea the terrain can probably morph just fine
As long as the exterior gradients don't distort it should be fine
what do gradients mean in this case? the same as in math, i.e. the direction in which the function icreases the most?
Yea, the direction in which distance increases
It's how you get the normals for collisions
The distances tend to also get distorted when you break the gradients, but you can sort of work around distances being subtly incorrect
I seriously need to write more tests though, you already have like 10x our tests if we discard doc tests which mostly check that things compile
I'm pretty sure there are 0 spatial query tests π
Write CollisionStarted/Ended/CollidingEntities tests
yeah that'd be very useful
I also only test raycasts π
Tho in a way you could say my game is a test for spherecasts and shape intersections too 
it's good for dogfooding bevy_xpbd
except sdfs ig they showed that the narrow phase should be more modular actually
Me using sdf collisions definitely does result in me finding less bugs, mostly just some architectural issues to the modularity stuff
But realistically parry bugs don't get fixed anyway π
still no docs or real examples π
Actually, I should ask this explicitly. Is there an easy existing way to set something like a "rest limit" for a RevoluteJoint, so my poor robot's head swivels back to forward?
with_angle_limits?
optionally specify the axis using with_aligned_axis
The angle limits are like the min,max limits on the DistanceJoint, right? And the aligned axis needs to be Y, so the head can turn...
yeah it's just min and max angles in radians
and aligned axis of Y would mean that it can e.g. look left and right
I think
Yes.... let neck_joint = RevoluteJoint::new(body_id, head_id) .with_aligned_axis(Vec3::Y) .with_local_anchor_1(Vec3::new(0.0, TORSO_HEIGHT + JOINT_SPACING, 0.0)) .with_local_anchor_2(Vec3::new(0.0, HEAD_HEIGHT / 2.0, 0.0)) .with_angle_limits(-PI / 2., PI / 2.);
but it's the z axis (in local space) that I want to set as the "rest limit", while still having this other limits. It seems to me to be almost exactly the rotational version of what the distance-joint is linearly (if the distance joint were fixed in place and along a line).
so do you want limits along two axes? like looking up/down and left/right
or just one
For now I'd be happy with just one.
Limits exactly like I have above, except a springiness returning to the center.
ah so min and max angles, but it should still try to return to the rest position (looking forward)
unless I'm misunderstanding
yes, exactly
a hacky workaround would be to have two revolute joints for the same entity pair; one would be a hard constraint with the angle limits, and the other would be a very soft constraint with [0.0, 0.0] as the limits
eventually I might want some more sophisticated version allowing looking up and down and tilting to the side (like, human neck is a pivotal joint technically but close enough to a spherical joint.
Oooh, I'll try that!!!
the soft constraint would just have a very high compliance to make it softly push the head to the center
or a low compliance if I want to really make it stay there, yeah?
yep
actually, that works great. is there any downside?
not really, I guess it's a bit more expensive to have two separate joints, but it shouldn't matter since it should be able to handle even hundreds (or thousands?) just fine
probably thousands
I should make an example/benchmark that simulates thousands of slightly offset pendula with different colors to display the butterfly effect in action as well as testing joint performance
bloom could make it look pretty with the rainbow colors
Experimentally, Compliance of around 10.0 gives me a nice soft effect which tends towards the intended direction. I'm thinking I'll leave it like that normally, but then adjust it to be somewhat lower when I want to have the robot actually look at something of interest or whatever.
That looks pretty good :P
Got a cube to loop forever, unfortunately I couldn't take a video because wayland is being sassy
And the program crashed, pain
Anyway, soccer on a torus is fun
So, hmmm. This problem only happens with the shoulder and wrist joints (X axis and Y axis revolute joints). The others can be touching.
I also notice that (space or not) the arms don't seem to ever sleep. That's odd.
Hmmm no, still happening but more rarely. sigh.
also the unfortunate thing right now is that negative scaling doesnt work with all colliders nor could it very easily
I was thinking maybe a translation or rotation might be able to mirror some of the scaling easily
but im unsure atm
I would imagine that it'd be possible to flip X/Y/Z for all shapes somehow
Yep
cones for example would need to be reworked a lot
I have a relatively basic scene as a demo (character controller + static boxes) - the game seems to freeze for a few seconds after starting with some frames taking (by eye) 100ms or more - but after playing for maybe 5 seconds, it usually "recovers" and runs smooth (60fps?). I'm on a 2017 Macbook in case that's relevant, running Bevy 0.12.0. At least once, though, I've seen it get slower and slower until it freezes completely and apparently never recover.
I'm wondering if there's some kind of "death spiral" from attempting to be fixed-timestep, and it just happens to usually recover?
I haven't completely ruled out any other causes, but there's not much in the demo besides bevy_xpbd
Okay, after profiling, looks like it's https://github.com/bevyengine/bevy/issues/9964 and not really physics-related π«
Does enhanced-determinism feature enables full cross-platform determinism?
And is it compatible with parallel or simd?
I believe it should, but it's not verified to work for all features yet. It does produce the same snapshot for Windows, Mac and Linux in a simple test that we have though
I'm interested in win/Linux/android
Compatible with parallel for now at least, but not compatible with simd
I see
If I want max performance, should I ignore determinism and enable parallel+ simd?
Because I believe simd depends on architecture implementation details
probably yes
But the difference probably isn't huge
If I want just 2d physics with some rigid bodies and a lot of non-rb colliders (mostly circles), how much worse performance should I expect compared to Rapier?
If you don't have thousands of dynamic bodies constantly colliding with each other, performance should be just fine
It's a bullet hell
RBs are mostly ships
And a lot of bullets that collide with ships but not each other
Most of bullets are not RB but manually controlled
#1124043933886976171 message
Should be fine even if they collided with each other, and if they don't, then it definitely should be fine
Wow
Yeah, will try it first then
Will need to think of some way of automatically generating collision shapes for ships based on their sprites tho
People expect shape-accurate collisions since ships can often be pretty large
Not a touhou situation where I can have just a small dot as a collider
Haven't tried it, but Rapier has this: https://github.com/shnewto/bevy_rapier_collider_gen
It's small enough that it should be straightforward to adapt for bevy_xpbd, especially because they both use parry
I will try it, tho last time I took a look at it, it was pixel perfect
Works for 16x16 Sprites, but we operate on up to 1024x
But well, nothing some collider optimisations can't solve
Replaced the arm connectors with DistanceJoint. I'm still getting occasional yeets into the ether that I don't understand. π¦
Tried to reproduce but of course it's not doing it when I want it to. Basically suddenly Something Happens and the velocities go extreme.
Also, why won't things stay asleep? How do I diagnose this?
here, arms and head, but occasionally other things light too...
@vestal minnow is the early-return at https://docs.rs/bevy_xpbd_3d/latest/src/bevy_xpbd_3d/constraints/joints/distance.rs.html#139 perhaps a bug? if the distance (current length) is 0 but the DistanceLimit min is greater than 0, won't this cause the correction to get skipped?
Source of the Rust file src/constraints/joints/distance.rs.
2023-11-08T01:44:24.855462Z WARN bevy_xpbd_3d::plugins::solver: 192v0 and 194v0 are overlapping at spawn, which can result in explosive behavior.
Huh, I guess I just never pulled that change before
Is there any way to change that behavior? I know it's more of a side effect, rather than intended behavior, but is there a good way to prevent explosive behavior like in particular
In my case I don't even get explosive behavior ... Just a warning
The collisions I initially get might also be wrong, because I'm getting static-static collisions too ... Gonna have to see what causes that
I was thinking about that. There are really two different cases -- well, maybe more, but these two at least:
- situations where you've set things up so that the simulation has no option but to fail (constraints out of what it understands, either initially or because you've moved things outside the simulation)
- situations where the situation gets itself into a impossible state
I think there's a bug in current code where objects which start out touching (or even close to touching -- within the prediction distance which defaults to 0.01) get the warning when they needn't.
BUT there are still explosions that can happen even without overlapping start items. That's just one of the most surprising
I'm not sure it's easy to determine what a more-real-feeling failure state would be for some of these possibilities.
But I'm really, really sure that "two slowly moving medium-weight objects bump in just the wrong way and then react with the force of a million atomic bombs" is not it
I think there is only really one case where you can't produce a reasonable collision response
Which would be when the collision point ends up being at the perfect center of another collider, which can't produce valid normals
I think the first step might be to put in checks (maybe as an optional feature) for Surprisingly High Delta-V in the physics steps, and
- log them with warnings and
- clamp them to some limit, or even lower them to 0.
maybe also a "trace" level log at that point with enough information to figure out what went wrong. not sure how hard that would be.
In my case enemies just spawn right against the wall, which isn't really a problem, but the warning is annoying π
Yeah, my particular case I run into this is when my fruit combine, creating a bigger one, and now it's intersecting with other ones. I handle it by lerping the radius of the collider, but I kind of feel like it's a work around
It does π
yeah, "on spawn it's already colliding" is the first type of situation. as I understand it, it's not just that it's colliding but that it's REALLY out of compliance so the force used to "correct" is over the top.
we talked about a "handle overlaps with a gentle push to the outside" option a couple of days ago
ah is that where it's just touching but a lot of surface, maybe? dunno. definitely a bug though!
This might also be where I'm getting my periodic random explosions. I have a rag-doll-like figure and sometimes it's just going along and then OH NO.
I'll try that tomorrow. I have found that adding "thickness" to my joints so the anchors are not touching but rather have a gap bigger than the prediction distance solves 99% of the cases.
I guess my other 1% are
but it can cause contact stability issues in cases where moving bodies bump into each other.
I should try to simply what I have down to a test case.
but for now... off for the night
@vestal minnow Why is it called fixed_(once_)hz when it takes a timestep duration as input? 
funny you bring that up, just got done debugging an issue with that hahah
I'm assuming it's just a typo and it's meant to be like the bevy one e.g. Time::<Fixed>::from_hz(60.0) vs Time::new_with(Physics::fixed_hz(1.0 / 60.0))
Well, 1 / 60 s = 60 Hz π
But yeah I somehow thought that was how Bevy's from_hz worked, but it's not obviously
(it's not 60 Hz)
It's .0166...Hz :')
When I saw that line of code suddenly this data made sense to me:
We had: Position(Vec3(-2.2298813, -938642.2, 7.834011))
Server: Position(Vec3(12.785339, 72134.08, 10.852114))
Can't really make a patch for that tho since it would break semver pretty badly I guess
For me it was when my character was deformed into oblivion due to floating point precision and I reasoned I was just falling at the speed of light π
Ah yes, for me it was a bit less obvious
I just got a gray screen after a frame or two
Which doesn't explain a lot when your terminal is also full of deprication warnings from naga_oil 
It was only when I noticed those numbers that I started suspecting that maybe it wasn't just the shaders
Does this physics engine have good cross-platform determinism?
I want to make a rollback networking game using it and was wondering
Everywhere I look I see @sleek thicket promoting xpbd π
It's so hard not to: XPBD was so much more natural to me
XPBD had something that I couldn't figure out in Rapier: The contact position when doing a shapecast. That's what brought me over. It's spiralled into me sending in pull requests lol
Is there actually something broken with Rapier, though?
(I didn't use it long enough to find out)
Ah the child colliders lagging behind their parent thing?
I think I saw that earlier today
Now that you mention it, I think I may have been seeing that before I switched to xpbd as well
Oh wow it's proper getting left behind
Hopefully xpbd can eventually catch up on the perf front too
To be fair xpbd has that same issue, well not the gizmos lagging one frame behind. That was fixed on bevy_rapier main 3 months ago but there hasn't been a new release :V
I don't know 
I'll probably switch over to xpbd when some more of the issues with stability have been fixed, because Jondolf is a lot more responsive
Heh, I know nothing about physics sims
haha
I don't know anything about physics sims either but that's what I did
12 ish years of unity and I've never really had to care much about physics past OnTriggerEnter
In XPBD I use the CollisionStarted events
use bevy::{ecs::query::ReadOnlyWorldQuery, prelude::*};
use bevy_xpbd_2d::prelude::*;
pub trait FilteredCollisionEvent: Event {
type Query1: ReadOnlyWorldQuery;
type Filter1: ReadOnlyWorldQuery;
type Query2: ReadOnlyWorldQuery;
type Filter2: ReadOnlyWorldQuery;
fn should_keep(
entity1: Entity,
query1: &Query<Self::Query1, Self::Filter1>,
entity2: Entity,
query2: &Query<Self::Query2, Self::Filter2>,
) -> bool;
fn new(a: Entity, b: Entity) -> Self;
}
pub fn republish_collision_events<T: FilteredCollisionEvent>(
mut unfiltered_events: EventReader<CollisionStarted>,
query1: Query<T::Query1, T::Filter1>,
query2: Query<T::Query2, T::Filter2>,
mut filtered_events: EventWriter<T>,
) {
for CollisionStarted(a, b) in unfiltered_events.read() {
for (a, b) in [(*a, *b), (*b, *a)] {
if T::should_keep(a, &query1, b, &query2) {
filtered_events.send(T::new(a, b));
}
}
}
}
^ This, in fact
Oh like concrete ones?
This is my "Attacker damages Defender" stuff:
#[derive(Event)]
struct AttackCollision {
attacker: Entity,
defender: Entity,
}
impl FilteredCollisionEvent for AttackCollision {
type Query1 = &'static Team<CombatTeam>;
type Filter1 = With<AttackCollider>;
type Query2 = &'static Team<CombatTeam>;
type Filter2 = With<DefenseCollider>;
fn should_keep(
entity1: Entity,
query1: &Query<Self::Query1, Self::Filter1>,
entity2: Entity,
query2: &Query<Self::Query2, Self::Filter2>,
) -> bool {
match query1.get(entity1) {
Ok(attacker_team) => match query2.get(entity2) {
Ok(defender_team) => attacker_team.can_damage(defender_team),
_ => false,
},
_ => false,
}
}
fn new(a: Entity, b: Entity) -> Self {
Self {
attacker: a,
defender: b,
}
}
}
Registered with this:
.add_systems((
// ...
republish_collision_events::<AttackCollision>,
// ...
))
And then acted upon with this:
fn process_combat_collisions<T: TeamDifferentiator>(
mut attack_collision_events: EventReader<AttackCollision>,
mut attacker_query: Query<&mut AttackCollider>,
defender_query: Query<&DefenseCollider>,
mut hitpoints_query: Query<&mut Hitpoints>,
) {
for AttackCollision { attacker, defender } in attack_collision_events.read() {
if let Ok(ref mut attack_collider) = attacker_query.get_mut(*attacker) {
if attack_collider.remaining_hits.unwrap_or(1) == 0 {
continue;
}
if let Ok(defense_collider) = defender_query.get(*defender) {
if !defense_collider.exposed {
continue;
}
if let Ok(ref mut defender_hitpoints) =
hitpoints_query.get_mut(defense_collider.hitpoints)
{
if defender_hitpoints.is_dead() {
continue;
}
defender_hitpoints.current -= attack_collider.damage;
attack_collider.remaining_hits = attack_collider.remaining_hits.map(|v| v - 1);
}
}
}
}
}
This little ditty is what I've been using to avoid having to copy-paste the same function twice to cover entity1 and entity2 being "backwards" in the event:
for (a, b) in [(*a, *b), (*b, *a)] {
Looking at it, that layers check is wrong... I should have been looking at the teams, not the layers π€¦ββοΈ
* Updated the code above to fix this
folks, what is the correct way to add mass to an instance that has a mesh and collider from a scene?
I'm doing:
commands.spawn((
Aircraft,
Mass(100.0),
SceneBundle {
scene: asset_server.load("piper_cub/piper_pa18.glb#Scene0"),
..default()
},
RigidBody::Dynamic,
AsyncSceneCollider::new(Some(ComputedCollider::TriMesh)),
));
yet I get:
WARN bevy_xpbd_3d::plugins::prepare: Dynamic rigid body 2v0 has no mass or inertia. This can cause NaN values. Consider adding a MassPropertiesBundleor aCollider with mass.
also, I noticed that with 0.3, using the cubes example on f64 they dance and sometimes explode without any change to their velocities π¬
Stepped out so Iβm on my mobile atm so code is hard to read with such a small width. Poke me a bit later on and Iβll take a proper look. Iβve not got to pickups yet but Iβll probably republish the collision event as a PickupCollected event and then have a per-type system. Enum sounds ok at first but I made the decision a while back that that feels too much like OOP for ECS (for me)
I guess weβll see in a few months whether or not I regret that decision π
Does it still work normally? It might be that the warning gets logged before the mass of the collider has been added since the mesh might not be instantly loaded at startup
I've got my own version of the CollidingEntities component that also keeps track of which entities started or stopped colliding this frame.
This way you can just have separate systems handle things.
(It's for bevy_rapier but it should be trivial to port)
Also weird that it works with f32 but not f64 
It could maybe be a sleeping problem, so perhaps adding SleepingDisabled works?
yep that solves it
WRT to the Mass with AsyncSceneCollider, no it doesn't work normally
the async_collider example does work though, albeit it does give the warning
are you spawning it in Startup?
yep, I am
so does the body just vanish when touching things?
because if not, then it should have some mass
I have gravity, and with the AsyncSceneCollider, it doesn't fall down. Neither by adding a Mass component
even this should fall down
commands.spawn((RigidBody::Dynamic, Mass(1.0)));
yes, that falls down. If I set a cuboid collider for this instance, with the SceneBundle, and I give it Mass, it does fall down
do you have a minimal repro for the issue that I could try?
let me try and create a reproducer from the example (which I didn't realize existed..)
it has to do with the model I'm using, but still haven't discovered why
does it matter if it's a trimesh collider or a convex hull/decomposition?
and is it rendered correctly with the PhysicsDebugPlugin
with PhysicsDebugPlugin and DisableSleeping, I can see the collider when using TriMesh, but not when using ConvexDecomposition. Neither work.
Also, just realized that the game window freezes, and doesn't process closing button clicks (I used to kill it with Ctrl-C on the terminal process)
tried again, and now I don't see the collider with TriMesh.. I suppose I'm hitting the race sometimes
convex decomp is very slow for complex meshes
can even take minutes for large environments
the window freeze also happens for TriMesh
anyways, thanks for being willing to debug this with me :). I suppose I can workaround it for now, I wanted to tackle a complete different thing
and you're running in release mode?
nope.. let me try for speed
debug is ridiculously slow in Rust without optimizations
release can be over 100x speed
Yea you gotta set 3rd party crates to opt-level 3 or crates like bevy_ecs, parry and xpbd won't run very nicely
This is how I configured them, re-enabling debug-assertions (opt-level > 0 disables it) because otherwise bevy will make certian errors hard to debug
[profile.dev]
opt-level = 1
debug-assertions = true
[profile.dev.package."*"]
opt-level = 3
debug-assertions = true
I do have that set
Hmmm ... Shouldn't make a huge difference in debug vs release then
:/
@sleek thicket The main reason it annoys me is because this makes it a competitive atmosphere, rather than collaborative
It also directly makes me unmotivated to do what you just said: fix rapier
because some of these issues are fixed
It's not fully tested yet, so it most likely isn't 100% cross-platform deterministic, but we do have a simple test that creates identical snapshots across Windows, Linux and MacOS, so for simple cases it should work.
Johan has a rollback networking demo called bevy_gaff to test and demonstrate the determinism (and networking). It does have occasional desyncs in some cases though, which we'll try to investigate more and hopefully fix
And yeah I agree 100%, I'm not a fan of the general negativity towards rapier. It's good to highlight issues (in bevy_xpbd also!), but in a constructive manner instead of in a way that seems discouraging to the developers. The message by .β§². was most likely meant to be somewhat joking, but still comes off as competitive at least to rapier devs
Improvements and fixes to rapier also benefit xpbd and vice versa, since they can get inspiration from each other. A large chunk of the API of bevy_xpbd is pretty heavily inspired by bevy_rapier (and heron, which originally inspired bevy_rapier's modern API) even though I do change things and experiment with different APIs
Because negativity tends to not help, good will does
A lot of issues are open despite being fixed and yeah people are having issues because of no release. I can't fix that because I don't have control over closing or releases.
I've also been on vacation from working on OSS stuff these past few weeks, just coming back more now
Yes, the reason I am trying to switch to xpbd is because I can easily find the point where two colliders meet for animation purposes
its techniquely possible in rapier3d but requires a few 'hacky' dynamic collider group runtime changes which I am trying to avoid
bevy_rapier does give access to shape cast hit points though. cast_shape returns an Option<(Entity, Toi)>, and Toi has a ToiDetails that has the points, called witness1 and witness2 for some convention reasons
https://github.com/dimforge/bevy_rapier/blob/fdf71724f1ac45c1fe26d0e67ba41c52b960407c/src/geometry/mod.rs#L82
unless that's new
That's honestly what was my main issue on rapier, not having active maintenance ... The PR I made to fix rapier pulling in render deps in my server took so long to get merged, that it was merged after I switched to xpbd
Rapier itself definitely had them though because the spatial queries in xpbd are mostly based on rapier's spatial query pipeline
Not new I think, but I remember things being rather inconsistent on spatial queries ... What are those convention reasons? I never found witness1/2 to be very meaningful names when working with it
Also, the new version of bevy_rapier did get released now, but it required a nudge from @royal helm (and work done by @DevilIra)
I saw a talk on CCD that referred to it as witness, don't know the original reasons though
I think I've seen devil ira do the past few rapier ports
yeah they've done a lot of them
But hey on the flip side ... rapier probably didn't release with a fail quite as epic as from_hz working the wrong way π
Better to have your release late than have your delta times be 3600x higher and tickrate be 1/3600th of what you wanted right? 
this time for bevy_xpbd I had a 0.12 branch "mostly working" like two weeks before it released
so that people could migrate early if they wanted
still the wrong way π
idk how my brain messed that up, I just saw Bevy's from_hz and the current PhysicsTimestep::Fixed(1.0 / 60.0) and smashed them together
somehow I logicked the input as "A timestep of 1.0 / 60.0 s becomes the desired frequency for 60 Hz, so it must be correct" 
FWIW semver says 0.x.y means "unstable API; anything goes. But it may be worth bumping to 0.4 just to signal that it's worth reading the release notes
the x is unstable yes, but y shouldn't have breaking changes
since it's just the patch number
it should really only fix very clear bugs or issues in docs
but changing how the timestep value is interpreted is very breaking (although a minor change)
not sure what the convention is for fixing things like this though, since it is a clearly wrong unit but also breaking
depends on how many people are already on 0.3
although I guess most people won't even touch the timestep
there's lots of numbers. make a 0.4.0 π
that's like if Bevy released 0.13 tomorrow, it feels weird
(although not quite the same scale ofc)
Best approach: Get all the features and improvements for 0.4 done ASAP and do a normal release π
Your call, of course!
yeah I guess I can do 0.3.2 tomorrow
it is a clear oversight that doesn't make sense, so it's probably fine to do as a patch
@vestal minnow any possibility of adding an exclude_sensors and its ilk to SpatialQueryFilter?
is there a sensor layer by default?
well that isn't really same
I need any Collider that is also a Sensor
or well the opposite, I need to exclude any collider that is a sensor
I'm not the end user though
itd be relatively hacky if I just said 1 << 31 is Sensor colliders
Maybe we should release sdf collision support 
Is this shape/raycast related?
yes, I'd need it for wanderlust to be ported
I feel like those should just be skipped in the construction of the bvh, I don't think sensors should be observable π€
I don't think I've ever seen raycasts on Sensors be working as intended behavior
What would the water be sensing for?
Not sure if I'd want that behavior to be on the water entity but yea I guess that is a possible approach
If you're ray/shapecasting you can get hits on colliders with neither Sensor not RigidBody I think. The systems handling character control or projectiles would then probably be the one detecting the water and responding to it
But yea since it's possible to model it both ways excluding all sensors by defualt could also be a footgun ... But having Sensors be included by default is definitely the more common one π€
I made bevy run at 20fps (with fixed_once_hz 1./60., um, "hz" for xpbd) and set SubsetCount to 1 so you can watch my poor robot explode in real time.
I just set it spinning a little bit, and then ... well, watch!
I think the auto adding of stuff is based on having Collider for some components and RigidBody for the rest
Can't say for sure tho, most of that auto adding stuff is broken for me because xpbd doesn't acknowledge the existance of SdfColliders π₯²
They can only collide with other SdfColliders if that's what you're asking, but other than that it works fine as long as I generate the swept aabbs and handle narrow phase hits for them
The neck is two revolutejoints, one with compliance 0.0 and one with compliance 10.0 to fake a motor. The shoulders are distance joints with compliance 0.001, and the wrists are distance joints with compliance 0.1. In this configuration I have them with rest_length of 0.0.
sry was gone for a bit, had to finish a physics assignment for school
how dare you π
Did you only take that bit to do the whole assignment? π
Any idea what is causing the exploding robot behavior? The torso collider shouldn't grow like that, should it???
Yea ideally there'd be some middleground, where colliders are mostly defined as simple primitives, and all primitives can interact with either sdfs or trimeshes and convex hulls
I had started it a bit earlier but then proceeded to spend time here on Discord... and it was due 10 minutes ago
I sent it 1 minute before it was due, but noticed a pretty bad error so I modified it 1 minute after... so technically I did send it in time :)
I do feel like even if xpbd had support for both there would need to be feature flags for them tho, wouldn't want to use the wrong thing by accident. Trimeshes would destroy my games's performance so I'd rather not touch them at all π
You remind me one one of my friends, he always started on his assignments just before the deadline and then handed it in after π
Yea that would be great, I think it might be one of the big reasons @vestal minnow seems pretty obsessed with bevy_geometry/bevy_primitives/whatever
The instant before doom -- the body has become the size of the world
I'm pretty sure this kind of scaling is because of invalid rotations
The robot was the world turtle all along
Like, applying one quaternion but not the inverse?
Wouldn't it just be non-normalized rotations?
yeah that probably
As the errors add up I'd imagine the errors accelerate and it explodes in size when you multiply it by the rotation
ah, that makes sense.
The torso collider is a convex hull -- all of the others are basic shapes.
Yeah we could do this, or maybe an equivalent to rapier's QueryFilterFlags
you can have a collider without a rigid body, and it will detect collisions, but it currently won't trigger collision response because it's not really a physical object in that sense
I think Unity might treat them as static bodies tho
Still happens if I make it a squashed cylinder, though
Wait it does detect collisions even without being a rigid body or sensor? Why?
I thought that leaving it circular might help, and it seems to slightly....
unless I'm misremembering
but nope, here we go...
I mean it might do that, but if it does that should probably change, cause Sensor exists with a reason
Sensor makes a rigid body pass-through, doesn't necessarily say anything about bodyless colliders
but yeah I'm unsure what the expected behavior is
that it does nothing?
it might be weird to see a collider in debug rendering and not have it do anything at all
@vestal minnow should I file a bug for this?
also, I really need to fix my ground texture
If we were to separate collision detection from the rest of the crate, you'd expect Collider to work on its own and report contacts without knowing anything about rigid bodies, and sensors are only required in the existence of rigid bodies
just basing the substep count off of this
Hmmm yea maybe we need some other construct for these "can only be found by ray/shapecast" situations π€
Maybe a feature that specifically ignores that collider for collisions, and make some bundles to make it harder to miss anything ... Idk
I'm seeing this intermittently with higher substep counts. Reducing it to 1 makes it easy to reproduce
these explosions typically happen because of conflicting constraints and/or incorrect joint anchor configurations which leave things in an unrecoverable state
Maybe a larger rest length for the wrists and a higher compliance for the 0.0 neck joint? To see if it's related to them
It definitely gets into an unrecoverable state.
Will try.
LOL I tried completely detaching the head and wrists, but my camera follows the head, and that falls off, and with substep 1, goes through the ground
Increasing spacing helps, but with just the torso and arms, it can still get into explosive states
Do you think the growing collider is a symptom of the constraints being in conflict, or the cause?
Hmm, also, it seems like it might be sleep related?
There, I waited for the torso to sleep and then just moved forward slightly.
yeah it could be related, I've noticed sleeping randomly causing jitters and stuff as well
Definitely reproducible that way. But that isn't the only case.
Also, I should be able to tie the arm closely to the torso, right?
I think renaming CollisionLayers's fields to membership and interactions would be useful
also maybe removing External* from Force/Torque stuff
The layers are named like Godot iirc but I think I agree
rapier had them as membership and filter but that also implied the opposite of what it does for filter
And yeah I want to remove External, but one counter argument was that Force may imply that it also gives access to the total force including gravity and constraint forces... I think we could also give access to those though
Constraints compute the forces anyway, and gravity of course is known, so we could probably add them to something like total_force in Force
I did begin to implement this at some point but I think I got sidetracked and left it
Would be interesting if you could tag forces and other things could nullify them or somethin
or just read it
Maybe overengineering it though
The constraint forces are just computed based on the Lagrange multipliers, they don't actually do anything
So you probably can't easily nullify them based on the force
I'm sorry to keep going on, but this driving me a little crazy. Is the collider shown as bigger because it is responding to the constraints, or is something making it grow and then that pushes stuff into impossible states?
Are there situations where a collider is expected to expand?
Looks like that struct isn't in the version I was using back then but witness1 and witness2 are Vec2s on the Toi struct directly! Well there we go! Guess I owe Rapier an apology.
No more reason to move away from Rapier now, so I guess I'll ditch xpbd now! See ya!
(To be abundantly clear, this is a joke... I still prefer XPBD's APIs and that cloth thing you posted yesterday was fire)
To be clear, I am doing nothing to rescale the collider. (Well, I do initially to make the elliptical cylinder β but the same problem happens with a basic cylinder.)
I'm not doing any transforms or anything after β all I'm doing is applying external force to the sphere that serves as the "foot".
It's some sort of interaction with the arms, which are attached with a distance joint
With a distance joint each, of course.
I made a version with the head and hands detached and that still happens.
The sleep is one way to trigger it, but it also happens with spinning
I changed the collider to a cylinder, and the arms are boxes.
Hmmm, though β maybe it is sleep-related. Look at the color in #1124043933886976171 message
It seems to be asleep even as it spins and grows.
Yeah I'll stick SleepingDisabled on there and see what happens.
It's also very weird that the collider grows but the mesh doesn't.
Does xpbd support scaling of colliders?
You can scale colliders (i think that's a parry feature) and there's ColliderTransform for child colliders, but idk if there's anything more than that
Does it match the Transform hierarchy in that sense though?
If you change the transform-scale of the rigid body to which a collider is attached, the collider will also scale. Presumably also if you change the transform of a collider on its own. But I'm still mystified by the collider growing because it's unhappy about joints.
Like, if you bend my arm back into a painful position, I don't respond my growing my torso until it is bigger than a house.
hmm does xpbd ever use GlobalTransform?
Because rotation and scale are combined in the matrix
Collider transforms do match the Transform hierarchy, but they don't support shear, and they don't use GlobalTransform. The visual scaling you're seeing is because the joints cause things to go into a weird state where rotations most likely aren't normalized, but this doesn't affect the actual collider scale, only Transform.scale does.
Or I don't know if parry also handles unnormalized rotations weirdly, but it doesn't affect the computed scale at least
Why does the weird state manifest as the collider debug visual inflating?
And... this is a bug, right? The joints are in what is a valid state to begin, and nothing is moved or scaled by anything outside xpbd after that.
So, I decided to test if the issue I had with Godot also happens with XPBD, and unfortunately it does. But it is not as pronounced. Is this an issue worth reporting or simple to fix? Sorry if this is not the ideal format for this kind of query, short video, 41 seconds.
The tl;dr is that when the circle collider hits between two cuboids, the aligned cuboids do not appear to act as a seamless surface.
It seems (to me) that this would be a base requirement when taking a level from LDTk or anything like that and having it work consistently. But I also understand that I might be oversimplifying the issue because it seems common.
is it intended behavior that CollidingEntities is non-empty before bodies actually starting pushing each other? Seems to start happening whenever they are within 0.5 units or so of each other...
When I've done this in the past, I only add outer edges as constraints. That's on a different bevy_xpbd fork than this though.
OK. I am a noob, so I am not quite sure what that means, but at least it is a known issue, right?
you basically create a bunch of one-way colliders instead of a bunch of boxes
but the way I handled it I wrote it specifically for bevy_ecs_tilemaps
Ah, OK. Yeah, that makes sense. Seems like a bit of an annoying thing to have to do for someone who almost reached for Google to make a for-loop. π
hah, yeah. I spent a lot of time trying to get it right (and wrong), and it still blows up in some rare cases
alternatively it might be able to skip contacts if they happened on a tile that has a neighbor in the direction the contact normal is pointing
some engines allow you to hook in and ignore specific collisions based on your own criteria, I'm a bit out of the loop on jondolfs version, though
it looks very modular, though π
I have another level where the ball crashes with two surfaces that are rotated -45 and 45 degrees and it seems to be 100% stable, but they intersect, like a cross.
And it feels like it has to do something very similar for that to happen, where it gets the collision data from each of the colliders and decides based on data from both of them to just bounce straight back up.
Is the problem that the circle collider sees the hard corner?
not sure I understand the case
I think you understand better than me the failure case I have in the video where aligned surfaces are not treated as a uniform thing. And I don't really understand how tessellating a shape from, say, SVG using Lyon would work doing that. I think this issue would just be worse when it intersects with 5-10 triangle colliders at the same time.
But it does this perfectly, where the ball bounces down into the center of the X and right back up again.
the way contacts is normally resolved with xpbd is that it treats one object at a time, so it probably bounces with both and the combination makes it bounce back up?
I'd guess your issue with the boxes would probably be less visible if you increased the timestep.. but that's not really a satisfying way to "solve" it
Yes, that makes sense. But why doesn't it make sense in the flat-plane case? If you have two cubes with a seam, intuitively (and I know I cannot really trust my intuition on this, because it is often wrong) would be that the bounce angle from the left cube and the right cube would cancel each other out, making it seem like a flat surface.
I think the ball hits it at an angle, so it moves both up and to the right, so it misses the other box (because the ball is too far up)
when a circle hits the corner of a box, it should probably resolve from the corner along the normal of the circle
Hm. It behaves perfectly when just moving left and right on the surface. And I think it needs to intersect with two cubes to have an exit angle produced. Perhaps there is a setting for it and it defaults to just lokoing at one.
I'd think it is because the vertical velocity increases it moves further down into the box during one frame and the normal changes from straight up to somewhat diagonal
Yes, but would it not do this...? Sorry, I am a noob so please bear with me. And also, xpbd does this a lot better than Godot.
(2 seconds, I need to MS Paint for two seconds.)
the easiest way is probably to just change the timestep if you can afford it
or make the circle bigger relative to its velocity
haha π
how I implemented it (not sure if jondolf changed it) it hits the left one first, then it's moved up and to the right, and then it checks if it overlaps with the right one, and it probably doesn't in your case
Yeah, that is what I am saying. I would want it to do an intersection with both and blend the output. Perhaps that is a tall order.
It seems to already have things where output is blended on restitution, etc, so I don't know. It feels so odd to discuss a ball and two cubes in a world where at the same time you have a demo with 1000 3D cubes running at 9000 FPS.
I think it's discussed in one of the xpbd papers
But I would argue this is broken. Like, as a 2D physics engine, it just doesn't really work. There is nothing physical about the behavior. Is this better in 3D? I could make the game with a 3D physics engine and render in 2D.
I mean, you could not reasonably even make a Breakout/Arkanoid-clone with this.
I think a lot of engines work that way
Yeah. Well... It seems Unity does it correctly. But I only have a Threadripper, I don't have time to recompile that much. π
I don't want to use Unity.
unity uses a fork of box2d iirc
I have made the same mechanics three times. I fled from Unity because I really disliked the experience, mostly how heavy it was. This is years ago. Then I ran into this behavior in Godot, and it seems to be on Godots list of known issues.
I remember that what I do in my game is treat tilemaps as their own collision shape, and they always just spit out one normal, and it actually looks at adjacent tiles before it spits out the final normal. So in your case the normal would always be up
Yeah, but this is just a test level. My Godot-level for testing looks like this. So I would love to be able to do arbitrary shapes.
i get it π
"I just want everything. :)" π
π
i think xpbd is quite performant compared to traditional engines. so low timestep might not actually be so bad
God damn, perhaps Unity is whipped enough to be a good alternative at this point. In Unity the landscapes typically look like this.
How do I test that super quickly?
Sorry, I tried looking it up. Is it a resource in the config?
The clock representing physics time, following Time. Can be configured to use a fixed or variable timestep.
found it. And I also found the answer to my issue
the default overlapping distance is set to 1 in 2D... and I was treating the units as meters when it's probably intended to be pixels
it defaults to 0.01 on 3d, so it's kind of surprising
Is this related to substeps? I don't really understand it. If I could have perfect deterministic physics, I would obviously love that. Even if that means locking it to fixed time.
sorry, I think maybe I linked you the wrong thing. will have a quick look
I think you might have linked to the right thing. I tried adding this: .insert_resource(Time::new_with(Physics::fixed_hz(1.0 / 144.0))).
And I am having a hard time making it fail.
Ah, I made it fail. Agh.
you could also increase substep count, but as the docs say, you may have to enable f64 if you make it too high
because the substep interval will be too small for f32 to work properly
Yeah, OK, that is interesting.
Even setting it as .insert_resource(Time::new_with(Physics::fixed_hz(1.0 / (144.0 * 2.0)))) makes it fail every once in a while. I hope one day I can understand why it doesn't enumerate the colliders in one step and applies the force in the next, but then again, I never make physics engines and probably never will. π
ooh, a lot of things to respond to
Probably because of what NiseVoid said: #1124043933886976171 message
I would suspect that the rotation quaternion isn't normalized (have a length of 1) because of the invalid state, so when the rotation is applied to the gizmo rendering, it acts like a scaling factor, and the collider looks bigger. Could be wrong about this though.
If they are in a valid state initially, then yeah, it could be a bug. If they have collisions against each other, it could also be this existing issue which you already also encountered: https://github.com/Jondolf/bevy_xpbd/issues/229
This is very doable, but it has caveats.
The current solver uses the "Gauss-Seidel method", which in the context of collisions would essentially mean "Compute overlap for collision A and solve it, then compute overlap for collision B and solve it". This means that in your case, it would first bounce off of the corner of one box, but in it's new position, it's no longer colliding with the other box, so that contact isn't handled.
The main alternative is the "Jacobi method" which first adds up all corrections and only then applies them all at once. So it basically does "Compute overlaps for collisions A and B, and then solve them both". In this case, the bounces against opposite corners should cancel out, because they're combined into a single correction vector instead of being applied separately.
The main caveat is that the Jacobi method has worse "convergence", meaning that it typically takes more solver iterations/substeps to reach the desired state. This would mainly affect cases with several ongoing interactions though (like joint chains or tall cube stacks), so in your case it should have the same convergence as Gauss-Seidel
I believe we could quite easily make the solver method easily changeable though, since we could have each constraint's solve method just return the corrections instead of applying them directly, and have the solver decide how to apply them (Gauss-Seidel or Jacobi)
This in general is just a tricky issue. Bodies are moved discretely (in small steps), and at least without Continuous Collision Detection, they will move slightly inside other colliders before the contacts can be resolved. In your video's case, this means that the ball can hit the side of another box when it hits the intersection of two boxes, because it's not hitting just the top surface of the boxes, but going slightly into the ground and hitting the corner or edge. It's hard to know when these collisions should be ignored, so it's an issue in a lot of engines.
unless it's floating
you can also force the character controller to maintain some very small fixed offset from the ground, and I don't see why that wouldn't be possible for dynamic bodies
yeah I more-so meant for traditional capsule-like characters, not this specific case
I think it'd be nice if we had 2D convex decomposition from polygons, similar to this https://github.com/schteppe/poly-decomp.js/
(not strictly related to what we're discussing tho)
that looks like a polyline maybe
it has a spline detail configuration
so it's not actually making perfectly detailed spline colliders, AFAIK that isn't possible
(except with SDFs?
)
parry makes collider updates a bit cumbersome, you generally need to create a new shape from scratch I believe
might depend on the shape though, haven't tested
I do that to create navmeshes, I first create a CDT with the outer points as constraints, then filter triangles that are out, then merge triangles that are in when possible while keeping convex
Wait I'm dumb, we do have it π
https://docs.rs/bevy_xpbd_2d/latest/bevy_xpbd_2d/components/struct.Collider.html#method.convex_decomposition
A collider used for detecting collisions and generating contacts.
somehow I assumed we only had convex decomp in 3D, even though I created these methods...
(using parry)
creating colliders from meshes is 3D-only for now tho like in rapier
maybe we could instead have a built-in way to create colliders from images with transparency since that'll be more common in 2D
A whopping 7 line PR to fix the Hertz thing: https://github.com/Jondolf/bevy_xpbd/pull/231
I think I will just release 0.3.2 with this since it is a clear oversight and footgun, even though it technically is breaking for the people who configure the timestep
Hey y'all. I am looking for someone to support me in building a little 2d example using xpbd. I talked to @vestal minnow and he mentioned this helpful group of people here β€οΈ
Another perk: i am fine if the example will be open source for others to benefit off. its more like a "how would one build this".
It will be funded! Want to write some rust for money - feel free to ping me π
Yeah I was about to suggest that
That's a good place to hopefully find people interested in collaborating, but if you have specific issues regarding how to do things or if you face issues, this help thread is a good place to ask
Hey, I'm going to try to get bevy_xpbd 3d physics working with big_space, since I don't want to write my own floating origin and physics engine if I don't have to. Was curious if you had any thoughts on this?
I see there's a custom Position component but it's pretty much the same as Vec3
In this case, the computed GlobalTransform would be too imprecise at far away coordinates from the origin, and preferably physics could be done relative to the GridCell position(s)
The edge case being that an entity may be centered on a particular GridCell, but actually overlaps with another or multiple
Preferrably there would be a generic solution where physics "just works" at large distances and/or scales. But if that's not something I can do, I can always just center physics around the player's position (since the render/simulation distance isn't particularly large), and replace the SyncPlugin?
If that were the case, I don't know if modifying the position like that every frame would be a good idea for both performance and physics itself (like could it cause things to clip into each other)?
(If I can figure this out I'll turn it into a crate)
It might actually be easiest to implement your own custom SyncPlugin, and just use f64 positions, then convert those to a Vec3 Transform + grid cell π€
xpbd seems to only support f32 though?
Ideally bevy would upstream some solution to extend the usable space, and then other crates could easily integrate with it, without these kinds of issues on the edges of grid cells
There's a feature flag for f32 vs f64, if you disable default features you should be able to turn f64 on
maybe I should implement true floating origin? where everything is repositioned every frame around the player
that way there's no cells
then I could just use that relative Vec3 position for xpbd
I'm not sure how well xpbd reponds to those changes in positions atm, tho that would definitely work as long as it is intended behavior that only things near you get simulated (accurately)
ok I'll play around with that - if big_space + xpbd with f64 can get me the precision I need to a certain distance (somewhere in the range of 10s of millions) I think that will be fine for now
I don't necessarily need infinite distance. 20,000 from origin is just simply not sufficient
thanks @cinder summit
FYI I released the patch #1172212721400414339
So if timesteps are broken again for those who configured it with seconds, replace it with Hertz π
Is CCD planned for the near future or still far off?
Probably not the near future since I'm prioritizing other things for the time being (like joints now, and then maybe experimenting with making a parry alternative)
I haven't looked into what CCD requires in depth yet, so it's hard to say
- substepping has generally been enough so far
FWIW SleepingDisabled does not help. I think that's a red herring.
Honestly a high enough fixed timestep eliminated the need for me; not sure if this helps your case
@vestal minnow I can confirm that adding normalize() to the rotations in position_constraints.rs fixes my exploding problem.
Doesn't seem to be necessarily in angular_constraints, but I think that's because it happens that the constraints are applied with positional_constraints second, so it's covered
Like this?
if body1.rb.is_dynamic() && body1.dominance() <= body2.dominance() {
body1.accumulated_translation.0 += p * inv_mass1;
*body1.rotation += Self::get_delta_rot(rot1, inv_inertia1, r1, p);
*body1.rotation = body1.rotation.normalize();
}
if body2.rb.is_dynamic() && body2.dominance() <= body1.dominance() {
body2.accumulated_translation.0 -= p * inv_mass2;
*body2.rotation -= Self::get_delta_rot(rot2, inv_inertia2, r2, p);
*body2.rotation = body2.rotation.normalize();
}
(except 2D needs to be handled separately ofc)
yes except there was some fighting witht he compiler over 2d... yes exactly
in 3d it is *body1.rotation.0 = *body1.rotation.0.normalize();
ya
unless you want to implement normalize() for Rotation
A PR would be nice if it works π
Yeah, I'll do that -- I just am not sure what to do with the 2D. (Can that get un-normalized?)
Well it can't be normalized since it's not a vector or quaternion (unless you think of it as a Z rotation axis, but then the rotation would always be 1)
but I guess we could wrap the rotation so that it's always in the [0, 2pi] range?
this seems relevant https://github.com/bevyengine/bevy/issues/2548 π
(I was referring to this not being relevant, not that GH issue haha)
yeah
should I do #[cfg(feature = "3d")] { *body1.rotation.0 = *body1.rotation.0.normalize(); }
hmmm or no wait I have a better idea -- get_delta_rot could be changed to something that returns (or sets?) the new rotation and normalizes there. Then normalize only needs to be done in the 3d version, and it only needs to be done in one place.