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:
@@ -1,250 +0,0 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use na::{Isometry2, Vector2};
|
||||
use rapier::counters::Counters;
|
||||
use rapier::dynamics::{ImpulseJointSet, IntegrationParameters, RigidBodyHandle, RigidBodySet};
|
||||
use rapier::geometry::{Collider, ColliderSet};
|
||||
use std::f32;
|
||||
|
||||
use wrapped2d::b2;
|
||||
// use wrapped2d::dynamics::joints::{PrismaticJointDef, RevoluteJointDef, WeldJointDef};
|
||||
use wrapped2d::user_data::NoUserData;
|
||||
|
||||
fn na_vec_to_b2_vec(v: Vector2<f32>) -> b2::Vec2 {
|
||||
b2::Vec2 { x: v.x, y: v.y }
|
||||
}
|
||||
|
||||
fn b2_vec_to_na_vec(v: b2::Vec2) -> Vector2<f32> {
|
||||
Vector2::new(v.x, v.y)
|
||||
}
|
||||
|
||||
fn b2_transform_to_na_isometry(v: b2::Transform) -> Isometry2<f32> {
|
||||
Isometry2::new(b2_vec_to_na_vec(v.pos), v.rot.angle())
|
||||
}
|
||||
|
||||
pub struct Box2dWorld {
|
||||
world: b2::World<NoUserData>,
|
||||
rapier2box2d: HashMap<RigidBodyHandle, b2::BodyHandle>,
|
||||
}
|
||||
|
||||
impl Box2dWorld {
|
||||
#[profiling::function]
|
||||
pub fn from_rapier(
|
||||
gravity: Vector2<f32>,
|
||||
bodies: &RigidBodySet,
|
||||
colliders: &ColliderSet,
|
||||
impulse_joints: &ImpulseJointSet,
|
||||
) -> Self {
|
||||
let mut world = b2::World::new(&na_vec_to_b2_vec(gravity));
|
||||
world.set_continuous_physics(bodies.iter().any(|b| b.1.is_ccd_enabled()));
|
||||
|
||||
let mut res = Box2dWorld {
|
||||
world,
|
||||
rapier2box2d: HashMap::new(),
|
||||
};
|
||||
|
||||
res.insert_bodies(bodies);
|
||||
res.insert_colliders(colliders);
|
||||
res.insert_joints(impulse_joints);
|
||||
res
|
||||
}
|
||||
|
||||
fn insert_bodies(&mut self, bodies: &RigidBodySet) {
|
||||
for (handle, body) in bodies.iter() {
|
||||
let body_type = if !body.is_dynamic() {
|
||||
b2::BodyType::Static
|
||||
} else {
|
||||
b2::BodyType::Dynamic
|
||||
};
|
||||
|
||||
let linear_damping = 0.0;
|
||||
let angular_damping = 0.0;
|
||||
|
||||
// if let Some(rb) = body.downcast_ref::<RigidBody<f32>>() {
|
||||
// linear_damping = rb.linear_damping();
|
||||
// angular_damping = rb.angular_damping();
|
||||
// } else {
|
||||
// linear_damping = 0.0;
|
||||
// angular_damping = 0.0;
|
||||
// }
|
||||
|
||||
let def = b2::BodyDef {
|
||||
body_type,
|
||||
position: na_vec_to_b2_vec(body.position().translation.vector),
|
||||
angle: body.position().rotation.angle(),
|
||||
linear_velocity: na_vec_to_b2_vec(*body.linvel()),
|
||||
angular_velocity: body.angvel(),
|
||||
linear_damping,
|
||||
angular_damping,
|
||||
bullet: body.is_ccd_enabled(),
|
||||
..b2::BodyDef::new()
|
||||
};
|
||||
let b2_handle = self.world.create_body(&def);
|
||||
self.rapier2box2d.insert(handle, b2_handle);
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_colliders(&mut self, colliders: &ColliderSet) {
|
||||
for (_, collider) in colliders.iter() {
|
||||
if let Some(parent) = collider.parent() {
|
||||
let b2_body_handle = self.rapier2box2d[&parent];
|
||||
let mut b2_body = self.world.body_mut(b2_body_handle);
|
||||
Self::create_fixture(&collider, &mut *b2_body);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn insert_joints(&mut self, _impulse_joints: &ImpulseJointSet) {
|
||||
/*
|
||||
for joint in impulse_joints.iter() {
|
||||
let body_a = self.rapier2box2d[&joint.1.body1];
|
||||
let body_b = self.rapier2box2d[&joint.1.body2];
|
||||
|
||||
match &joint.1.params {
|
||||
JointParams::BallJoint(params) => {
|
||||
let def = RevoluteJointDef {
|
||||
body_a,
|
||||
body_b,
|
||||
collide_connected: true,
|
||||
local_anchor_a: na_vec_to_b2_vec(params.local_anchor1.coords),
|
||||
local_anchor_b: na_vec_to_b2_vec(params.local_anchor2.coords),
|
||||
reference_angle: 0.0,
|
||||
enable_limit: false,
|
||||
lower_angle: 0.0,
|
||||
upper_angle: 0.0,
|
||||
enable_motor: false,
|
||||
motor_speed: 0.0,
|
||||
max_motor_torque: 0.0,
|
||||
};
|
||||
|
||||
self.world.create_joint(&def);
|
||||
}
|
||||
JointParams::FixedJoint(params) => {
|
||||
let def = WeldJointDef {
|
||||
body_a,
|
||||
body_b,
|
||||
collide_connected: true,
|
||||
local_anchor_a: na_vec_to_b2_vec(params.local_frame1.translation.vector),
|
||||
local_anchor_b: na_vec_to_b2_vec(params.local_frame2.translation.vector),
|
||||
reference_angle: 0.0,
|
||||
frequency: 0.0,
|
||||
damping_ratio: 0.0,
|
||||
};
|
||||
|
||||
self.world.create_joint(&def);
|
||||
}
|
||||
JointParams::PrismaticJoint(params) => {
|
||||
let def = PrismaticJointDef {
|
||||
body_a,
|
||||
body_b,
|
||||
collide_connected: true,
|
||||
local_anchor_a: na_vec_to_b2_vec(params.local_anchor1.coords),
|
||||
local_anchor_b: na_vec_to_b2_vec(params.local_anchor2.coords),
|
||||
local_axis_a: na_vec_to_b2_vec(params.local_axis1().into_inner()),
|
||||
reference_angle: 0.0,
|
||||
enable_limit: params.limits_enabled,
|
||||
lower_translation: params.limits[0],
|
||||
upper_translation: params.limits[1],
|
||||
enable_motor: false,
|
||||
max_motor_force: 0.0,
|
||||
motor_speed: 0.0,
|
||||
};
|
||||
|
||||
self.world.create_joint(&def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
fn create_fixture(collider: &Collider, body: &mut b2::MetaBody<NoUserData>) {
|
||||
let center = na_vec_to_b2_vec(
|
||||
collider
|
||||
.position_wrt_parent()
|
||||
.copied()
|
||||
.unwrap_or(na::one())
|
||||
.translation
|
||||
.vector,
|
||||
);
|
||||
let mut fixture_def = b2::FixtureDef::new();
|
||||
|
||||
fixture_def.restitution = collider.material().restitution;
|
||||
fixture_def.friction = collider.material().friction;
|
||||
fixture_def.density = collider.density();
|
||||
fixture_def.is_sensor = collider.is_sensor();
|
||||
fixture_def.filter = b2::Filter::new();
|
||||
|
||||
let shape = collider.shape();
|
||||
|
||||
if let Some(b) = shape.as_ball() {
|
||||
let mut b2_shape = b2::CircleShape::new();
|
||||
b2_shape.set_radius(b.radius);
|
||||
b2_shape.set_position(center);
|
||||
body.create_fixture(&b2_shape, &mut fixture_def);
|
||||
} else if let Some(p) = shape.as_convex_polygon() {
|
||||
let vertices: Vec<_> = p
|
||||
.points()
|
||||
.iter()
|
||||
.map(|p| na_vec_to_b2_vec(p.coords))
|
||||
.collect();
|
||||
let b2_shape = b2::PolygonShape::new_with(&vertices);
|
||||
body.create_fixture(&b2_shape, &mut fixture_def);
|
||||
} else if let Some(c) = shape.as_cuboid() {
|
||||
let b2_shape = b2::PolygonShape::new_box(c.half_extents.x, c.half_extents.y);
|
||||
body.create_fixture(&b2_shape, &mut fixture_def);
|
||||
// } else if let Some(polygon) = shape.as_polygon() {
|
||||
// let points: Vec<_> = poly
|
||||
// .vertices()
|
||||
// .iter()
|
||||
// .map(|p| collider.position_wrt_parent() * p)
|
||||
// .map(|p| na_vec_to_b2_vec(p.coords))
|
||||
// .collect();
|
||||
// let b2_shape = b2::PolygonShape::new_with(&points);
|
||||
// body.create_fixture(&b2_shape, &mut fixture_def);
|
||||
} else if let Some(heightfield) = shape.as_heightfield() {
|
||||
let mut segments = heightfield.segments();
|
||||
let seg1 = segments.next().unwrap();
|
||||
let mut vertices = vec![
|
||||
na_vec_to_b2_vec(seg1.a.coords),
|
||||
na_vec_to_b2_vec(seg1.b.coords),
|
||||
];
|
||||
|
||||
// TODO: this will not handle holes properly.
|
||||
segments.for_each(|seg| {
|
||||
vertices.push(na_vec_to_b2_vec(seg.b.coords));
|
||||
});
|
||||
|
||||
let b2_shape = b2::ChainShape::new_chain(&vertices);
|
||||
body.create_fixture(&b2_shape, &mut fixture_def);
|
||||
} else {
|
||||
eprintln!("Creating a shape unknown to the Box2d backend.");
|
||||
}
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
pub fn step(&mut self, counters: &mut Counters, params: &IntegrationParameters) {
|
||||
counters.step_started();
|
||||
self.world
|
||||
.step(params.dt, params.num_solver_iterations.get() as i32, 1);
|
||||
counters.step_completed();
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
pub fn sync(&self, bodies: &mut RigidBodySet, colliders: &mut ColliderSet) {
|
||||
for (handle, body) in bodies.iter_mut() {
|
||||
if let Some(pb2_handle) = self.rapier2box2d.get(&handle) {
|
||||
let b2_body = self.world.body(*pb2_handle);
|
||||
let pos = b2_transform_to_na_isometry(b2_body.transform().clone());
|
||||
body.set_position(pos, false);
|
||||
|
||||
for coll_handle in body.colliders() {
|
||||
let collider = &mut colliders[*coll_handle];
|
||||
collider.set_position(
|
||||
pos * collider.position_wrt_parent().copied().unwrap_or(na::one()),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,8 +9,6 @@ pub use crate::plugin::TestbedPlugin;
|
||||
pub use crate::testbed::{Testbed, TestbedApp, TestbedGraphics, TestbedState};
|
||||
pub use bevy::prelude::{Color, KeyCode};
|
||||
|
||||
#[cfg(all(feature = "dim2", feature = "other-backends"))]
|
||||
mod box2d_backend;
|
||||
#[cfg(feature = "dim2")]
|
||||
mod camera2d;
|
||||
#[cfg(feature = "dim3")]
|
||||
|
||||
@@ -173,7 +173,7 @@ impl PhysxWorld {
|
||||
gravity: gravity.into_physx(),
|
||||
thread_count: num_threads as u32,
|
||||
broad_phase_type: BroadPhaseType::Abp,
|
||||
solver_type: SolverType::Pgs,
|
||||
solver_type: SolverType::Tgs,
|
||||
friction_type,
|
||||
ccd_max_passes: integration_parameters.max_ccd_substeps as u32,
|
||||
..SceneDescriptor::new(())
|
||||
@@ -211,7 +211,7 @@ impl PhysxWorld {
|
||||
actor.set_angular_velocity(&angvel, true);
|
||||
actor.set_solver_iteration_counts(
|
||||
// Use our number of solver iterations as their number of position iterations.
|
||||
integration_parameters.num_solver_iterations.get() as u32,
|
||||
integration_parameters.num_solver_iterations as u32,
|
||||
1,
|
||||
);
|
||||
|
||||
@@ -770,6 +770,8 @@ impl AdvanceCallback<PxArticulationLink, PxRigidDynamic> for OnAdvance {
|
||||
}
|
||||
|
||||
unsafe extern "C" fn ccd_filter_shader(data: *mut FilterShaderCallbackInfo) -> PxFilterFlags {
|
||||
(*(*data).pairFlags) |= physx_sys::PxPairFlags::DetectCcdContact;
|
||||
unsafe {
|
||||
(*(*data).pairFlags) |= physx_sys::PxPairFlags::DetectCcdContact;
|
||||
}
|
||||
PxFilterFlags::empty()
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::camera2d::OrbitCamera;
|
||||
#[cfg(feature = "dim3")]
|
||||
use crate::camera3d::OrbitCamera;
|
||||
use crate::settings::ExampleSettings;
|
||||
use crate::testbed::{RapierSolverType, RunMode, TestbedStateFlags};
|
||||
use crate::testbed::{RunMode, TestbedStateFlags};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
|
||||
@@ -13,22 +13,6 @@ pub struct SerializableTestbedState {
|
||||
pub selected_example: usize,
|
||||
pub selected_backend: usize,
|
||||
pub example_settings: ExampleSettings,
|
||||
pub solver_type: RapierSolverType,
|
||||
pub physx_use_two_friction_directions: bool,
|
||||
pub camera: OrbitCamera,
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim2")]
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
|
||||
pub struct SerializableCameraState {
|
||||
pub zoom: f32,
|
||||
pub center: na::Point2<f32>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "dim3")]
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug, Default, Clone)]
|
||||
pub struct SerializableCameraState {
|
||||
pub distance: f32,
|
||||
pub position: na::Point3<f32>,
|
||||
pub center: na::Point3<f32>,
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use bevy::prelude::*;
|
||||
use std::env;
|
||||
use std::mem;
|
||||
use std::num::NonZeroUsize;
|
||||
|
||||
use crate::debug_render::{DebugRenderPipelineResource, RapierDebugRenderPlugin};
|
||||
use crate::graphics::BevyMaterialComponent;
|
||||
@@ -30,8 +29,6 @@ use rapier::pipeline::PhysicsHooks;
|
||||
#[cfg(feature = "dim3")]
|
||||
use rapier::{control::DynamicRayCastVehicleController, prelude::QueryFilter};
|
||||
|
||||
#[cfg(all(feature = "dim2", feature = "other-backends"))]
|
||||
use crate::box2d_backend::Box2dWorld;
|
||||
use crate::harness::{Harness, RapierBroadPhaseType};
|
||||
#[cfg(all(feature = "dim3", feature = "other-backends"))]
|
||||
use crate::physx_backend::PhysxWorld;
|
||||
@@ -48,8 +45,6 @@ use crate::graphics::BevyMaterial;
|
||||
// use bevy::render::render_resource::RenderPipelineDescriptor;
|
||||
|
||||
const RAPIER_BACKEND: usize = 0;
|
||||
#[cfg(all(feature = "dim2", feature = "other-backends"))]
|
||||
const BOX2D_BACKEND: usize = 1;
|
||||
pub(crate) const PHYSX_BACKEND_PATCH_FRICTION: usize = 1;
|
||||
pub(crate) const PHYSX_BACKEND_TWO_FRICTION_DIR: usize = 2;
|
||||
|
||||
@@ -101,14 +96,6 @@ bitflags::bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)]
|
||||
pub enum RapierSolverType {
|
||||
#[default]
|
||||
TgsSoft,
|
||||
TgsSoftNoWarmstart,
|
||||
PgsLegacy,
|
||||
}
|
||||
|
||||
pub type SimulationBuilders = Vec<(&'static str, fn(&mut Testbed))>;
|
||||
|
||||
#[derive(Resource)]
|
||||
@@ -131,7 +118,6 @@ pub struct TestbedState {
|
||||
pub selected_example: usize,
|
||||
pub selected_backend: usize,
|
||||
pub example_settings: ExampleSettings,
|
||||
pub solver_type: RapierSolverType,
|
||||
pub broad_phase_type: RapierBroadPhaseType,
|
||||
pub physx_use_two_friction_directions: bool,
|
||||
pub snapshot: Option<PhysicsSnapshot>,
|
||||
@@ -148,7 +134,6 @@ impl TestbedState {
|
||||
selected_example: self.selected_example,
|
||||
selected_backend: self.selected_backend,
|
||||
example_settings: self.example_settings.clone(),
|
||||
solver_type: self.solver_type,
|
||||
physx_use_two_friction_directions: self.physx_use_two_friction_directions,
|
||||
camera,
|
||||
}
|
||||
@@ -161,7 +146,6 @@ impl TestbedState {
|
||||
self.selected_example = state.selected_example;
|
||||
self.selected_backend = state.selected_backend;
|
||||
self.example_settings = state.example_settings;
|
||||
self.solver_type = state.solver_type;
|
||||
self.physx_use_two_friction_directions = state.physx_use_two_friction_directions;
|
||||
*camera = state.camera;
|
||||
}
|
||||
@@ -172,8 +156,6 @@ struct SceneBuilders(SimulationBuilders);
|
||||
|
||||
#[cfg(feature = "other-backends")]
|
||||
struct OtherBackends {
|
||||
#[cfg(feature = "dim2")]
|
||||
box2d: Option<Box2dWorld>,
|
||||
#[cfg(feature = "dim3")]
|
||||
physx: Option<PhysxWorld>,
|
||||
}
|
||||
@@ -222,8 +204,6 @@ impl TestbedApp {
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut backend_names = vec!["rapier"];
|
||||
#[cfg(all(feature = "dim2", feature = "other-backends"))]
|
||||
backend_names.push("box2d");
|
||||
#[cfg(all(feature = "dim3", feature = "other-backends"))]
|
||||
backend_names.push("physx (patch friction)");
|
||||
#[cfg(all(feature = "dim3", feature = "other-backends"))]
|
||||
@@ -249,7 +229,6 @@ impl TestbedApp {
|
||||
example_settings: ExampleSettings::default(),
|
||||
selected_example: 0,
|
||||
selected_backend: RAPIER_BACKEND,
|
||||
solver_type: RapierSolverType::default(),
|
||||
broad_phase_type: RapierBroadPhaseType::default(),
|
||||
physx_use_two_friction_directions: true,
|
||||
nsteps: 1,
|
||||
@@ -260,8 +239,6 @@ impl TestbedApp {
|
||||
let harness = Harness::new_empty();
|
||||
#[cfg(feature = "other-backends")]
|
||||
let other_backends = OtherBackends {
|
||||
#[cfg(feature = "dim2")]
|
||||
box2d: None,
|
||||
#[cfg(feature = "dim3")]
|
||||
physx: None,
|
||||
};
|
||||
@@ -383,7 +360,7 @@ impl TestbedApp {
|
||||
self.harness
|
||||
.physics
|
||||
.integration_parameters
|
||||
.num_solver_iterations = NonZeroUsize::new(4).unwrap();
|
||||
.num_solver_iterations = 4;
|
||||
|
||||
// Init world.
|
||||
let mut testbed = Testbed {
|
||||
@@ -403,20 +380,6 @@ impl TestbedApp {
|
||||
self.harness.step();
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "dim2", feature = "other-backends"))]
|
||||
{
|
||||
if self.state.selected_backend == BOX2D_BACKEND {
|
||||
self.other_backends.box2d.as_mut().unwrap().step(
|
||||
&mut self.harness.physics.pipeline.counters,
|
||||
&self.harness.physics.integration_parameters,
|
||||
);
|
||||
self.other_backends.box2d.as_mut().unwrap().sync(
|
||||
&mut self.harness.physics.bodies,
|
||||
&mut self.harness.physics.colliders,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "dim3", feature = "other-backends"))]
|
||||
{
|
||||
if self.state.selected_backend == PHYSX_BACKEND_PATCH_FRICTION
|
||||
@@ -671,18 +634,6 @@ impl Testbed<'_, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_, '_> {
|
||||
self.state.vehicle_controller = None;
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "dim2", feature = "other-backends"))]
|
||||
{
|
||||
if self.state.selected_backend == BOX2D_BACKEND {
|
||||
self.other_backends.box2d = Some(Box2dWorld::from_rapier(
|
||||
self.harness.physics.gravity,
|
||||
&self.harness.physics.bodies,
|
||||
&self.harness.physics.colliders,
|
||||
&self.harness.physics.impulse_joints,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "dim3", feature = "other-backends"))]
|
||||
{
|
||||
if self.state.selected_backend == PHYSX_BACKEND_PATCH_FRICTION
|
||||
@@ -1462,22 +1413,6 @@ fn update_testbed(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "dim2", feature = "other-backends"))]
|
||||
{
|
||||
if state.selected_backend == BOX2D_BACKEND {
|
||||
let harness = &mut *harness;
|
||||
other_backends.box2d.as_mut().unwrap().step(
|
||||
&mut harness.physics.pipeline.counters,
|
||||
&harness.physics.integration_parameters,
|
||||
);
|
||||
other_backends
|
||||
.box2d
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.sync(&mut harness.physics.bodies, &mut harness.physics.colliders);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "dim3", feature = "other-backends"))]
|
||||
{
|
||||
if state.selected_backend == PHYSX_BACKEND_PATCH_FRICTION
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user