Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bevy 0.15.0 rc.3 #2

Merged
merged 10 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 10 additions & 22 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ edition = "2021"
readme = "README.md"
license-file = "LICENSE"

[[bin]]
name = "yahs"
path = "src/main.rs"

[features]
default = [
# Default to a native dev build.
Expand All @@ -17,35 +21,19 @@ dev = [
# library.
"bevy/dynamic_linking",
"bevy/bevy_dev_tools",
"bevy/sysinfo_plugin",
]
dev_native = [
"dev",
# Enable system information plugin for native dev builds.
"bevy/sysinfo_plugin",
"iyes_perf_ui/sysinfo",
]
config-files = ["ron", "bevy_common_assets", "serde"]
inspect = ["bevy-inspector-egui", "bevy_panorbit_camera/bevy_egui"]

[dependencies]
# core dependencies
bevy = "0.14.2"
bevy-trait-query = "0.6.0"
# physics dependencies
avian3d = { version = "0.1.2", features = ["debug-plugin"] }
# ui dependencies
bevy_panorbit_camera = { version = "0.20.0" }
bevy-inspector-egui = { version = "0.27.0", features = ["highlight_changes"], optional = true }
iyes_perf_ui = "0.3.0"
# file io dependencies
bevy_common_assets = { version = "0.11.0", features = ["ron"], optional = true }
ron = { version = "0.8.1", optional = true }
serde = { version = "1.0", features = ["derive"], optional = true }
parry3d = { version = "0.17.2", features = ["parallel"] }

[[bin]]
name = "yahs"
path = "src/main.rs"
bevy = "0.15.0-rc.3"
avian3d = { git = "https://github.com/Jondolf/avian.git", branch = "bevy-0.15", features = ["debug-plugin"] }
bevy-trait-query = { git = "https://github.com/JoJoJet/bevy-trait-query.git", branch = "bevy-0.15-rc" }
iyes_perf_ui = { git = "https://github.com/JohnathanFL/iyes_perf_ui.git", branch = "main" }

# -----------------------------------------------------------------------------
# Some Bevy optimizations
Expand All @@ -66,7 +54,7 @@ type_complexity = "allow"
# Compile with Performance Optimizations:
# https://bevyengine.org/learn/quick-start/getting-started/setup/#compile-with-performance-optimizations

# Enable a small amount of optimization in the dev profile.
# Enable a small amount of optimization in the dev profile for our code.
[profile.dev]
opt-level = 1

Expand Down
160 changes: 160 additions & 0 deletions docs/devlog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,165 @@
# development log

## 2024-11-26

I added a `GasMonitor` to the UI for displaying the gas properties in real time.
With that in place, I can now notice that the balloon's density is reported as
NaN, which is probably why buoyancy is not working. I think I found the bug. The
density was not being updated in the system that updates gas properties from
the atmosphere. Fixed that, but buoyancy is still pegged at 0. Curious, the
buoyant system was querying `With<SimulatedBody>`, maybe something is messed up
with the query because this system is definitely running every frame. A default
`ForceBundle` is supposed to be added to the balloon when it is added to the
world, so I'm curious why the buoyancy component is not being added. The
`Weight` component is being added... Ah, the buoyancy system is also querying
`Volume` components, weight is not. Maybe the query isn't turning up the bodies
because the `Volume` component is not being added? With Bevy 0.15 we can enforce
such a thing with the `#[require(x)]` attribute. Turns out there's no system
that updates the volume because I wanted to calculate it from the balloon's
primitive shape. I'll change buoyancy to query the balloon and get its volume
instead. That fixed the buoyancy system so it runs, but the force results might
not be correct.

```sh
INFO yahs::simulator::forces: Weight [0, -5.1347504, 0]
INFO yahs::simulator::forces: Buoyancy [0, 3888.388, 0]
INFO yahs::simulator::forces: Drag [NaN, NaN, NaN]
```

I traced the drag force NaN to the drag area returning nan from
`balloon.shape.diameter()` at startup before the shape is set up.

```sh
INFO yahs::simulator::forces::aero: balloon shape: Sphere { radius: NaN }
ERROR yahs::simulator::forces: Drag has NaN magnitude!
ERROR yahs::simulator::forces: Buoyancy has NaN magnitude!
INFO yahs::simulator::forces::aero: balloon shape: Sphere { radius: 4.2564797 }
INFO yahs::simulator::forces::aero: balloon shape: Sphere { radius: 4.2810054 }
INFO yahs::simulator::forces::aero: balloon shape: Sphere { radius: 4.2810054 }
```

I enforced that the mesh volumes are updated before the forces are calculated,
but there might be a few frames at the beginning where the Mesh isn't
initialized yet. Maybe it works a little differently because it's an asset?
I noticed that the balloon was being spawned after the ground plane, and scene
setup was not constrained to run in any system set. So the forces probably ran
before the scene was done loading. I added a few conditions:

- The app starts in the `Loading` state.
- The scene advances to the `Running` state when it is done setting up the scene.
- The physics systems only run when the app is in the `Running` state.

Weird, something else is going on. The balloon shape is a real number when it is
spawned and before the forces run, but when the forces run it is NaN.

```sh
INFO bevy_winit::system: Creating new window "🎈" (0v1#4294967296)
INFO yahs::app3d::scene: sphere: Sphere { radius: 0.5 }
INFO bevy_dev_tools::states: yahs::simulator::core::SimState transition: Some(Loading) => Some(Running)
INFO yahs::app3d::scene: sim state: Res(State(Running))
INFO yahs::app3d::scene: balloon spawned: 19v1 Balloon { material_properties: BalloonMaterial { name: "Latex", max_temperature: 373.0, density: 920.0, emissivity: 0.9, absorptivity: 0.9, thermal_conductivity: 0.13, specific_heat: 2000.0, poissons_ratio: 0.5, elasticity: 10000000.0, max_strain: 0.8, max_stress: 500000.0, thickness: 0.0001 }, shape: Sphere { radius: 0.5 } } Sphere { radius: 0.5 }
INFO yahs::simulator::forces::aero: balloon shape: Sphere { radius: NaN }
ERROR yahs::simulator::forces: Drag has NaN magnitude!
ERROR yahs::simulator::forces: Buoyancy has NaN magnitude!
WARN avian3d::collision::narrow_phase: 18v1#4294967314 (Ground) and 19v1#4294967315 (Balloon) are overlapping at spawn, which can result in explosive behavior.
INFO yahs::app3d::scene: sim state: Res(State(Running))
INFO yahs::simulator::forces::aero: balloon shape: Sphere { radius: 4.2564797 }
INFO yahs::app3d::scene: sim state: Res(State(Running))
INFO yahs::simulator::forces::aero: balloon shape: Sphere { radius: 4.2810054 }
INFO yahs::app3d::scene: sim state: Res(State(Running))
INFO yahs::simulator::forces::aero: balloon shape: Sphere { radius: 4.2810054 }
```

I noticed that density is initialized to NaN with the ideal gas and the volume
of the balloon is derived from the ideal gas volume. The volume is calculated
before the force, so that explains where this NaN is coming from.

Found it. Ideal gas law has pressure in the denominator of the volume equation.
Pressure initializes to zero by default, so the volume is NaN. Changing the
default from zero to the standard atmospheric pressure fixes that issue.

I think the sim was crashing because it kept defaulting to use way too much
mass in the balloon. I added `with_volume()` to the ideal gas to fix that, so we
can spawn the balloon with a known volume at the default density.

It works!

## 2024-11-24

I found a Bevy 0.15 branch of
[iyes_perf_ui](https://github.com/IyesGames/iyes_perf_ui/pull/22), yay!

I spent some time today practicing with Events and Observers by adding debug UI
toggles. Not very productive but practice is practice.

## 2024-11-23

Now that the basic forces are working, I will add look to adding the other
fundamentals of the flight simulation:

- Ideal gas law, including expansion of gas volume as pressure changes.
- Stats or plots showing the state of the gas and balloon kinematics over time.
- A payload hanging from a tether would be fun too. For this we can lean on the
Avian [chain_3d](https://github.com/Jondolf/avian/blob/main/examples/chain_3d.rs)
example.

I upgraded Bevy to 0.15.0-rc.3 and it broke the build, especially with regard to
the avian physics plugins. In migrating to the new Bevy version I simplified
some things, like removing the `crate::properties::Mass` component and instead
using Avian's mass properties. There are some complications because after
upgrading bevy it is crashing due to `Mass` not being a component. I guess mass
properties [being refactored](https://github.com/Jondolf/avian/discussions/499).

The Avian maintainer created a new crate called
[bevy_heavy](https://github.com/Jondolf/bevy_heavy) that contains the new mass
properties tools that allow for directly updating mass properties on primitive
shapes. Then we can use primitive shapes for mass and volume. That simplifies
things by ~~removing mass, volume, and density as separate components~~. Turns
out it is not that simple and having them as separate components is useful and
clean. It is much simpler to write systems that update these components.

[Migrating to Bevy `0.15.0-rc.3`](https://github.com/bevyengine/bevy-website/tree/main/release-content/0.15/migration-guides)
is proving to be a bit of a challenge. The main feature from it that I want to
use is the new separation of meshes from rendering, since then we can use meshes
for calculations like volume and drag even if we want to use a CLI and don't
want to render anything. This feature also led to some welcome improvements to
Bevy's meshing tools.

Something about 0.15 seems to have broken bundles. I wonder if the API changed
or if there's some old garbage hanging around that is causing issues. I wiped
the cache and rebuilt the project (`cargo clean && cargo build`). It turns out
the reason that builds are failing is because some of the 3rd party dependencies
I'm using are not compatible with the new Bevy version. I need to go through and
update them or remove them.

- [x] `avian3d` -> branch `bevy-0.15`
- [ ] ~~`bevy_heavy`~~ remove for now
- [x] `bevy-trait-query` -> branch `bevy-0.15-rc`
- [ ] ~~`bevy_common_assets`~~ remove for now
- [ ] ~~`bevy_panorbit_camera`~~ remove for now
- [ ] ~~`iyes_perf_ui`~~ remove for now
- [ ] ~~`bevy-inspector-egui`~~ remove for now

I also removed `serde` from the dependencies. I won't be getting to config files
any time soon.

It's probably better to not use so many 3rd party plugins. Fortunately most of
these are debug tools and not essential to the simulator.

This demo does a great job using Egui and debug vectors:
[bevy_motion_matching](https://github.com/kahboon0425/bevy_motion_matching)
something to look into later.

I'm gonna do it. I'm going to make the simulator and the 3D app separate crates.
There are three reasons for this:

1. The simulator crate can be used as a library in other projects.
2. The 3D app can be built and run independently of the rest of the code.
3. I want faster compile times.

Nevermind, it complicated things way too much and was distracting. In the future
it might be worthwhile but it's probably best to just use feature flags anyway.

## 2024-11-18 again

I think I was a bit naive to install `bevy-trait-query`. It works for now but in
Expand Down
File renamed without changes.
File renamed without changes.
20 changes: 20 additions & 0 deletions src/app3d/camera.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use bevy::prelude::*;

// use crate::controls::CameraControls;

pub struct CameraPlugin;

impl Plugin for CameraPlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, setup);
}
}

fn setup(mut commands: Commands) {
commands.spawn((
// Note we're setting the initial position below with yaw, pitch, and radius, hence
// we don't set transform on the camera.
Camera3d::default(),
Transform::from_xyz(0.0, 20., 50.0).looking_at(Vec3::new(0., 20., 0.), Vec3::Y),
));
}
13 changes: 9 additions & 4 deletions src/controls.rs → src/app3d/controls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ impl Plugin for ControlsPlugin {
}
}

#[allow(dead_code)]
#[derive(Resource, Default)]
pub struct KeyBindingsConfig {
pub camera_controls: CameraControls,
Expand All @@ -25,9 +26,11 @@ pub struct CameraControls {

#[derive(Reflect)]
pub struct DebugControls {
pub toggle_wireframe: KeyCode,
pub toggle_inspector: KeyCode,
pub toggle_wireframe: KeyCode,
pub toggle_physics_debug: KeyCode,
pub toggle_perf_ui: KeyCode,
pub toggle_anything_else: KeyCode,
}

#[derive(Reflect)]
Expand All @@ -52,9 +55,11 @@ impl Default for CameraControls {
impl Default for DebugControls {
fn default() -> Self {
Self {
toggle_wireframe: KeyCode::KeyW,
toggle_inspector: KeyCode::KeyI,
toggle_perf_ui: KeyCode::KeyP,
toggle_wireframe: KeyCode::F1,
toggle_inspector: KeyCode::F2,
toggle_physics_debug: KeyCode::F3,
toggle_perf_ui: KeyCode::F4,
toggle_anything_else: KeyCode::F5,
}
}
}
Expand Down
23 changes: 20 additions & 3 deletions src/app3d/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
mod scene;
mod camera;
mod ui;
pub mod controls;

// Re-export the plugins so they can be added to the app with `app.add_plugins`.
pub use scene::ScenePlugin;
pub use ui::InterfacePlugins;
use scene::ScenePlugin;
use ui::InterfacePlugin;
use controls::ControlsPlugin;
use camera::CameraPlugin;

use bevy::app::{PluginGroup, PluginGroupBuilder};

pub struct App3dPlugins;

impl PluginGroup for App3dPlugins {
fn build(self) -> PluginGroupBuilder {
PluginGroupBuilder::start::<Self>()
.add(InterfacePlugin)
.add(ControlsPlugin)
.add(ScenePlugin)
.add(CameraPlugin)
}
}
74 changes: 74 additions & 0 deletions src/app3d/scene.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
use avian3d::prelude::*;
use bevy::prelude::*;

use crate::simulator::*;

pub struct ScenePlugin;

impl Plugin for ScenePlugin {
fn build(&self, app: &mut App) {
app.add_systems(Startup, (spawn_balloon, simple_scene));
// app.add_systems(PostStartup, |mut commands: Commands| {
// commands.set_state(SimState::Running);
// });
}
}

/// set up a simple 3D scene
fn simple_scene(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let ground_size = Vec3::new(50.0, 0.1, 50.0);
let plane = meshes.add(Plane3d::default().mesh().size(ground_size.x, ground_size.z).subdivisions(10));
let plane_material = materials.add(StandardMaterial {
base_color: Color::srgb(0.5, 0.5, 0.5),
perceptual_roughness: 0.5,
..default()
});

// ground
commands.spawn((
Name::new("Ground"),
RigidBody::Static,
Mesh3d(plane.clone()),
MeshMaterial3d(plane_material.clone()),
ColliderConstructor::TrimeshFromMesh,
));
}

fn spawn_balloon(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
) {
let debug_material = materials.add(StandardMaterial {
base_color: Color::srgba(1.0, 0.0, 0.0, 0.5),
perceptual_roughness: 0.0,
metallic: 1.0,
..default()
});
let sphere = Sphere::default();
let shape = meshes.add(sphere.mesh().ico(5).unwrap());
let species = GasSpecies::helium();
commands.spawn((
Name::new("Balloon"),
SimulatedBody,
BalloonBundle {
balloon: Balloon {
material_properties: BalloonMaterial::default(),
shape: sphere,
},
gas: IdealGas::new(species).with_mass(Mass::new(0.01)),
},
RigidBody::Dynamic,
Collider::sphere(sphere.radius),
Transform {
translation: Vec3::new(0.0, 10.0, 0.0),
..default()
},
MeshMaterial3d(debug_material),
Mesh3d(shape),
));
}
Loading
Loading