feat: solver improvements + release v0.29.0 (#876)

* feat: solver improvements

* feat: add function to get/set whether gyroscopic forces are enabled on a rigid-body

* chore: switch to released versions of parry and wide instead of local patches

* fix cargo doc

* chore: typo fixes

* chore: clippy fix

* Release v0.29.0

* chore: more clippy fixes
This commit is contained in:
Sébastien Crozet
2025-09-05 19:31:58 +02:00
committed by GitHub
parent 317322b31b
commit 134f433903
94 changed files with 5066 additions and 8136 deletions

View File

@@ -1,12 +1,11 @@
use rapier::counters::Counters;
use rapier::math::Real;
use std::num::NonZeroUsize;
use crate::debug_render::DebugRenderPipelineResource;
use crate::harness::{Harness, RapierBroadPhaseType};
use crate::testbed::{
PHYSX_BACKEND_PATCH_FRICTION, PHYSX_BACKEND_TWO_FRICTION_DIR, RapierSolverType, RunMode,
TestbedActionFlags, TestbedState, TestbedStateFlags,
PHYSX_BACKEND_PATCH_FRICTION, PHYSX_BACKEND_TWO_FRICTION_DIR, RunMode, TestbedActionFlags,
TestbedState, TestbedStateFlags,
};
pub use bevy_egui::egui;
@@ -15,9 +14,11 @@ use crate::PhysicsState;
use crate::settings::SettingValue;
use bevy_egui::EguiContexts;
use bevy_egui::egui::{ComboBox, Slider, Ui, Window};
use rapier::dynamics::IntegrationParameters;
use web_time::Instant;
#[cfg(feature = "dim3")]
use rapier::dynamics::FrictionModel;
pub(crate) fn update_ui(
ui_context: &mut EguiContexts,
state: &mut TestbedState,
@@ -113,45 +114,11 @@ pub(crate) fn update_ui(
if state.selected_backend == PHYSX_BACKEND_PATCH_FRICTION
|| state.selected_backend == PHYSX_BACKEND_TWO_FRICTION_DIR
{
let mut num_iterations = integration_parameters.num_solver_iterations.get();
ui.add(Slider::new(&mut num_iterations, 1..=40).text("pos. iters."));
integration_parameters.num_solver_iterations =
NonZeroUsize::new(num_iterations).unwrap();
ui.add(
Slider::new(&mut integration_parameters.num_solver_iterations, 0..=10)
.text("pos. iters."),
);
} else {
// Solver type.
let mut changed = false;
egui::ComboBox::from_label("solver type")
.width(150.0)
.selected_text(format!("{:?}", state.solver_type))
.show_ui(ui, |ui| {
let solver_types = [
RapierSolverType::TgsSoft,
RapierSolverType::TgsSoftNoWarmstart,
RapierSolverType::PgsLegacy,
];
for sty in solver_types {
changed = ui
.selectable_value(&mut state.solver_type, sty, format!("{sty:?}"))
.changed()
|| changed;
}
});
if changed {
match state.solver_type {
RapierSolverType::TgsSoft => {
*integration_parameters = IntegrationParameters::tgs_soft();
}
RapierSolverType::TgsSoftNoWarmstart => {
*integration_parameters =
IntegrationParameters::tgs_soft_without_warmstart();
}
RapierSolverType::PgsLegacy => {
*integration_parameters = IntegrationParameters::pgs_legacy();
}
}
}
// Broad-phase.
let mut changed = false;
egui::ComboBox::from_label("broad-phase")
@@ -177,12 +144,30 @@ pub(crate) fn update_ui(
state.action_flags.set(TestbedActionFlags::RESTART, true);
}
// Solver iterations.
let mut num_iterations = integration_parameters.num_solver_iterations.get();
ui.add(Slider::new(&mut num_iterations, 1..=40).text("num solver iters."));
integration_parameters.num_solver_iterations =
NonZeroUsize::new(num_iterations).unwrap();
// Friction model.
#[cfg(feature = "dim3")]
egui::ComboBox::from_label("friction-model")
.width(150.0)
.selected_text(format!("{:?}", integration_parameters.friction_model))
.show_ui(ui, |ui| {
let friction_model = [FrictionModel::Simplified, FrictionModel::Coulomb];
for model in friction_model {
changed = ui
.selectable_value(
&mut integration_parameters.friction_model,
model,
format!("{model:?}"),
)
.changed()
|| changed;
}
});
// Solver iterations.
ui.add(
Slider::new(&mut integration_parameters.num_solver_iterations, 0..=10)
.text("num solver iters."),
);
ui.add(
Slider::new(
&mut integration_parameters.num_internal_pgs_iterations,
@@ -190,13 +175,6 @@ pub(crate) fn update_ui(
)
.text("num internal PGS iters."),
);
ui.add(
Slider::new(
&mut integration_parameters.num_additional_friction_iterations,
0..=40,
)
.text("num additional frict. iters."),
);
ui.add(
Slider::new(
&mut integration_parameters.num_internal_stabilization_iterations,
@@ -210,7 +188,7 @@ pub(crate) fn update_ui(
);
let mut substep_params = *integration_parameters;
substep_params.dt /= substep_params.num_solver_iterations.get() as Real;
substep_params.dt /= substep_params.num_solver_iterations as Real;
let curr_erp = substep_params.contact_erp();
let curr_cfm_factor = substep_params.contact_cfm_factor();
ui.add(
@@ -411,7 +389,7 @@ fn profiling_ui(ui: &mut Ui, counters: &Counters) {
fn serialization_string(timestep_id: usize, physics: &PhysicsState) -> String {
let t = Instant::now();
// let t = Instant::now();
// let bf = bincode::serialize(&physics.broad_phase).unwrap();
let bf = bincode::serialize(&physics.broad_phase).unwrap();
// println!("bf: {}", Instant::now() - t);
// let t = Instant::now();
let nf = bincode::serialize(&physics.narrow_phase).unwrap();
@@ -426,7 +404,7 @@ fn serialization_string(timestep_id: usize, physics: &PhysicsState) -> String {
let js = bincode::serialize(&physics.impulse_joints).unwrap();
// println!("js: {}", Instant::now() - t);
let serialization_time = Instant::now() - t;
// let hash_bf = md5::compute(&bf);
let hash_bf = md5::compute(&bf);
let hash_nf = md5::compute(&nf);
let hash_bodies = md5::compute(&bs);
let hash_colliders = md5::compute(&cs);
@@ -441,8 +419,8 @@ Hashes at frame: {}
|_ Joints [{:.1}KB]: {}"#,
serialization_time.as_secs_f64() * 1000.0,
timestep_id,
"<fixme>", // bf.len() as f32 / 1000.0,
"<fixme>", // format!("{:?}", hash_bf).split_at(10).0,
bf.len() as f32 / 1000.0,
format!("{:?}", hash_bf).split_at(10).0,
nf.len() as f32 / 1000.0,
format!("{hash_nf:?}").split_at(10).0,
bs.len() as f32 / 1000.0,