From 9d2fdb294049c3b760c779f01976154b20a17e8e Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Fri, 7 Mar 2025 14:36:51 +0100 Subject: [PATCH 01/12] fix timestamp buffer not being big enough --- src/startup.rs | 2 +- src/step.rs | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/startup.rs b/src/startup.rs index b5e6e71..d9e490b 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -48,7 +48,7 @@ pub fn setup_app(mut commands: Commands, device: Res) { let features = device.features(); let timestamps = features .contains(Features::TIMESTAMP_QUERY) - .then(|| GpuTimestamps::new(device.wgpu_device(), 512)); + .then(|| GpuTimestamps::new(device.wgpu_device(), 1024)); commands.insert_resource(Timestamps { timestamps, ..Default::default() diff --git a/src/step.rs b/src/step.rs index d3edea7..fdb436f 100644 --- a/src/step.rs +++ b/src/step.rs @@ -177,7 +177,10 @@ fn step_simulation_multisteps( timestamps: Some(timestamps), ..Default::default() }; - + debug_assert!( + timestamps_ms.len() >= num_substeps * 2 * 9, + "GpuTimestamps should be initialized with a bigger size" + ); for i in 0..num_substeps { let mut timings = [ &mut new_timings.grid_sort, @@ -190,7 +193,8 @@ fn step_simulation_multisteps( &mut new_timings.particles_update, &mut new_timings.integrate_bodies, ]; - let times = ×tamps_ms[i * timings.len() * 2..]; + let start_index = i * timings.len() * 2; + let times = ×tamps_ms[start_index..]; for (k, timing) in timings.iter_mut().enumerate() { **timing += times[k * 2 + 1] - times[k * 2]; From 1627788390d7f4ade34032f5e1c92d4176d63f30 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Wed, 12 Mar 2025 14:53:16 +0100 Subject: [PATCH 02/12] cell size at the same size of particle size leads to beter results --- examples/rocks.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/rocks.rs b/examples/rocks.rs index b0754d4..d7cc32f 100644 --- a/examples/rocks.rs +++ b/examples/rocks.rs @@ -34,7 +34,7 @@ pub fn setup_scene(mut commands: Commands) { * Ground */ let ground_size = 200.1; - let ground_height = 0.1; + let ground_height = 2.0; commands.spawn(( Transform::from_xyz(0.0, -ground_height, 0.0), @@ -112,7 +112,7 @@ pub fn setup_mpm_particles( dt: (1.0 / 60.0) / (app_state.num_substeps as f32), }; - let cell_width = 0.5; + let cell_width = 1.0; let mut particles = vec![]; for rock in &rocks { @@ -120,7 +120,7 @@ pub fn setup_mpm_particles( let rock_size = vector![1.0, 1.0, 1.0]; let volume = rock_size.x * rock_size.y * rock_size.z; - let density = 2700.0; + let density = 700.0; particles.push(Particle { position: vector![position.x, position.y, position.z], velocity: Vector3::zeros(), From 3ef1319c34ccc1d56a3abdb3d2df5054818b14d8 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Wed, 12 Mar 2025 16:36:02 +0100 Subject: [PATCH 03/12] matrix configuration wip code --- Cargo.lock | 27 ++++++++++++ Cargo.toml | 3 ++ examples/{rocks.rs => cube.rs} | 81 +++++++++++++++++++++++----------- 3 files changed, 85 insertions(+), 26 deletions(-) rename examples/{rocks.rs => cube.rs} (61%) diff --git a/Cargo.lock b/Cargo.lock index 9076de2..473bcf3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -565,6 +565,32 @@ dependencies = [ "syn", ] +[[package]] +name = "bevy_editor_cam" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "493cf8fbcd67e0a335ec072c5946810747903a0c3202dce58dd0eda9df7a6680" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_derive", + "bevy_ecs", + "bevy_gizmos", + "bevy_image", + "bevy_input", + "bevy_log", + "bevy_math", + "bevy_picking", + "bevy_reflect", + "bevy_render", + "bevy_time", + "bevy_transform", + "bevy_utils", + "bevy_window", +] + [[package]] name = "bevy_encase_derive" version = "0.15.3" @@ -1207,6 +1233,7 @@ version = "0.1.0" dependencies = [ "async-channel", "bevy", + "bevy_editor_cam", "bevy_rapier3d", "bytemuck", "futures", diff --git a/Cargo.toml b/Cargo.toml index 6e58d37..04e8eef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,9 @@ wgsparkl3d = { git = "https://github.com/dimforge/wgsparkl.git", rev = "f64d3911 parry3d = "0.18" bevy_rapier3d = "0.29" +[dev-dependencies] +bevy_editor_cam = "0.5" + [patch.crates-io] # rapier3d = { path = "../rapier/crates/rapier3d" } # rapier3d = { path = "../rapier/crates/rapier3d" } diff --git a/examples/rocks.rs b/examples/cube.rs similarity index 61% rename from examples/rocks.rs rename to examples/cube.rs index d7cc32f..8b98e00 100644 --- a/examples/rocks.rs +++ b/examples/cube.rs @@ -1,5 +1,7 @@ use bevy::prelude::*; use bevy::render::renderer::RenderDevice; +use bevy_editor_cam::DefaultEditorCamPlugins; +use bevy_editor_cam::prelude::EditorCam; use bevy_rapier3d::geometry::RapierColliderHandle; use bevy_rapier3d::plugin::ReadRapierContext; use bevy_rapier3d::prelude::{Collider, RigidBody}; @@ -9,6 +11,7 @@ use bevy_wgsparkl::resources::{AppState, PhysicsContext}; use nalgebra::{Vector3, vector}; use wgrapier3d::dynamics::body::{BodyCoupling, BodyCouplingEntry}; use wgsparkl3d::models::DruckerPrager; +use wgsparkl3d::solver::ParticlePhase; use wgsparkl3d::{ models::ElasticCoefficients, pipeline::MpmData, @@ -17,7 +20,7 @@ use wgsparkl3d::{ pub fn main() { App::new() - .add_plugins(DefaultPlugins) + .add_plugins((DefaultPlugins, DefaultEditorCamPlugins)) .add_plugins(bevy_rapier3d::plugin::RapierPhysicsPlugin::<()>::default()) .add_plugins(RapierDebugRenderPlugin::default()) .add_plugins(bevy_wgsparkl::WgSparklPlugin) @@ -28,6 +31,10 @@ pub fn main() { pub fn setup_scene(mut commands: Commands) { commands.spawn(( Camera3d::default(), + EditorCam { + last_anchor_depth: 110f64, + ..Default::default() + }, Transform::from_xyz(-30.0, 30.0, 100.0).looking_at(Vec3::new(0.0, 10.0, 0.0), Vec3::Y), )); /* @@ -68,9 +75,9 @@ pub fn setup_mpm_particles( let grid_size_x = 25; let grid_size_y = 25; let grid_size_z = 25; - let num_rocks = grid_size_x * grid_size_y * grid_size_z; + let num_particles = grid_size_x * grid_size_y * grid_size_z; - let rocks = (0..num_rocks) + let particle_positions = (0..num_particles) .into_iter() .map(|i| { let x = i % grid_size_x; @@ -103,7 +110,7 @@ pub fn setup_mpm_particles( let device = device.wgpu_device(); if !app_state.restarting { - app_state.num_substeps = 32; + app_state.num_substeps = 16; app_state.gravity_factor = 1.0; }; @@ -115,27 +122,46 @@ pub fn setup_mpm_particles( let cell_width = 1.0; let mut particles = vec![]; - for rock in &rocks { - let position = vector![rock.x, rock.y, rock.z]; - - let rock_size = vector![1.0, 1.0, 1.0]; - let volume = rock_size.x * rock_size.y * rock_size.z; - let density = 700.0; - particles.push(Particle { - position: vector![position.x, position.y, position.z], - velocity: Vector3::zeros(), - volume: ParticleMassProps::new(density * volume, volume.cbrt() / 2.0), - model: ElasticCoefficients::from_young_modulus(10_000_000.0, 0.2), - plasticity: Some(DruckerPrager { - // TODO: tune these values. - h0: 45.0f32.to_radians(), - h1: 50.0f32.to_radians(), - h2: 0.4, - h3: 15.0f32.to_radians(), - ..DruckerPrager::new(10_000_000.0, 0.2) - }), - phase: None, - }); + for x in -1..2 { + for z in -1..2 { + let x = x as f32; + let z = z as f32; + let offset = vector![x * grid_size_x as f32, 0f32, z * grid_size_z as f32] * 2f32; + for particle in &particle_positions { + let position = vector![particle.x, particle.y, particle.z]; + + let particle_size = vector![1.0, 1.0, 1.0]; + let volume = particle_size.x * particle_size.y * particle_size.z; + let density = 1700.0; + particles.push(Particle { + position: nalgebra::Rotation::from_axis_angle( + &Vector3::z_axis(), + 5f32.to_radians(), + ) * vector![position.x, position.y, position.z] + + offset, + velocity: Vector3::zeros(), + volume: ParticleMassProps::new(density * volume, volume.cbrt() / 2.0), + model: ElasticCoefficients::from_young_modulus( + 100_000_000.0 * 10f32.powf((z - 1f32)), + 0.2 + x * 0.05f32, + ), + plasticity: Some(DruckerPrager { + h0: (45.0f32 + x * 20f32).to_radians(), + h1: (70.0f32 + x * 20f32).to_radians() + z, + h2: 1.6 + z * 0.5f32, + h3: 25.0f32.to_radians() + x, + ..DruckerPrager::new( + 100_000_000.0 * 10f32.powf((z - 1f32)), + 0.2 + x * 0.05f32, + ) + }), + phase: Some(ParticlePhase { + phase: 0.5 + 0.5 * x, + max_stretch: (0.0 + z).clamp(0.0, 1.0), + }), + }); + } + } } println!("Number of simulated particles: {}", particles.len()); @@ -152,5 +178,8 @@ pub fn setup_mpm_particles( cell_width, 60_000, ); - commands.insert_resource(PhysicsContext { data, particles }); + commands.insert_resource(PhysicsContext { + data, + particles: particles, + }); } From 2915eb3dce4ede9a53b73d1c0b7f530af37f6705 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Thu, 13 Mar 2025 14:40:18 +0100 Subject: [PATCH 04/12] add feature shader_format_glsl --- Cargo.toml | 2 +- examples/cube.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 04e8eef..a47571b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" license = "Apache-2.0 OR Custom" [dependencies] -bevy = "0.15" +bevy = { version = "0.15", features = ["shader_format_glsl"] } bytemuck = "1" async-channel = "2" futures = "0.3" diff --git a/examples/cube.rs b/examples/cube.rs index 8b98e00..3f21759 100644 --- a/examples/cube.rs +++ b/examples/cube.rs @@ -110,7 +110,7 @@ pub fn setup_mpm_particles( let device = device.wgpu_device(); if !app_state.restarting { - app_state.num_substeps = 16; + app_state.num_substeps = 8; app_state.gravity_factor = 1.0; }; From 384d897a3979d12a361e52d3477376e95428d6da Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Thu, 13 Mar 2025 14:42:12 +0100 Subject: [PATCH 05/12] fmt --- src/instancing3d.rs | 6 +++--- src/prep_vertex_buffer.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/instancing3d.rs b/src/instancing3d.rs index d09bc1c..c0879de 100644 --- a/src/instancing3d.rs +++ b/src/instancing3d.rs @@ -5,16 +5,17 @@ use bevy::{ core_pipeline::core_3d::Transparent3d, ecs::{ query::QueryItem, - system::{lifetimeless::*, SystemParamItem}, + system::{SystemParamItem, lifetimeless::*}, }, pbr::{ MeshPipeline, MeshPipelineKey, RenderMeshInstances, SetMeshBindGroup, SetMeshViewBindGroup, }, prelude::*, render::{ + Render, RenderApp, RenderSet, extract_component::{ExtractComponent, ExtractComponentPlugin}, mesh::{ - allocator::MeshAllocator, MeshVertexBufferLayoutRef, RenderMesh, RenderMeshBufferInfo, + MeshVertexBufferLayoutRef, RenderMesh, RenderMeshBufferInfo, allocator::MeshAllocator, }, render_asset::RenderAssets, render_phase::{ @@ -23,7 +24,6 @@ use bevy::{ }, render_resource::*, view::ExtractedView, - Render, RenderApp, RenderSet, }, }; use bytemuck::{Pod, Zeroable}; diff --git a/src/prep_vertex_buffer.rs b/src/prep_vertex_buffer.rs index 13c6d26..f121d98 100644 --- a/src/prep_vertex_buffer.rs +++ b/src/prep_vertex_buffer.rs @@ -1,6 +1,6 @@ +use wgcore::Shader; use wgcore::kernel::{KernelInvocationBuilder, KernelInvocationQueue}; use wgcore::tensor::GpuScalar; -use wgcore::Shader; use wgebra::WgSvd2; use wgebra::WgSvd3; use wgpu::{Buffer, BufferUsages, ComputePipeline, Device}; From 29b3612d1c4720171a519906c7b8e9a536f75726 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Thu, 13 Mar 2025 14:48:36 +0100 Subject: [PATCH 06/12] fix clippy --- examples/cube.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/examples/cube.rs b/examples/cube.rs index 3f21759..03d34e9 100644 --- a/examples/cube.rs +++ b/examples/cube.rs @@ -78,7 +78,6 @@ pub fn setup_mpm_particles( let num_particles = grid_size_x * grid_size_y * grid_size_z; let particle_positions = (0..num_particles) - .into_iter() .map(|i| { let x = i % grid_size_x; let y = (i / grid_size_x) % grid_size_y; @@ -142,7 +141,7 @@ pub fn setup_mpm_particles( velocity: Vector3::zeros(), volume: ParticleMassProps::new(density * volume, volume.cbrt() / 2.0), model: ElasticCoefficients::from_young_modulus( - 100_000_000.0 * 10f32.powf((z - 1f32)), + 100_000_000.0 * 10f32.powf(z - 1f32), 0.2 + x * 0.05f32, ), plasticity: Some(DruckerPrager { @@ -151,7 +150,7 @@ pub fn setup_mpm_particles( h2: 1.6 + z * 0.5f32, h3: 25.0f32.to_radians() + x, ..DruckerPrager::new( - 100_000_000.0 * 10f32.powf((z - 1f32)), + 100_000_000.0 * 10f32.powf(z - 1f32), 0.2 + x * 0.05f32, ) }), @@ -178,8 +177,5 @@ pub fn setup_mpm_particles( cell_width, 60_000, ); - commands.insert_resource(PhysicsContext { - data, - particles: particles, - }); + commands.insert_resource(PhysicsContext { data, particles }); } From a42d225294f1c68247b1999546dbcb82d5449664 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Thu, 13 Mar 2025 14:54:09 +0100 Subject: [PATCH 07/12] add comment --- src/step.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/step.rs b/src/step.rs index fdb436f..3fe81e3 100644 --- a/src/step.rs +++ b/src/step.rs @@ -177,6 +177,8 @@ fn step_simulation_multisteps( timestamps: Some(timestamps), ..Default::default() }; + // `GpuTimestamps` uses a buffer of 2 `Timestamps`, one for the start and one for the end of the operation, + // it's holding 9 floats (see `timings` below). debug_assert!( timestamps_ms.len() >= num_substeps * 2 * 9, "GpuTimestamps should be initialized with a bigger size" From 0214d7b44c29cef785d2f762349d90aea89c108a Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Tue, 18 Mar 2025 15:49:05 +0100 Subject: [PATCH 08/12] reward example to display several configurations for particles --- Cargo.lock | 72 ++++++-- Cargo.toml | 1 + examples/configurations.rs | 363 +++++++++++++++++++++++++++++++++++++ examples/cube.rs | 181 ------------------ 4 files changed, 420 insertions(+), 197 deletions(-) create mode 100644 examples/configurations.rs delete mode 100644 examples/cube.rs diff --git a/Cargo.lock b/Cargo.lock index 473bcf3..b23b141 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -136,7 +136,7 @@ dependencies = [ "ndk-context", "ndk-sys 0.6.0+11769913", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1022,6 +1022,19 @@ dependencies = [ "syn", ] +[[package]] +name = "bevy_rich_text3d" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57601b9430ef61d3f17d74f3da0731460bf00fc465da4c45626214b8be1152f6" +dependencies = [ + "bevy", + "cosmic-text", + "sys-locale", + "thiserror 2.0.12", + "zeno 0.3.2", +] + [[package]] name = "bevy_scene" version = "0.15.3" @@ -1235,6 +1248,7 @@ dependencies = [ "bevy", "bevy_editor_cam", "bevy_rapier3d", + "bevy_rich_text3d", "bytemuck", "futures", "nalgebra", @@ -1465,7 +1479,7 @@ dependencies = [ "polling", "rustix", "slab", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -1965,7 +1979,7 @@ dependencies = [ "encase_derive", "glam", "nalgebra", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -2459,7 +2473,7 @@ checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" dependencies = [ "log", "presser", - "thiserror", + "thiserror 1.0.69", "windows 0.58.0", ] @@ -2682,7 +2696,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.69", "walkdir", "windows-sys 0.45.0", ] @@ -2959,7 +2973,7 @@ dependencies = [ "rustc-hash 1.1.0", "spirv", "termcolor", - "thiserror", + "thiserror 1.0.69", "unicode-xid", ] @@ -2978,7 +2992,7 @@ dependencies = [ "regex", "regex-syntax 0.8.5", "rustc-hash 1.1.0", - "thiserror", + "thiserror 1.0.69", "tracing", "unicode-ident", ] @@ -3023,7 +3037,7 @@ dependencies = [ "log", "ndk-sys 0.5.0+25.2.9519653", "num_enum", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3038,7 +3052,7 @@ dependencies = [ "ndk-sys 0.6.0+11769913", "num_enum", "raw-window-handle", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3559,7 +3573,7 @@ dependencies = [ "slab", "smallvec", "spade", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3822,7 +3836,7 @@ dependencies = [ "profiling", "rustc-hash 2.1.1", "simba", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -3955,7 +3969,7 @@ checksum = "6006a627c1a38d37f3d3a85c6575418cfe34a5392d60a686d0071e1c8d427acb" dependencies = [ "cpal", "lewton", - "thiserror", + "thiserror 1.0.69", ] [[package]] @@ -4254,7 +4268,7 @@ checksum = "cbd59f3f359ddd2c95af4758c18270eddd9c730dde98598023cdabff472c2ca2" dependencies = [ "skrifa", "yazi", - "zeno", + "zeno 0.2.3", ] [[package]] @@ -4318,7 +4332,16 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +dependencies = [ + "thiserror-impl 2.0.12", ] [[package]] @@ -4332,6 +4355,17 @@ dependencies = [ "syn", ] +[[package]] +name = "thiserror-impl" +version = "2.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -4801,7 +4835,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror", + "thiserror 1.0.69", "wgpu-hal", "wgpu-types", ] @@ -4843,7 +4877,7 @@ dependencies = [ "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", - "thiserror", + "thiserror 1.0.69", "wasm-bindgen", "web-sys", "wgpu-types", @@ -5536,6 +5570,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd15f8e0dbb966fd9245e7498c7e9e5055d9e5c8b676b95bd67091cd11a1e697" +[[package]] +name = "zeno" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc0de2315dc13d00e5df3cd6b8d2124a6eaec6a2d4b6a1c5f37b7efad17fcc17" + [[package]] name = "zerocopy" version = "0.7.35" diff --git a/Cargo.toml b/Cargo.toml index a47571b..c868e4d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ bevy_rapier3d = "0.29" [dev-dependencies] bevy_editor_cam = "0.5" +bevy_rich_text3d = "0.2" [patch.crates-io] # rapier3d = { path = "../rapier/crates/rapier3d" } diff --git a/examples/configurations.rs b/examples/configurations.rs new file mode 100644 index 0000000..ced1638 --- /dev/null +++ b/examples/configurations.rs @@ -0,0 +1,363 @@ +use bevy::input::common_conditions; +use bevy::prelude::*; +use bevy::render::renderer::RenderDevice; +use bevy_editor_cam::DefaultEditorCamPlugins; +use bevy_editor_cam::prelude::EditorCam; +use bevy_rapier3d::geometry::RapierColliderHandle; +use bevy_rapier3d::plugin::ReadRapierContext; +use bevy_rapier3d::prelude::{Collider, RigidBody}; +use bevy_rapier3d::render::RapierDebugRenderPlugin; +use bevy_rich_text3d::{Text3d, Text3dBounds, Text3dPlugin, Text3dStyling, TextAtlas}; +use bevy_wgsparkl::components::MpmCouplingEnabled; +use bevy_wgsparkl::resources::{AppState, PhysicsContext}; +use nalgebra::{Vector3, vector}; +use wgrapier3d::dynamics::body::{BodyCoupling, BodyCouplingEntry}; +use wgsparkl3d::models::DruckerPrager; +use wgsparkl3d::solver::ParticlePhase; +use wgsparkl3d::{ + models::ElasticCoefficients, + pipeline::MpmData, + solver::{Particle, ParticleMassProps, SimulationParams}, +}; + +pub fn main() { + App::new() + .add_plugins((DefaultPlugins, DefaultEditorCamPlugins)) + .add_plugins(bevy_rapier3d::plugin::RapierPhysicsPlugin::<()>::default()) + .add_plugins(RapierDebugRenderPlugin::default()) + .add_plugins(bevy_wgsparkl::WgSparklPlugin) + .add_plugins(Text3dPlugin { + load_system_fonts: true, + ..Default::default() + }) + .add_systems(PostUpdate, setup_mpm_particles) + .add_systems( + Update, + reset_scene.run_if(common_conditions::input_just_pressed(KeyCode::KeyR)), + ) + .add_systems(Startup, setup_scene) + .run(); +} +pub fn setup_scene(mut commands: Commands) { + commands.spawn(( + Camera3d::default(), + EditorCam { + last_anchor_depth: 110f64, + ..Default::default() + }, + Transform::from_xyz(0.0, 30.0, 100.0).looking_at(Vec3::new(0.0, 10.0, 0.0), Vec3::Y), + )); + /* + * Ground + */ + let ground_size = 1200.1; + let ground_height = 2.0; + + commands.spawn(( + Transform::from_xyz(0.0, -ground_height, 0.0), + Collider::cuboid(ground_size, ground_height, ground_size), + RigidBody::Fixed, + MpmCouplingEnabled, + )); +} + +pub fn reset_scene(mut commands: Commands, mut app_state: ResMut) { + app_state.restarting = true; + app_state.particles_initialized = false; + commands.remove_resource::(); +} + +pub fn setup_mpm_particles( + mut commands: Commands, + device: Res, + mut app_state: ResMut, + rapier: ReadRapierContext, + coupling: Query<&RapierColliderHandle, With>, + mut standard_materials: ResMut>, +) { + if rapier.rapier_context.get_single().is_err() { + return; // Rapier isn’t initialized yet. + } + + let rapier = rapier.single(); + + if rapier.colliders.colliders.is_empty() { + return; // Rapier isn’t initialized yet. + } + + if app_state.particles_initialized { + return; // Already initialized. + } + + let grid_size_x = 10; + let grid_size_y = 10; + let grid_size_z = 10; + let num_particles = grid_size_x * grid_size_y * grid_size_z; + + let particle_positions = (0..num_particles) + .map(|i| { + let x = i % grid_size_x; + let y = (i / grid_size_x) % grid_size_y; + let z = (i / (grid_size_x * grid_size_y)) % grid_size_z; + Vector3::new(x as f32, y as f32 + 1f32, z as f32) + }) + .collect::>(); + + app_state.particles_initialized = true; + + let coupling: Vec<_> = coupling + .iter() + .map(|co_handle| { + let co = &rapier.colliders.colliders[co_handle.0]; + println!("Coupled collider: {:?}", co.shape().shape_type()); + println!( + "Coupled collider pose: {:?}", + co.position().translation.vector + ); + let rb_handle = co.parent().unwrap(); + BodyCouplingEntry { + body: rb_handle, + collider: co_handle.0, + mode: BodyCoupling::OneWay, // TODO: try out two-ways for the particles to affect the rigid bodies. + } + }) + .collect(); + + let device = device.wgpu_device(); + + if !app_state.restarting { + app_state.num_substeps = 25; + app_state.gravity_factor = 1.0; + }; + + let params = SimulationParams { + gravity: vector![0.0, -9.81, 0.0] * app_state.gravity_factor, + dt: (1.0 / 60.0) / (app_state.num_substeps as f32), + }; + + let cell_width = 1.0; + let mut particles = vec![]; + let mut configurations = vec![]; + + // line with plasticity, varying stiffness + for x in -1..2 { + let young_modulus = match x { + -1 => 500_000.0, + 0 => 100_000_000.0, + 1 => 200_000_000.0, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, 0.48); + let plasticity = Some(DruckerPrager { + h0: 45f32.to_radians(), + h1: 70f32.to_radians(), + h2: 1.6, + h3: 25.0f32.to_radians(), + ..DruckerPrager::new(model.lambda, model.mu) + }); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, -2), + split_particles: false, + density: 1700f32, + model, + plasticity, + phase: None, + description: format!("No Phase.\nmodulus: {}M", young_modulus / 1_000_000f32), + }); + } + + // line with plasticity, varying density + for x in -1..2 { + let young_modulus = 1_000_000.0; + let density = match x { + -1 => 100f32, + 0 => 1500f32, + 1 => 6800f32, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, 0.2); + let plasticity = Some(DruckerPrager { + h0: 45.0f32.to_radians(), + h1: 70f32.to_radians(), + h2: 1.6, + h3: 25.0f32.to_radians(), + ..DruckerPrager::new(model.lambda, model.mu) + }); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, -1), + split_particles: false, + density: density, + model, + plasticity, + phase: Some(ParticlePhase { + phase: 1.0, + max_stretch: f32::MAX, + }), + description: format!("With plasticity.\ndensity: {}", density), + }); + } + + // line with plasticity, varying young modulus + for x in -1..2 { + let young_modulus = match x { + -1 => 500_000.0, + 0 => 10_000_000.0, + 1 => 200_000_000.0, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, 0.2); + let plasticity = Some(DruckerPrager { + h0: 45.0f32.to_radians(), + h1: 70.0f32.to_radians(), + h2: 1.6, + h3: 25.0f32.to_radians(), + ..DruckerPrager::new(model.lambda, model.mu) + }); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, 0), + split_particles: false, + density: 1700f32, + model, + plasticity, + phase: Some(ParticlePhase { + phase: 1.0, + max_stretch: f32::MAX, + }), + description: format!( + "With plasticity.\nmodulus: {}M", + young_modulus / 1_000_000f32 + ), + }); + } + + // line without plasticity, varying young modulus + for x in -1..2 { + let young_modulus = match x { + -1 => 1_000_000.0, + 0 => 50_000_000.0, + 1 => 200_000_000.0, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, 0.2); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, 1), + split_particles: false, + density: 1700f32, + model, + plasticity: None, + phase: Some(ParticlePhase { + phase: 1.0, + max_stretch: f32::MAX, + }), + description: format!( + "Without plasticity.\nmodulus: {}M", + young_modulus / 1_000_000.0 + ), + }); + } + // line without plasticity, varying poisson_ratio + for x in -1..2 { + let young_modulus = 1_000_000.0; + let poisson_ratio = match x { + -1 => -0.2f32, + 0 => 0.3, + 1 => 0.48, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, 2), + split_particles: false, + density: 1700f32, + model, + plasticity: None, + phase: Some(ParticlePhase { + phase: 1.0, + max_stretch: f32::MAX, + }), + description: format!("Without plasticity.\npoisson: {}", poisson_ratio), + }); + } + + // Text material. + let mat = standard_materials.add(StandardMaterial { + base_color_texture: Some(TextAtlas::DEFAULT_IMAGE.clone_weak()), + alpha_mode: AlphaMode::Blend, + unlit: true, + ..Default::default() + }); + + for (i, c) in configurations.iter().enumerate() { + let x = c.coords.x as f32 * 3f32; + let z = c.coords.y as f32 * 3f32; + let offset = vector![ + x * grid_size_x as f32, + 3f32, + z * grid_size_x as f32 * 0.7f32 + ] * 2f32; + for particle in &particle_positions { + let position = vector![particle.x, particle.y, particle.z]; + + let particle_size = vector![1.0, 1.0, 1.0]; + let volume = particle_size.x * particle_size.y * particle_size.z; + let density = c.density; + particles.push(Particle { + position: nalgebra::Rotation::from_axis_angle( + &Vector3::z_axis(), + 1f32.to_radians(), + ) * vector![position.x, position.y, position.z] + + offset, + velocity: Vector3::zeros(), + volume: ParticleMassProps::new(density * volume, volume.cbrt() / 2.0), + model: c.model, + plasticity: c.plasticity, + phase: c.phase, + }); + } + commands.spawn(( + Text3d::new(&c.description), + Text3dStyling { + size: 40., + color: Srgba::new(1., 1., 1., 1.), + ..Default::default() + }, + Text3dBounds { width: 500. }, + Mesh3d::default(), + MeshMaterial3d(mat.clone()), + Transform::from_translation(Vec3::new( + offset.x, + 5f32, + offset.z + 10f32 + grid_size_z as f32, + )) + .with_scale(Vec3::splat(0.1)) + .with_rotation(Quat::from_rotation_x(-90f32.to_radians())), + )); + } + + println!("Number of simulated particles: {}", particles.len()); + + println!("Coupled: {}", coupling.len()); + + let data = MpmData::with_select_coupling( + device, + params, + &particles, + &rapier.rigidbody_set.bodies, + &rapier.colliders.colliders, + coupling, + cell_width, + 60_000, + ); + commands.insert_resource(PhysicsContext { data, particles }); +} + +#[derive(Debug)] +pub struct ParticlesConfiguration { + pub coords: IVec2, + pub split_particles: bool, + pub density: f32, + pub model: ElasticCoefficients, + pub plasticity: Option, + pub phase: Option, + pub description: String, +} diff --git a/examples/cube.rs b/examples/cube.rs deleted file mode 100644 index 03d34e9..0000000 --- a/examples/cube.rs +++ /dev/null @@ -1,181 +0,0 @@ -use bevy::prelude::*; -use bevy::render::renderer::RenderDevice; -use bevy_editor_cam::DefaultEditorCamPlugins; -use bevy_editor_cam::prelude::EditorCam; -use bevy_rapier3d::geometry::RapierColliderHandle; -use bevy_rapier3d::plugin::ReadRapierContext; -use bevy_rapier3d::prelude::{Collider, RigidBody}; -use bevy_rapier3d::render::RapierDebugRenderPlugin; -use bevy_wgsparkl::components::MpmCouplingEnabled; -use bevy_wgsparkl::resources::{AppState, PhysicsContext}; -use nalgebra::{Vector3, vector}; -use wgrapier3d::dynamics::body::{BodyCoupling, BodyCouplingEntry}; -use wgsparkl3d::models::DruckerPrager; -use wgsparkl3d::solver::ParticlePhase; -use wgsparkl3d::{ - models::ElasticCoefficients, - pipeline::MpmData, - solver::{Particle, ParticleMassProps, SimulationParams}, -}; - -pub fn main() { - App::new() - .add_plugins((DefaultPlugins, DefaultEditorCamPlugins)) - .add_plugins(bevy_rapier3d::plugin::RapierPhysicsPlugin::<()>::default()) - .add_plugins(RapierDebugRenderPlugin::default()) - .add_plugins(bevy_wgsparkl::WgSparklPlugin) - .add_systems(PostUpdate, setup_mpm_particles) - .add_systems(Startup, setup_scene) - .run(); -} -pub fn setup_scene(mut commands: Commands) { - commands.spawn(( - Camera3d::default(), - EditorCam { - last_anchor_depth: 110f64, - ..Default::default() - }, - Transform::from_xyz(-30.0, 30.0, 100.0).looking_at(Vec3::new(0.0, 10.0, 0.0), Vec3::Y), - )); - /* - * Ground - */ - let ground_size = 200.1; - let ground_height = 2.0; - - commands.spawn(( - Transform::from_xyz(0.0, -ground_height, 0.0), - Collider::cuboid(ground_size, ground_height, ground_size), - RigidBody::Fixed, - MpmCouplingEnabled, - )); -} - -pub fn setup_mpm_particles( - mut commands: Commands, - device: Res, - mut app_state: ResMut, - rapier: ReadRapierContext, - coupling: Query<&RapierColliderHandle, With>, -) { - if rapier.rapier_context.get_single().is_err() { - return; // Rapier isn’t initialized yet. - } - - let rapier = rapier.single(); - - if rapier.colliders.colliders.is_empty() { - return; // Rapier isn’t initialized yet. - } - - if app_state.particles_initialized { - return; // Already initialized. - } - - let grid_size_x = 25; - let grid_size_y = 25; - let grid_size_z = 25; - let num_particles = grid_size_x * grid_size_y * grid_size_z; - - let particle_positions = (0..num_particles) - .map(|i| { - let x = i % grid_size_x; - let y = (i / grid_size_x) % grid_size_y; - let z = (i / (grid_size_x * grid_size_y)) % grid_size_z; - Vector3::new(x as f32, y as f32 + 1f32, z as f32) - }) - .collect::>(); - - app_state.particles_initialized = true; - - let coupling: Vec<_> = coupling - .iter() - .map(|co_handle| { - let co = &rapier.colliders.colliders[co_handle.0]; - println!("Coupled collider: {:?}", co.shape().shape_type()); - println!( - "Coupled collider pose: {:?}", - co.position().translation.vector - ); - let rb_handle = co.parent().unwrap(); - BodyCouplingEntry { - body: rb_handle, - collider: co_handle.0, - mode: BodyCoupling::OneWay, // TODO: try out two-ways for the particles to affect the rigid bodies. - } - }) - .collect(); - - let device = device.wgpu_device(); - - if !app_state.restarting { - app_state.num_substeps = 8; - app_state.gravity_factor = 1.0; - }; - - let params = SimulationParams { - gravity: vector![0.0, -9.81, 0.0] * app_state.gravity_factor, - dt: (1.0 / 60.0) / (app_state.num_substeps as f32), - }; - - let cell_width = 1.0; - let mut particles = vec![]; - - for x in -1..2 { - for z in -1..2 { - let x = x as f32; - let z = z as f32; - let offset = vector![x * grid_size_x as f32, 0f32, z * grid_size_z as f32] * 2f32; - for particle in &particle_positions { - let position = vector![particle.x, particle.y, particle.z]; - - let particle_size = vector![1.0, 1.0, 1.0]; - let volume = particle_size.x * particle_size.y * particle_size.z; - let density = 1700.0; - particles.push(Particle { - position: nalgebra::Rotation::from_axis_angle( - &Vector3::z_axis(), - 5f32.to_radians(), - ) * vector![position.x, position.y, position.z] - + offset, - velocity: Vector3::zeros(), - volume: ParticleMassProps::new(density * volume, volume.cbrt() / 2.0), - model: ElasticCoefficients::from_young_modulus( - 100_000_000.0 * 10f32.powf(z - 1f32), - 0.2 + x * 0.05f32, - ), - plasticity: Some(DruckerPrager { - h0: (45.0f32 + x * 20f32).to_radians(), - h1: (70.0f32 + x * 20f32).to_radians() + z, - h2: 1.6 + z * 0.5f32, - h3: 25.0f32.to_radians() + x, - ..DruckerPrager::new( - 100_000_000.0 * 10f32.powf(z - 1f32), - 0.2 + x * 0.05f32, - ) - }), - phase: Some(ParticlePhase { - phase: 0.5 + 0.5 * x, - max_stretch: (0.0 + z).clamp(0.0, 1.0), - }), - }); - } - } - } - - println!("Number of simulated particles: {}", particles.len()); - - println!("Coupled: {}", coupling.len()); - - let data = MpmData::with_select_coupling( - device, - params, - &particles, - &rapier.rigidbody_set.bodies, - &rapier.colliders.colliders, - coupling, - cell_width, - 60_000, - ); - commands.insert_resource(PhysicsContext { data, particles }); -} From ebadbefb6653fd4315c19cb68016780bbbb8996b Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Tue, 18 Mar 2025 17:55:55 +0100 Subject: [PATCH 09/12] better conf use + add line description for first 2 --- examples/configurations.rs | 159 +++++++++++++++++-------------------- 1 file changed, 73 insertions(+), 86 deletions(-) diff --git a/examples/configurations.rs b/examples/configurations.rs index ced1638..7a56323 100644 --- a/examples/configurations.rs +++ b/examples/configurations.rs @@ -126,103 +126,101 @@ pub fn setup_mpm_particles( let device = device.wgpu_device(); if !app_state.restarting { - app_state.num_substeps = 25; + app_state.num_substeps = 16; app_state.gravity_factor = 1.0; }; + // Text material. + let mat = standard_materials.add(StandardMaterial { + base_color_texture: Some(TextAtlas::DEFAULT_IMAGE.clone_weak()), + alpha_mode: AlphaMode::Blend, + unlit: true, + ..Default::default() + }); + let params = SimulationParams { gravity: vector![0.0, -9.81, 0.0] * app_state.gravity_factor, dt: (1.0 / 60.0) / (app_state.num_substeps as f32), }; - let cell_width = 1.0; + let cell_width = 1f32; let mut particles = vec![]; let mut configurations = vec![]; - // line with plasticity, varying stiffness - for x in -1..2 { - let young_modulus = match x { - -1 => 500_000.0, - 0 => 100_000_000.0, - 1 => 200_000_000.0, - _ => unreachable!(), - }; - let model = ElasticCoefficients::from_young_modulus(young_modulus, 0.48); - let plasticity = Some(DruckerPrager { - h0: 45f32.to_radians(), - h1: 70f32.to_radians(), - h2: 1.6, - h3: 25.0f32.to_radians(), - ..DruckerPrager::new(model.lambda, model.mu) - }); - configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, -2), - split_particles: false, - density: 1700f32, - model, - plasticity, - phase: None, - description: format!("No Phase.\nmodulus: {}M", young_modulus / 1_000_000f32), - }); - } - - // line with plasticity, varying density - for x in -1..2 { - let young_modulus = 1_000_000.0; - let density = match x { - -1 => 100f32, - 0 => 1500f32, - 1 => 6800f32, - _ => unreachable!(), - }; - let model = ElasticCoefficients::from_young_modulus(young_modulus, 0.2); - let plasticity = Some(DruckerPrager { - h0: 45.0f32.to_radians(), - h1: 70f32.to_radians(), - h2: 1.6, - h3: 25.0f32.to_radians(), - ..DruckerPrager::new(model.lambda, model.mu) - }); - configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, -1), - split_particles: false, - density: density, - model, - plasticity, - phase: Some(ParticlePhase { - phase: 1.0, - max_stretch: f32::MAX, - }), - description: format!("With plasticity.\ndensity: {}", density), - }); + let mut display_text_for_line = |z: f32, text: String| { + commands.spawn(( + Text3d::new(text), + Text3dStyling { + size: 40., + color: Srgba::new(1., 1., 1., 1.), + ..Default::default() + }, + Text3dBounds { width: 500. }, + Mesh3d::default(), + MeshMaterial3d(mat.clone()), + Transform::from_translation(Vec3::new( + -2f32 * grid_size_x as f32 * 3f32 * 2f32, + 5f32, + z * grid_size_z as f32 * 0.7f32 * 3f32 * 2f32 + grid_size_z as f32 / 2f32, + )) + .with_scale(Vec3::splat(0.1)) + .with_rotation(Quat::from_rotation_x(-90f32.to_radians())), + )); + }; + { + let young_modulus = 1_000_000_000.0; + display_text_for_line(-1f32, format!("modulus = {}M", young_modulus / 1_000_000.0)); + // line with plasticity, varying poisson + for x in -1..2 { + let poisson_ratio = match x { + -1 => 0.0, + 0 => 0.2, + 1 => 0.4, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); + let plasticity = Some(DruckerPrager { + h0: 35.0f32.to_radians(), + h1: 9.0f32.to_radians(), + h2: 0.2, + h3: 10.0f32.to_radians(), + ..DruckerPrager::new(model.lambda, model.mu) + }); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, -1), + density: 3700f32, + model, + plasticity, + phase: None, + description: format!("With plasticity.\n poisson: {}", poisson_ratio), + }); + } } + let poisson_ratio = 0f32; + display_text_for_line(0f32, format!("poisson = {}", poisson_ratio)); // line with plasticity, varying young modulus for x in -1..2 { let young_modulus = match x { - -1 => 500_000.0, + -1 => 1_000_000.0, 0 => 10_000_000.0, - 1 => 200_000_000.0, + 1 => 100_000_000.0, _ => unreachable!(), }; - let model = ElasticCoefficients::from_young_modulus(young_modulus, 0.2); + let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); let plasticity = Some(DruckerPrager { - h0: 45.0f32.to_radians(), - h1: 70.0f32.to_radians(), - h2: 1.6, - h3: 25.0f32.to_radians(), + h0: 35.0f32.to_radians(), + h1: 9.0f32.to_radians(), + h2: 0.2, + h3: 10.0f32.to_radians(), ..DruckerPrager::new(model.lambda, model.mu) }); configurations.push(ParticlesConfiguration { coords: IVec2::new(x, 0), - split_particles: false, - density: 1700f32, + density: 3700f32, model, plasticity, - phase: Some(ParticlePhase { - phase: 1.0, - max_stretch: f32::MAX, - }), + phase: None, description: format!( "With plasticity.\nmodulus: {}M", young_modulus / 1_000_000f32 @@ -238,11 +236,10 @@ pub fn setup_mpm_particles( 1 => 200_000_000.0, _ => unreachable!(), }; - let model = ElasticCoefficients::from_young_modulus(young_modulus, 0.2); + let model = ElasticCoefficients::from_young_modulus(young_modulus, 0f32); configurations.push(ParticlesConfiguration { coords: IVec2::new(x, 1), - split_particles: false, - density: 1700f32, + density: 3700f32, model, plasticity: None, phase: Some(ParticlePhase { @@ -267,8 +264,7 @@ pub fn setup_mpm_particles( let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); configurations.push(ParticlesConfiguration { coords: IVec2::new(x, 2), - split_particles: false, - density: 1700f32, + density: 3700f32, model, plasticity: None, phase: Some(ParticlePhase { @@ -279,21 +275,13 @@ pub fn setup_mpm_particles( }); } - // Text material. - let mat = standard_materials.add(StandardMaterial { - base_color_texture: Some(TextAtlas::DEFAULT_IMAGE.clone_weak()), - alpha_mode: AlphaMode::Blend, - unlit: true, - ..Default::default() - }); - for (i, c) in configurations.iter().enumerate() { let x = c.coords.x as f32 * 3f32; let z = c.coords.y as f32 * 3f32; let offset = vector![ x * grid_size_x as f32, 3f32, - z * grid_size_x as f32 * 0.7f32 + z * grid_size_z as f32 * 0.7f32 ] * 2f32; for particle in &particle_positions { let position = vector![particle.x, particle.y, particle.z]; @@ -354,7 +342,6 @@ pub fn setup_mpm_particles( #[derive(Debug)] pub struct ParticlesConfiguration { pub coords: IVec2, - pub split_particles: bool, pub density: f32, pub model: ElasticCoefficients, pub plasticity: Option, From 7234b43561bd26a65ec57db5bf438dc2b395a245 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Wed, 19 Mar 2025 09:28:20 +0100 Subject: [PATCH 10/12] last 2 lines description --- examples/configurations.rs | 155 ++++++++++++++++++++----------------- 1 file changed, 82 insertions(+), 73 deletions(-) diff --git a/examples/configurations.rs b/examples/configurations.rs index 7a56323..928842d 100644 --- a/examples/configurations.rs +++ b/examples/configurations.rs @@ -197,85 +197,94 @@ pub fn setup_mpm_particles( } } - let poisson_ratio = 0f32; - display_text_for_line(0f32, format!("poisson = {}", poisson_ratio)); - // line with plasticity, varying young modulus - for x in -1..2 { - let young_modulus = match x { - -1 => 1_000_000.0, - 0 => 10_000_000.0, - 1 => 100_000_000.0, - _ => unreachable!(), - }; - let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); - let plasticity = Some(DruckerPrager { - h0: 35.0f32.to_radians(), - h1: 9.0f32.to_radians(), - h2: 0.2, - h3: 10.0f32.to_radians(), - ..DruckerPrager::new(model.lambda, model.mu) - }); - configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, 0), - density: 3700f32, - model, - plasticity, - phase: None, - description: format!( - "With plasticity.\nmodulus: {}M", - young_modulus / 1_000_000f32 - ), - }); + { + let poisson_ratio = 0f32; + display_text_for_line(0f32, format!("poisson = {}", poisson_ratio)); + // line with plasticity, varying young modulus + for x in -1..2 { + let young_modulus = match x { + -1 => 1_000_000.0, + 0 => 10_000_000.0, + 1 => 100_000_000.0, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); + let plasticity = Some(DruckerPrager { + h0: 35.0f32.to_radians(), + h1: 9.0f32.to_radians(), + h2: 0.2, + h3: 10.0f32.to_radians(), + ..DruckerPrager::new(model.lambda, model.mu) + }); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, 0), + density: 3700f32, + model, + plasticity, + phase: None, + description: format!( + "With plasticity.\nmodulus: {}M", + young_modulus / 1_000_000f32 + ), + }); + } } - // line without plasticity, varying young modulus - for x in -1..2 { - let young_modulus = match x { - -1 => 1_000_000.0, - 0 => 50_000_000.0, - 1 => 200_000_000.0, - _ => unreachable!(), - }; - let model = ElasticCoefficients::from_young_modulus(young_modulus, 0f32); - configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, 1), - density: 3700f32, - model, - plasticity: None, - phase: Some(ParticlePhase { - phase: 1.0, - max_stretch: f32::MAX, - }), - description: format!( - "Without plasticity.\nmodulus: {}M", - young_modulus / 1_000_000.0 - ), - }); + { + let poisson_ratio = 0f32; + display_text_for_line(1f32, format!("poisson = {}", poisson_ratio)); + // line without plasticity, varying young modulus + for x in -1..2 { + let young_modulus = match x { + -1 => 1_000_000.0, + 0 => 50_000_000.0, + 1 => 200_000_000.0, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, 1), + density: 3700f32, + model, + plasticity: None, + phase: Some(ParticlePhase { + phase: 1.0, + max_stretch: f32::MAX, + }), + description: format!( + "Without plasticity.\nmodulus: {}M", + young_modulus / 1_000_000.0 + ), + }); + } } - // line without plasticity, varying poisson_ratio - for x in -1..2 { + { let young_modulus = 1_000_000.0; - let poisson_ratio = match x { - -1 => -0.2f32, - 0 => 0.3, - 1 => 0.48, - _ => unreachable!(), - }; - let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); - configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, 2), - density: 3700f32, - model, - plasticity: None, - phase: Some(ParticlePhase { - phase: 1.0, - max_stretch: f32::MAX, - }), - description: format!("Without plasticity.\npoisson: {}", poisson_ratio), - }); + display_text_for_line(2f32, format!("modulus = {}M", young_modulus / 1_000_000.0)); + // line without plasticity, varying poisson_ratio + for x in -1..2 { + let poisson_ratio = match x { + -1 => -0.2f32, + 0 => 0.3, + 1 => 0.48, + _ => unreachable!(), + }; + let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); + configurations.push(ParticlesConfiguration { + coords: IVec2::new(x, 2), + density: 3700f32, + model, + plasticity: None, + phase: Some(ParticlePhase { + phase: 1.0, + max_stretch: f32::MAX, + }), + description: format!("Without plasticity.\npoisson: {}", poisson_ratio), + }); + } } - for (i, c) in configurations.iter().enumerate() { + for c in configurations.iter() { let x = c.coords.x as f32 * 3f32; let z = c.coords.y as f32 * 3f32; let offset = vector![ From cd334f9215aa9775022ccc410c6ab162e230d772 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Thu, 27 Mar 2025 11:55:37 +0100 Subject: [PATCH 11/12] changed dbg assert to normal assert ; + cleanup example conf --- examples/configurations.rs | 75 ++++++++++++++++++++------------------ src/step.rs | 2 +- 2 files changed, 41 insertions(+), 36 deletions(-) diff --git a/examples/configurations.rs b/examples/configurations.rs index 928842d..61d99c6 100644 --- a/examples/configurations.rs +++ b/examples/configurations.rs @@ -146,8 +146,14 @@ pub fn setup_mpm_particles( let cell_width = 1f32; let mut particles = vec![]; let mut configurations = vec![]; - - let mut display_text_for_line = |z: f32, text: String| { + let get_position_for_line = |z: f32| -> bevy::math::Vec3 { + bevy::math::Vec3::new( + -2f32 * grid_size_x as f32 * 3f32 * 2f32, + 5f32, + z * grid_size_z as f32 * 0.7f32 * 3f32 * 2f32 + grid_size_z as f32 / 2f32, + ) + }; + let mut display_text_at_world_pos = |world_pos: bevy::math::Vec3, text: String| { commands.spawn(( Text3d::new(text), Text3dStyling { @@ -158,18 +164,18 @@ pub fn setup_mpm_particles( Text3dBounds { width: 500. }, Mesh3d::default(), MeshMaterial3d(mat.clone()), - Transform::from_translation(Vec3::new( - -2f32 * grid_size_x as f32 * 3f32 * 2f32, - 5f32, - z * grid_size_z as f32 * 0.7f32 * 3f32 * 2f32 + grid_size_z as f32 / 2f32, - )) - .with_scale(Vec3::splat(0.1)) - .with_rotation(Quat::from_rotation_x(-90f32.to_radians())), + Transform::from_translation(world_pos) + .with_scale(Vec3::splat(0.1)) + .with_rotation(Quat::from_rotation_x(-90f32.to_radians())), )); }; { let young_modulus = 1_000_000_000.0; - display_text_for_line(-1f32, format!("modulus = {}M", young_modulus / 1_000_000.0)); + let z = -1f32; + display_text_at_world_pos( + get_position_for_line(z), + format!("modulus = {}M", young_modulus / 1_000_000.0), + ); // line with plasticity, varying poisson for x in -1..2 { let poisson_ratio = match x { @@ -187,7 +193,7 @@ pub fn setup_mpm_particles( ..DruckerPrager::new(model.lambda, model.mu) }); configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, -1), + coords: IVec2::new(x, z as i32), density: 3700f32, model, plasticity, @@ -199,7 +205,11 @@ pub fn setup_mpm_particles( { let poisson_ratio = 0f32; - display_text_for_line(0f32, format!("poisson = {}", poisson_ratio)); + let z = 0f32; + display_text_at_world_pos( + get_position_for_line(z), + format!("poisson = {}", poisson_ratio), + ); // line with plasticity, varying young modulus for x in -1..2 { let young_modulus = match x { @@ -217,7 +227,7 @@ pub fn setup_mpm_particles( ..DruckerPrager::new(model.lambda, model.mu) }); configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, 0), + coords: IVec2::new(x, z as i32), density: 3700f32, model, plasticity, @@ -232,7 +242,11 @@ pub fn setup_mpm_particles( { let poisson_ratio = 0f32; - display_text_for_line(1f32, format!("poisson = {}", poisson_ratio)); + let z = 1f32; + display_text_at_world_pos( + get_position_for_line(z), + format!("poisson = {}", poisson_ratio), + ); // line without plasticity, varying young modulus for x in -1..2 { let young_modulus = match x { @@ -243,7 +257,7 @@ pub fn setup_mpm_particles( }; let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, 1), + coords: IVec2::new(x, z as i32), density: 3700f32, model, plasticity: None, @@ -260,7 +274,11 @@ pub fn setup_mpm_particles( } { let young_modulus = 1_000_000.0; - display_text_for_line(2f32, format!("modulus = {}M", young_modulus / 1_000_000.0)); + let z = 2f32; + display_text_at_world_pos( + get_position_for_line(z), + format!("modulus = {}M", young_modulus / 1_000_000.0), + ); // line without plasticity, varying poisson_ratio for x in -1..2 { let poisson_ratio = match x { @@ -271,7 +289,7 @@ pub fn setup_mpm_particles( }; let model = ElasticCoefficients::from_young_modulus(young_modulus, poisson_ratio); configurations.push(ParticlesConfiguration { - coords: IVec2::new(x, 2), + coords: IVec2::new(x, z as i32), density: 3700f32, model, plasticity: None, @@ -311,24 +329,11 @@ pub fn setup_mpm_particles( phase: c.phase, }); } - commands.spawn(( - Text3d::new(&c.description), - Text3dStyling { - size: 40., - color: Srgba::new(1., 1., 1., 1.), - ..Default::default() - }, - Text3dBounds { width: 500. }, - Mesh3d::default(), - MeshMaterial3d(mat.clone()), - Transform::from_translation(Vec3::new( - offset.x, - 5f32, - offset.z + 10f32 + grid_size_z as f32, - )) - .with_scale(Vec3::splat(0.1)) - .with_rotation(Quat::from_rotation_x(-90f32.to_radians())), - )); + + display_text_at_world_pos( + Vec3::new(offset.x, 5f32, offset.z + 10f32 + grid_size_z as f32), + c.description.clone(), + ); } println!("Number of simulated particles: {}", particles.len()); diff --git a/src/step.rs b/src/step.rs index 3fe81e3..a7513a1 100644 --- a/src/step.rs +++ b/src/step.rs @@ -179,7 +179,7 @@ fn step_simulation_multisteps( }; // `GpuTimestamps` uses a buffer of 2 `Timestamps`, one for the start and one for the end of the operation, // it's holding 9 floats (see `timings` below). - debug_assert!( + assert!( timestamps_ms.len() >= num_substeps * 2 * 9, "GpuTimestamps should be initialized with a bigger size" ); From e6eeb67518688f769e073cf141d2424e6af665fe Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Thu, 27 Mar 2025 12:14:38 +0100 Subject: [PATCH 12/12] reduced duplicate wording in example configurations --- examples/configurations.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/examples/configurations.rs b/examples/configurations.rs index 61d99c6..96d0d5b 100644 --- a/examples/configurations.rs +++ b/examples/configurations.rs @@ -174,7 +174,10 @@ pub fn setup_mpm_particles( let z = -1f32; display_text_at_world_pos( get_position_for_line(z), - format!("modulus = {}M", young_modulus / 1_000_000.0), + format!( + "With plasticity.\nmodulus = {}M", + young_modulus / 1_000_000.0 + ), ); // line with plasticity, varying poisson for x in -1..2 { @@ -198,7 +201,7 @@ pub fn setup_mpm_particles( model, plasticity, phase: None, - description: format!("With plasticity.\n poisson: {}", poisson_ratio), + description: format!("poisson: {}", poisson_ratio), }); } } @@ -208,7 +211,7 @@ pub fn setup_mpm_particles( let z = 0f32; display_text_at_world_pos( get_position_for_line(z), - format!("poisson = {}", poisson_ratio), + format!("With plasticity.\npoisson = {}", poisson_ratio), ); // line with plasticity, varying young modulus for x in -1..2 { @@ -232,10 +235,7 @@ pub fn setup_mpm_particles( model, plasticity, phase: None, - description: format!( - "With plasticity.\nmodulus: {}M", - young_modulus / 1_000_000f32 - ), + description: format!("modulus: {}M", young_modulus / 1_000_000f32), }); } } @@ -245,7 +245,7 @@ pub fn setup_mpm_particles( let z = 1f32; display_text_at_world_pos( get_position_for_line(z), - format!("poisson = {}", poisson_ratio), + format!("Without plasticity.\npoisson = {}", poisson_ratio), ); // line without plasticity, varying young modulus for x in -1..2 { @@ -265,10 +265,7 @@ pub fn setup_mpm_particles( phase: 1.0, max_stretch: f32::MAX, }), - description: format!( - "Without plasticity.\nmodulus: {}M", - young_modulus / 1_000_000.0 - ), + description: format!("modulus: {}M", young_modulus / 1_000_000.0), }); } } @@ -277,7 +274,10 @@ pub fn setup_mpm_particles( let z = 2f32; display_text_at_world_pos( get_position_for_line(z), - format!("modulus = {}M", young_modulus / 1_000_000.0), + format!( + "Without plasticity.\nmodulus = {}M", + young_modulus / 1_000_000.0 + ), ); // line without plasticity, varying poisson_ratio for x in -1..2 { @@ -297,7 +297,7 @@ pub fn setup_mpm_particles( phase: 1.0, max_stretch: f32::MAX, }), - description: format!("Without plasticity.\npoisson: {}", poisson_ratio), + description: format!("poisson: {}", poisson_ratio), }); } }