Skip to content

Commit

Permalink
physics: restructure force systems
Browse files Browse the repository at this point in the history
  • Loading branch information
philiplinden committed Nov 16, 2024
1 parent 365e37e commit f305d5b
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 48 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ dev_native = [
# Enable system information plugin for native dev builds.
"bevy/sysinfo_plugin",
]
ron = ["ron", "bevy_common_assets"]
configs = ["ron", "bevy_common_assets"]
inspect = ["bevy-inspector-egui"]

[dependencies]
Expand Down
5 changes: 4 additions & 1 deletion docs/devlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,17 @@ think about it, that might be easier and simpler in the long run. If we need to
know each force's value and identity, we can add it to a resource or something
that the UI can query.

Update: it was not better. Still ran into the forever accumulating force issue
using a `ForceCollection` aggregator component and generic vectors. However, I
found a way to
I fell in love with [iyes_perf_ui](https://github.com/IyesGames/iyes_perf_ui).
It is simple and easy to work with. Egui was adding a lot of overhead, more than
I want right now. This is perfect until I'm done with the basic features of the
simulation.

- Fixed systems for computing the weight, buoyancy, and drag forces.
- Dropped egui.
- Added `iyes_perf_ui` for performance monitoring and other quick-n-dirty tools.
- Added `iyes_perf_ui` for performance monitoring and other UI.

## 2024-11-14

Expand Down
19 changes: 15 additions & 4 deletions src/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,27 @@ fn simple_scene(
},
));
// ground
let ground_size = Vec3::new(8.0, 0.1, 8.0);
let ground_size = Vec3::new(4.0, 0.1, 4.0);
commands.spawn((
Name::new("Ground"),
PbrBundle {
mesh: meshes.add(Cuboid::new(ground_size.x, ground_size.y, ground_size.z)),
material: materials.add(Color::srgb(0.75, 0.75, 0.75)),
transform: Transform::from_translation(Vec3::new(0.0, -0.05, 0.0)),
material: materials.add(Color::srgba(0.75, 0.75, 0.75, 0.1)),
transform: Transform::from_translation(Vec3::new(0.0, -2.0, 0.0)),
..default()
},
RigidBody::Static,
Collider::cuboid(ground_size.x / 2.0, ground_size.y / 2.0, ground_size.z / 2.0),
Collider::cuboid(ground_size.x, ground_size.y, ground_size.z),
));
commands.spawn((
Name::new("Ceiling"),
PbrBundle {
mesh: meshes.add(Cuboid::new(ground_size.x, ground_size.y, ground_size.z)),
material: materials.add(Color::srgba(0.75, 0.75, 0.75, 0.1)),
transform: Transform::from_translation(Vec3::new(0.0, 3.0, 0.0)),
..default()
},
RigidBody::Static,
Collider::cuboid(ground_size.x, ground_size.y, ground_size.z),
));
}
7 changes: 4 additions & 3 deletions src/simulator/balloon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,21 @@ fn spawn_balloon(
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let radius = 0.3;
commands.spawn((
Name::new("BalloonBundle"),
BalloonBundle {
balloon: Balloon::default(),
gas: IdealGasBundle::new(
Collider::sphere(1.0),
Collider::sphere(radius),
GasSpecies::air(),
Temperature::STANDARD,
Pressure::STANDARD,
),
pbr: PbrBundle {
mesh: meshes.add(Sphere::new(1.0)),
mesh: meshes.add(Sphere::new(radius)),
material: materials.add(Color::srgb_u8(124, 144, 255)),
transform: Transform::from_xyz(0.0, 2.0, 0.0),
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
},
},
Expand Down
73 changes: 38 additions & 35 deletions src/simulator/forces.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ pub struct ForcesPlugin;

impl Plugin for ForcesPlugin {
fn build(&self, app: &mut App) {
app.register_type::<Force>();
app.register_type::<ForceCollection>();
app.register_type::<WeightForce>();
app.register_type::<BuoyantForce>();
app.register_type::<DragForce>();

// Disable the default forces since we apply our own.
app.insert_resource(Gravity(Vec3::ZERO));
Expand All @@ -30,7 +31,10 @@ impl Plugin for ForcesPlugin {
)
.before(PhysicsStepSet::First),
);
app.add_systems(Update, on_rigid_body_added.in_set(ForceUpdateOrder::First));
app.add_systems(
Update,
on_rigid_body_added.in_set(ForceUpdateOrder::First),
);
app.add_systems(
Update,
(update_weight_force, update_buoyant_force, update_drag_force)
Expand All @@ -49,26 +53,19 @@ enum ForceUpdateOrder {
Prepare,
Apply,
}
/// A generic struct representing any force vector applied to an entity.
/// This is not a physics force, but rather a force vector. We could use bare
/// `Vec3` structs, but this provides a type for clarity.
pub type Force = Vec3;

/// A component to store all `Force`s acting on an entity. This component collects
/// all the force vectors that act on an entity, such as weight and buoyancy.
#[derive(Component, Default, Reflect)]
pub struct ForceCollection {
pub items: Vec<Force>,
}

/// Add a `ForceCollection` to entities with a `RigidBody` when they are added.
fn on_rigid_body_added(mut commands: Commands, query: Query<Entity, Added<RigidBody>>) {
for entity in &query {
commands.entity(entity).insert(ForceCollection::default());
info!("RigidBody added to entity {:?}", entity);
commands.entity(entity).insert((WeightForce::default(), BuoyantForce::default(), DragForce::default(), ForceCollection::default()));
}
}

/// Downward force (N) vector due to gravity as a function of altitude (m) and
/// mass (kg). The direction of this force is always world-space down.
#[derive(Component, Default, Reflect)]
pub struct WeightForce(Vec3);

/// Force (N) from gravity at an altitude (m) above mean sea level.
fn g(position: Vec3) -> f32 {
let altitude = position.y; // [m]
Expand All @@ -82,13 +79,17 @@ pub fn weight(position: Vec3, mass: f32) -> Vec3 {
}

fn update_weight_force(
mut bodies: Query<(&mut ForceCollection, &Position, &Mass), With<RigidBody>>,
mut bodies: Query<(&mut WeightForce, &Position, &Mass), With<RigidBody>>,
) {
for (mut forces, position, mass) in bodies.iter_mut() {
forces.items.push(weight(position.0, mass.kg()));
for (mut force, position, mass) in bodies.iter_mut() {
force.0 = weight(position.0, mass.kg());
}
}

/// Upward force (N) vector due to atmosphere displaced by the given gas volume.
#[derive(Component, Default, Reflect)]
pub struct BuoyantForce(Vec3);

/// Upward force (N) vector due to atmosphere displaced by the given gas volume.
/// The direction of this force is always world-space up.
pub fn buoyancy(position: Vec3, volume: Volume, ambient_density: Density) -> Vec3 {
Expand All @@ -97,14 +98,18 @@ pub fn buoyancy(position: Vec3, volume: Volume, ambient_density: Density) -> Vec

fn update_buoyant_force(
atmosphere: Res<Atmosphere>,
mut bodies: Query<(&mut ForceCollection, &Position, &Volume), With<RigidBody>>,
mut bodies: Query<(&mut BuoyantForce, &Position, &Volume), With<RigidBody>>,
) {
for (mut forces, position, volume) in bodies.iter_mut() {
for (mut force, position, volume) in bodies.iter_mut() {
let density = atmosphere.density(position.0);
forces.items.push(buoyancy(position.0, *volume, density));
force.0 = buoyancy(position.0, *volume, density);
}
}

/// Force (N) due to drag as a solid body moves through a fluid.
#[derive(Component, Default, Reflect)]
pub struct DragForce(Vec3);

/// Force (N) due to drag as a solid body moves through a fluid.
pub fn drag(ambient_density: f32, velocity: Vec3, drag_area: f32, drag_coeff: f32) -> Vec3 {
let direction = -velocity.normalize();
Expand All @@ -115,27 +120,25 @@ pub fn drag(ambient_density: f32, velocity: Vec3, drag_area: f32, drag_coeff: f3
#[allow(unused_mut)]
fn update_drag_force(
atmosphere: Res<Atmosphere>,
mut bodies: Query<
(
&ForceCollection,
&Position,
&LinearVelocity,
// &DragArea,
// &DragCoeff,
),
With<RigidBody>,
>,
mut bodies: Query<(&mut DragForce, &Position, &LinearVelocity), With<RigidBody>>,
) {
// Todo: update drag force
}

/// Dump all the forces into a single vector that can be queried and summed.
/// TODO: maybe use observer pattern to find and update this collection, or
/// populate it by emitting an event from each force system to populate the
/// array.
#[derive(Component, Default, Reflect)]
struct ForceCollection(Vec<Vec3>);

/// Set the `ExternalForce` to the sum of all forces in the `Forces` collection.
/// This effectively applies all the calculated force vectors to the physics
/// rigid body without regard to where the forces came from.
fn update_total_external_force(
mut forces: Query<(&mut ExternalForce, &ForceCollection), With<RigidBody>>,
mut external_forces: Query<(&mut ExternalForce, &ForceCollection), With<RigidBody>>,
) {
for (mut physics_force, collection) in forces.iter_mut() {
physics_force.set_force(collection.items.iter().sum());
for (mut physics_force, forces) in external_forces.iter_mut() {
physics_force.set_force(forces.0.iter().sum());
}
}
1 change: 0 additions & 1 deletion src/ui/dev_tools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ pub(super) fn plugin(app: &mut App) {
FrameTimeDiagnosticsPlugin,
EntityCountDiagnosticsPlugin,
SystemInformationDiagnosticsPlugin,
PerfUiPlugin,
// rendering
#[cfg(not(target_arch = "wasm32"))]
WireframePlugin,
Expand Down
10 changes: 7 additions & 3 deletions src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
mod dev_tools;

use bevy::{app::PluginGroupBuilder, prelude::*};
use iyes_perf_ui::prelude::*;

/// A plugin group that includes all interface-related plugins
pub struct InterfacePlugins;

impl PluginGroup for InterfacePlugins {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>().add(CoreUiPlugin)
PluginGroupBuilder::start::<Self>()
.add(CoreUiPlugin)
// .add(DynamicsStatsPlugin)
// .add(KinematicsStatsPlugin)
// .add(FlightStatsPlugin)
}
}

Expand All @@ -19,8 +24,7 @@ pub struct CoreUiPlugin;
impl Plugin for CoreUiPlugin {
fn build(&self, app: &mut App) {
app.add_plugins((
// TODO: plugins that sets up the basics.

PerfUiPlugin,
#[cfg(feature = "dev")]
dev_tools::plugin,
));
Expand Down

0 comments on commit f305d5b

Please sign in to comment.