mirror of
https://github.com/bevyengine/bevy.git
synced 2026-07-01 08:12:51 -04:00
create-pull-request/patch
183 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
10e9ec77fb |
Add mesh compression and motion blur to scene viewer (#24570)
## Objective Allow testing more features in the `scene_viewer` example. ## Solution Add mesh compression and motion blur options to the command line. Ideally the mesh compression would allow control over individual attributes, but this is enough for basic smoke testing. ```rust /// enable mesh attribute compression #[argh(switch)] mesh_attribute_compression: bool, /// enable mesh index compression #[argh(switch)] mesh_index_compression: bool, /// enable motion blur #[argh(switch)] motion_blur: bool, /// set the motion blur shutter angle #[argh(option)] motion_blur_shutter_angle: Option<f32>, ``` ## Testing ```sh # Mesh compression cargo run --example scene_viewer --features "free_camera bevy_dev_tools" -- --mesh-attribute-compression --mesh-index-compression # Motion blur cargo run --example scene_viewer --features "free_camera bevy_dev_tools" -- "assets//models/animated/Fox.glb" --motion-blur --motion-blur-shutter-angle 10 ``` |
||
|
|
0b49ff72d4 |
Snap to view (#23674)
# Objective - Adds ``SnapToView`` camera controller as solution to #23499 ## Solution - Adds ``snap_to_view`` module behind ``free_camera`` feature flag ## Testing - Manually tested with ``cargo run --example free_camera_controller --features="free_camera bevy_dev_tools"`` and ``cargo run --example scene_viewer --features="free_camera bevy_dev_tools"``: - All six hotkeys works. - [LCtrl +] Numpad1 - Snap to front/back - [LCtrl +] Numpad3 - Snap to right/left - [LCtrl +] Numpad7 - Snap to top/bottom - Tested on Linux (Wayland) --- ## Showcase https://github.com/user-attachments/assets/cca71180-c273-473f-a168-9793438d861f Add ``SnapToViewCamera`` component to any ``Camera3d`` entity. Change parameters inside ``SnapToViewCamera`` to change snap speed and hotkeys. ```rust app.add_plugins(SnapToViewPlugin); commands.spawn(( Camera3d::default(), SnapToViewCamera::default(), )); ``` --------- Co-authored-by: taishi-sama <alexandra.2002.mikh@gmail.com> |
||
|
|
535cf401cc |
Reframe old "scene" terminology as "world serialization" (#23630)
Part 2 of #23619 In **Bevy 0.19** we are landing a subset of Bevy's Next Generation Scene system (often known as BSN), which now lives in the `bevy_scene` / `bevy::scene` crate. However the old `bevy_scene` system still needs to stick around for a bit longer, as it provides some features that Bevy's Next Generation Scene system doesn't (yet!): 1. It is not _yet_ possible to write a World _to_ BSN, so the old system is still necessary for "round trip World serialization". 2. The GLTF scene loader has not yet been ported to BSN, so the old system is still necessary to spawn GLTF scenes in Bevy. For this reason, we have renamed the old `bevy_scene` crate to `bevy_world_serialization`. If you were referencing `bevy_scene::*` or `bevy::scene::*` types, rename those paths to `bevy_world_serialization::*` and `bevy::world_serialization::*` respectively. Additionally, to avoid confusion / conflicts with the new scene system, all "scene" terminology / types have been reframed as "world serialization": - `Scene` -> `WorldAsset` (as this was always just a World wrapper) - `SceneRoot` -> `WorldAssetRoot` - `DynamicScene` -> `DynamicWorld` - `DynamicScene::from_scene` -> `DynamicWorld::from_world_asset` - `DynamicSceneBuilder` -> `DynamicWorldBuilder` - `DynamicSceneRoot` -> `DynamicWorldRoot` - `SceneInstanceReady` -> `WorldInstanceReady` - `SceneLoader` -> `WorldAssetLoader` - `ScenePlugin` -> `WorldSerializationPlugin` - `SceneRootTemplate` -> `WorldAssetRootTemplate` - `SceneSpawner` -> `WorldInstanceSpawner` - `SceneFilter` -> `WorldFilter` - `SceneLoaderError` -> `WorldAssetLoaderError` - `SceneSpawnError` -> `WorldInstanceSpawnError` Note that I went with `bevy_world_serialization` over `bevy_ecs_serialization`, as that is what all of the internal features described themselves as. I think it is both more specific and does a better job of making itself decoupled from `bevy_ecs` proper. |
||
|
|
ed86a8917e |
Add infinite grid to scene_viewer (#23523)
# Objective - The scene viewer is a void and is easy to get lost in it - Having a grid that shows the ground plane and main axis should help ## Solution - Add the new infinite grid to the scene_viewer example ## Testing I ran the example and like you can see in the screenshot it worked --- ## Showcase <img width="1280" height="720" alt="scene_viewer_FXzUE3pCSQ" src="https://github.com/user-attachments/assets/35736f93-3944-4762-b06f-05a18276425b" /> |
||
|
|
9fd2637846 |
Add tools to avoid unnecessary AssetEvent::Modified events that lead to rendering performance costs (#16751) (#22460)
# Objective - Fixes #16751 ## Solution - `Assets::get_mut` now returns a wrapper `AssetMut` type instead of `&mut impl Asset`. - `AssetMut` implements `Deref` and `DerefMut`. - `DerefMut` marks assets as changed. - when dropped `AssetMut` will add `AssetEvent::Modified` event to a queue only in case asset was marked as changed. ## Testing - Did you test these changes? If so, how? - No unit tests were added, change is pretty straightforward. - Test project: https://github.com/MatrixDev/bevy-feature-16751-test. - With change: ~100 fps. - Without change: ~15 fps. - Are there any parts that need more testing? - I don't really see how this can break anything or add a measurable overhead. - `AssetEvent::Modified` will now be sent after the asset was modified instead of before. It should not affect anything but still worth noting. - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Have a big amount of entities that constantly update their materials. - Properties of those materials should be animated in a stepped maned (like changing color every 0.1 seconds). - Update material only if value has actually changed: ```rust if material.base_color != new_color { material.base_color = new_color; } ``` - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? - tested on macos (Mackbook M1) - not a platform-specific issue PS: This is my first PR, so please don’t judge. |
||
|
|
c6ca738746 |
Adds Frustum Gizmo (#22762)
# Objective - Adopts #10038 by @tim-blackbird - Half of #19468 (no camera gizmo, just frustum) - Does Part 3 of and fixes #13878 ## Solution I stand on the shoulders of giants and have updated #10038 to main, with the following changes: - The frustum gizmos are now immediate gizmos, not retained - The current view’s frustum is drawn around the border of the screen as a color like so (note the green border at the left, bottom, and right edges of the screen). <img width="1286" height="752" alt="Screenshot 2026-01-31 at 9 18 41 PM" src="https://github.com/user-attachments/assets/7ed2b4db-1710-4be1-b6ca-00725d09944f" /> Also thanks to @RCoder01 for their github gist attached to the original PR; my updates basically ended up being the same although code is more or less in its proper place now. ## Testing - I ran some scene_viewer gltf files in the bevy repo (e.g. `cargo run --example scene_viewer --features "free_camera" -- assets/models/cubes/Cubes.glb`). I guess none have multiple cameras though to cycle through though as far as I could tell? But at least this shows you that toggling the frusta shows the faint border around the screen. - I ran the light_gizmos example `cargo run --example light_gizmos`. Only `SpotLight` has gizmos drawn (`PointLight` and `DirectionalLight` have components that wrap `Frustum` but not `Frustum` itself). It’s the yellow gizmo in the following screenshot. Since there are dedicated light gizmos, using a Frustum gizmo on a light seems unnecessary. <img width="1278" height="740" alt="Screenshot 2026-01-31 at 9 36 54 PM" src="https://github.com/user-attachments/assets/6e676bb8-32d4-4d90-9225-ee3a878745a6" /> - Like the original author, I modified the `split_screen` example to see a camera frustum gizmo from one player on another player’s screen. I removed players 3 and 4, added a frustum gizmo for player 2’s camera, and moved player 1’s camera far enough so that you can see the frustum. <img width="1274" height="740" alt="Screenshot 2026-01-31 at 9 09 46 PM" src="https://github.com/user-attachments/assets/fff38469-9d00-46ba-9098-fdf8418b54fa" /> --- ## Showcase <details> <summary>Modified `split_screen` example code</summary> ```rust //! Renders four cameras to the same window to accomplish "split screen". use std::f32::consts::PI; use bevy::{ camera::Viewport, light::CascadeShadowConfigBuilder, prelude::*, window::WindowResized, }; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems(Update, (set_camera_viewports, button_system)) .run(); } /// set up a simple 3D scene fn setup( mut commands: Commands, asset_server: Res<AssetServer>, mut meshes: ResMut<Assets<Mesh>>, mut materials: ResMut<Assets<StandardMaterial>>, ) { // plane commands.spawn(( Mesh3d(meshes.add(Plane3d::default().mesh().size(100.0, 100.0))), MeshMaterial3d(materials.add(Color::srgb(0.3, 0.5, 0.3))), )); commands.spawn(SceneRoot( asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/animated/Fox.glb")), )); // Light commands.spawn(( Transform::from_rotation(Quat::from_euler(EulerRot::ZYX, 0.0, 1.0, -PI / 4.)), DirectionalLight { shadow_maps_enabled: true, ..default() }, CascadeShadowConfigBuilder { num_cascades: if cfg!(all( feature = "webgl2", target_arch = "wasm32", not(feature = "webgpu") )) { // Limited to 1 cascade in WebGL 1 } else { 2 }, first_cascade_far_bound: 200.0, maximum_distance: 280.0, ..default() } .build(), )); // Cameras and their dedicated UI for (index, (camera_name, camera_pos)) in [ ("Player 1", Vec3::new(300.0, 300.0, -150.0)), ("Player 2", Vec3::new(150.0, 150., 50.0)), ] .iter() .enumerate() { let camera = commands .spawn(( Camera3d::default(), Transform::from_translation(*camera_pos).looking_at(Vec3::ZERO, Vec3::Y), Camera { // Renders cameras with different priorities to prevent ambiguities order: index as isize, ..default() }, CameraPosition { pos: index as u32 % 2, }, ShowFrustumGizmo { color: if index == 0 { Some(Color::NONE) } else { None }, }, )) .id(); // Set up UI if index == 0 { commands.spawn(( UiTargetCamera(camera), Node { width: percent(100), height: percent(100), ..default() }, children![ ( Text::new(*camera_name), Node { position_type: PositionType::Absolute, top: px(12), left: px(12), ..default() }, ), buttons_panel(), ], )); } } fn buttons_panel() -> impl Bundle { ( Node { position_type: PositionType::Absolute, width: percent(100), height: percent(100), display: Display::Flex, flex_direction: FlexDirection::Row, justify_content: JustifyContent::SpaceBetween, align_items: AlignItems::Center, padding: UiRect::all(px(20)), ..default() }, children![ rotate_button("<", Direction::Left), rotate_button(">", Direction::Right), ], ) } fn rotate_button(caption: &str, direction: Direction) -> impl Bundle { ( RotateCamera(direction), Button, Node { width: px(40), height: px(40), border: UiRect::all(px(2)), justify_content: JustifyContent::Center, align_items: AlignItems::Center, ..default() }, BorderColor::all(Color::WHITE), BackgroundColor(Color::srgb(0.25, 0.25, 0.25)), children![Text::new(caption)], ) } } #[derive(Component)] struct CameraPosition { pos: u32, } #[derive(Component)] struct RotateCamera(Direction); enum Direction { Left, Right, } fn set_camera_viewports( windows: Query<&Window>, mut window_resized_reader: MessageReader<WindowResized>, mut query: Query<(&CameraPosition, &mut Camera)>, ) { // We need to dynamically resize the camera's viewports whenever the window size changes // so then each camera always takes up half the screen. // A resize_event is sent when the window is first created, allowing us to reuse this system for initial setup. for window_resized in window_resized_reader.read() { let window = windows.get(window_resized.window).unwrap(); let size = window.physical_size(); for (camera_position, mut camera) in &mut query { camera.viewport = Some(Viewport { physical_position: camera_position.pos * size, physical_size: size, ..default() }); } } } fn button_system( interaction_query: Query< (&Interaction, &ComputedUiTargetCamera, &RotateCamera), (Changed<Interaction>, With<Button>), >, mut camera_query: Query<&mut Transform, With<Camera>>, ) { for (interaction, computed_target, RotateCamera(direction)) in &interaction_query { if let Interaction::Pressed = *interaction { // Since TargetCamera propagates to the children, we can use it to find // which side of the screen the button is on. if let Some(mut camera_transform) = computed_target .get() .and_then(|camera| camera_query.get_mut(camera).ok()) { let angle = match direction { Direction::Left => -0.1, Direction::Right => 0.1, }; camera_transform.rotate_around(Vec3::ZERO, Quat::from_axis_angle(Vec3::Y, angle)); } } } } ``` </details> --------- Co-authored-by: devil-ira <justthecooldude@gmail.com> Co-authored-by: Robert Swain <robert.swain@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
|
|
6ca4769128 |
Minimal responsive FontSize support (#22614)
# Objective
Add responsive font sizes supporting rem and viewport units to
`bevy_text` with minimal changes to the APIs and systems.
## Solution
Introduce a new `FontSize` enum:
```rust
pub enum FontSize {
/// Font Size in logical pixels.
Px(f32),
/// Font size as a percentage of the viewport width.
Vw(f32),
/// Font size as a percentage of the viewport height.
Vh(f32),
/// Font size as a percentage of the smaller of the viewport width and height.
VMin(f32),
/// Font size as a percentage of the larger of the viewport width and height.
VMax(f32),
/// Font Size relative to the value of the `RemSize` resource.
Rem(f32),
}
```
This replaces the `f32` value of `TextFont`'s `font_size` field.
The viewport variants work the same way as their respective `Val`
counterparts.
`Rem` values are multiplied by the value of the `RemSize` resource
(which newtypes an `f32`).
`FontSize` provides an `eval` method that takes a logical viewport size
and rem base size and returns an `f32` logical font size. The resolved
logical font size is then written into the `Attributes` passed to Cosmic
Text by `TextPipeline::update_buffer`.
Any text implementation using `bevy_text` must now provide viewport and
rem base values when calling `TextPipeline::update_buffer` or
`create_measure`.
`Text2d` uses the size of the primary window to resolve viewport values
(or `Vec2::splat(1000)` if no primary window is found). This is a
deliberate compromise, a single `Text2d` can be rendered to multiple
viewports using `RenderLayers`, so it's difficult to find a rule for
which viewport size should be chosen.
### Change detection
`ComputedTextBlock` has two new fields: `uses_viewport_sizes` and
`uses_rem_sizes`, which are set to true in `TextPipeline::update_buffer`
iff any text section in the block uses viewport or rem font sizes,
respectively.
The `ComputedTextBlock::needs_rerender` method has been modified to take
take two bool parameters:
```rust
pub fn needs_rerender(
&self,
is_viewport_size_changed: bool,
is_rem_size_changed: bool,
) -> bool {
self.needs_rerender
|| (is_viewport_size_changed && self.uses_viewport_sizes)
|| (is_rem_size_changed && self.uses_rem_sizes)
}
```
This ensures that text reupdates will also be scheduled if one of the text section's uses a viewport font size and the local viewport size changed, or if one of the text section's uses a rem font size and the rem size changed.
#### Limitations
There are some limitations because we don't have any sort of font style inheritance yet:
* "rem" units aren't proper rem units, and just based on the value of a resource.
* "em" units are resolved based on inherited font size, so can't be implemented without inheritance support.
#### Notes
* This PR is quite small and not very technical. Reviewers don't need to be especially familiar with `bevy_text`. Most of the changes are to the examples.
* We could consider using `Val` instead of `FontSize`, then we could use `Val`'s constructor functions which would be much nicer, but some variants might not have sensible interpretations in both UI and Text2d contexts. Also we'd have to make `Val` accessible to `bevy_text`.
## Testing
The changes to the text systems are relatively trivial and easy to understand. I already added a minor change to the `text` example to use `Vh` font size for the "hello bevy" text in the bottom right corner. If you change the size of the window, you should see the text change size in response. The text initially flickers before it updates because of some unrelated asset/image changes that mean that font textures aren't ready until the frame after the text update that changes the font size.
Most of the example migrations were automated using regular expressions, and there are bound to be mistakes in those changes. It's infeasible to check every single example thoroughly, but it's early enough in the release cycle that I don't think we should be too worried if a few bugs slip in.
---------
Co-authored-by: Kevin Chen <chen.kevin.f@gmail.com>
|
||
|
|
9d2db8838f |
Improve frustum culling of skinned meshes through per-joint bounds (#21837)
## Objective Mostly fix #4971 by adding a new option for updating skinned mesh `Aabb` components from joint transforms. https://github.com/user-attachments/assets/c25b31fa-142d-462b-9a1d-012ea928f839 This fixes cases where vertex positions are only modified through skinning. It doesn't fix other cases like morph targets and vertex shaders. The PR kind of upstreams [`bevy_mod_skinned_aabb`](https://github.com/greeble-dev/bevy_mod_skinned_aabb), but with some changes to make it simpler and more reliable. ### Dependencies - (MERGED) #21732 (or something similar) is desirable to make the new option work with `RenderAssetUsages::RENDER_WORLD`-only meshes. - This PR is authored as if 21732 has landed. But if that doesn't happen then I can adjust this PR to note the limitation. - (Optional) #21845 adds an option related to skinned mesh bounds. - Either PR can land first - the second will need to be updated. ## Background If a main world entity has a `Mesh3d` component then it's automatically assigned an `Aabb` component. This is done by `bevy_camera` or `bevy_gltf`. The `Aabb` is used by `bevy_camera` for frustum culling. It can also be used by `bevy_picking` as an optimization, and by third party crates. But there's a problem - the `Aabb` can be wrong if something changes the mesh's vertex positions after the `Aabb` is calculated. This can be done by vertex shaders - notably skinning and morph targets - or by mutating the `Mesh` asset (#4294). For the skinning case, the most common solution has been to disable frustum culling via the `NoFrustumCulling` component. This is simple, and might even be the most efficient approach for apps where meshes tend to stay on-screen. But it's annoying to implement, bad for apps where meshes are often off-screen, and it only fixes frustum culling - it doesn't help other systems that use the `Aabb`. ## Solution This PR adds a reliable and reasonably efficient method of updating the `Aabb` of a skinned mesh from its animated joint transforms. See the "How does it work" section for more detail. The glTF loader can add skinned bounds automatically if a new `GltfSkinnedMeshBoundsPolicy` option is enabled in `GltfPlugin` or `GltfLoaderSettings`: ```rust app.add_plugins(DefaultPlugins.set(GltfPlugin { skinned_mesh_bounds_policy: GltfSkinnedMeshBoundsPolicy::Dynamic, ..default() })) ``` _The new glTF loader option is enabled by default_. I think this is the right choice for several reasons: - Bugs caused by skinned mesh culling have been a regular pain for both new and experienced users. Now the most common case Just Works(tm). - The CPU cost is modest (see later section), and sophisticated users can opt-out. - GPU limited apps might see a performance increase if the user was previously disabling culling. Non-glTF cases require some manual steps. The user must ask `Mesh` to generate the skinned bounds, and then add the `DynamicSkinnedMeshBounds` marker component to their mesh entity. ```rust mesh.generate_skinned_mesh_bounds()?; let mesh_asset = mesh_assets.add(mesh); entity.insert((Mesh3d(mesh_asset), DynamicSkinnedMeshBounds)); ``` See the `custom_skinned_mesh` example for real code. ## Bonus Features ### `GltfSkinnedMeshBoundsPolicy::NoFrustumCulling` This is a convenience for users who prefer the `NoFrustumCulling` workaround, but want to avoid the hassle of adding it after a glTF scene has been spawned. ```rust app.add_plugins(DefaultPlugins.set(GltfPlugin { skinned_mesh_bounds_policy: GltfSkinnedMeshBoundsPolicy::NoFrustumCulling, ..default() })) ``` PR #21845 is also adding an option related to skinned mesh bounds. I'm fine if that PR lands first - I'll update this PR to include the option. ### Gizmos `bevy_gizmos::SkinnedMeshBoundsGizmoPlugin` can draw the per-joint AABBs. ```rust fn toggle_skinned_mesh_bounds(mut config: ResMut<GizmoConfigStore>) { config.config_mut::<SkinnedMeshBoundsGizmoConfigGroup>().1.draw_all ^= true; } ``` The name is debatable. It's not technically drawing the bounds of the skinned mesh - it's drawing the per-joint bounds that contribute to the bounds of the skinned mesh. ## Testing ```sh cargo run --example test_skinned_mesh_bounds # Press `B` to show mesh bounds, 'J' to show joint bounds. cargo run --example scene_viewer --features "free_camera" -- "assets/models/animated/Fox.glb" cargo run --example scene_viewer --features "free_camera" -- "assets/models/SimpleSkin/SimpleSkin.gltf" # More complicated mesh downloaded from https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/RecursiveSkeletons cargo run --example scene_viewer --features "free_camera" -- "RecursiveSkeletons.glb" cargo run --example custom_skinned_mesh ``` I also hacked `custom_skinned_mesh` to simulate awkward cases like rotated and off-screen entities. ## How Does It Work? <details><summary>Click to expand</summary> ### Summary `Mesh::generated_skinned_mesh_bounds` calculates an AABB for each joint in the mesh - the AABB encloses all the vertices skinned to that joint. Then every frame, `bevy_camera::update_skinned_mesh_bounds` uses the current joint transforms to calculate an `Aabb` that encloses all the joint AABBs. This approach is reliable, in that the final `Aabb` will always enclose the skinned vertices. But it can be larger than necessary. In practice it's tight enough to be useful, and rarely more than 50% bigger. This approach works even with non-rigid transforms and soft skinning. If there's any doubt then I can add more detail. ### Awkward Bits The solution is not as simple and efficient as it could be. #### Problem 1: Joint transforms are world-space, `Aabb` is entity-space. - Ideally we'd use the world-space joint transforms to calculate a world-space `Aabb`, but that's not possible. - The obvious solution is to transform the joints to entity-space, so the `Aabb` is directly calculated in entity-space. - But that means an extra matrix multiply per joint. - This PR calculates the `Aabb` in world-space and then transforms it to entity-space. - That avoids a matrix multiply per-joint, but can increase the size of the `Aabb`. #### Problem 2: Joint AABBs are in a surprising(?) space. - When creating joint AABBs from a mesh, the intuitive solution would be to calculate them in joint-space. - Then the update just has to transform them by the world-space joint transform. - But to calculate them in joint-space we need both the bind pose vertex positions and the bind pose joint transforms. - These two parts are in separate assets - `Mesh` and `SkinnedMeshInverseBindposes` - and those assets can be mixed and matched. - So we'd need to calculate a `SkinnedMeshBoundsAsset` for each combination of `Mesh` and `SkinnedMeshInverseBindposes`. - (`bevy_mod_skinned_aabb` uses this approach - it's slow and fragile.) - This PR calculates joint AABBs in *mesh-space* (or more strictly speaking: bind pose space). - That can be done with just the `Mesh` asset. - One downside is that the update needs an extra matrix multiply so we can go from mesh-space to world-space. - However, this might become a performance advantage if frustum culling changes - see the "Future Options" section. - Another minor downside is that mesh-space AABBs (red in the screenshot below) tend to be bigger than joint-space AABBs (green), since joints with one long axis might be at an awkward angle in mesh-space. <img width="1085" height="759" alt="image" src="https://github.com/user-attachments/assets/a02a28c3-8882-412c-9be1-64109b767da7" /> ### Future Options For frustum culling there's a cheeky way to optimize and simplify skinned bounds - put frustum culling in the renderer and calculate a world-space AABB during `extract_skins`. The joint transform will be already loaded and in the right space, so we can avoid an entity lookup and matrix multiply. I estimate this would make skinned bounds 3x faster. Another option is to change main world frustum culling to use a world-space AABB. So there would be a new `GlobalAabb` component that gets updated each frame from `Aabb` and the entity transform (which is basically the same as transform propagation and the relationship between `Transform` and `GlobalTransform`). This has some advantages and disadvantages but I won't get into them here - I think putting frustum culling into the renderer is a better option. (Note that putting frustum culling into the renderer doesn't mean removing the current main world visibility system - it just means the main world system would be separate opt-in system) </details> ## Performance <details><summary>Click to expand</summary> ### Initialization Creating the skinned bounds asset for `Fox.glb` (576 verts, 22 skinned joints) takes **0.03ms**. Loading the whole glTF takes 8.7ms, so this is a **<1% increase**. ### Per-Frame The `many_foxes` example has 1000 skinned meshes, each with 22 skinned joints. Updating the skinned bounds takes **0.086ms**. This is a throughput of roughly 250,000 joints per millisecond, using two threads. <img width="2404" height="861" alt="image" src="https://github.com/user-attachments/assets/c27165ae-dc6c-4f6b-bbfb-4e211ab0263c" /> The whole animation update takes 3.67ms (where "animation update" = advancing players + graph evaluation + transform propagation). So we can kinda sorta claim that this PR increases the cost of skinned animation by roughly **3%**. But that's very hand-wavey and situation dependent. This was tested on an AMD Ryzen 7900 but with `TaskPoolOptions::with_num_threads(6)` to simulate a lower spec CPU. Comparing against a few other threading options: - Non-parallel: **0.141ms**. - 6 threads (2 compute threads): **0.086ms**. - 24 threads (15 compute threads): **0.051ms**. So the parallel iterator is better but quickly hits diminishing returns as the number of threads increases. ### Future Options The "How Does It Work" section mentions moving skinned mesh bounds into the renderer's skin extraction. Based on some microbenchmarks, I estimate this would reduce non-parallel `many_foxes` from 0.141ms to 0.049ms, so roughly 3x faster. Requiring AVX2 (to enable broadcast loads) or pre-splatting (to fake broadcast loads for SSE) would knock off another 25%. And fancier SIMD approaches could do better again. There's also approaches that trade reliability for performance. For character rigs, an effective optimization is to fold face and finger joints into a single bound on the head and hand joints. This can reduce the number of joints required by 50-80%. </details> ## FAQ <details><summary>Click to expand</summary> #### Why can't it be automatically added to any mesh? Then the glTF importer and custom mesh generators wouldn't need special logic. `bevy_mod_skinned_aabb` took the automatic approach, and I don't think the outcome was good. It needs some surprisingly fiddly and fragile logic to decide when an entity has the right combination of assets in the right loaded state. And it can never work with `RenderAssetUsages::RENDER_WORLD`. So this PR takes a more modest and manual approach. I think there's plenty of scope to generalise and automate as the asset pipeline matures. If the glTF importer becomes a purer glTF -> BSN transform, then adding skinned bounds could be a general scene/asset transform that's shared with other importers and custom mesh generators. #### Why is the data in `Mesh`? Shouldn't it go in `SkinnedMesh` or `SkinnedMeshInverseBindposes`? That might seem intuitive, but it wouldn't work in practice - the data is derived from `Mesh` alone. `SkinnedMesh` doesn't work because it's per mesh instance, so the data would be duplicated. `SkinnedMeshInverseBindposes` doesn't work because it can be shared between multiple meshes. The names are a bit misleading - `Mesh` does contain some skinning data, while `SkinnedMesh` and `SkinnedMeshInverseBindposes` are more like joint bindings one step removed from the vertex data. #### Why not put the bounds on the joint entities? This is surprisingly tricky in practice because multiple meshes can be bound to the same joint entity. So there would need to be logic that tracks the bindings and updates the bounds as meshes are added and removed. #### Why is the `DynamicSkinnedMeshBounds` component required? It's an optimisation for users who want to opt out. It might also be useful for future expansion, like adding options to approximate the bounds with an AABB attached to a single joint. #### Why are the update system and `DynamicSkinnedMeshBounds` component in `bevy_camera`? Shouldn't they be in `bevy_mesh`? `bevy_camera` is the owner and main user of `Aabb`, and already has some mesh related logic (`calculate_bounds` automatically adds an `Aabb` to mesh entities). So putting it in `bevy_camera` is consistent with the current structure. I'd agree that it's a little awkward though and could change in future. </details> ## What Do Other Engines Do? <details><summary>Click to expand</summary> - **Unreal**: Automatically uses [collision shapes](https://dev.epicgames.com/documentation/en-us/unreal-engine/physics-asset-editor-in-unreal-engine) attached to joints, which is similar to this PR in practice but fragile and inefficient. Also supports various fixed bounds options. - **Unity**: Fixed bounds attached to the root bone. Automatically calculated from animation poses or specified manually ([documentation](https://docs.unity3d.com/6000.4/Documentation/Manual/troubleshooting-skinned-mesh-renderer-visibility.html)). - **Godot**: Appears to use roughly the same method as this PR, although I didn't 100% confirm. See [`MeshStorage::mesh_get_aabb`](https://github.com/godotengine/godot/blob/fafc07335bdecacd96b548c4119fbe1f47ee5866/servers/rendering/renderer_rd/storage_rd/mesh_storage.cpp#L650) and [`RendererSceneCull::_update_instance_aabb`](https://github.com/godotengine/godot/blob/235a32ad11f40ecba26d6d9ceea8ab245c13adb0/servers/rendering/renderer_scene_cull.cpp#L1991). - **O3DE**: Fixed bounds attached to root bone, plus option to approximate the AABB from joint origins and a fudge factor. - **Northlight** (Remedy, Alan Wake 2): Specifically for vegetation, calculates bounds from joint extents on GPU ([source](https://gdcvault.com/play/1034310/Large-Scale-GPU-Based-Skinning), slide 48) An approach that's been proposed several times for Bevy is copying Unity's "fixed AABB from animation poses". I think this is more complicated and less reliable than many people expect. More complicated because linking animations to meshes can often be difficult. Less reliable because it doesn't account for ragdolls and procedural animation. But it could still be viable for for simple cases like a single self-contained glTF with basic animation. </details> --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
|
|
07bdee178c |
Move occlusion culling out of the experimental namespace. (#22631)
With #22603 landed, all known issues that could cause Bevy to cull meshes that shouldn't have been culled are fixed, so there now seems to be consensus that we can remove occlusion culling from the `experimental` namespace. This patch does that (and in fact removes the `experimental` module from `bevy_render` entirely, as it's now empty). |
||
|
|
a88af65738 |
Contact Shadows (#22382)
# Objective - Implement contact shadows to add fine shadow detail where shadow cascades cannot. ## Solution - Extend our existing pbr implementation using our existing raymarching functions. --- ## Showcase <img width="1824" height="1180" alt="image" src="https://github.com/user-attachments/assets/e93b79c5-c596-4a9e-b94d-20bdde1d863b" /> <img width="1824" height="1180" alt="image" src="https://github.com/user-attachments/assets/0fd7dffa-60b8-4b92-8fad-7f993d4d89dd" /> https://github.com/user-attachments/assets/e74b190d-9ae3-4aaf-97f0-b520930a0667 https://github.com/user-attachments/assets/e80ccb26-bbaa-4d25-a823-8ea12354c5b9 https://github.com/user-attachments/assets/b04f4b00-92bd-4a2f-b7dd-5157d8fbe0ab <img width="1073" height="685" alt="image" src="https://github.com/user-attachments/assets/b7629908-dd32-48db-8ee7-a4d2dd8f66c2" /> <img width="1073" height="685" alt="image" src="https://github.com/user-attachments/assets/3de0258e-9191-4180-ac57-41b32e1205bd" /> <img width="1073" height="685" alt="image" src="https://github.com/user-attachments/assets/951477f9-e9a9-426f-ae8d-18ae50cc7b85" /> <img width="1073" height="685" alt="image" src="https://github.com/user-attachments/assets/2291453c-da57-4fcc-a6b0-f60f6eac6cbb" /> <img width="1073" height="685" alt="image" src="https://github.com/user-attachments/assets/5820cdff-ea54-4294-b520-2a8d8dc24996" /> <img width="1073" height="685" alt="image" src="https://github.com/user-attachments/assets/3ea16481-7689-4e99-87e2-1589f1532e4c" /> --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: charlotte 🌸 <charlotte.c.mcelwain@gmail.com> |
||
|
|
a3ad40d412 |
Alternative glTF coordinate conversion (#20394)
## Objective Change glTF coordinate conversion to satisfy some common use cases while dodging the more controversial aspects. This fixes #20621, but at the cost of removing one feature. ## Summary The Bevy glTF loader can optionally convert nodes and meshes from glTF's "+Z forward" semantics to Bevy's "-Z forward". But the current implementation [has issues](https://github.com/bevyengine/bevy/issues/20621), particularly with cameras and lights. It might also cause problems for users who want to re-orient the scene as a whole while preserving the original node semantics. This PR replaces node conversion with a simpler correction to the scene root and mesh entities. The new approach satisfies many use cases and fixes the issues with cameras and lights. But it could be a regression for some users. ## Background There's been confusion over how glTF behaves and what users might want from coordinate conversion. This section recaps the basic concepts, glTF's semantics, the current loader behaviour, and some potential user stories. Or you can skip to the next section if you want to get straight to the changes. <details> <summary>Click to expand</summary> ### Coordinate Systems and Semantics 3D coordinate systems can have semantics assigned to their axes. These semantics are often defined as a forward axis, an up axis, and a [handedness](https://en.wikipedia.org/wiki/Right-hand_rule) - the side axis is implicit in the other choices. Bevy's standard semantics are "-Z = forward, +Y = up, right handed". This standard is codified by the `forward` and `up` methods of `Transform` and `GlobalTransform`, and by the renderer's interpretation of camera and light transforms. There are debates about the standard and whether users should be able to choose different semantics. This PR does not account for those debates, and assumes that users want to follow the current standard. Other engines, DCCs, and file formats can have [different semantics](https://mastodon.social/@acegikmo/113313928426095165). Unlike Bevy, some vary their semantics by object type - a camera's forward axis may not be the same as a light's. Some only specify an up axis, leaving the forward and side axes unspecified. Assets might not follow the standard semantics of their file format. Static mesh hierarchies and skeletal animation rigs may even have per-node or per-joint semantics - a character rig could be +Y forward in the scene, while the head joint is +Z forward. One character rig might have both feet +X forward, while another rig might have the left foot +X forward and the right foot -X forward. This creates complexity, but also creates jobs, so no-one can say if it's good or bad. ### Asset Loaders And Coordinate Conversion Bevy currently has a glTF loader, and I'm assuming it will get in-repo FBX and USD loaders at some point. These loaders are likely to follow a common pattern: - The files contain meshes, which correspond to Bevy `Mesh` assets and skinned meshes. - Bevy meshes can only have a single material, so what the file format considers a single mesh might be multiple Bevy meshes. - The files have a node hierarchy, where nodes roughly correspond to Bevy entities with a `Transform`. - Nodes can optionally be mesh instances, cameras, lights or skinned mesh joints. - The loader outputs the assets and a `Scene` with an entity hierarchy that tries to match the file's node hierarchy. - Some aspects of nodes (e.g. pivot transforms) can't be represented in Bevy within a single entity. - So a 1:1 mapping might not be possible - instead nodes become multiple entities, or some data is lost (e.g. baking down pivot transforms). - Users can choose to spawn the scene, or they can ignore it and use the assets directly. Users may want asset loaders that convert assets to Bevy's standard semantics, so `Transform::forward` matches the asset. But the details of conversion can be contentious - users may want some parts of the scene to be converted differently from other parts, and assets may have ambiguities than can only be resolved by the user. There will never be a simple "it just works" option, although there could be a least worst default that satisfies the biggest group of users. Converting in the loader is not the only option. The user could edit the assets themselves or run a conversion script in DCC. But that's a pain - particularly for users who rely on asset packs and don't have DCC experience. Another option is to implement an asset transform that does coordinate conversion. But having the options right there in the loader is convenient. ### User Stories For coordinate conversion in the loader, some user stories might be: - "I want to spawn a scene on an entity with Bevy semantics and have it look right." - This is probably the most common case - the user wants to do `SceneRoot(load("my.gltf"))` and have it visually match the entity's `Transform::forward()`, and cameras and lights should do the right thing. - The user might not care about the semantics of mesh assets and nodes in the scene - they just want the scene as a whole to look right. - "I want to spawn a scene, and convert some or all of the nodes to Bevy semantics." - The user might have nodes in their scene that they want to animate manually or hook up to other systems that assume Bevy semantics. - That becomes easier if the loader can convert the node's forward to match `Transform::forward()`. - Conversely, some users might want nodes to stay as they are (particularly skeletal animation rigs). - "I want a mesh asset that's converted to Bevy semantics. I'm not using a scene." - Maybe the user is doing `Mesh3d(load("mesh.gltf#Mesh0"))` and wants it to match the entity's forward. - Or this is the first stage of an asset pipeline and the remaining stages expect Bevy semantics. - "I don't want the loader to touch anything." - Maybe they've already converted the file, or want to convert it post-load, or don't want to use Bevy semantics at all. - "I want one of the other conversion stories, but the loader should convert to my chosen semantics rather than Bevy's". - Z-up is not a crime. ### glTF Semantics glTF [scene semantics](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#coordinate-system-and-units) are "+Z = forward, +Y = up, right handed". This is almost the same as Bevy, except that scene forward is +Z instead of Bevy's -Z. Some glTF assets do not follow the spec's scene semantics. The Kenney asset packs use a mix of +Z and -Z forward. At least [one of the Khronos sample assets](https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main/Models/Duck) uses +X forward. That said, the majority of Kenney assets and almost all the Khronos sample assets I tested do follow the spec. glTF [camera node](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#view-matrix) and [light node](https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_lights_punctual/README.md#adding-light-instances-to-nodes) semantics are different from glTF scene semantics - they're -Z forward, same as Bevy. The glTF spec doesn't explicitly say if non-camera/light nodes and mesh buffers have semantics. I'm guessing that some users will have nodes and meshes that follow the spec's scene semantics, and might want them converted to Bevy semantics. But as noted in the user stories, it's likely that other users will have different needs. glTF and Bevy allow a single node/entity to be both a mesh and a camera or a light. This only makes sense if the user intends the mesh to have the same semantics as cameras and lights. I think it's very unlikely that significant numbers of users will want support for this combination - many other DCCs, file formats and engines don't support it at all. ### How The Bevy glTF Loader Works The loader maps glTF nodes to Bevy entities. It also adds entities for two cases: 1. A single "scene root" entity is added as a parent of the glTF root nodes. - Note that this is not the user's entity with the `SceneRoot` component - the scene root entity is a child of that entity. 2. Mesh primitive entities are added as a child of each glTF mesh node. - In glTF, a single mesh node can contain multiple primitives. - But in Bevy a mesh component can only contain a single primitive, so one entity can't contain multiple primitives. - So, for each primitive, Bevy adds a child entity with a mesh component. A single branch of the resulting scene hierarchy might look like this: - User entity with `SceneRoot` component. - Scene root entity. - glTF root node entity. - glTF intermediate node entities. - glTF mesh node entity (does not contain `Mesh3d` component) - Mesh primitive entities (does contain `Mesh3d` component). ### glTF Loader Changes In 0.17 In Bevy 0.16, the only user story supported by the glTF loader was "no conversion". During the 0.17 cycle, #19633 and some follow up PRs implemented an option that converts nodes, meshes and animation tracks. The changes do satisfy some user stories, including the common "convert scene semantics" (mostly) and "convert mesh semantics". But there's some problems (#20621): - The conversion depends on converting both nodes and meshes. - Some users might want to convert the scene without converting nodes and/or meshes. - Light and camera nodes get complicated. - glTF camera/light nodes already match Bevy semantics, so they need a counter-conversion (since their parent might have been converted). - Animation tracks for lights and cameras are not correctly converted. - (Counterpoint: This is fixable at the cost of some complexity) - Child nodes of lights and cameras are not correctly converted. - (Counterpoint: Also fixable, and probably a niche case?) - The conversion can't support a node that's a mesh instance and also a light and/or a camera. - (Counterpoint: As mentioned earlier, this is probably a very niche or non-existent use case.) </details> ## Solution The big change in this PR is the removal of node conversion. Instead, corrective transforms are applied to the scene root entity and mesh primitive entities. Before this PR: - Scene root entity. - glTF root node entity. <-- CONVERTED - glTF intermediate node entities. <-- CONVERTED - glTF mesh node entity. <-- CONVERTED - Mesh primitive entities. After this PR: - Scene root entity. <-- CORRECTIVE (if scene conversion enabled) - glTF root node entity. - glTF intermediate node entities. - glTF mesh node entity. - Mesh primitive entities. <-- CORRECTIVE (if mesh conversion enabled) The result is visually the same even though the scene internals are different. Cameras and lights now work correctly, including when animated. The new conversion is also simpler. There's no need to convert animations, and the scene part of the conversion only changes a single entity: ```diff +let world_root_transform = convert_coordinates.scene_conversion_transform(); let world_root_id = world - .spawn((Transform::default(), Visibility::default())) + .spawn((world_root_transform, Visibility::default())) .with_children(|parent| { for node in scene.nodes() { ``` Removing node conversion might be a regression for some users. My guess is that most users just want to spawn a scene with the correct orientation and don't worry about individual node transforms, so on balance this PR will be win. But I don't have much evidence to back that up. There might also be a path to adding node conversion back in as an option - see the "Future" section below. The previous conversion option - `GltfPlugin::use_model_forward_direction` - has been split into two separate options for scene and mesh conversion. ```diff struct GltfPlugin { ... - use_model_forward_direction: bool, + convert_coordinates: GltfConvertCoordinates, } ``` ```rust struct GltfConvertCoordinates { scenes: bool, meshes: bool, } ``` This might be turn out to be unnecessary flexibility, but I think it's the safer option for now in case users have unexpected needs. Both options are disabled by default. ### Testing I've tested various examples and glTFs with each combination of options, including glTFs with animated cameras and lights. ```sh # Visually the same as current Bevy *without* conversion. cargo run --example scene_viewer "assets/models/faces/faces.glb" cargo run --example scene_viewer "assets/models/faces/faces.glb" --convert-mesh-coordinates # Visually the same as current Bevy *with* conversion. cargo run --example scene_viewer "assets/models/faces/faces.glb" --convert-scene-coordinates cargo run --example scene_viewer "assets/models/faces/faces.glb" --convert-scene-coordinates --convert-mesh-coordinates cargo run --example animated_mesh ``` ## Future <details> <summary>Click to expand</summary> This PR removes node conversion, which is a desirable feature for some users. There are a couple of ways it could be added back as an option. The difficult part of node conversion is how to support camera and light nodes. glTF's camera/light semantics already match Bevy's -Z forward, so simply converting every node from +Z to -Z forward will leave camera and light nodes facing the wrong direction. The obvious solution is to special case camera/light node transforms - this is what the 0.17 conversion tries to do. But it's surprisingly complex to get right due to animation, child nodes, and nodes that can be meshes and cameras and lights. E.g. children of cameras and lights need a counter-conversion applied to their transform and animation tracks. For cameras, an alternative would be to split them multiple entities. The existing entity would correspond to the glTF node and be converted like every other node. But the Bevy `Camera` component would be on a new child entity and have a corrective transform. Before: - Parent glTF node entity. - Camera glTF node entity with `Camera` component and animated transform. - glTF node parented to camera node. After: - Parent glTF node entity. - Camera glTF node entity with animated transform. - New child entity with `Camera` component and corrective transform. - glTF node parented to camera node. Lights are already set up this way, so they only need the corrective transform. This approach is simpler since nodes are treated uniformly. And it's arguably a better reflection of the glTF format - glTF cameras are kind of a separate thing from nodes, and can be given a name that's different to their node's name. So it could be better for some users. The downside is that the glTF node entity might have the wrong semantics from the perspective of some users (although not all). And it will be annoying for users who currently assume the `Camera` component is on the node entity. </details> ## Alternatives <details> <summary>Click to expand</summary> ### What About The Forward Flag Proposal? There's a [proposal](https://github.com/bevyengine/bevy/pull/20135) to allow per-transform semantics, aka the "forward flag". This means the axis of `Transform::forward()` and others would depend on a variable in the `Transform`. In theory the forward flag might avoid the need for coordinate conversion in the loader. But whether that works in practice is unclear, and the proposal appears to be stalled. ### What Do Other Engines Do? [Godot's semantics](https://docs.godotengine.org/en/4.4/tutorials/assets_pipeline/importing_3d_scenes/model_export_considerations.html#d-asset-direction-conventions) are the same as the glTF standard. Godot doesn't offer any conversion options. Unreal's default semantics are "+X forward, +Z up, left handed", except meshes are typically "+Y forward, +Z up". Their glTF importer converts nodes and meshes to Unreal's mesh semantics - this is done by swapping the Y and Z axes, which implicitly flips the X for handedness. So Unreal's approach is actually closer to the current main approach of node + mesh conversion, versus this PR's scene + mesh conversion. The Unreal importer also supports a custom scene/mesh rotation and translation that's applied after normal conversion. There's no option to disable conversion. </details> --------- Co-authored-by: Carter Anderson <mcanders1@gmail.com> Co-authored-by: Alice I Cecile <alice.i.cecile@gmail.com> |
||
|
|
f664896193 |
Fix scene viewer animation switching (#21871)
## Objective The `scene_viewer` example doesn't correctly switch between animations. It plays the new animation but also keeps playing any previous animations, so the animation graph mixes them all together. I suspect this was accidentally broken when animation graphs were added in #11989, but I haven't confirmed. ## Solution Stop all animations and then play the new animation. ## Testing ```sh # Press enter to switch animation, or space to pause. cargo run --example scene_viewer --features "free_camera" -- "assets/models/animated/Fox.glb" ``` Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
|
|
9a9817bba1 |
Update PanCam and FreeCam to use full term Camera (#21592)
# Objective This PR fixes #21569, which proposes renaming the newly introduced camera controller modules `FreeCam` and `PanCam` to use the full term `Camera`. ## Solution * Renamed the `PanCam` controller, `PanCamPlugin`, and related methods to use the full term `Camera` instead of the abbreviation `Cam`. * Renamed the module from `pan_cam` to `pan_camera` for consistency with naming conventions. * Updated the example `pan_camera_controller` and adjusted usage of the renamed controller and plugin. * Updated documentation and release notes accordingly. ## Follow-up Work I see two options from here: 1. **Use this PR as a reference** for renaming `FreeCam`. The process is similar and could be a great first issue for someone looking to contribute to the new camera modules or Bevy in general. Most of the changes follow the same pattern, although `FreeCam` has more examples that need updating. One could find them using `grep` (e.g., `grep FreeCam`) or by reviewing the diff from the PR that introduced `FreeCam`: #20215 2. **I can continue and update this PR** to also handle the `FreeCam` renaming, if you'd prefer to resolve the entire issue in one go. --------- Co-authored-by: syszery <syszery@users.noreply.github.com> |
||
|
|
66e8232412 |
Add bevy_camera_controllers crate and move freecam implementation into it (#20215)
# Objective Moving the camera around is really important to validate that our scenes are rendered correctly. Bevy engine devs currently do this via a fairly cursed "library example" which includes a basic freecam controller (which is technically distinct from a flycam apparently). This has three problems: 1. Oh god why are we taking pseudo-dependencies on other examples. 2. Something like this would be useful for debugging for users. 3. Something like this would be useful for the editor and other tooling. ## Solution Create a new `bevy_camera_controllers` crate, and move the existing freecam implementation into it, nearly verbatim. This cleans up some ugly tech debt in how we do this, makes it easier to add a camera controller to other examples, and also gives us a scaffold for future camera controllers. This PR has been marked `X-Blessed`, as I went over this plan with @cart in a [meeting on 2025-06-23](https://discord.com/channels/691052431525675048/692572690833473578/1386847828923519038), and we both agreed that this was the right first step. ## Testing I've tested the examples that rely on this camera controller: they work just like before. ## Notes for reviewers - I don't intend to land this in Bevy 0.17: the existing example code is not high enough quality for me to be happy shipping this - we're also soft feature-frozen; I was just in the mood to do this today - this PR has some minimal cleanup: just enough naming and docs work to make this code not an active liability. Any more will risk derailing this PR and making it harder to review - I've opted to expose top-level feature flags for the various camera controllers. This is a bit noisy, but it was the only sensible way I could see to both have "no camera controllers by default" and "still easy to use these controllers in examples" - this will not be the only camera controller in this crate, or the Bevy Editor - this is not the place to discuss "what should the default camera controller for the Bevy Editor be" - if you think this crate, or this particular move is the wrong strategy for some other reason though, please do speak up :) - my personal (unblessed) hope is that we continue to add camera controllers to this crate as needed for various first-party tooling. I will probably largely push-back on adding camera controllers that we do not actively use to this crate, since I don't think they make great libraries in general (much better to copy-paste) ## TODO - [x] add release note. I'm waiting until after Bevy 0.17 ships to do this - [x] update the examples/README.md file. I was lazy and didn't want to constantly resolve merge conflicts on that while this PR sits - [x] change to singular crate name ## Future work - split apart the giant camera controller component - make keybinding better, either with or without a real input manager solution - split apart the system to make it more modular - make the system handle fixed timesteps better - use the camera controller in more examples for debugging - add more camera controllers! --------- Co-authored-by: atlv <email@atlasdostal.com> Co-authored-by: Jan Hohenheim <jan@hohenheim.ch> |
||
|
|
ff7837ef38 |
Rename animation to gltf_animation (#21388)
# Objective - Step towards #20867 ## Solution - Do a rename ## Testing - Ran some examples |
||
|
|
efb8e1dee4 |
Split AnimationTarget into two components (#20774)
## Objective
Add flexibility by refactoring `AnimationTarget` into two separate
components. This will smooth the path for future animation features.
## Background
`bevy_animation` animates entities by assigning them `AnimationTarget`
components:
```rust
struct AnimationTarget {
player: Entity,
id: AnimationTargetId,
}
```
- `player: Entity` links to an entity that contains an `AnimationPlayer`
component. An `AnimationPlayer` plays `AnimationClip` assets.
- `id: AnimationTargetId` identifies which tracks in an `AnimationClip`
apply to the target entity.
When loading a glTF these components are automatically created. They can
also be created manually.
## Problem
The two parts of `AnimationTarget` often go together but sometimes would
be better separated:
1. I might want to calculate the `AnimationTargetId` first, but not link
it up to an `AnimationPlayer` until later (see #18262 for an example).
2. I might want to use `AnimationTargetId` but not use `AnimationPlayer`
- maybe I've got a different component that plays `AnimationClip`s.
In theory `player` could be left as `Entity::PLACEHOLDER`, but that's
messy and will trigger a warning in `animate_targets`.
## Solution
This PR splits `AnimationTarget` into two components:
1. `AnimationTargetId` is just the original struct with a component
derive.
2. `AnimationPlayerTarget` is a new unit struct `(Entity)`.
I'm not convinced `AnimationPlayerTarget` is a good name, but it does
fit the usual source/target naming for entity relationships.
`AnimationPlayerRef` was another candidate.
`AnimationPlayerTarget` could be a relationship target, but there would
be a performance cost from making `AnimationPlayer` a relationship
source. Maybe it's still a good idea, but that's probably best left to
another PR.
### Performance
Profiled on `many_foxes` - difference was negligible.
### Testing
Examples `animated_mesh`, `animated_transform`, `animated_ui`,
`animation_masks`, `eased_motion`, `scene_viewer`.
## Future
If this PR lands then I'll probably file a follow up that adds more
flexibility to the the glTF loader creation of `AnimationTargetId` and
`AnimationPlayer`. This will help #18262 and enable some other features.
|
||
|
|
4d74baf1ae |
BufferedEvent -> Message Rename (#20953)
This renames the concept of `BufferedEvent` to `Message`, and updates our APIs, comments, and documentation to refer to these types as "messages" instead of "events". It also removes/updates anything that considers messages to be "observable", "listenable", or "triggerable". This is a followup to https://github.com/bevyengine/bevy/pull/20731, which omitted the `BufferedEvent -> Message` rename for brevity. See that post for rationale. |
||
|
|
13877fa84d |
Add a new trait to accept more types in the Val-helper functions (#20551)
# Objective - Allow the `Val`-helper functions to accept more types besides just `f32` Fixes #20549 ## Solution - Adds a new trait that can be implemented for numbers - That trait has a method that converts `self` to `f32` ## Testing - I tested it using Rust's testing framework (although I didn't leave the tests in, as I don't deem them important enough) <details> <summary>Rust test</summary> ```rust #[cfg(test)] mod tests { use super::*; #[test] fn test_val_helpers_work() { let p = px(10_u8); assert_eq!(p, Val::Px(10.0)); let p = px(10_u16); assert_eq!(p, Val::Px(10.0)); let p = px(10_u32); assert_eq!(p, Val::Px(10.0)); let p = px(10_u64); assert_eq!(p, Val::Px(10.0)); let p = px(10_u128); assert_eq!(p, Val::Px(10.0)); let p = px(10_i8); assert_eq!(p, Val::Px(10.0)); let p = px(10_i16); assert_eq!(p, Val::Px(10.0)); let p = px(10_i32); assert_eq!(p, Val::Px(10.0)); let p = px(10_i64); assert_eq!(p, Val::Px(10.0)); let p = px(10_i128); assert_eq!(p, Val::Px(10.0)); let p = px(10.3_f32); assert_eq!(p, Val::Px(10.3)); let p = px(10.6_f64); assert_eq!(p, Val::Px(10.6)); } } ``` </details> --- ## Showcase ```rust // Same as Val::Px(10.) px(10); px(10_u8); px(10.0); ``` |
||
|
|
8c8cbafd98 |
Add option to scene_viewer that enables glTF coordinate conversion (#20609)
Add a `--use-model-forward-direction` option to the `scene_viewer` example. This enables `GltfPlugin::use_model_forward_direction`, which is useful for testing issues like #20608. I suspect the option can be `bool` rather than `Option<bool>`, but it's consistent with other `scene_viewer` options. ## Testing ```sh cargo run --example scene_viewer -- "assets/models/faces/faces.glb" --use-model-forward-direction ``` |
||
|
|
03dd839b82 |
Use bevy::camera in examples instead of bevy::render::camera re-export (#20477)
# Objective - Prepare for removing re-exports ## Solution - title ## Testing - cargo check --examples |
||
|
|
8e52194d70 |
CI fixes for Rust 1.89 (#20462)
Adopted from #20456 Notes: * The origin of the `dead_code` lints were coming from the `ShaderType ` derive macro. This has been reported as https://github.com/teoxoy/encase/issues/102, and a temporary workspace-wide `allow` added to the top level Cargo.toml. * One of the lints pointed out that `PartialEq` and `Eq` may not work as expected for function pointers, so `CloneBehavior` no longer implements either trait, and pattern matching is used in instead. Original PR Description: ># Objective > >Unbreak CI. > > ## Solution > > Fix the lints. > >I've opted for anonymous lifetimes in every revealed case so far; please let me know if you think I should used named lifetimes in specific cases and why. > >## Testing > >Is CI green? > >## Context > > This lint originally had a much larger splash damage, with fairly negative effects on Bevy. See https://github.com/rust-lang/rust/issues/131725. > > The more restricted former is much more helpful, despite the large diff in this PR. Bevy is a large code base! > >## TODO > >- [x] discuss proposed lifetime lint fixes >,- [x] use cargo clippy --fix to fix newly uncovered docs misformatting >- [x] fix newly revealed dead code issues >- [x] ensure CI is green --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Mike <mike.hsu@gmail.com> |
||
|
|
d05c435848 |
Replace Handle::Weak with Handle::Uuid. (#19896)
# Objective - Progress towards #19024. ## Solution - Remove `Handle::Weak`! If users were relying on `Handle::Weak` for some purpose, they can almost certainly replace it with raw `AssetId` instead. If they cannot, they can make their own enum that holds either a Handle or an AssetId. In either case, we don't need weak handles! Sadly we still need Uuid handles since we rely on them for "default" assets and "invalid" assets, as well as anywhere where a component wants to impl default with a non-defaulted asset handle. One step at a time though! |
||
|
|
92e65d5eb1 | Upgrade to Rust 1.88 (#19825) | ||
|
|
7645ce91ed |
Add newlines before impl blocks (#19746)
# Objective Fix https://github.com/bevyengine/bevy/issues/19617 # Solution Add newlines before all impl blocks. I suspect that at least some of these will be objectionable! If there's a desired Bevy style for this then I'll update the PR. If not then we can just close it - it's the work of a single find and replace. |
||
|
|
5e69518f10 |
Don't restrict the scene viewer to loading assets from approved paths. (#18828)
The purpose of the scene viewer is to load arbitrary glTF scenes, so it's inconvenient if they have to be moved into the Bevy assets directory first. Thus this patch switches the scene viewer to use `UnapprovedPathMode::Allow`. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com> |
||
|
|
d8fa57bd7b |
Switch ChildOf back to tuple struct (#18672)
# Objective In #17905 we swapped to a named field on `ChildOf` to help resolve variable naming ambiguity of child vs parent (ex: `child_of.parent` clearly reads as "I am accessing the parent of the child_of relationship", whereas `child_of.0` is less clear). Unfortunately this has the side effect of making initialization less ideal. `ChildOf { parent }` reads just as well as `ChildOf(parent)`, but `ChildOf { parent: root }` doesn't read nearly as well as `ChildOf(root)`. ## Solution Move back to `ChildOf(pub Entity)` but add a `child_of.parent()` function and use it for all accesses. The downside here is that users are no longer "forced" to access the parent field with `parent` nomenclature, but I think this strikes the right balance. Take a look at the diff. I think the results provide strong evidence for this change. Initialization has the benefit of reading much better _and_ of taking up significantly less space, as many lines go from 3 to 1, and we're cutting out a bunch of syntax in some cases. Sadly I do think this should land in 0.16 as the cost of doing this _after_ the relationships migration is high. |
||
|
|
f57c7a43c4 |
reexport entity set collections in entity module (#18413)
# Objective Unlike for their helper typers, the import paths for `unique_array::UniqueEntityArray`, `unique_slice::UniqueEntitySlice`, `unique_vec::UniqueEntityVec`, `hash_set::EntityHashSet`, `hash_map::EntityHashMap`, `index_set::EntityIndexSet`, `index_map::EntityIndexMap` are quite redundant. When looking at the structure of `hashbrown`, we can also see that while both `HashSet` and `HashMap` have their own modules, the main types themselves are re-exported to the crate level. ## Solution Re-export the types in their shared `entity` parent module, and simplify the imports where they're used. |
||
|
|
84b09b9398 |
Newtype Anchor (#18439)
# Objective The `Anchor` component doesn't need to be a enum. The variants are just mapped to `Vec2`s so it could be changed to a newtype with associated const values, saving the space needed for the discriminator by the enum. Also there was no benefit I think in hiding the underlying `Vec2` representation of `Anchor`s. Suggested by @atlv24. Fixes #18459 Fixes #18460 ## Solution Change `Anchor` to a struct newtyping a `Vec2`, and its variants into associated constants. ## Migration Guide The anchor component has been changed from an enum to a struct newtyping a `Vec2`. The `Custom` variant has been removed, instead to construct a custom `Anchor` use its tuple constructor: ```rust Sprite { anchor: Anchor(Vec2::new(0.25, 0.4)), ..default() } ``` The other enum variants have been replaced with corresponding constants: * `Anchor::BottomLeft` to `Anchor::BOTTOM_LEFT` * `Anchor::Center` to `Anchor::CENTER` * `Anchor::TopRight` to `Anchor::TOP_RIGHT` * .. and so on for the remaining variants |
||
|
|
25103df301 |
Update gamepad_viewer to use children macro (#18282)
# Objective Contributes to #18238 Updates the `gamepad_viewer`, example to use the `children!` macro. ## Solution Updates examples to use the Improved Spawning API merged in https://github.com/bevyengine/bevy/pull/17521 ## Testing - Did you test these changes? If so, how? - Opened the examples before and after and verified the same behavior was observed. I did this on Ubuntu 24.04.2 LTS using `--features wayland`. - Are there any parts that need more testing? - Other OS's and features can't hurt, but this is such a small change it shouldn't be a problem. - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Run the examples yourself with and without these changes. - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? - see above --- ## Showcase n/a ## Migration Guide n/a |
||
|
|
f1331069e7 |
Implement SpawnableList for Vec<Bundle> (#18259)
# Objective In updating examples to use the Improved Spawning API I got tripped up on being able to spawn children with a Vec. I eventually figured out that I could use `Children::spawn(SpawnIter(my_vec.into_iter()))` but thought there might be a more ergonomic way to approach it. After tinkering with it for a while I came up with the implementation here. It allows authors to use `Children::spawn(my_vec)` as an equivalent implementation. ## Solution - Implements `<R: Relationship, B: Bundle SpawnableList<R> for Vec<B>` - uses `alloc::vec::Vec` for compatibility with `no_std` (`std::Vec` also inherits implementations against the `alloc::vec::Vec` because std is a re-export of the alloc struct, thanks @bushrat011899 for the info on this!) ## Testing - Did you test these changes? If so, how? - Opened the examples before and after and verified the same behavior was observed. I did this on Ubuntu 24.04.2 LTS using `--features wayland`. - Are there any parts that need more testing? - Other OS's and features can't hurt, but this is such a small change it shouldn't be a problem. - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Run the examples yourself with and without these changes. - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? - see above ## Showcase n/a ## Migration Guide - Optional: you may use the new API to spawn `Vec`s of `Bundle` instead of using the `SpawnIter` approach. |
||
|
|
2ad5908e58 |
Make Query::single (and friends) return a Result (#18082)
# Objective As discussed in #14275, Bevy is currently too prone to panic, and makes the easy / beginner-friendly way to do a large number of operations just to panic on failure. This is seriously frustrating in library code, but also slows down development, as many of the `Query::single` panics can actually safely be an early return (these panics are often due to a small ordering issue or a change in game state. More critically, in most "finished" products, panics are unacceptable: any unexpected failures should be handled elsewhere. That's where the new With the advent of good system error handling, we can now remove this. Note: I was instrumental in a) introducing this idea in the first place and b) pushing to make the panicking variant the default. The introduction of both `let else` statements in Rust and the fancy system error handling work in 0.16 have changed my mind on the right balance here. ## Solution 1. Make `Query::single` and `Query::single_mut` (and other random related methods) return a `Result`. 2. Handle all of Bevy's internal usage of these APIs. 3. Deprecate `Query::get_single` and friends, since we've moved their functionality to the nice names. 4. Add detailed advice on how to best handle these errors. Generally I like the diff here, although `get_single().unwrap()` in tests is a bit of a downgrade. ## Testing I've done a global search for `.single` to track down any missed deprecated usages. As to whether or not all the migrations were successful, that's what CI is for :) ## Future work ~~Rename `Query::get_single` and friends to `Query::single`!~~ ~~I've opted not to do this in this PR, and smear it across two releases in order to ease the migration. Successive deprecations are much easier to manage than the semantics and types shifting under your feet.~~ Cart has convinced me to change my mind on this; see https://github.com/bevyengine/bevy/pull/18082#discussion_r1974536085. ## Migration guide `Query::single`, `Query::single_mut` and their `QueryState` equivalents now return a `Result`. Generally, you'll want to: 1. Use Bevy 0.16's system error handling to return a `Result` using the `?` operator. 2. Use a `let else Ok(data)` block to early return if it's an expected failure. 3. Use `unwrap()` or `Ok` destructuring inside of tests. The old `Query::get_single` (etc) methods which did this have been deprecated. |
||
|
|
b73811d40e |
Remove ChildOf::get and Deref impl (#18080)
# Objective There are currently three ways to access the parent stored on a ChildOf relationship: 1. `child_of.parent` (field accessor) 2. `child_of.get()` (get function) 3. `**child_of` (Deref impl) I will assert that we should only have one (the field accessor), and that the existence of the other implementations causes confusion and legibility issues. The deref approach is heinous, and `child_of.get()` is significantly less clear than `child_of.parent`. ## Solution Remove `impl Deref for ChildOf` and `ChildOf::get`. The one "downside" I'm seeing is that: ```rust entity.get::<ChildOf>().map(ChildOf::get) ``` Becomes this: ```rust entity.get::<ChildOf>().map(|c| c.parent) ``` I strongly believe that this is worth the increased clarity and consistency. I'm also not really a huge fan of the "pass function pointer to map" syntax. I think most people don't think this way about maps. They think in terms of a function that takes the item in the Option and returns the result of some action on it. ## Migration Guide ```rust // Before **child_of // After child_of.parent // Before child_of.get() // After child_of.parent // Before entity.get::<ChildOf>().map(ChildOf::get) // After entity.get::<ChildOf>().map(|c| c.parent) ``` |
||
|
|
4880a231de |
Implement occlusion culling for directional light shadow maps. (#17951)
Two-phase occlusion culling can be helpful for shadow maps just as it can for a prepass, in order to reduce vertex and alpha mask fragment shading overhead. This patch implements occlusion culling for shadow maps from directional lights, when the `OcclusionCulling` component is present on the entities containing the lights. Shadow maps from point lights are deferred to a follow-up patch. Much of this patch involves expanding the hierarchical Z-buffer to cover shadow maps in addition to standard view depth buffers. The `scene_viewer` example has been updated to add `OcclusionCulling` to the directional light that it creates. This improved the performance of the rend3 sci-fi test scene when enabling shadows. |
||
|
|
8de6b16e9d |
Implement occlusion culling for the deferred rendering pipeline. (#17934)
Deferred rendering currently doesn't support occlusion culling. This PR implements it in a straightforward way, mirroring what we already do for the non-deferred pipeline. On the rend3 sci-fi base test scene, this resulted in roughly a 2× speedup when applied on top of my other patches. For that scene, it was useful to add another option, `--add-light`, which forces the addition of a shadow-casting light, to the scene viewer, which I included in this patch. |
||
|
|
dda97880c4 |
Implement experimental GPU two-phase occlusion culling for the standard 3D mesh pipeline. (#17413)
*Occlusion culling* allows the GPU to skip the vertex and fragment shading overhead for objects that can be quickly proved to be invisible because they're behind other geometry. A depth prepass already eliminates most fragment shading overhead for occluded objects, but the vertex shading overhead, as well as the cost of testing and rejecting fragments against the Z-buffer, is presently unavoidable for standard meshes. We currently perform occlusion culling only for meshlets. But other meshes, such as skinned meshes, can benefit from occlusion culling too in order to avoid the transform and skinning overhead for unseen meshes. This commit adapts the same [*two-phase occlusion culling*] technique that meshlets use to Bevy's standard 3D mesh pipeline when the new `OcclusionCulling` component, as well as the `DepthPrepass` component, are present on the camera. It has these steps: 1. *Early depth prepass*: We use the hierarchical Z-buffer from the previous frame to cull meshes for the initial depth prepass, effectively rendering only the meshes that were visible in the last frame. 2. *Early depth downsample*: We downsample the depth buffer to create another hierarchical Z-buffer, this time with the current view transform. 3. *Late depth prepass*: We use the new hierarchical Z-buffer to test all meshes that weren't rendered in the early depth prepass. Any meshes that pass this check are rendered. 4. *Late depth downsample*: Again, we downsample the depth buffer to create a hierarchical Z-buffer in preparation for the early depth prepass of the next frame. This step is done after all the rendering, in order to account for custom phase items that might write to the depth buffer. Note that this patch has no effect on the per-mesh CPU overhead for occluded objects, which remains high for a GPU-driven renderer due to the lack of `cold-specialization` and retained bins. If `cold-specialization` and retained bins weren't on the horizon, then a more traditional approach like potentially visible sets (PVS) or low-res CPU rendering would probably be more efficient than the GPU-driven approach that this patch implements for most scenes. However, at this point the amount of effort required to implement a PVS baking tool or a low-res CPU renderer would probably be greater than landing `cold-specialization` and retained bins, and the GPU driven approach is the more modern one anyway. It does mean that the performance improvements from occlusion culling as implemented in this patch *today* are likely to be limited, because of the high CPU overhead for occluded meshes. Note also that this patch currently doesn't implement occlusion culling for 2D objects or shadow maps. Those can be addressed in a follow-up. Additionally, note that the techniques in this patch require compute shaders, which excludes support for WebGL 2. This PR is marked experimental because of known precision issues with the downsampling approach when applied to non-power-of-two framebuffer sizes (i.e. most of them). These precision issues can, in rare cases, cause objects to be judged occluded that in fact are not. (I've never seen this in practice, but I know it's possible; it tends to be likelier to happen with small meshes.) As a follow-up to this patch, we desire to switch to the [SPD-based hi-Z buffer shader from the Granite engine], which doesn't suffer from these problems, at which point we should be able to graduate this feature from experimental status. I opted not to include that rewrite in this patch for two reasons: (1) @JMS55 is planning on doing the rewrite to coincide with the new availability of image atomic operations in Naga; (2) to reduce the scope of this patch. A new example, `occlusion_culling`, has been added. It demonstrates objects becoming quickly occluded and disoccluded by dynamic geometry and shows the number of objects that are actually being rendered. Also, a new `--occlusion-culling` switch has been added to `scene_viewer`, in order to make it easy to test this patch with large scenes like Bistro. [*two-phase occlusion culling*]: https://medium.com/@mil_kru/two-pass-occlusion-culling-4100edcad501 [Aaltonen SIGGRAPH 2015]: https://www.advances.realtimerendering.com/s2015/aaltonenhaar_siggraph2015_combined_final_footer_220dpi.pdf [Some literature]: https://gist.github.com/reduz/c5769d0e705d8ab7ac187d63be0099b5?permalink_comment_id=5040452#gistcomment-5040452 [SPD-based hi-Z buffer shader from the Granite engine]: https://github.com/Themaister/Granite/blob/master/assets/shaders/post/hiz.comp ## Migration guide * When enqueuing a custom mesh pipeline, work item buffers are now created with `bevy::render::batching::gpu_preprocessing::get_or_create_work_item_buffer`, not `PreprocessWorkItemBuffers::new`. See the `specialized_mesh_pipeline` example. ## Showcase Occlusion culling example:  Bistro zoomed out, before occlusion culling:  Bistro zoomed out, after occlusion culling:  In this scene, occlusion culling reduces the number of meshes Bevy has to render from 1591 to 585. |
||
|
|
ba5e71f53d |
Parent -> ChildOf (#17427)
Fixes #17412 ## Objective `Parent` uses the "has a X" naming convention. There is increasing sentiment that we should use the "is a X" naming convention for relationships (following #17398). This leaves `Children` as-is because there is prevailing sentiment that `Children` is clearer than `ParentOf` in many cases (especially when treating it like a collection). This renames `Parent` to `ChildOf`. This is just the implementation PR. To discuss the path forward, do so in #17412. ## Migration Guide - The `Parent` component has been renamed to `ChildOf`. |
||
|
|
5a9bc28502 |
Support non-Vec data structures in relations (#17447)
# Objective The existing `RelationshipSourceCollection` uses `Vec` as the only possible backing for our relationships. While a reasonable choice, benchmarking use cases might reveal that a different data type is better or faster. For example: - Not all relationships require a stable ordering between the relationship sources (i.e. children). In cases where we a) have many such relations and b) don't care about the ordering between them, a hash set is likely a better datastructure than a `Vec`. - The number of children-like entities may be small on average, and a `smallvec` may be faster ## Solution - Implement `RelationshipSourceCollection` for `EntityHashSet`, our custom entity-optimized `HashSet`. -~~Implement `DoubleEndedIterator` for `EntityHashSet` to make things compile.~~ - This implementation was cursed and very surprising. - Instead, by moving the iterator type on `RelationshipSourceCollection` from an erased RPTIT to an explicit associated type we can add a trait bound on the offending methods! - Implement `RelationshipSourceCollection` for `SmallVec` ## Testing I've added a pair of new tests to make sure this pattern compiles successfully in practice! ## Migration Guide `EntityHashSet` and `EntityHashMap` are no longer re-exported in `bevy_ecs::entity` directly. If you were not using `bevy_ecs` / `bevy`'s `prelude`, you can access them through their now-public modules, `hash_set` and `hash_map` instead. ## Notes to reviewers The `EntityHashSet::Iter` type needs to be public for this impl to be allowed. I initially renamed it to something that wasn't ambiguous and re-exported it, but as @Victoronz pointed out, that was somewhat unidiomatic. In https://github.com/bevyengine/bevy/pull/17447/commits/1a8564898f1803cae4e99bbf909a40ab824fb8a0, I instead made the `entity_hash_set` public (and its `entity_hash_set`) sister public, and removed the re-export. I prefer this design (give me module docs please), but it leads to a lot of churn in this PR. Let me know which you'd prefer, and if you'd like me to split that change out into its own micro PR. |
||
|
|
3742e621ef |
Allow clippy::too_many_arguments to lint without warnings (#17249)
# Objective Many instances of `clippy::too_many_arguments` linting happen to be on systems - functions which we don't call manually, and thus there's not much reason to worry about the argument count. ## Solution Allow `clippy::too_many_arguments` globally, and remove all lint attributes related to it. |
||
|
|
64efd08e13 |
Prefer Display over Debug (#16112)
# Objective Fixes #16104 ## Solution I removed all instances of `:?` and put them back one by one where it caused an error. I removed some bevy_utils helper functions that were only used in 2 places and don't add value. See: #11478 ## Testing CI should catch the mistakes ## Migration Guide `bevy::utils::{dbg,info,warn,error}` were removed. Use `bevy::utils::tracing::{debug,info,warn,error}` instead. --------- Co-authored-by: SpecificProtagonist <vincentjunge@posteo.net> |
||
|
|
78d2149503 |
Fix panics in scene_viewer and audio_control (#16983)
# Objective Fixes #16978 While testing, discovered that the morph weight interface in `scene_viewer` has been broken for a while (panics when loaded model has morph weights), probably since #15591. Fixed that too. While testing, saw example text in morph interface with [wrong padding](https://bevyengine.org/learn/contribute/helping-out/creating-examples/#visual-guidelines). Fixed that too. Left the small font size because there may be a lot of morphs to display, so that seems intentional. ## Solution Use normal queries and bail early ## Testing Morph interface can be tested with ``` cargo run --example scene_viewer assets/models/animated/MorphStressTest.gltf ``` ## Discussion I noticed that this fix is different than what is happening in #16976. Feel free to discard this for an alternative fix. I opened this anyway to document the issue with morph weight display. This is on top of #16966 which is required to test. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com> Co-authored-by: François Mockers <mockersf@gmail.com> |
||
|
|
00c2edf7b2 |
Revert most of #16222 and add gamepad accessors (#16425)
# Objective #16222 regressed the user experience of actually using gamepads: ```rust // Before 16222 gamepad.just_pressed(GamepadButton::South) // After 16222 gamepad.digital.just_pressed(GamepadButton::South) // Before 16222 gamepad.get(GamepadButton::RightTrigger2) // After 16222 gamepad.analog.get(GamepadButton::RighTrigger2) ``` Users shouldn't need to think about "digital vs analog" when checking if a button is pressed. This abstraction was intentional and I strongly believe it is in our users' best interest. Buttons and Axes are _both_ digital and analog, and this is largely an implementation detail. I don't think reverting this will be controversial. ## Solution - Revert most of #16222 - Add the `Into<T>` from #16222 to the internals - Expose read/write `digital` and `analog` accessors on gamepad, in the interest of enabling the mocking scenarios covered in #16222 (and allowing the minority of users that care about the "digital" vs "analog" distinction in this context to make that distinction) --------- Co-authored-by: Hennadii Chernyshchyk <genaloner@gmail.com> Co-authored-by: Rob Parrett <robparrett@gmail.com> |
||
|
|
3ada15ee1c |
Add more Glam types and constructors to prelude (#16261)
# Objective Glam has some common and useful types and helpers that are not in the prelude of `bevy_math`. This includes shorthand constructors like `vec3`, or even `Vec3A`, the aligned version of `Vec3`. ```rust // The "normal" way to create a 3D vector let vec = Vec3::new(2.0, 1.0, -3.0); // Shorthand version let vec = vec3(2.0, 1.0, -3.0); ``` ## Solution Add the following types and methods to the prelude: - `vec2`, `vec3`, `vec3a`, `vec4` - `uvec2`, `uvec3`, `uvec4` - `ivec2`, `ivec3`, `ivec4` - `bvec2`, `bvec3`, `bvec3a`, `bvec4`, `bvec4a` - `mat2`, `mat3`, `mat3a`, `mat4` - `quat` (not sure if anyone uses this, but for consistency) - `Vec3A` - `BVec3A`, `BVec4A` - `Mat3A` I did not add the u16, i16, or f64 variants like `dvec2`, since there are currently no existing types like those in the prelude. The shorthand constructors are currently used a lot in some places in Bevy, and not at all in others. In a follow-up, we might want to consider if we have a preference for the shorthand, and make a PR to change the codebase to use it more consistently. |
||
|
|
282ca735ba |
Use Name component for gamepad (#16233)
# Objective Addressing a suggestion I made in Discord: store gamepad name as a `Name` component. Advantages: - Will be nicely displayed in inspector / editor. - Easier to spawn in tests, just `world.spawn(Gamepad::default())`. ## Solution `Gamepad` component now stores only vendor and product IDs and `Name` stores the gamepad name. Since `GamepadInfo` is no longer necessary, I removed it and merged its fields into the connection event. ## Testing - Run unit tests. --- ## Migration Guide - `GamepadInfo` no longer exists: - Name now accesible via `Name` component. - Other information available on `Gamepad` component directly. - `GamepadConnection::Connected` now stores all info fields directly. |
||
|
|
b0058dc54b |
Gamepad improvements (#16222)
# Objective Closes #16221. ## Solution - Make `Gamepad` fields public and remove delegates / getters. - Move `impl Into` to `Axis` methods (delegates for `Axis` used `impl Into` to allow passing both `GamepadAxis` and `GamepadButton`). - Improve docs. ## Testing - I run tests. Not sure if the migration guide is needed, since it's a feature from RC, but I wrote it just in case. --- ## Migration Guide - `Gamepad` fields are now public. - Instead of using `Gamepad` delegates like `Gamepad::just_pressed`, call these methods directly on the fields. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
|
|
015f2c69ca |
Merge Style properties into Node. Use ComputedNode for computed properties. (#15975)
# Objective Continue improving the user experience of our UI Node API in the direction specified by [Bevy's Next Generation Scene / UI System](https://github.com/bevyengine/bevy/discussions/14437) ## Solution As specified in the document above, merge `Style` fields into `Node`, and move "computed Node fields" into `ComputedNode` (I chose this name over something like `ComputedNodeLayout` because it currently contains more than just layout info. If we want to break this up / rename these concepts, lets do that in a separate PR). `Style` has been removed. This accomplishes a number of goals: ## Ergonomics wins Specifying both `Node` and `Style` is now no longer required for non-default styles Before: ```rust commands.spawn(( Node::default(), Style { width: Val::Px(100.), ..default() }, )); ``` After: ```rust commands.spawn(Node { width: Val::Px(100.), ..default() }); ``` ## Conceptual clarity `Style` was never a comprehensive "style sheet". It only defined "core" style properties that all `Nodes` shared. Any "styled property" that couldn't fit that mold had to be in a separate component. A "real" style system would style properties _across_ components (`Node`, `Button`, etc). We have plans to build a true style system (see the doc linked above). By moving the `Style` fields to `Node`, we fully embrace `Node` as the driving concept and remove the "style system" confusion. ## Next Steps * Consider identifying and splitting out "style properties that aren't core to Node". This should not happen for Bevy 0.15. --- ## Migration Guide Move any fields set on `Style` into `Node` and replace all `Style` component usage with `Node`. Before: ```rust commands.spawn(( Node::default(), Style { width: Val::Px(100.), ..default() }, )); ``` After: ```rust commands.spawn(Node { width: Val::Px(100.), ..default() }); ``` For any usage of the "computed node properties" that used to live on `Node`, use `ComputedNode` instead: Before: ```rust fn system(nodes: Query<&Node>) { for node in &nodes { let computed_size = node.size(); } } ``` After: ```rust fn system(computed_nodes: Query<&ComputedNode>) { for computed_node in &computed_nodes { let computed_size = computed_node.size(); } } ``` |
||
|
|
7482a0d26d |
aligning public apis of Time,Timer and Stopwatch (#15962)
Fixes #15834 ## Migration Guide The APIs of `Time`, `Timer` and `Stopwatch` have been cleaned up for consistency with each other and the standard library's `Duration` type. The following methods have been renamed: - `Stowatch::paused` -> `Stopwatch::is_paused` - `Time::elapsed_seconds` -> `Time::elasped_secs` (including `_f64` and `_wrapped` variants) |
||
|
|
f602edad09 |
Text Rework cleanup (#15887)
# Objective Cleanup naming and docs, add missing migration guide after #15591 All text root nodes now use `Text` (UI) / `Text2d`. All text readers/writers use `Text<Type>Reader`/`Text<Type>Writer` convention. --- ## Migration Guide Doubles as #15591 migration guide. Text bundles (`TextBundle` and `Text2dBundle`) were removed in favor of `Text` and `Text2d`. Shared configuration fields were replaced with `TextLayout`, `TextFont` and `TextColor` components. Just `TextBundle`'s additional field turned into `TextNodeFlags` component, while `Text2dBundle`'s additional fields turned into `TextBounds` and `Anchor` components. Text sections were removed in favor of hierarchy-based approach. For root text entities with `Text` or `Text2d` components, child entities with `TextSpan` will act as additional text sections. To still access text spans by index, use the new `TextUiReader`, `Text2dReader` and `TextUiWriter`, `Text2dWriter` system parameters. |
||
|
|
93fc2d12cf |
Remove incorrect equality comparisons for asset load error types (#15890)
# Objective
The type `AssetLoadError` has `PartialEq` and `Eq` impls, which is
problematic due to the fact that the `AssetLoaderError` and
`AddAsyncError` variants lie in their impls: they will return `true` for
any `Box<dyn Error>` with the same `TypeId`, even if the actual value is
different. This can lead to subtle bugs if a user relies on the equality
comparison to ensure that two values are equal.
The same is true for `DependencyLoadState`,
`RecursiveDependencyLoadState`.
More generally, it is an anti-pattern for large error types involving
dynamic dispatch, such as `AssetLoadError`, to have equality
comparisons. Directly comparing two errors for equality is usually not
desired -- if some logic needs to branch based on the value of an error,
it is usually more correct to check for specific variants and inspect
their fields.
As far as I can tell, the only reason these errors have equality
comparisons is because the `LoadState` enum wraps `AssetLoadError` for
its `Failed` variant. This equality comparison is only used to check for
`== LoadState::Loaded`, which we can easily replace with an `is_loaded`
method.
## Solution
Remove the `{Partial}Eq` impls from `LoadState`, which also allows us to
remove it from the error types.
## Migration Guide
The types `bevy_asset::AssetLoadError` and `bevy_asset::LoadState` no
longer support equality comparisons. If you need to check for an asset's
load state, consider checking for a specific variant using
`LoadState::is_loaded` or the `matches!` macro. Similarly, consider
using the `matches!` macro to check for specific variants of the
`AssetLoadError` type if you need to inspect the value of an asset load
error in your code.
`DependencyLoadState` and `RecursiveDependencyLoadState` are not
released yet, so no migration needed,
---------
Co-authored-by: Joseph <21144246+JoJoJet@users.noreply.github.com>
|
||
|
|
d96a9d15f6 |
Migrate from Query::single and friends to Single (#15872)
# Objective - closes #15866 ## Solution - Simply migrate where possible. ## Testing - Expect that CI will do most of the work. Examples is another way of testing this, as most of the work is in that area. --- ## Notes For now, this PR doesn't migrate `QueryState::single` and friends as for now, this look like another issue. So for example, QueryBuilders that used single or `World::query` that used single wasn't migrated. If there is a easy way to migrate those, please let me know. Most of the uses of `Query::single` were removed, the only other uses that I found was related to tests of said methods, so will probably be removed when we remove `Query::single`. |
||
|
|
bdd0af6bfb |
Deprecate SpatialBundle (#15830)
# Objective - Required components replace bundles, but `SpatialBundle` is yet to be deprecated ## Solution - Deprecate `SpatialBundle` - Insert `Transform` and `Visibility` instead in examples using it - In `spawn` or `insert` inserting a default `Transform` or `Visibility` with component already requiring either, remove those components from the tuple ## Testing - Did you test these changes? If so, how? Yes, I ran the examples I changed and tests - Are there any parts that need more testing? The `gamepad_viewer` and and `custom_shader_instancing` examples don't work as intended due to entirely unrelated code, didn't check main. - How can other people (reviewers) test your changes? Is there anything specific they need to know? Run examples, or just check that all spawned values are identical - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? Linux, wayland trough x11 (cause that's the default feature) --- ## Migration Guide `SpatialBundle` is now deprecated, insert `Transform` and `Visibility` instead which will automatically insert all other components that were in the bundle. If you do not specify these values and any other components in your `spawn`/`insert` call already requires either of these components you can leave that one out. before: ```rust commands.spawn(SpatialBundle::default()); ``` after: ```rust commands.spawn((Transform::default(), Visibility::default()); ``` |