jondolf / bevy_xpbd Goto Github PK
View Code? Open in Web Editor NEW2D and 3D physics engine based on Extended Position Based Dynamics for Bevy.
Home Page: https://crates.io/crates/bevy_xpbd_3d
License: Apache License 2.0
2D and 3D physics engine based on Extended Position Based Dynamics for Bevy.
Home Page: https://crates.io/crates/bevy_xpbd_3d
License: Apache License 2.0
You mentioned in #1 that you were struggling with "unstable collisions", and this was something you'd like to fix before releasing. Just though it might be useful to have an issue for it.
Maybe explaining it and having some extra eyes on it would help :)
(fwiw I was also having trouble with unstable things as I added friction in the tutorial series), and I never quite figured it out, perhaps this is the same thing?
Was wondering if there's any plans to support marching cubes or some other variant of destructible terrain in this engine. Or if that's a bit too high level for xpbd, maybe there could be some sort of example along those lines?
Hi Jondolf, author of bevy_xpbd-the tutorial series here :) fun to see I inspired something and the project still goes on :)
From time to time, I've been toying with the idea of picking up and finishing my tutorial. My plan was to wrap up the friction chapter, clean up the language, and then making my own bevy_xpbd repo public and release on crates.io... which I guess I no longer have to do since you're way ahead of me :P
I'm still wondering if I should finish the tutorial itself, though, and I'm thinking about looking at your code for inspiration :) ...but I'm wondering: would you mind dual-licensing your code under Apache-2 as well? That way anything you/we make can easily be moved between the various crates in the bevy ecosystem.
Also: what's your plan for nalgebra/parry types in public API, is it going to stay or not?
Documentation doesn't clearly state if ExternalForce
should be computed in the global referential or in the object's referential.
Hi,
Firstly, great work with this library man! The seamless integration with Bevy is a winner. I know your busy with school work so no rush on this one. But if some thing obvious stands out to you here, please let me know.
I have a weird one. I've copied the many_shapes.rs
example, where instead I'm just using block and they appear every 2 seconds at the top of the screen. By the time I get to 10 the whole thing is laggy, which is weird as many_shapes.rs
seems to have a lot more ridged bodies + colliders in the scene? I can't figure out what the big difference is here?
Here is the full main.rs file. Simpler than many_shapes.rs
really:
use bevy::window::WindowMode;
use bevy::{prelude::*, sprite::MaterialMesh2dBundle};
use bevy_xpbd_2d::{math::*, prelude::*};
use rand::Rng;
#[derive(Resource)]
struct WordSpawnTimer(Timer);
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
resizable: false,
mode: WindowMode::BorderlessFullscreen,
..default()
}),
..default()
}))
.add_plugins(PhysicsPlugins::default())
.insert_resource(WordSpawnTimer(Timer::from_seconds(
2.0,
TimerMode::Repeating,
)))
.insert_resource(ClearColor(Color::rgb(0.05, 0.05, 0.1)))
.insert_resource(SubstepCount(6))
.insert_resource(Gravity(Vector::NEG_Y * 1000.0))
.add_systems(Startup, (setup_graphics, setup_scene))
.add_systems(Update, (spawn_blocks, keyboard_input))
.run();
}
fn setup_graphics(mut commands: Commands) {
// Add a camera so we can see the debug-render.
commands.spawn(Camera2dBundle::default());
}
fn setup_scene(mut commands: Commands, window: Query<&Window>) {
let window = window.single();
let width = window.resolution.width();
let height = window.resolution.height();
// Floor
commands.spawn((
RigidBody::Static,
Position(Vector::new(0.0, -height / 2.0)),
Collider::cuboid(width, 10.0),
));
// Left wall
commands.spawn((
RigidBody::Static,
Position(Vector::new(-width / 2.0, 0.0)),
Collider::cuboid(10.0, height),
));
// Right wall
commands.spawn((
RigidBody::Static,
Position(Vector::new(width / 2.0, 0.0)),
Collider::cuboid(10.0, height),
));
}
fn random_colour() -> Color {
let mut rng = rand::thread_rng();
Color::rgb(rng.gen(), rng.gen(), rng.gen())
}
fn spawn_blocks(
mut commands: Commands,
time: Res<Time>,
mut timer: ResMut<WordSpawnTimer>,
window: Query<&Window>,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
) {
if timer.0.tick(time.delta()).just_finished() {
// let mut rng = rand::thread_rng();
let window = window.single();
let width = window.resolution.width();
let height = window.resolution.height();
// let half_width = width / 2.0;
let dim = width.min(height) / 10.0;
let square = (
Collider::cuboid(dim, dim),
MaterialMesh2dBundle {
mesh: meshes.add(shape::Box::new(dim, dim, dim).into()).into(),
material: materials.add(ColorMaterial::from(random_colour())),
..default()
},
);
// let position = Vector::new(rng.gen_range(-half_width..half_width), height / 2.0 + dim);
let position = Vector::new(0.0, height / 2.0);
commands.spawn((
square,
RigidBody::Dynamic,
Position(position),
Friction::new(0.001),
));
}
}
fn keyboard_input(
keys: Res<Input<KeyCode>>,
mut app_exit_events: ResMut<Events<bevy::app::AppExit>>,
) {
if keys.just_pressed(KeyCode::Escape) {
app_exit_events.send(bevy::app::AppExit);
}
}
I'll have a look over the Johan Helsing video's to see if anything stands out to me.
word
Sometimes CollidingEntities starts behaving incorrectly. Sometimes after the end of a collision with an object, its entity is not removed from the list, resulting in a hang in the air for the player's dynamic controller, as shown below. In case the incorrect behavior of the component has started, it starts accumulating in CollidingEntities all entities it has encountered. Sometimes incorrect behavior is not observed.
Cube controller code:
app.add_systems(PhysicsSchedule, move_player.run_if(in_state(EditorState::Game)).before(PhysicsStepSet::BroadPhase))
...
fn move_player(
keyboard_input: Res<Input<KeyCode>>,
mut query: Query<(Entity, &mut LinearVelocity, &mut AngularVelocity, &PlayerController, &CollidingEntities, &mut Transform)>,
time : Res<Time>
) {
for (e, mut vel, mut rot, controller, colliding, tranform) in query.iter_mut() {
if colliding.len() > 0 {
info!("colliding: {:?}", colliding);
let frw = tranform.forward();
let up = tranform.up();
let mut target_vel = Vector::new(0.0, 0.0, 0.0);
if keyboard_input.pressed(KeyCode::W) {
target_vel += frw;
}
if keyboard_input.pressed(KeyCode::S) {
target_vel -= frw;
}
//rotate
if keyboard_input.pressed(KeyCode::A) {
rot.y = 2.0;
}
if keyboard_input.pressed(KeyCode::D) {
rot.y = -2.0;
}
if !keyboard_input.pressed(KeyCode::A) && !keyboard_input.pressed(KeyCode::D) {
rot.y -= 10.0 * rot.y * time.delta_seconds();
}
target_vel *= controller.speed;
if keyboard_input.pressed(KeyCode::Space) {
target_vel += up * controller.jump_speed;
}
//smooth change vel
let cur_vel = vel.0.clone();
let cur_vel = vel.0 + (target_vel - cur_vel) * 10.0 * time.delta_seconds();
vel.0 = cur_vel;
} else {
}
}
}
Full code can be founded at https://github.com/rewin123/space_editor/blob/v0.1/examples/platformer.rs
Tested on 8b2ea8f in main branch
It's unclear what the default value is, or if it's globally configurable.
When using xpbd and bevy as crates, if I use a local bevy repository (by using path = "../bevy" in Cargo.toml), the compiler complains about
the trait `bevy::prelude::Component` is not implemented for `bevy_xpbd_3d::components::Position`
Any advice?
If I make a rigid body with a single capsule collider with an off-center origin, e.g.:
// 1m tall character with origin at (0,0); using Z-up so gravity is (0, 0, -9.8)
SharedShape::capsule(point3(0.0, 0.0, 0.25), point3(0.0, 0.0, 0.75), 0.25),
If I inspect the inferred CenterOfMass component, it correctly shows as CenterOfMass(Vec3(0.0, 0.0, 0.5))
. However the object behaves as if the center of mass was at (0, 0, -0.5)
, so the capsule wobbles upright on one end instead of falling over.
The same thing happens if I make a centered capsule and use a compound collider to offset it:
let cap = SharedShape::capsule_z(0.25, 0.25);
let xf = Isometry3::translation(0.0, 0.0, 0.5);
let c = SharedShape::compound(vec![(xf, cap)]);
[Actually the same thing happens in 2.0. In the latest it fails on a todo
in as_support_map
for compound
.]
Colliders seem to work fine if their center of mass is (0,0,0).
(I haven't made a small repro for this yet but I can.)
We should make it possible to configure the default values used for friction and restitution. It's annoying to set each body's friction separately if your world is full of ice, for example.
While we can't change the value returned by e.g. Restitution::default()
at runtime, it should be very straightforward to do in the PreparePlugin
when initializing missing components for bodies and colliders. We can store the default values in resources and use them for the default values of the components.
How do we want to name the resources? Do we want each component to have a separate resource, or should we group properties together?
Here are a few ideas:
// All separate
struct DefaultFriction(Friction);
struct DefaultRestitution(Restitution);
struct DefaultLinearDamping(Scalar);
struct DefaultAngularDamping(Scalar);
// Grouped
struct DefaultMaterialProperties {
friction: Friction,
restitution: Restitution,
}
struct DefaultDamping {
linear: Scalar,
angular: Scalar,
}
// All together
struct DefaultPhysicsProperties {
friction: Friction,
restitution: Restitution,
linear_damping: Scalar,
angular_damping: Scalar,
}
The Default could also be replaced by Global or World, whichever one is more clear.
Personally, I prefer the first option of using separate resources, since it's a bit more explicit and consistent in terms of our naming conventions, but if others have different ideas, feel free to share.
This is a useful primitive, that can be checked much more quickly (and accurately) than the equivalent polyline or convex hull.
It's also a vital component of slime volleyball!
I made an entity with a position that has a child which also has a position. Both of them have a nonzero z component for draw ordering. That caused the z component of the transform to go off like crazy.
I think this is caused by position_to_transform
taking the z coordinate of the child's original transform and treating it as a global transform.
let new_transform = GlobalTransform::from(
Transform::from_translation(pos.as_f32().extend(transform.translation.z))
.with_rotation(Quaternion::from(*rot).as_f32()),
)
.reparented_to(&GlobalTransform::from(parent_transform));
I changed this to
let new_transform = GlobalTransform::from(
Transform::from_translation(pos.as_f32().extend(transform.translation.z + parent_transform.translation.z))
.with_rotation(Quaternion::from(*rot).as_f32()),
)
.reparented_to(&GlobalTransform::from(parent_transform));
but I don't know if that still works if the parent is scaled. Maybe it would be best to just set it after doing the GlobalTransform::from
?
Can you give me an example of loading a third-party model to generate collisions? I loaded a third-party model myself to generate collisions, which became very slow
In my game I want to prevent projectile-ball
bouncing when it hits other balls in grid.
projectile-ball
and grid-ball
actually created from the same function and I set Restitution { coefficient: 0.0, combine_rule: CoefficientCombine::Multiply }
for all balls.
When I shoot with projectile-ball
I set it's LinearVelocity.
Some magnetic force is applying for all grid-balls
as ExternalForce
That is all that affected both grid-ball
and projectile-ball
.
I want my ball to completely stop when they started to collide/touch.
What I see right now is that balls have some kind of Inertia
.
For example projectile-ball
bounces back (depends on the hit angle):
Enother example is why my projectile-ball
pushes other grid-ball
s:
How can I completely stop balls on the first touch?
I am trying to replace rapier
engine with xpbd
.
Due to very similar syntax I switched from rapier
to xpbd
in just a few hours, awesome!
However I can not proceed with my game development.
Debug mode cargo run
extremely slow. 2
- 10
fps...
7 balls + 1 projectile ball + 2 next balls + 2 walls as cuboids + 2 lines as cuboids = that is all
And even for this small amount of entities physics engine is extremely slow.
I am using simple colliders+positions, maybe I am missing something?
In comparison to bevy_rapier
- I can run about 30 entities without any lags.
Is there any diagnostic for this engine, so at least I can try to investigate what system cause this?
I can only see that comment out Collider
increase my frame rate to 20
fps...
Tips from [Why is performance so bad?](https://docs.rs/bevy_xpbd_2d/latest/bevy_xpbd_2d/#why-is-performance-so-bad) section do not help.
How do I check for collisions between two entities? The docs has this:
fn my_system(mut collision_event_reader: EventReader<Collision>) {
for Collision(contact) in collision_event_reader.iter() {
println!("{:?} and {:?} are colliding", contact.entity1, contact.entity2);
}
}
But how do I check between two specific entities? This is the ideal API I am imagining:
fn my_system(
player_query: Query<Entity, With<Player>>,
bullet_query: Query<Entity, With<Bullet>>,
) {
let player = player_query.single();
for bullet in bullet_query.iter() {
if let Collision(contact) = check_collision(player, bullet) {
do_something(contact);
}
}
}
Is there a way to do this with this library?
Because AngVel
implements Deref<f32>
, we will get std::f32::to_radians
, which converts from degrees to radians, but AngVel
is already in radians...
Not sure how we'd fix this besides removing the derive for Deref
from AngVel
and the other components... It's a trade-off and we'd lose some nice ergonomics. Just putting this here in case anyone else has a good idea about how to go about it.
Sometimes when removing colliders I get panic at src/plugins/spatial_query/pipeline.rs:135:67
:
fn update_incremental_internal(...) {
// ...
if refit_and_balance {
let _ = self.qbvh.refit(0.0, &mut self.workspace, |entity_index| {
// Construct entity ID
let generation = self.entity_generations.get(entity_index).map_or(0, |i| *i);
let entity = utils::entity_from_index_and_gen(*entity_index, generation);
// Compute and return AABB
let (iso, shape, _) = self.colliders.get(&entity).unwrap(); // <-- here
let aabb = shape.get_shape().compute_aabb(iso);
aabb
});
self.qbvh.rebalance(0.0, &mut self.workspace);
}
// ...
}
Happens on 6ec8bc4
I have a wall creation system and my game and I need to update colliders when player change walls.
Currently I just create new collider trimesh every update. But it would be better if I could replace the old trimesh with a new one to avoid reallocation (from slice, for example).
Cubes start moving after a complete stop, as if they are possessed:
The issue is mitigated by enabling f64
precision.
Note that it happens even when objects are close to (0, 0) and is unrelated to #84: I've tested both with and without the PR, same result.
After #90, convex-convex collisions use contact manifolds, i.e. many contact points instead of one. This mitigates pretty much all drifting and explosive behaviour.
However, using the same approach for collisions against non-convex colliders (like trimeshes) caused bodies with convex colliders (like cubes) to sink into the non-convex colliders, sometimes even going straight through. For this reason, they still use the old single contact point method for now.
Fixing this would be really important though, as it would resolve essentially all remaining contact instability that I'm aware of, so let me know if you have any ideas about how to implement it correctly. I'll also look into it more and try to find a fix.
Currently, bevy_xpbd
uses the components Pos
and Rot
for describing the position and orientation of bodies. At the end of each iteration of the main physics loop, these are synchronized with bevy's Transform
s.
I'd like to discuss if we should remove the separate components and move to just using bevy's own Transform
s.
Rot
implementations for 2D and 3D, all rotations use Quat
s)Transform
and PrevTransform
instead of Pos
, PrevPos
, Rot
, and PrevRot
)Transform
s directlybevy_rapier
)Transform
hierarchies, scaling and shearing can cause serious problems (see comments below)Transform
at once. Separate systems with Pos
and Rot
can run simultaneously.f64
version of Transform
unless we make a custom one (adding f64
as a crate feature: #7)Pos
uses Vec2
and Rot
uses a scalar value. Transform
s just have a Vec3
and a Quat
, which can be considered less ergonomic for 2D. However, bevy users are used to working with them, and they might provide more freedom, so this may not be an issue.Personally, at least from an API standpoint, I think it makes sense to move to using just Transform
s, as it would generally be much more convenient and familiar for bevy users, and it would also probably reduce the engine's code and complexity. Using Transform
s for physics can cause many problems as well though, which is why I'd like to hear what others think.
Currently, if an object is moved while the simulation is paused, its transform is not updated, so the collision queries for example will not work until the simulation is resumed
Configurations with their own fixed schedule passed to PhysicsPlugins::new()
have incorrect time dilation.
In my case I pass Bevy's FixedUpdate
schedule that I have configurated to run at 1./16.
. This causes physics sim to run in slow-motion. Setting PhysicsTimestep::Fixed
in addition does not solve the time dilation problem.
I pass my own FixedUpdate
to keep my schedules in sync.
Static level geometry is often expressed in TriMesh colliders. When the level is big, debug render tries to draw millions of lines using an immediate mode API, which is painfully slow (10 fps)
Other solutions include:
I'm messing around with some simple planets and I'm trying to manually set the mass in order to calculate gravitational pull or what not. Right now, I can do something like that:
#[derive(Bundle)]
pub struct PlanetBundle {
pub planet: Planet,
pub position: Position,
pub rigid_body: RigidBody,
pub mass: Mass,
}
But it's never exactly what I set it to after the first frame or so. For example, when I set a mass of 200.0
it eventually gets changed to 219.31
or something. I remember seeing some code in the lib that added to the mass based off the mass properties so that's probably why.
Is there any way to override the default behavior of the mass changing?
I have a game with a ship as rigid body with a collider and engines attached to it as children, each has colliders and mass as well. I've enabled debug renderer to see the colliders. Engines' colliders don't move with teh ship, but instead stay at (0, 0, 0). Also, they don't have any rotation or scale applied. I'm not sure if this is a bug with only debug renderer, or handling of hierarchy is not even intended, but this does bother me while I'm transitioning to this engine from rapier as an experiment.
I'd like to grave some objects fly, i.e. I'd like to be able to compute their lift, drag, and have everything work like by magic.
Is that something possible ? If yes how would I do that ? 1-entity constraints ?
This is most likely an issue in Parry. See dimforge/parry#166.
Hi ! I'm trying to make my local fork of bevy_mod_wanderlust
work with bevy_xpbd
and one of the things that's tripping me up is that I can't find any direct parallel for bevy_rapier3d::parry::query::contact
. Bevy_mod_wanderlust
does some interesting iterative position adjusting in the case they're penetrating the ground already and relies on contact
to know which direction to back out from:
if let Ok(Some(contact)) = bevy_rapier3d::parry::query::contact(
&cast_iso,
&*shape_caster.raw,
&ground_iso,
&*ground_collider.raw,
0.0,
) {
// Adjust position so we're no longer contacting
}
bevy_xpbd
has a similar SpatialQuery::shape_intersections
but it only returns an Entity. I think I could align the entities with the Contacts in the physics world or something but I think they'd be out of date with those from the shape_intersections if you we're to run it multiple times in one frame meanwhile adjusting positions right? That's just my assumption, I'm not sure.
shape_intersections
I think still should return Contacts but that function isn't what bevy_rapier3d::parry::query::contact
does. shape_intersections
returns all entities colliding with that one specific shape. Instead, I think it'd be better to ask for a function to be added to SpatialQuery that returns the contact points between two colliders given their isometries? I might be able to PR this if you'd prefer.
Anyways, very much enjoying the library :D
Future features in the readme lists Collision Filtering as something not yet implemented and I would like to get the ball rolling if possible.
Some topics that were discussed on Discord included:
Adding a schedule after the SubstepSet::NarrowPhase
, and exposing a way to filter collisions from the Collisions
resource gives a very open-ended and straightforward way to allow for modifying collisions.
I've got a working example on this fork here.
I'm in two minds about whether it's worth the schedule to have built-in sets (e.g. First
, Filter
, Modify
, Last
), or whether that complexity should be left up to the user. I can see a potential want to pre-filter collisions with faster filters before any slower ones execute, for example.
@Jondolf suggested something in the following form:
ContactFilter::new()
.with_excluded_entities([...])
.with_predicate(|mut contact: ContactData| {
// Modify contact (optional)
contact.penetration = 0.1;
// Return the contact or use None to ignore contact
Some(contact)
}),
It was also suggested that some form of combination rule may be needed to handle when two entities with conflicting filter predicates are present.
Being able to modify the individual contacts is desirable. Therefore, being able to return Some(contact)
from a post-processing step is more useful than only being able to remove or keep collisions.
@Jondolf showed the following code on Discord as something that it would be nice to be able to do. There was discussion about how this may not be possible with one-shot systems, but using run_system_with
* may allow it as long as the overhead was acceptable.
* run_system_with
was added to bevy with this merged but unreleased-at-the-time-of-writing pull request.
fn setup(mut commands: Commands, contact_hook_pipeline: ContactHookPipeline) {
commands.spawn((
ContactHook::new(
&contact_hook_pipeline,
|In(mut contact): In<ContactData>, query: Query<&MyBundle>| {
// Modify contact, query for entities, do whatever
// Return new contact data to narrow phase; if None, skip contact
Some(contact)
}
),
));
}
Something along the lines of (Body1, CollidesWith(Contacts), Body2)
was suggested by @Jondolf.
Bevy currently has a tracking issue for entity relations here: bevyengine/bevy#3742
Should filtering be treated as a separate issue from modification?
My current personal needs for collision filtering are very simplistic: I just want to implement one-way platforms, which is easily solved by the first bullet point above. I therefore have a very narrow view of what needs exist when it comes to being able to filter/modify collisions, and so would like to get input from other interested parties.
One shortfall of bevy_rapier that I would like to avoid was that it seemed impossible to register more than one set of query params to use with collision hooks because the parameters are registered on the plugin itself as a generic type. Being able to access queries while filtering and modifying collisions seems very important in an ECS.
I've started work on global filters and entity-entity collision exclusion in a fork here, but am looking for input. I'd be interested in creating a pull request at some point, even if it's only for the global collision hook, as it's a small enough change that gives quite a bit of power from the get-go.
I'm trying to figure out how to apply a force to the player, but I can't figure out how.
I have roughly something like this:
commands.spawn((
...
RigidBody::Dynamic,
ExternalForce::default(),
Player,
));
fn system(mut force_query: Query<&mut ExternalForce, With<Player>>) {
for mut force in &mut force_query {
force.apply_force(Vec2::Y * 10.);
}
}
But doing so have no effect on the player. I can query and mutate the velocity instead and it will work, so I know that my code is not completely broken at least.
init_rigid_bodies
should run after TransformPropagate
, since it uses GlobalTransform
when Position
is missing.
Otherwise newly spawned entities fall back to (0, 0, 0) position.
This would mean that new entities would start moving according to physics only on the next frame. To mitigate that, transform propagation could be run twice โ before and after the physics. The 'before' system can have a condition to run only if there are added rigid bodies.
Fixing this should make child colliders possible (at least for static bodies).
Rapier have AsyncSceneCollider
to automatically generate collision after scene spawn.
I would suggest to add a similar feature for convenience, but with the ability to specify collider layers.
Currently, you can set it to e.g. 2.0 (with max combine rule) in the move_marbles example and things will explode.
I'm writing some interpolation code that keeps track of Transforms from the previous physics tick and interpolates between that and the current Transform every regular update, storing it in a separate entity for rendering. Problem is I need access to PhysicsLoop::accumulator
, which currently is private (because of pub(crate)
). Could this be changed?
Also noticed that the PhysicsLoop
can't be found in the docs.
If it possible to change RigidBody
?
I want to change from RigidBody::Kinematic => RigidBody::Dynamic
in some system.
I can not find any example how to do this.
It seems that the engine isn't deterministic across machines/OS. For me, the cubes_simulation_is_deterministic_across_machines
test used to produce insta snapshots that worked in CI, but I'm guessing that it was because I used to run cargo insta test
in Ubuntu, which is the same OS that our GitHub actions use. Now that I'm running it on Windows, the snapshots are different and CI fails.
For now, I think we should remove the test since it's misleading if the engine isn't actually deterministic across operating systems. Eventually it'd be nice to have proper determinism as well.
Is there a way to manually mutate the Rotation
component? Looking at the methods, it looks like that they all just return new structs. Is there a way to actually change the rotation manually?
Took a bit to find this, so a doc alias would be useful.
I am pretty sure that the generalized inverse masses calculated in solve_vel should be based on the delta_v direction not the collision normal?
I have a short lived bullet, when it gets despawned using commands.entity(entity).despawn();
i get a crash:
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', /Users/rj/src/bevy_xpbd/crates/bevy_xpbd_2d/../../src/plugins/spatial_query/pipeline.rs:82:59
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in system `bevy_xpbd_2d::plugins::spatial_query::update_query_pipeline`!
Encountered a panic in exclusive system `bevy_xpbd_2d::plugins::setup::run_physics_schedule`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: RecvError', /Users/rj/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_render-0.11.0/src/pipelined_rendering.rs:110:77
might need to check in there that the entity still has a collider - i suppose it doesn't if it's being despawned?
not exactly sure what triggers it, but happens pretty soon if i fly around blasting bullets that are set to despawn after a second or so.
Just creating this to track (haven't started anything).
Stageless should clean up the substep looping quite a bit :)
Okay, so after #4 the algorithm logic got a lot less awkward, and that opens up some possibilities. Currently DELTA_TIME
is hard-coded to 60 Hz, but it should probably be configurable at some level.
The obvious thing would be to just make it a resource:
pub struct PhysicsTimeStep(pub f32)
However I'm wondering, would that hurt performance? Does the rust compiler precompute constants, that means we shouldn't do this?
If so, perhaps we should consider if we can somehow use const-generics to still make it configurable at build-time (at least at an internal level).
Second question is: would it make sense to also allow a variable timestep? i.e. consume the remainder of the accumulator with one not-whole physics step.
Would obviously not be deterministic, but could perhaps produce smoother visuals if you don't do smoothing in your renderer.
I discovered that I was getting desyncs in my determinstic networked game because PreviousGlobalTransform
wasn't registered as a rollback component. I would need these changes to register it as a rollback component.
I have a branch to fix a couple of places where assert_eq
is changed to assert_relative_eq
to make the tests pass on a mac M1.
This one I want to flag/query though - since it has a specific epsilon, and the difference in expected and observed values is much larger than the epsilon.
If this difference between left and right is within the acceptable range?
I could change the epsilon to make it pass? or change the epsilon just for apple-m1
?
Seems weird it's such a large difference.
Anyway, happy to try and get all tests passing on m1 with a bit of guidance. thanks
The failing test:
assert_relative_eq!(
mass_props.mass.0,
original_mass_props.mass.0,
epsilon = 0.000_001
);
output from cargo test
:
failures:
---- components::world_queries::tests::mass_properties_add_sub_works stdout ----
thread 'components::world_queries::tests::mass_properties_add_sub_works' panicked at 'assert_relative_eq!(mass_props.mass.0, original_mass_props.mass.0, epsilon = 0.000_001)
left = 15.642822
right = 15.6427965
', crates/bevy_xpbd_2d/../../src/components/world_queries.rs:257:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
components::world_queries::tests::mass_properties_add_sub_works
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.