From f7132cfafa03143a4b8ce19323fb0d15ce4e2bf8 Mon Sep 17 00:00:00 2001 From: narasan49 Date: Wed, 14 Aug 2024 14:19:08 +0900 Subject: [PATCH] Add force and its example --- assets/shaders/add_force.wgsl | 41 ++++++++++++ examples/mouse_interaction.rs | 120 ++++++++++++++++++++++++++++++++++ src/euler_fluid.rs | 43 ++++++++++-- src/euler_fluid/add_force.rs | 92 ++++++++++++++++++++++++++ 4 files changed, 289 insertions(+), 7 deletions(-) create mode 100644 assets/shaders/add_force.wgsl create mode 100644 examples/mouse_interaction.rs create mode 100644 src/euler_fluid/add_force.rs diff --git a/assets/shaders/add_force.wgsl b/assets/shaders/add_force.wgsl new file mode 100644 index 0000000..dce38dc --- /dev/null +++ b/assets/shaders/add_force.wgsl @@ -0,0 +1,41 @@ +#import bevy_fluid::fluid_uniform::SimulationUniform; + +@group(0) @binding(0) var force: array>; +@group(0) @binding(1) var position: array>; +@group(0) @binding(2) var u: texture_storage_2d; +@group(0) @binding(3) var v: texture_storage_2d; + +@group(1) @binding(0) var constants: SimulationUniform; + +@compute +@workgroup_size(1, 64, 1) +fn add_force( + @builtin(global_invocation_id) invocation_id: vec3, +) { + let x_u = vec2(i32(invocation_id.x), i32(invocation_id.y)); + let x_v = vec2(x_u.y, x_u.x); + var n = arrayLength(&force); + var net_force = vec2(0.0, 0.0); + + loop { + if (n == 0) { + break; + } + n = n - 1u; + let f = force[n]; + let p = position[n]; + let force_u = f.x * gaussian_2d(vec2(x_u), p, 10.0); + let force_v = f.y * gaussian_2d(vec2(x_v), p, 10.0); + net_force = net_force + vec2(force_u, force_v); + } + + let u_val = textureLoad(u, x_u).r; + let v_val = textureLoad(v, x_v).r; + textureStore(u, x_u, vec4(u_val + net_force.x * constants.dt, 0.0, 0.0, 0.0)); + textureStore(v, x_v, vec4(v_val + net_force.y * constants.dt, 0.0, 0.0, 0.0)); +} + +fn gaussian_2d(x: vec2, x0: vec2, sigma: f32) -> f32 { + let b = -1.0 / (2.0 * sigma * sigma); + return exp(b * dot(x - x0, x - x0)); +} \ No newline at end of file diff --git a/examples/mouse_interaction.rs b/examples/mouse_interaction.rs new file mode 100644 index 0000000..d13260a --- /dev/null +++ b/examples/mouse_interaction.rs @@ -0,0 +1,120 @@ +extern crate bevy_fluid; + +// use advection_plugin::AdvectionPlugin; +use bevy::{ + asset::AssetMetaCheck, + input::mouse::MouseMotion, + prelude::*, + render::{ + settings::{Backends, WgpuSettings}, + RenderPlugin, + }, + sprite::MaterialMesh2dBundle, + window::PrimaryWindow, +}; + +use bevy_fluid::euler_fluid::{ + add_force::AddForceMaterial, advection::AdvectionMaterial, fluid_material::VelocityMaterial, + FluidPlugin, +}; + +const WIDTH: f32 = 1280.0; +const HEIGHT: f32 = 720.0; + +fn main() { + let mut app = App::new(); + // [workaround] Asset meta files cannot be found on browser. + // see also: https://github.com/bevyengine/bevy/issues/10157 + let meta_check = if cfg!(target_arch = "wasm32") { + AssetMetaCheck::Never + } else { + AssetMetaCheck::Always + }; + + app.add_plugins( + DefaultPlugins + .set(WindowPlugin { + primary_window: Some(Window { + resolution: (WIDTH, HEIGHT).into(), + title: "bevy fluid".to_string(), + ..default() + }), + ..default() + }) + .set(RenderPlugin { + render_creation: bevy::render::settings::RenderCreation::Automatic(WgpuSettings { + backends: Some(Backends::DX12 | Backends::BROWSER_WEBGPU), + ..default() + }), + ..default() + }) + .set(AssetPlugin { + meta_check, + ..default() + }), + ) + .add_plugins(FluidPlugin) + .add_systems(Startup, setup_scene) + .add_systems(Update, on_advection_initialized) + .add_systems(Update, mouse_motion); + + app.run(); +} + +fn setup_scene(mut commands: Commands) { + commands + .spawn(Camera2dBundle::default()) + .insert(Name::new("Camera")); +} + +fn on_advection_initialized( + mut commands: Commands, + advection: Option>, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + if let Some(advection) = advection { + if advection.is_changed() { + info!("prepare velocity texture"); + // spwan plane to visualize advection + let mesh = meshes.add(Rectangle::default()); + let material = materials.add(VelocityMaterial { + offset: 0.5, + scale: 0.1, + u: Some(advection.u_in.clone()), + v: Some(advection.v_in.clone()), + }); + + commands.spawn(MaterialMesh2dBundle { + mesh: mesh.into(), + transform: Transform::default().with_scale(Vec3::splat(512.)), + material, + ..default() + }); + } + } +} + +fn mouse_motion( + mouse_button_input: Res>, + mut mouse_motion: EventReader, + mut force_material: ResMut, + q_window: Query<&Window, With>, +) { + if mouse_button_input.pressed(MouseButton::Left) { + if let Some(cursor_position) = q_window.single().cursor_position() { + let force = mouse_motion + .read() + .map(|mouse| mouse.delta) + .collect::>(); + let position = vec![cursor_position; force.len()]; + force_material.force = force; + force_material.position = position; + + return; + } + } + + force_material.force = vec![]; + force_material.position = vec![]; +} diff --git a/src/euler_fluid.rs b/src/euler_fluid.rs index 051f72f..3e494a4 100644 --- a/src/euler_fluid.rs +++ b/src/euler_fluid.rs @@ -1,3 +1,4 @@ +pub mod add_force; pub mod advection; pub mod fluid_material; pub mod geometry; @@ -5,6 +6,7 @@ pub mod grid_label; pub mod projection; pub mod uniform; +use add_force::{AddForceBindGroup, AddForceMaterial, AddForcePipeline}; use advection::{AdvectionBindGroup, AdvectionMaterial, AdvectionPipeline}; use bevy::{ asset::load_internal_asset, @@ -19,7 +21,9 @@ use bevy::{ renderer::RenderDevice, Render, RenderApp, RenderSet, }, + sprite::Material2dPlugin, }; +use fluid_material::VelocityMaterial; use geometry::{CircleCollectionBindGroup, CircleCollectionMaterial, CrircleUniform, Velocity}; use grid_label::{GridLabelBindGroup, GridLabelMaterial, GridLabelPipeline}; use projection::{ @@ -41,15 +45,15 @@ const WORKGROUP_SIZE: u32 = 8; const FLUID_UNIFORM_SHADER_HANDLE: Handle = Handle::weak_from_u128(0x8B9323522322463BA8CF530771C532EF); -const COORDINATE_SHADER_HANDLE: Handle = Handle::weak_from_u128(0x9F8E2E5B1E5F40C096C31175C285BF11); +const COORDINATE_SHADER_HANDLE: Handle = + Handle::weak_from_u128(0x9F8E2E5B1E5F40C096C31175C285BF11); pub struct FluidPlugin; impl Plugin for FluidPlugin { fn build(&self, app: &mut App) { - app - // .add_plugins(ExtractResourcePlugin::::default()) - .add_plugins(ExtractResourcePlugin::::default()) + app.add_plugins(ExtractResourcePlugin::::default()) + .add_plugins(ExtractResourcePlugin::::default()) .add_plugins(ExtractResourcePlugin::::default()) .add_plugins(ExtractResourcePlugin::::default()) .add_plugins(ExtractResourcePlugin::::default()) @@ -69,6 +73,10 @@ impl Plugin for FluidPlugin { Render, prepare_bind_group.in_set(RenderSet::PrepareBindGroups), ) + .add_systems( + Render, + add_force::prepare_bind_group.in_set(RenderSet::PrepareBindGroups), + ) .add_systems( Render, advection::prepare_bind_group.in_set(RenderSet::PrepareBindGroups), @@ -116,7 +124,7 @@ impl Plugin for FluidPlugin { fn finish(&self, app: &mut App) { let render_app = app.sub_app_mut(RenderApp); render_app.init_resource::(); - // render_app.init_resource::(); + render_app.init_resource::(); render_app.init_resource::(); render_app.init_resource::(); render_app.init_resource::(); @@ -173,6 +181,12 @@ fn setup(mut commands: Commands, mut images: ResMut>) { v_in: v0.clone(), v_out: v1.clone(), }); + commands.insert_resource(AddForceMaterial { + force: vec![], + position: vec![], + u: u1.clone(), + v: v1.clone(), + }); commands.insert_resource(DivergenceMaterial { u: u1.clone(), v: v1.clone(), @@ -199,14 +213,14 @@ fn setup(mut commands: Commands, mut images: ResMut>) { commands.spawn(SimulationUniform { dx: 1.0f32, - dt: 0.1f32, + dt: 0.5f32, rho: 1.293f32, }); } fn update(mut query: Query<&mut SimulationUniform>, _time: Res