bad98f6c4d
628 Commits
Author | SHA1 | Message | Date | |
---|---|---|---|---|
![]() |
74dedb2841
|
Testbed for 3d (#15993)
# Objective - Progress towards #15918 - Add tests for 3d ## Solution - Add tests that cover lights, bloom, gltf and animation - Removed examples `contributors` and `load_gltf` as they don't contribute additional checks to CI ## Testing - `CI_TESTING_CONFIG=.github/example-run/testbed_3d.ron cargo run --example testbed_3d --features "bevy_ci_testing"` |
||
![]() |
683d6c90a9
|
Remove AVIF feature (#15973)
Resolves #15968. Since this feature never worked, and enabling it in the `image` crate requires system dependencies, we've decided that it's best to just remove it and let other plugin crates offer support for it as needed. ## Migration Guide AVIF images are no longer supported. They never really worked, and require system dependencies (libdav1d) to work correctly, so, it's better to simply offer this support via an unofficial plugin instead as needed. The corresponding types have been removed from Bevy to account for this. |
||
![]() |
76744bf58c
|
Mark ghost nodes as experimental and partially feature flag them (#15961)
# Objective As discussed in #15341, ghost nodes are a contentious and experimental feature. In the interest of enabling ecosystem experimentation, we've decided to keep them in Bevy 0.15. That said, we don't use them internally, and don't expect third-party crates to support them. If the experimentation returns a negative result (they aren't very useful, an alternative design is preferred etc) they will be removed. We should clearly communicate this status to users, and make sure that users don't use ghost nodes in their projects without a very clear understanding of what they're getting themselves into. ## Solution To make life easy for users (and Bevy), `GhostNode` and all associated helpers remain public and are always available. However, actually constructing these requires enabling a feature flag that's clearly marked as experimental. To do so, I've added a meaningless private field. When the feature flag is enabled, our constructs (`new` and `default`) can be used. I've added a `new` constructor, which should be preferred over `Default::default` as that can be readily deprecated, allowing us to prompt users to swap over to the much nicer `GhostNode` syntax once this is a unit struct again. Full credit: this was mostly @cart's design: I'm just implementing it! ## Testing I've run the ghost_nodes example and it fails to compile without the feature flag. With the feature flag, it works fine :) --------- Co-authored-by: Zachary Harrold <zac@harrold.com.au> |
||
![]() |
e1b9f545fb
|
Introduce testbed examples starting with 2d (#15954)
# Objective - Make progress for #15918 - Start with 2d ## Solution - Remove screenshots for existing examples as they're not deterministic - Create new "testbed" example category, with a 2d one to start ## Testing - Run `CI_TESTING_CONFIG=.github/example-run/testbed_2d.ron cargo run --example testbed_2d --features "bevy_ci_testing"` - ??? - Check the screenshots |
||
![]() |
6d3965f520
|
Overflow clip margin (#15561)
# Objective Limited implementation of the CSS property `overflow-clip-margin` https://developer.mozilla.org/en-US/docs/Web/CSS/overflow-clip-margin Allows you to control the visible area for clipped content when using overfllow-clip, -hidden, or -scroll and expand it with a margin. Based on #15442 Fixes #15468 ## Solution Adds a new field to Style: `overflow_clip_margin: OverflowClipMargin`. The field is ignored unless overflow-clip, -hidden or -scroll is set on at least one axis. `OverflowClipMargin` has these associated constructor functions: ``` pub const fn content_box() -> Self; pub const fn padding_box() -> Self; pub const fn border_box() -> Self; ``` You can also use the method `with_margin` to increases the size of the visible area: ``` commands .spawn(NodeBundle { style: Style { width: Val::Px(100.), height: Val::Px(100.), padding: UiRect::all(Val::Px(20.)), border: UiRect::all(Val::Px(5.)), overflow: Overflow::clip(), overflow_clip_margin: OverflowClipMargin::border_box().with_margin(25.), ..Default::default() }, border_color: Color::BLACK.into(), background_color: GRAY.into(), ..Default::default() }) ``` `with_margin` expects a length in logical pixels, negative values are clamped to zero. ## Notes * To keep this PR as simple as possible I omitted responsive margin values support. This could be added in a follow up if we want it. * CSS also supports a `margin-box` option but we don't have access to the margin values in `Node` so it's probably not feasible to implement atm. ## Testing ```cargo run --example overflow_clip_margin``` <img width="396" alt="overflow-clip-margin" src="https://github.com/user-attachments/assets/07b51cd6-a565-4451-87a0-fa079429b04b"> ## Migration Guide Style has a new field `OverflowClipMargin`. It allows users to set the visible area for clipped content when using overflow-clip, -hidden, or -scroll and expand it with a margin. There are three associated constructor functions `content_box`, `padding_box` and `border_box`: * `content_box`: elements painted outside of the content box area (the innermost part of the node excluding the padding and border) of the node are clipped. This is the new default behaviour. * `padding_box`: elements painted outside outside of the padding area of the node are clipped. * `border_box`: elements painted outside of the bounds of the node are clipped. This matches the behaviour from Bevy 0.14. There is also a `with_margin` method that increases the size of the visible area by the given number in logical pixels, negative margin values are clamped to zero. `OverflowClipMargin` is ignored unless overflow-clip, -hidden or -scroll is also set on at least one axis of the UI node. --------- Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com> |
||
![]() |
5157fef84b
|
Add window drag move and drag resize without decoration example. (#15814)
# Objective Add an example for the new drag move and drag resize introduced by PR #15674 and fix #15734. ## Solution I created an example that allows the user to exercise drag move and drag resize separately. The user can also choose what direction the resize works in.  ### Name The example is called `window_drag_move`. Happy to have that bikeshedded. ### Contentious Refactor? This PR removed the `ResizeDirection` enumeration in favor of using `CompassOctant` which had the same variants. Perhaps this is contentious. ### Unsafe? In PR #15674 I mentioned that `start_drag_move()` and `start_drag_resize()`'s requirement to only be called in the presence of a left-click looks like a compiler-unenforceable contract that can cause intermittent panics when not observed, so perhaps the functions should be marked them unsafe. **I have not made that change** here since I didn't see a clear consensus on that. ## Testing I exercised this on x86 macOS. However, winit for macOS does not support drag resize. It reports a good error when `start_drag_resize()` is called. I'd like to see it tested on Windows and Linux. --- ## Showcase Example window_drag_move shows how to drag or resize a window without decoration. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
0e30b68b20
|
Add mesh picking backend and MeshRayCast system parameter (#15800)
# Objective Closes #15545. `bevy_picking` supports UI and sprite picking, but not mesh picking. Being able to pick meshes would be extremely useful for various games, tools, and our own examples, as well as scene editors and inspectors. So, we need a mesh picking backend! Luckily, [`bevy_mod_picking`](https://github.com/aevyrie/bevy_mod_picking) (which `bevy_picking` is based on) by @aevyrie already has a [backend for it]( |
||
![]() |
6a39c33d49
|
Use oslog for ios (#13364)
# Objective On mobile devices, it's best to use the OS's native logging due to the difficulty of accessing the console. This is already done for Android. This is an updated version of https://github.com/bevyengine/bevy/pull/4462. ## Solution This PR uses Absolucy's [tracing-oslog](https://github.com/Absolucy/tracing-oslog) ([ZLib license](https://github.com/Absolucy/tracing-oslog/blob/main/LICENSE.md)) for iOS in order to use Apple's `os_log`. ## Testing I ran `examples/mobile` with the logging from `examples/app/logs.rs` on an iOS device, I then checked the logs could be filtered in the MacOS Console.app. ## Changelog - Change bevy_log to use Apple's os_log on iOS. ## Questions for Reviewers It's worth noting that the dependency this adds hasn't had bug fixes released in a few years, so we may want to consider one or more of: 1. a feature flag to opt-in, and it would also allow `os_log` on MacOS 2. merge as-is and have some (minor?) upstream bugs 3. hold off on this PR until a suitable alternative dependency arises 4. maintain our own implementation ## Future work In a follow-up PR it might be good to make the `subsystem` field have a better default value, like [this one](https://github.com/bevyengine/bevy/blob/main/examples/mobile/bevy_mobile_example.xcodeproj/project.pbxproj#L363). That value can be retrieved programmatically if we bind another system API (For posterity in Swift this is `Bundle.main.bundleIdentifier`, but the C/ObjC equivalent is likely easier to bind). This would almost always be the correct value, while the current default is unlikely to ever be correct. --------- Co-authored-by: Dusty DeWeese <dustin.deweese@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com> Co-authored-by: François Mockers <francois.mockers@vleue.com> |
||
![]() |
e563f86a1d
|
Simplified easing curves (#15711)
# Objective Simplify the API surrounding easing curves. Broaden the base of types that support easing. ## Solution There is now a single library function, `easing_curve`, which constructs a unit-parametrized easing curve between two values based on an `EaseFunction`: ```rust /// Given a `start` and `end` value, create a curve parametrized over [the unit interval] /// that connects them, using the given [ease function] to determine the form of the /// curve in between. /// /// [the unit interval]: Interval::UNIT /// [ease function]: EaseFunction pub fn easing_curve<T: Ease>(start: T, end: T, ease_fn: EaseFunction) -> EasingCurve<T> { //... } ``` As this shows, the type of the output curve is generic only in `T`. In particular, as long as `T` is `Reflect` (and `FromReflect` etc. — i.e., a standard "well-behaved" reflectable type), `EasingCurve<T>` is also `Reflect`, and there is no special field handling nonsense. Therefore, `EasingCurve` is the kind of thing that would be able to be easily changed in an editor. This is made possible by storing the actual `EaseFunction` on `EasingCurve<T>` instead of indirecting through some kind of function type (which generally leads to issues with reflection). The types that can be eased are those that implement a trait `Ease`: ```rust /// A type whose values can be eased between. /// /// This requires the construction of an interpolation curve that actually extends /// beyond the curve segment that connects two values, because an easing curve may /// extrapolate before the starting value and after the ending value. This is /// especially common in easing functions that mimic elastic or springlike behavior. pub trait Ease: Sized { /// Given `start` and `end` values, produce a curve with [unlimited domain] /// that: /// - takes a value equivalent to `start` at `t = 0` /// - takes a value equivalent to `end` at `t = 1` /// - has constant speed everywhere, including outside of `[0, 1]` /// /// [unlimited domain]: Interval::EVERYWHERE fn interpolating_curve_unbounded(start: &Self, end: &Self) -> impl Curve<Self>; } ``` (I know, I know, yet *another* interpolation trait. See 'Future direction'.) The other existing easing functions from the previous version of this module have also become new members of `EaseFunction`: `Linear`, `Steps`, and `Elastic` (which maybe needs a different name). The latter two are parametrized. ## Testing Tested using the `easing_functions` example. I also axed the `cubic_curve` example which was of questionable value and replaced it with `eased_motion`, which uses this API in the context of animation: https://github.com/user-attachments/assets/3c802992-6b9b-4b56-aeb1-a47501c29ce2 --- ## Future direction Morally speaking, `Ease` is incredibly similar to `StableInterpolate`. Probably, we should just merge `StableInterpolate` into `Ease`, and then make `SmoothNudge` an automatic extension trait of `Ease`. The reason I didn't do that is that `StableInterpolate` is not implemented for `VectorSpace` because of concerns about the `Color` types, and I wanted to avoid controversy. I think that may be a good idea though. As Alice mentioned before, we should also probably get rid of the `interpolation` dependency. The parametrized `Elastic` variant probably also needs some additional work (e.g. renaming, in/out/in-out variants, etc.) if we want to keep it. |
||
![]() |
aa626e4f0b
|
Per-meshlet compressed vertex data (#15643)
# Objective - Prepare for streaming by storing vertex data per-meshlet, rather than per-mesh (this means duplicating vertices per-meshlet) - Compress vertex data to reduce the cost of this ## Solution The important parts are in from_mesh.rs, the changes to the Meshlet type in asset.rs, and the changes in meshlet_bindings.wgsl. Everything else is pretty secondary/boilerplate/straightforward changes. - Positions are quantized in centimeters with a user-provided power of 2 factor (ideally auto-determined, but that's a TODO for the future), encoded as an offset relative to the minimum value within the meshlet, and then stored as a packed list of bits using the minimum number of bits needed for each vertex position channel for that meshlet - E.g. quantize positions (lossly, throws away precision that's not needed leading to using less bits in the bitstream encoding) - Get the min/max quantized value of each X/Y/Z channel of the quantized positions within a meshlet - Encode values relative to the min value of the meshlet. E.g. convert from [min, max] to [0, max - min] - The new max value in the meshlet is (max - min), which only takes N bits, so we only need N bits to store each channel within the meshlet (lossless) - We can store the min value and that it takes N bits per channel in the meshlet metadata, and reconstruct the position from the bitstream - Normals are octahedral encoded and than snorm2x16 packed and stored as a single u32. - Would be better to implement the precise variant of octhedral encoding for extra precision (no extra decode cost), but decided to keep it simple for now and leave that as a followup - Tried doing a quantizing and bitstream encoding scheme like I did for positions, but struggled to get it smaller. Decided to go with this for simplicity for now - UVs are uncompressed and take a full 64bits per vertex which is expensive - In the future this should be improved - Tangents, as of the previous PR, are not explicitly stored and are instead derived from screen space gradients - While I'm here, split up MeshletMeshSaverLoader into two separate types Other future changes include implementing a smaller encoding of triangle data (3 u8 indices = 24 bits per triangle currently), and more disk-oriented compression schemes. References: * "A Deep Dive into UE5's Nanite Virtualized Geometry" https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf#page=128 (also available on youtube) * "Towards Practical Meshlet Compression" https://arxiv.org/pdf/2404.06359 * "Vertex quantization in Omniforce Game Engine" https://daniilvinn.github.io/2024/05/04/omniforce-vertex-quantization.html ## Testing - Did you test these changes? If so, how? - Converted the stanford bunny, and rendered it with a debug material showing normals, and confirmed that it's identical to what's on main. EDIT: See additional testing in the comments below. - Are there any parts that need more testing? - Could use some more size comparisons on various meshes, and testing different quantization factors. Not sure if 4 is a good default. EDIT: See additional testing in the comments below. - Also did not test runtime performance of the shaders. EDIT: See additional testing in the comments below. - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Use my unholy script, replacing the meshlet example https://paste.rs/7xQHk.rs (must make MeshletMesh fields pub instead of pub crate, must add lz4_flex as a dev-dependency) (must compile with meshlet and meshlet_processor features, mesh must have only positions, normals, and UVs, no vertex colors or tangents) --- ## Migration Guide - TBD by JMS55 at the end of the release |
||
![]() |
99b9a2fcd7
|
box shadow (#15204)
# Objective UI box shadow support Adds a new component `BoxShadow`: ```rust pub struct BoxShadow { /// The shadow's color pub color: Color, /// Horizontal offset pub x_offset: Val, /// Vertical offset pub y_offset: Val, /// Horizontal difference in size from the occluding uninode pub spread_radius: Val, /// Blurriness of the shadow pub blur_radius: Val, } ``` To use `BoxShadow`, add the component to any Bevy UI node and a shadow will be drawn beneath that node. Also adds a resource `BoxShadowSamples` that can be used to adjust the shadow quality. #### Notes * I'm not super happy with the field names. Maybe we need a `struct Size { width: Val, height: Val }` type or something. * The shader isn't very optimised but I don't see that it's too important for now as the number of shadows being rendered is not going to be massive most of the time. I think it's more important to get the API and geometry correct with this PR. * I didn't implement an inset property, it's not essential and can easily be added in a follow up. * Shadows are only rendered for uinodes, not for images or text. * Batching isn't supported, it would need out-of-the-scope-of-this-pr changes to the way the UI handles z-ordering for it to be effective. # Showcase ```cargo run --example box_shadow -- --samples 4``` <img width="391" alt="br" src="https://github.com/user-attachments/assets/4e8add96-dc93-46e0-9e35-d995eb0943ad"> ```cargo run --example box_shadow -- --samples 10``` <img width="391" alt="s10" src="https://github.com/user-attachments/assets/ecb384c9-4012-4cd6-9dea-5180904bf28e"> |
||
![]() |
4bf647ff3b
|
Add Order Independent Transparency (#14876)
# Objective - Alpha blending can easily fail in many situations and requires sorting on the cpu ## Solution - Implement order independent transparency (OIT) as an alternative to alpha blending - The implementation uses 2 passes - The first pass records all the fragments colors and position to a buffer that is the size of N layers * the render target resolution. - The second pass sorts the fragments, blends them and draws them to the screen. It also currently does manual depth testing because early-z fails in too many cases in the first pass. ## Testing - We've been using this implementation at foresight in production for many months now and we haven't had any issues related to OIT. --- ## Showcase   ## Future work - Add an example showing how to use OIT for a custom material - Next step would be to implement a per-pixel linked list to reduce memory use - I'd also like to investigate using a BinnedRenderPhase instead of a SortedRenderPhase. If it works, it would make the transparent pass significantly faster. --------- Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com> Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com> Co-authored-by: Charlotte McElwain <charlotte.c.mcelwain@gmail.com> |
||
![]() |
91bed8ce51
|
Screen shake example (#15567)
# Objective Closes https://github.com/bevyengine/bevy/issues/15564 ## Solution Adds a screen shake example. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
01387101df
|
add example for ease functions (#15703)
# Objective - Followup to #15675 - Add an example showcasing the functions ## Solution - Add an example showcasing the functions - Some of the functions from the interpolation crate are messed up, fixed in #15706  --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Joona Aalto <jondolf.dev@gmail.com> |
||
![]() |
8adc9e9d6e
|
Feature-gate all image formats (#15586)
# Objective Bevy supports feature gates for each format it supports, but several formats that it loads via the `image` crate do not have feature gates. Additionally, the QOI format is supported by the `image` crate and wasn't available at all. This fixes that. ## Solution The following feature gates are added: * `avif` * `ff` (Farbfeld) * `gif` * `ico` * `qoi` * `tiff` None of these formats are enabled by default, despite the fact that all these formats appeared to be enabled by default before. Since `default-features` was disabled for the `image` crate, it's likely that using any of these formats would have errored by default before this change, although this probably needs additional testing. ## Testing The changes seemed minimal enough that a compile test would be sufficient. ## Migration guide Image formats that previously weren't feature-gated are now feature-gated, meaning they will have to be enabled if you use them: * `avif` * `ff` (Farbfeld) * `gif` * `ico` * `tiff` Additionally, the `qoi` feature has been added to support loading QOI format images. Previously, these formats appeared in the enum by default, but weren't actually enabled via the `image` crate, potentially resulting in weird bugs. Now, you should be able to add these features to your projects to support them properly. |
||
![]() |
31409ebc61
|
Add Image methods for easy access to a pixel's color (#10392)
# Objective If you want to draw / generate images from the CPU, such as: - to create procedurally-generated assets - for games whose artstyle is best implemented by poking pixels directly from the CPU, instead of using shaders It is currently very unergonomic to do in Bevy, because you have to deal with the raw bytes inside `image.data`, take care of the pixel format, etc. ## Solution This PR adds some helper methods to `Image` for pixel manipulation. These methods allow you to use Bevy's user-friendly `Color` struct to read and write the colors of pixels, at arbitrary coordinates (specified as `UVec3` to support any texture dimension). They handle encoding/decoding to the `Image`s `TextureFormat`, incl. any sRGB conversion. While we are at it, also add methods to help with direct access to the raw bytes. It is now easy to compute the offset where the bytes of a specific pixel coordinate are found, or to just get a Rust slice to access them. Caveat: `Color` roundtrips are obviously going to be lossy for non-float `TextureFormat`s. Using `set_color_at` followed by `get_color_at` will return a different value, due to the data conversions involved (such as `f32` -> `u8` -> `f32` for the common `Rgba8UnormSrgb` texture format). Be careful when comparing colors (such as checking for a color you wrote before)! Also adding a new example: `cpu_draw` (under `2d`), to showcase these new APIs. --- ## Changelog ### Added - `Image` APIs for easy access to the colors of specific pixels. --------- Co-authored-by: Pascal Hertleif <killercup@gmail.com> Co-authored-by: François <mockersf@gmail.com> Co-authored-by: ltdk <usr@ltdk.xyz> |
||
![]() |
6edb78a8c3
|
Inverse bevy_render bevy_winit dependency and move cursor to bevy_winit (#15649)
# Objective - `bevy_render` should not depend on `bevy_winit` - Fixes #15565 ## Solution - `bevy_render` no longer depends on `bevy_winit` - The following is behind the `custom_cursor` feature - Move custom cursor code from `bevy_render` to `bevy_winit` behind the `custom_cursor` feature - `bevy_winit` now depends on `bevy_render` (for `Image` and `TextureFormat`) - `bevy_winit` now depends on `bevy_asset` (for `Assets`, `Handle` and `AssetId`) - `bevy_winit` now depends on `bytemuck` (already in tree) - Custom cursor code in `bevy_winit` reworked to use `AssetId` (other than that it is taken over 1:1) - Rework `bevy_winit` custom cursor interface visibility now that the logic is all contained in `bevy_winit` ## Testing - I ran the screenshot and window_settings examples - Tested on linux wayland so far --- ## Migration Guide `CursorIcon` and `CustomCursor` previously provided by `bevy::render::view::cursor` is now available from `bevy::winit`. A new feature `custom_cursor` enables this functionality (default feature). |
||
![]() |
d9190e4ff6
|
Add Support for Triggering Events via AnimationEvent s (#15538)
# Objective Add support for events that can be triggered from animation clips. This is useful when you need something to happen at a specific time in an animation. For example, playing a sound every time a characters feet hits the ground when walking. Closes #15494 ## Solution Added a new field to `AnimationClip`: `events`, which contains a list of `AnimationEvent`s. These are automatically triggered in `animate_targets` and `trigger_untargeted_animation_events`. ## Testing Added a couple of tests and example (`animation_events.rs`) to make sure events are triggered when expected. --- ## Showcase `Events` need to also implement `AnimationEvent` and `Reflect` to be used with animations. ```rust #[derive(Event, AnimationEvent, Reflect)] struct SomeEvent; ``` Events can be added to an `AnimationClip` by specifying a time and event. ```rust // trigger an event after 1.0 second animation_clip.add_event(1.0, SomeEvent); ``` And optionally, providing a target id. ```rust let id = AnimationTargetId::from_iter(["shoulder", "arm", "hand"]); animation_clip.add_event_to_target(id, 1.0, HandEvent); ``` I modified the `animated_fox` example to show off the feature.  --------- Co-authored-by: Matty <weatherleymatthew@gmail.com> Co-authored-by: Chris Biscardi <chris@christopherbiscardi.com> Co-authored-by: François Mockers <francois.mockers@vleue.com> |
||
![]() |
25bfa80e60
|
Migrate cameras to required components (#15641)
# Objective Yet another PR for migrating stuff to required components. This time, cameras! ## Solution As per the [selected proposal](https://hackmd.io/tsYID4CGRiWxzsgawzxG_g#Combined-Proposal-1-Selected), deprecate `Camera2dBundle` and `Camera3dBundle` in favor of `Camera2d` and `Camera3d`. Adding a `Camera` without `Camera2d` or `Camera3d` now logs a warning, as suggested by Cart [on Discord](https://discord.com/channels/691052431525675048/1264881140007702558/1291506402832945273). I would personally like cameras to work a bit differently and be split into a few more components, to avoid some footguns and confusing semantics, but that is more controversial, and shouldn't block this core migration. ## Testing I ran a few 2D and 3D examples, and tried cameras with and without render graphs. --- ## Migration Guide `Camera2dBundle` and `Camera3dBundle` have been deprecated in favor of `Camera2d` and `Camera3d`. Inserting them will now also insert the other components required by them automatically. |
||
![]() |
f86ee32576
|
Add UI GhostNode (#15341)
# Objective - Fixes #14826 - For context, see #15238 ## Solution Add a `GhostNode` component to `bevy_ui` and update all the relevant systems to use it to traverse for UI children. - [x] `ghost_hierarchy` module - [x] Add `GhostNode` - [x] Add `UiRootNodes` system param for iterating (ghost-aware) UI root nodes - [x] Add `UiChildren` system param for iterating (ghost-aware) UI children - [x] Update `layout::ui_layout_system` - [x] Use ghost-aware root nodes for camera updates - [x] Update and remove children in taffy - [x] Initial spawn - [x] Detect changes on nested UI children - [x] Use ghost-aware children traversal in `update_uinode_geometry_recursive` - [x] Update the rest of the UI systems to use the ghost hierarchy - [x] `stack::ui_stack_system` - [x] `update::` - [x] `update_clipping_system` - [x] `update_target_camera_system` - [x] `accessibility::calc_name` ## Testing - [x] Added a new example `ghost_nodes` that can be used as a testbed. - [x] Added unit tests for _some_ of the traversal utilities in `ghost_hierarchy` - [x] Ensure this fulfills the needs for currently known use cases - [x] Reactivity libraries (test with `bevy_reactor`) - [ ] Text spans (mentioned by koe [on discord](https://discord.com/channels/691052431525675048/1285371432460881991/1285377442998915246)) --- ## Performance [See comment below](https://github.com/bevyengine/bevy/pull/15341#issuecomment-2385456820) ## Migration guide Any code that previously relied on `Parent`/`Children` to iterate UI children may now want to use `bevy_ui::UiChildren` to ensure ghost nodes are skipped, and their first descendant Nodes included. UI root nodes may now be children of ghost nodes, which means `Without<Parent>` might not query all root nodes. Use `bevy_ui::UiRootNodes` where needed to iterate root nodes instead. ## Potential future work - Benchmarking/optimizations of hierarchies containing lots of ghost nodes - Further exploration of UI hierarchies and markers for root nodes/leaf nodes to create better ergonomics for things like `UiLayer` (world-space ui) --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com> |
||
![]() |
e924df0e1a
|
Add features to switch NativeActivity and GameActivity usage (#12095)
# Objective Add two features to switch bevy to use `NativeActivity` or `GameActivity` on Android, use `GameActivity` by default. Also close #12058 and probably #12026 . ## Solution Add two features to the corresponding crates so you can toggle it, like what `winit` and `android-activity` crate did. --- ## Changelog Removed default `NativeActivity` feature implementation for Android, added two new features to enable `NativeActivity` and `GameActivity`, and use `GameActivity` by default. ## Migration Guide Because `cargo-apk` is not compatible with `GameActivity`, building/running using `cargo apk build/run -p bevy_mobile_example` is no longer possible. Users should follow the new workflow described in document. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com> Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com> Co-authored-by: Rich Churcher <rich.churcher@gmail.com> |
||
![]() |
c323db02e0
|
Add sub_camera_view , enabling sheared projection (#15537)
# Objective - This PR fixes #12488 ## Solution - This PR adds a new property to `Camera` that emulates the functionality of the [setViewOffset()](https://threejs.org/docs/#api/en/cameras/PerspectiveCamera.setViewOffset) API in three.js. - When set, the perspective and orthographic projections will restrict the visible area of the camera to a part of the view frustum defined by `offset` and `size`. ## Testing - In the new `camera_sub_view` example, a fixed, moving and control sub view is created for both perspective and orthographic projection - Run the example with `cargo run --example camera_sub_view` - The code can be tested by adding a `SubCameraView` to a camera --- ## Showcase  - Left Half: Perspective Projection - Right Half: Orthographic Projection - Small boxes in order: - Sub view of the left half of the full image - Sub view moving from the top left to the bottom right of the full image - Sub view of the full image (acting as a control) - Large box: No sub view <details> <summary>Shortened camera setup of `camera_sub_view` example</summary> ```rust // Main perspective Camera commands.spawn(Camera3dBundle { transform, ..default() }); // Perspective camera left half commands.spawn(Camera3dBundle { camera: Camera { sub_camera_view: Some(SubCameraView { // Set the sub view camera to the left half of the full image full_size: uvec2(500, 500), offset: ivec2(0, 0), size: uvec2(250, 500), }), order: 1, ..default() }, transform, ..default() }); // Perspective camera moving commands.spawn(( Camera3dBundle { camera: Camera { sub_camera_view: Some(SubCameraView { // Set the sub view camera to a fifth of the full view and // move it in another system full_size: uvec2(500, 500), offset: ivec2(0, 0), size: uvec2(100, 100), }), order: 2, ..default() }, transform, ..default() }, MovingCameraMarker, )); // Perspective camera control commands.spawn(Camera3dBundle { camera: Camera { sub_camera_view: Some(SubCameraView { // Set the sub view to the full image, to ensure that it matches // the projection without sub view full_size: uvec2(450, 450), offset: ivec2(0, 0), size: uvec2(450, 450), }), order: 3, ..default() }, transform, ..default() }); // Main orthographic camera commands.spawn(Camera3dBundle { projection: OrthographicProjection { ... } .into(), camera: Camera { order: 4, ..default() }, transform, ..default() }); // Orthographic camera left half commands.spawn(Camera3dBundle { projection: OrthographicProjection { ... } .into(), camera: Camera { sub_camera_view: Some(SubCameraView { // Set the sub view camera to the left half of the full image full_size: uvec2(500, 500), offset: ivec2(0, 0), size: uvec2(250, 500), }), order: 5, ..default() }, transform, ..default() }); // Orthographic camera moving commands.spawn(( Camera3dBundle { projection: OrthographicProjection { ... } .into(), camera: Camera { sub_camera_view: Some(SubCameraView { // Set the sub view camera to a fifth of the full view and // move it in another system full_size: uvec2(500, 500), offset: ivec2(0, 0), size: uvec2(100, 100), }), order: 6, ..default() }, transform, ..default() }, MovingCameraMarker, )); // Orthographic camera control commands.spawn(Camera3dBundle { projection: OrthographicProjection { ... } .into(), camera: Camera { sub_camera_view: Some(SubCameraView { // Set the sub view to the full image, to ensure that it matches // the projection without sub view full_size: uvec2(450, 450), offset: ivec2(0, 0), size: uvec2(450, 450), }), order: 7, ..default() }, transform, ..default() }); ``` </details> |
||
![]() |
120d66482e
|
Clarify purpose of shader_instancing example (#15456)
# Objective - The shader_instancing example can be misleading since it doesn't explain that bevy has built in automatic instancing. ## Solution - Explain that bevy has built in instancing and that this example is for advanced users. - Add a new automatic_instancing example that shows how to use the built in automatic instancing - Rename the shader_instancing example to custom_shader_instancing to highlight that this is a more advanced implementation --------- Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com> |
||
![]() |
78a3aae81b
|
feat(gltf): add name component to gltf mesh primitive (#13912)
# Objective - fixes https://github.com/bevyengine/bevy/issues/13473 ## Solution - When a single mesh is assigned multiple materials, it is divided into several primitive nodes, with each primitive assigned a unique material. Presently, these primitives are named using the format Mesh.index, which complicates querying. To improve this, we can assign a specific name to each primitive based on the material’s name, since each primitive corresponds to one material exclusively. ## Testing - I have included a simple example which shows how to query a material and mesh part based on the new name component. ## Changelog - adds `GltfMaterialName` component to the mesh entity of the gltf primitive node. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
9cc7e7c080
|
Meshlet screenspace-derived tangents (#15084)
* Save 16 bytes per vertex by calculating tangents in the shader at runtime, rather than storing them in the vertex data. * Based on https://jcgt.org/published/0009/03/04, https://www.jeremyong.com/graphics/2023/12/16/surface-gradient-bump-mapping. * Fixed visbuffer resolve to use the updated algorithm that flips ddy correctly * Added some more docs about meshlet material limitations, and some TODOs about transforming UV coordinates for the future.  For testing add a normal map to the bunnies with StandardMaterial like below, and then test that on both main and this PR (make sure to download the correct bunny for each). Results should be mostly identical. ```rust normal_map_texture: Some(asset_server.load_with_settings( "textures/BlueNoise-Normal.png", |settings: &mut ImageLoaderSettings| settings.is_srgb = false, )), ``` |
||
![]() |
c1486654d7
|
QuerySingle family of system params (#15476)
# Objective Add the following system params: - `QuerySingle<D, F>` - Valid if only one matching entity exists, - `Option<QuerySingle<D, F>>` - Valid if zero or one matching entity exists. As @chescock pointed out, we don't need `Mut` variants. Fixes: #15264 ## Solution Implement the type and both variants of system params. Also implement `ReadOnlySystemParam` for readonly queries. Added a new ECS example `fallible_params` which showcases `SingleQuery` usage. In the future we might want to add `NonEmptyQuery`, `NonEmptyEventReader` and `Res` to it (or maybe just stop at mentioning it). ## Testing Tested with the example. There is a lot of warning spam so we might want to implement #15391. |
||
![]() |
d70595b667
|
Add core and alloc over std Lints (#15281)
# Objective - Fixes #6370 - Closes #6581 ## Solution - Added the following lints to the workspace: - `std_instead_of_core` - `std_instead_of_alloc` - `alloc_instead_of_core` - Used `cargo +nightly fmt` with [item level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A) to split all `use` statements into single items. - Used `cargo clippy --workspace --all-targets --all-features --fix --allow-dirty` to _attempt_ to resolve the new linting issues, and intervened where the lint was unable to resolve the issue automatically (usually due to needing an `extern crate alloc;` statement in a crate root). - Manually removed certain uses of `std` where negative feature gating prevented `--all-features` from finding the offending uses. - Used `cargo +nightly fmt` with [crate level use formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A) to re-merge all `use` statements matching Bevy's previous styling. - Manually fixed cases where the `fmt` tool could not re-merge `use` statements due to conditional compilation attributes. ## Testing - Ran CI locally ## Migration Guide The MSRV is now 1.81. Please update to this version or higher. ## Notes - This is a _massive_ change to try and push through, which is why I've outlined the semi-automatic steps I used to create this PR, in case this fails and someone else tries again in the future. - Making this change has no impact on user code, but does mean Bevy contributors will be warned to use `core` and `alloc` instead of `std` where possible. - This lint is a critical first step towards investigating `no_std` options for Bevy. --------- Co-authored-by: François Mockers <francois.mockers@vleue.com> |
||
![]() |
efda7f3f9c
|
Simpler lint fixes: makes ci lints work but disables a lint for now (#15376)
Takes the first two commits from #15375 and adds suggestions from this comment: https://github.com/bevyengine/bevy/pull/15375#issuecomment-2366968300 See #15375 for more reasoning/motivation. ## Rebasing (rerunning) ```rust git switch simpler-lint-fixes git reset --hard main cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate cargo fmt --all git add --update git commit --message "rustfmt" cargo clippy --workspace --all-targets --all-features --fix cargo fmt --all -- --unstable-features --config normalize_comments=true,imports_granularity=Crate cargo fmt --all git add --update git commit --message "clippy" git cherry-pick e6c0b94f6795222310fb812fa5c4512661fc7887 ``` |
||
![]() |
89e98b208f
|
Initial implementation of the Bevy Remote Protocol (Adopted) (#14880)
# Objective Adopted from #13563. The goal is to implement the Bevy Remote Protocol over HTTP/JSON, allowing the ECS to be interacted with remotely. ## Solution At a high level, there are really two separate things that have been undertaken here: 1. First, `RemotePlugin` has been created, which has the effect of embedding a [JSON-RPC](https://www.jsonrpc.org/specification) endpoint into a Bevy application. 2. Second, the [Bevy Remote Protocol verbs](https://gist.github.com/coreh/1baf6f255d7e86e4be29874d00137d1d#file-bevy-remote-protocol-md) (excluding `POLL`) have been implemented as remote methods for that JSON-RPC endpoint under a Bevy-exclusive namespace (e.g. `bevy/get`, `bevy/list`, etc.). To avoid some repetition, here is the crate-level documentation, which explains the request/response structure, built-in-methods, and custom method configuration: <details> <summary>Click to view crate-level docs</summary> ```rust //! An implementation of the Bevy Remote Protocol over HTTP and JSON, to allow //! for remote control of a Bevy app. //! //! Adding the [`RemotePlugin`] to your [`App`] causes Bevy to accept //! connections over HTTP (by default, on port 15702) while your app is running. //! These *remote clients* can inspect and alter the state of the //! entity-component system. Clients are expected to `POST` JSON requests to the //! root URL; see the `client` example for a trivial example of use. //! //! The Bevy Remote Protocol is based on the JSON-RPC 2.0 protocol. //! //! ## Request objects //! //! A typical client request might look like this: //! //! ```json //! { //! "method": "bevy/get", //! "id": 0, //! "params": { //! "entity": 4294967298, //! "components": [ //! "bevy_transform::components::transform::Transform" //! ] //! } //! } //! ``` //! //! The `id` and `method` fields are required. The `param` field may be omitted //! for certain methods: //! //! * `id` is arbitrary JSON data. The server completely ignores its contents, //! and the client may use it for any purpose. It will be copied via //! serialization and deserialization (so object property order, etc. can't be //! relied upon to be identical) and sent back to the client as part of the //! response. //! //! * `method` is a string that specifies one of the possible [`BrpRequest`] //! variants: `bevy/query`, `bevy/get`, `bevy/insert`, etc. It's case-sensitive. //! //! * `params` is parameter data specific to the request. //! //! For more information, see the documentation for [`BrpRequest`]. //! [`BrpRequest`] is serialized to JSON via `serde`, so [the `serde` //! documentation] may be useful to clarify the correspondence between the Rust //! structure and the JSON format. //! //! ## Response objects //! //! A response from the server to the client might look like this: //! //! ```json //! { //! "jsonrpc": "2.0", //! "id": 0, //! "result": { //! "bevy_transform::components::transform::Transform": { //! "rotation": { "x": 0.0, "y": 0.0, "z": 0.0, "w": 1.0 }, //! "scale": { "x": 1.0, "y": 1.0, "z": 1.0 }, //! "translation": { "x": 0.0, "y": 0.5, "z": 0.0 } //! } //! } //! } //! ``` //! //! The `id` field will always be present. The `result` field will be present if the //! request was successful. Otherwise, an `error` field will replace it. //! //! * `id` is the arbitrary JSON data that was sent as part of the request. It //! will be identical to the `id` data sent during the request, modulo //! serialization and deserialization. If there's an error reading the `id` field, //! it will be `null`. //! //! * `result` will be present if the request succeeded and will contain the response //! specific to the request. //! //! * `error` will be present if the request failed and will contain an error object //! with more information about the cause of failure. //! //! ## Error objects //! //! An error object might look like this: //! //! ```json //! { //! "code": -32602, //! "message": "Missing \"entity\" field" //! } //! ``` //! //! The `code` and `message` fields will always be present. There may also be a `data` field. //! //! * `code` is an integer representing the kind of an error that happened. Error codes documented //! in the [`error_codes`] module. //! //! * `message` is a short, one-sentence human-readable description of the error. //! //! * `data` is an optional field of arbitrary type containing additional information about the error. //! //! ## Built-in methods //! //! The Bevy Remote Protocol includes a number of built-in methods for accessing and modifying data //! in the ECS. Each of these methods uses the `bevy/` prefix, which is a namespace reserved for //! BRP built-in methods. //! //! ### bevy/get //! //! Retrieve the values of one or more components from an entity. //! //! `params`: //! - `entity`: The ID of the entity whose components will be fetched. //! - `components`: An array of fully-qualified type names of components to fetch. //! //! `result`: A map associating each type name to its value on the requested entity. //! //! ### bevy/query //! //! Perform a query over components in the ECS, returning all matching entities and their associated //! component values. //! //! All of the arrays that comprise this request are optional, and when they are not provided, they //! will be treated as if they were empty. //! //! `params`: //! `params`: //! - `data`: //! - `components` (optional): An array of fully-qualified type names of components to fetch. //! - `option` (optional): An array of fully-qualified type names of components to fetch optionally. //! - `has` (optional): An array of fully-qualified type names of components whose presence will be //! reported as boolean values. //! - `filter` (optional): //! - `with` (optional): An array of fully-qualified type names of components that must be present //! on entities in order for them to be included in results. //! - `without` (optional): An array of fully-qualified type names of components that must *not* be //! present on entities in order for them to be included in results. //! //! `result`: An array, each of which is an object containing: //! - `entity`: The ID of a query-matching entity. //! - `components`: A map associating each type name from `components`/`option` to its value on the matching //! entity if the component is present. //! - `has`: A map associating each type name from `has` to a boolean value indicating whether or not the //! entity has that component. If `has` was empty or omitted, this key will be omitted in the response. //! //! ### bevy/spawn //! //! Create a new entity with the provided components and return the resulting entity ID. //! //! `params`: //! - `components`: A map associating each component's fully-qualified type name with its value. //! //! `result`: //! - `entity`: The ID of the newly spawned entity. //! //! ### bevy/destroy //! //! Despawn the entity with the given ID. //! //! `params`: //! - `entity`: The ID of the entity to be despawned. //! //! `result`: null. //! //! ### bevy/remove //! //! Delete one or more components from an entity. //! //! `params`: //! - `entity`: The ID of the entity whose components should be removed. //! - `components`: An array of fully-qualified type names of components to be removed. //! //! `result`: null. //! //! ### bevy/insert //! //! Insert one or more components into an entity. //! //! `params`: //! - `entity`: The ID of the entity to insert components into. //! - `components`: A map associating each component's fully-qualified type name with its value. //! //! `result`: null. //! //! ### bevy/reparent //! //! Assign a new parent to one or more entities. //! //! `params`: //! - `entities`: An array of entity IDs of entities that will be made children of the `parent`. //! - `parent` (optional): The entity ID of the parent to which the child entities will be assigned. //! If excluded, the given entities will be removed from their parents. //! //! `result`: null. //! //! ### bevy/list //! //! List all registered components or all components present on an entity. //! //! When `params` is not provided, this lists all registered components. If `params` is provided, //! this lists only those components present on the provided entity. //! //! `params` (optional): //! - `entity`: The ID of the entity whose components will be listed. //! //! `result`: An array of fully-qualified type names of components. //! //! ## Custom methods //! //! In addition to the provided methods, the Bevy Remote Protocol can be extended to include custom //! methods. This is primarily done during the initialization of [`RemotePlugin`], although the //! methods may also be extended at runtime using the [`RemoteMethods`] resource. //! //! ### Example //! ```ignore //! fn main() { //! App::new() //! .add_plugins(DefaultPlugins) //! .add_plugins( //! // `default` adds all of the built-in methods, while `with_method` extends them //! RemotePlugin::default() //! .with_method("super_user/cool_method".to_owned(), path::to::my:🆒:handler) //! // ... more methods can be added by chaining `with_method` //! ) //! .add_systems( //! // ... standard application setup //! ) //! .run(); //! } //! ``` //! //! The handler is expected to be a system-convertible function which takes optional JSON parameters //! as input and returns a [`BrpResult`]. This means that it should have a type signature which looks //! something like this: //! ``` //! # use serde_json::Value; //! # use bevy_ecs::prelude::{In, World}; //! # use bevy_remote::BrpResult; //! fn handler(In(params): In<Option<Value>>, world: &mut World) -> BrpResult { //! todo!() //! } //! ``` //! //! Arbitrary system parameters can be used in conjunction with the optional `Value` input. The //! handler system will always run with exclusive `World` access. //! //! [the `serde` documentation]: https://serde.rs/ ``` </details> ### Message lifecycle At a high level, the lifecycle of client-server interactions is something like this: 1. The client sends one or more `BrpRequest`s. The deserialized version of that is just the Rust representation of a JSON-RPC request, and it looks like this: ```rust pub struct BrpRequest { /// The action to be performed. Parsing is deferred for the sake of error reporting. pub method: Option<Value>, /// Arbitrary data that will be returned verbatim to the client as part of /// the response. pub id: Option<Value>, /// The parameters, specific to each method. /// /// These are passed as the first argument to the method handler. /// Sometimes params can be omitted. pub params: Option<Value>, } ``` 2. These requests are accumulated in a mailbox resource (small lie but close enough). 3. Each update, the mailbox is drained by a system `process_remote_requests`, where each request is processed according to its `method`, which has an associated handler. Each handler is a Bevy system that runs with exclusive world access and returns a result; e.g.: ```rust pub fn process_remote_get_request(In(params): In<Option<Value>>, world: &World) -> BrpResult { // ... } ``` 4. The result (or an error) is reported back to the client. ## Testing This can be tested by using the `server` and `client` examples. The `client` example is not particularly exhaustive at the moment (it only creates barebones `bevy/query` requests) but is still informative. Other queries can be made using `curl` with the `server` example running. For example, to make a `bevy/list` request and list all registered components: ```bash curl -X POST -d '{ "jsonrpc": "2.0", "id": 1, "method": "bevy/list" }' 127.0.0.1:15702 | jq . ``` --- ## Future direction There were a couple comments on BRP versioning while this was in draft. I agree that BRP versioning is a good idea, but I think that it requires some consensus on a couple fronts: - First of all, what does the version actually mean? Is it a version for the protocol itself or for the `bevy/*` methods implemented using it? Both? - Where does the version actually live? The most natural place is just where we have `"jsonrpc"` right now (at least if it's versioning the protocol itself), but this means we're not actually conforming to JSON-RPC any more (so, for example, any client library used to construct JSON-RPC requests would stop working). I'm not really against that, but it's at least a real decision. - What do we actually do when we encounter mismatched versions? Adding handling for this would be actual scope creep instead of just a little add-on in my opinion. Another thing that would be nice is making the internal structure of the implementation less JSON-specific. Right now, for example, component values that will appear in server responses are quite eagerly converted to JSON `Value`s, which prevents disentangling the handler logic from the communication medium, but it can probably be done in principle and I imagine it would enable more code reuse (e.g. for custom method handlers) in addition to making the internals more readily usable for other formats. --------- Co-authored-by: Patrick Walton <pcwalton@mimiga.net> Co-authored-by: DragonGamesStudios <margos.michal@gmail.com> Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com> Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com> |
||
![]() |
55dddaf72e
|
UI Scrolling (#15291)
# Objective - Fixes #8074 - Adopts / Supersedes #8104 ## Solution Adapted from #8104 and affords the same benefits. **Additions** - [x] Update scrolling on relayout (height of node or contents may have changed) - [x] Make ScrollPosition component optional for ui nodes to avoid checking every node on scroll - [x] Nested scrollviews **Omissions** - Removed input handling for scrolling from `bevy_ui`. Users should update `ScrollPosition` directly. ### Implementation Adds a new `ScrollPosition` component. Updating this component on a `Node` with an overflow axis set to `OverflowAxis::Scroll` will reposition its children by that amount when calculating node transforms. As before, no impact on the underlying Taffy layout. Calculating this correctly is trickier than it was in #8104 due to `"Update scrolling on relayout"`. **Background** When `ScrollPosition` is updated directly by the user, it can be trivially handled in-engine by adding the parent's scroll position to the final location of each child node. However, _other layout actions_ may result in a situation where `ScrollPosition` needs to be updated. Consider a 1000 pixel tall vertically scrolling list of 100 elements, each 100 pixels tall. Scrolled to the bottom, the `ScrollPosition.offset_y` is 9000, just enough to display the last element in the list. When removing an element from that list, the new desired `ScrollPosition.offset_y` is 8900, but, critically, that is not known until after the sizes and positions of the children of the scrollable node are resolved. All user scrolling code today handles this by delaying the resolution by one frame. One notable disadvantage of this is the inability to support `WinitSettings::desktop_app()`, since there would need to be an input AFTER the layout change that caused the scroll position to update for the results of the scroll position update to render visually. I propose the alternative in this PR, which allows for same-frame resolution of scrolling layout. **Resolution** _Edit: Below resolution is outdated, and replaced with the simpler usage of taffy's `Layout::content_size`._ When recursively iterating the children of a node, each child now returns a `Vec2` representing the location of their own bottom right corner. Then, `[[0,0, [x,y]]` represents a bounding box containing the scrollable area filled by that child. Scrollable parents aggregate those areas into the bounding box of _all_ children, then consider that result against `ScrollPosition` to ensure its validity. In the event that resolution of the layout of the children invalidates the `ScrollPosition` (e.g. scrolled further than there were children to scroll to), _all_ children of that node must be recursively repositioned. The position of each child must change as a result of the change in scroll position. Therefore, this implementation takes care to only spend the cost of the "second layout pass" when a specific node actually had a `ScrollPosition` forcibly updated by the layout of its children. ## Testing Examples in `ui/scroll.rs`. There may be more complex node/style interactions that were unconsidered. --- ## Showcase  ## Alternatives - `bevy_ui` doesn't support scrolling. - `bevy_ui` implements scrolling with a one-frame delay on reactions to layout changes. |
||
![]() |
8154164f1b
|
Allow animation clips to animate arbitrary properties. (#15282)
Currently, Bevy restricts animation clips to animating `Transform::translation`, `Transform::rotation`, `Transform::scale`, or `MorphWeights`, which correspond to the properties that glTF can animate. This is insufficient for many use cases such as animating UI, as the UI layout systems expect to have exclusive control over UI elements' `Transform`s and therefore the `Style` properties must be animated instead. This commit fixes this, allowing for `AnimationClip`s to animate arbitrary properties. The `Keyframes` structure has been turned into a low-level trait that can be implemented to achieve arbitrary animation behavior. Along with `Keyframes`, this patch adds a higher-level trait, `AnimatableProperty`, that simplifies the task of animating single interpolable properties. Built-in `Keyframes` implementations exist for translation, rotation, scale, and morph weights. For the most part, you can migrate by simply changing your code from `Keyframes::Translation(...)` to `TranslationKeyframes(...)`, and likewise for rotation, scale, and morph weights. An example `AnimatableProperty` implementation for the font size of a text section follows: #[derive(Reflect)] struct FontSizeProperty; impl AnimatableProperty for FontSizeProperty { type Component = Text; type Property = f32; fn get_mut(component: &mut Self::Component) -> Option<&mut Self::Property> { Some(&mut component.sections.get_mut(0)?.style.font_size) } } In order to keep this patch relatively small, this patch doesn't include an implementation of `AnimatableProperty` on top of the reflection system. That can be a follow-up. This patch builds on top of the new `EntityMutExcept<>` type in order to widen the `AnimationTarget` query to include write access to all components. Because `EntityMutExcept<>` has some performance overhead over an explicit query, we continue to explicitly query `Transform` in order to avoid regressing the performance of skeletal animation, such as the `many_foxes` benchmark. I've measured the performance of that benchmark and have found no significant regressions. A new example, `animated_ui`, has been added. This example shows how to use Bevy's built-in animation infrastructure to animate font size and color, which wasn't possible before this patch. ## Showcase https://github.com/user-attachments/assets/1fa73492-a9ce-405a-a8f2-4aacd7f6dc97 ## Migration Guide * Animation keyframes are now an extensible trait, not an enum. Replace `Keyframes::Translation(...)`, `Keyframes::Scale(...)`, `Keyframes::Rotation(...)`, and `Keyframes::Weights(...)` with `Box::new(TranslationKeyframes(...))`, `Box::new(ScaleKeyframes(...))`, `Box::new(RotationKeyframes(...))`, and `Box::new(MorphWeightsKeyframes(...))` respectively. |
||
![]() |
9386bd0114
|
feature gate picking backends (#15369)
# Objective Fixes #15306 ## Solution - Add feature gate on the module and the place where each one is used - Declare the features and make them default ## Testing - CI |
||
![]() |
58f6fa94a2
|
Spirv passthrough main (adopted, part deux) (#15352)
**Note:** This is an adoption of @Shfty 's adoption (#8131) of #3996! All I've done is updated the branch and run the docs CI. > **Note:** This is an adoption of #3996, originally authored by @molikto > > # Objective > Allow use of `wgpu::Features::SPIRV_SHADER_PASSTHROUGH` and the corresponding `wgpu::Device::create_shader_module_spirv` for SPIR-V shader assets. > > This enables use-cases where naga is not sufficient to load a given (valid) SPIR-V module, i.e. cases where naga lacks support for a given SPIR-V feature employed by a third-party codegen backend like `rust-gpu`. > > ## Solution > * Reimplemented the changes from [Spirv shader bypass #3996](https://github.com/bevyengine/bevy/pull/3996), on account of the original branch having been deleted. > * Documented the new `spirv_shader_passthrough` feature flag with the appropriate platform support context from [wgpu's documentation](https://docs.rs/wgpu/latest/wgpu/struct.Features.html#associatedconstant.SPIRV_SHADER_PASSTHROUGH). > > ## Changelog > * Adds a `spirv_shader_passthrough` feature flag to the following crates: > > * `bevy` > * `bevy_internal` > * `bevy_render` > * Extends `RenderDevice::create_shader_module` with a conditional call to `wgpu::Device::create_shader_module_spirv` if `spirv_shader_passthrough` is enabled and `wgpu::Features::SPIRV_SHADER_PASSTHROUGH` is present for the current platform. > * Documents the relevant `wgpu` platform support in `docs/cargo_features.md` --------- Co-authored-by: Josh Palmer <1253239+Shfty@users.noreply.github.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
e3b6b125a0
|
Add sprite and mesh alteration examples (#15298)
# Objective Add examples for manipulating sprites and meshes by either mutating the handle or direct manipulation of the asset, as described in #15056. Closes #3130. (The previous PR suffered a Git-tastrophe, and was unceremoniously closed, sry! 😅 ) --------- Co-authored-by: Jan Hohenheim <jan@hohenheim.ch> |
||
![]() |
fd329c0426
|
Allow to expect (adopted) (#15301)
# Objective > Rust 1.81 released the #[expect(...)] attribute, which works like #[allow(...)] but throws a warning if the lint isn't raised. This is preferred to #[allow(...)] because it tells us when it can be removed. - Adopts the parts of #15118 that are complete, and updates the branch so it can be merged. - There were a few conflicts, let me know if I misjudged any of 'em. Alice's [recommendation](https://github.com/bevyengine/bevy/issues/15059#issuecomment-2349263900) seems well-taken, let's do this crate by crate now that @BD103 has done the lion's share of this! (Relates to, but doesn't yet completely finish #15059.) Crates this _doesn't_ cover: - bevy_input - bevy_gilrs - bevy_window - bevy_winit - bevy_state - bevy_render - bevy_picking - bevy_core_pipeline - bevy_sprite - bevy_text - bevy_pbr - bevy_ui - bevy_gltf - bevy_gizmos - bevy_dev_tools - bevy_internal - bevy_dylib --------- Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com> Co-authored-by: Ben Frankel <ben.frankel7@gmail.com> Co-authored-by: Antony <antony.m.3012@gmail.com> |
||
![]() |
1b8c1c1242
|
simplify std::mem references (#15315)
# Objective - Fixes #15314 ## Solution - Remove unnecessary usings and simplify references to those functions. ## Testing CI |
||
![]() |
2ae5a21009
|
Implement percentage-closer soft shadows (PCSS). (#13497)
[*Percentage-closer soft shadows*] are a technique from 2004 that allow shadows to become blurrier farther from the objects that cast them. It works by introducing a *blocker search* step that runs before the normal shadow map sampling. The blocker search step detects the difference between the depth of the fragment being rasterized and the depth of the nearby samples in the depth buffer. Larger depth differences result in a larger penumbra and therefore a blurrier shadow. To enable PCSS, fill in the `soft_shadow_size` value in `DirectionalLight`, `PointLight`, or `SpotLight`, as appropriate. This shadow size value represents the size of the light and should be tuned as appropriate for your scene. Higher values result in a wider penumbra (i.e. blurrier shadows). When using PCSS, temporal shadow maps (`ShadowFilteringMethod::Temporal`) are recommended. If you don't use `ShadowFilteringMethod::Temporal` and instead use `ShadowFilteringMethod::Gaussian`, Bevy will use the same technique as `Temporal`, but the result won't vary over time. This produces a rather noisy result. Doing better would likely require downsampling the shadow map, which would be complex and slower (and would require PR #13003 to land first). In addition to PCSS, this commit makes the near Z plane for the shadow map configurable on a per-light basis. Previously, it had been hardcoded to 0.1 meters. This change was necessary to make the point light shadow map in the example look reasonable, as otherwise the shadows appeared far too aliased. A new example, `pcss`, has been added. It demonstrates the percentage-closer soft shadow technique with directional lights, point lights, spot lights, non-temporal operation, and temporal operation. The assets are my original work. Both temporal and non-temporal shadows are rather noisy in the example, and, as mentioned before, this is unavoidable without downsampling the depth buffer, which we can't do yet. Note also that the shadows don't look particularly great for point lights; the example simply isn't an ideal scene for them. Nevertheless, I felt that the benefits of the ability to do a side-by-side comparison of directional and point lights outweighed the unsightliness of the point light shadows in that example, so I kept the point light feature in. Fixes #3631. [*Percentage-closer soft shadows*]: https://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf ## Changelog ### Added * Percentage-closer soft shadows (PCSS) are now supported, allowing shadows to become blurrier as they stretch away from objects. To use them, set the `soft_shadow_size` field in `DirectionalLight`, `PointLight`, or `SpotLight`, as applicable. * The near Z value for shadow maps is now customizable via the `shadow_map_near_z` field in `DirectionalLight`, `PointLight`, and `SpotLight`. ## Screenshots PCSS off:  PCSS on:  --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Torstein Grindvik <52322338+torsteingrindvik@users.noreply.github.com> |
||
![]() |
c454db88a3
|
2580 Split examples PR feedback (#15181)
# Objective Applies feedback from previous PR #15135 'cause it got caught up in the merge train 🚂 I couldn't resist including roll, both for completeness and due to playing too many games that implemented it as a child. cc: @janhohenheim |
||
![]() |
8e7ef64bb1
|
Split zoom/orbit into separate examples (#15135)
# Objective As previously discussed, split camera zoom and orbiting examples to keep things less cluttered. See discussion on #15092 for context. |
||
![]() |
b9b43ad89c
|
Add examples for orthographic and perspective zoom (#15092)
# Objective Add examples for zooming (and orbiting) orthographic and perspective cameras. I'm pretty green with 3D, so please treat with suspicion! I note that if/when #15075 is merged, `.scale` will go away so this example uses `.scaling_mode`. Closes #2580 |
||
![]() |
a0faf9cd01
|
More triangles/vertices per meshlet (#15023)
### Builder changes - Increased meshlet max vertices/triangles from 64v/64t to 255v/128t (meshoptimizer won't allow 256v sadly). This gives us a much greater percentage of meshlets with max triangle count (128). Still not perfect, we still end up with some tiny <=10 triangle meshlets that never really get simplified, but it's progress. - Removed the error target limit. Now we allow meshoptimizer to simplify as much as possible. No reason to cap this out, as the cluster culling code will choose a good LOD level anyways. Again leads to higher quality LOD trees. - After some discussion and consulting the Nanite slides again, changed meshlet group error from _adding_ the max child's error to the group error, to doing `group_error = max(group_error, max_child_error)`. Error is already cumulative between LODs as the edges we're collapsing during simplification get longer each time. - Bumped the 65% simplification threshold to allow up to 95% of the original geometry (e.g. accept simplification as valid even if we only simplified 5% of the triangles). This gives us closer to log2(initial_meshlet_count) LOD levels, and fewer meshlet roots in the DAG. Still more work to be done in the future here. Maybe trying METIS for meshlet building instead of meshoptimizer. Using ~8 clusters per group instead of ~4 might also make a big difference. The Nanite slides say that they have 8-32 meshlets per group, suggesting some kind of heuristic. Unfortunately meshopt's compute_cluster_bounds won't work with large groups atm (https://github.com/zeux/meshoptimizer/discussions/750#discussioncomment-10562641) so hard to test. Based on discussion from https://github.com/bevyengine/bevy/discussions/14998, https://github.com/zeux/meshoptimizer/discussions/750, and discord. ### Runtime changes - cluster:triangle packed IDs are now stored 25:7 instead of 26:6 bits, as max triangles per cluster are now 128 instead of 64 - Hardware raster now spawns 128 * 3 vertices instead of 64 * 3 vertices to account for the new max triangles limit - Hardware raster now outputs NaN triangles (0 / 0) instead of zero-positioned triangles for extra vertex invocations over the cluster triangle count. Shouldn't really be a difference idt, but I did it anyways. - Software raster now does 128 threads per workgroup instead of 64 threads. Each thread now loads, projects, and caches a vertex (vertices 0-127), and then if needed does so again (vertices 128-254). Each thread then rasterizes one of 128 triangles. - Fixed a bug with `needs_dispatch_remap`. I had the condition backwards in my last PR, I probably committed it by accident after testing the non-default code path on my GPU. |
||
![]() |
8ac745ab10
|
UI texture slice texture flipping reimplementation (#15034)
# Objective Fixes #15032 ## Solution Reimplement support for the `flip_x` and `flip_y` fields. This doesn't flip the border geometry, I'm not really sure whether that is desirable or not. Also fixes a bug that was causing the side and center slices to tile incorrectly. ### Testing ``` cargo run --example ui_texture_slice_flip_and_tile ``` ## Showcase <img width="787" alt="nearest" src="https://github.com/user-attachments/assets/bc044bae-1748-42ba-92b5-0500c87264f6"> With tiling need to use nearest filtering to avoid bleeding between the slices. --------- Co-authored-by: Jan Hohenheim <jan@hohenheim.ch> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
d2624765d0
|
Implement animation masks, allowing fine control of the targets that animations affect. (#15013)
This commit adds support for *masks* to the animation graph. A mask is a set of animation targets (bones) that neither a node nor its descendants are allowed to animate. Animation targets can be assigned one or more *mask group*s, which are specific to a single graph. If a node masks out any mask group that an animation target belongs to, animation curves for that target will be ignored during evaluation. The canonical use case for masks is to support characters holding objects. Typically, character animations will contain hand animations in the case that the character's hand is empty. (For example, running animations may close a character's fingers into a fist.) However, when the character is holding an object, the animation must be altered so that the hand grips the object. Bevy currently has no convenient way to handle this. The only workaround that I can see is to have entirely separate animation clips for characters' hands and bodies and keep them in sync, which is burdensome and doesn't match artists' expectations from other engines, which all effectively have support for masks. However, with mask group support, this task is simple. We assign each hand to a mask group and parent all character animations to a node. When a character grasps an object in hand, we position the fingers as appropriate and then enable the mask group for that hand in that node. This allows the character's animations to run normally, while the object remains correctly attached to the hand. Note that even with this PR, we won't have support for running separate animations for a character's hand and the rest of the character. This is because we're missing additive blending: there's no way to combine the two masked animations together properly. I intend that to be a follow-up PR. The major engines all have support for masks, though the workflow varies from engine to engine: * Unity has support for masks [essentially as implemented here], though with layers instead of a tree. However, when using the Mecanim ("Humanoid") feature, precise control over bones is lost in favor of predefined muscle groups. * Unreal has a feature named [*layered blend per bone*]. This allows for separate blend weights for different bones, effectively achieving masks. I believe that the combination of blend nodes and masks make Bevy's animation graph as expressible as that of Unreal, once we have support for additive blending, though you may have to use more nodes than you would in Unreal. Moreover, separating out the concepts of "blend weight" and "which bones this node applies to" seems like a cleaner design than what Unreal has. * Godot's `AnimationTree` has the notion of [*blend filters*], which are essentially the same as masks as implemented in this PR. Additionally, this patch fixes a bug with weight evaluation whereby weights weren't properly propagated down to grandchildren, because the weight evaluation for a node only checked its parent's weight, not its evaluated weight. I considered submitting this as a separate PR, but given that this PR refactors that code entirely to support masks and weights under a unified "evaluated node" concept, I simply included the fix here. A new example, `animation_masks`, has been added. It demonstrates how to toggle masks on and off for specific portions of a skin. This is part of #14395, but I'm going to defer closing that issue until we have additive blending. [essentially as implemented here]: https://docs.unity3d.com/560/Documentation/Manual/class-AvatarMask.html [*layered blend per bone*]: https://dev.epicgames.com/documentation/en-us/unreal-engine/using-layered-animations-in-unreal-engine [*blend filters*]: https://docs.godotengine.org/en/stable/tutorials/animation/animation_tree.html ## Migration Guide * The serialized format of animation graphs has changed with the addition of animation masks. To upgrade animation graph RON files, add `mask` and `mask_groups` fields as appropriate. (They can be safely set to zero.) |
||
![]() |
a4640046fc
|
Adds ShaderStorageBuffer asset (#14663)
Adds a new `Handle<Storage>` asset type that can be used as a render asset, particularly for use with `AsBindGroup`. Closes: #13658 # Objective Allow users to create storage buffers in the main world without having to access the `RenderDevice`. While this resource is technically available, it's bad form to use in the main world and requires mixing rendering details with main world code. Additionally, this makes storage buffers easier to use with `AsBindGroup`, particularly in the following scenarios: - Sharing the same buffers between a compute stage and material shader. We already have examples of this for storage textures (see game of life example) and these changes allow a similar pattern to be used with storage buffers. - Preventing repeated gpu upload (see the previous easier to use `Vec` `AsBindGroup` option). - Allow initializing custom materials using `Default`. Previously, the lack of a `Default` implement for the raw `wgpu::Buffer` type made implementing a `AsBindGroup + Default` bound difficult in the presence of buffers. ## Solution Adds a new `Handle<Storage>` asset type that is prepared into a `GpuStorageBuffer` render asset. This asset can either be initialized with a `Vec<u8>` of properly aligned data or with a size hint. Users can modify the underlying `wgpu::BufferDescriptor` to provide additional usage flags. ## Migration Guide The `AsBindGroup` `storage` attribute has been modified to reference the new `Handle<Storage>` asset instead. Usages of Vec` should be converted into assets instead. --------- Co-authored-by: IceSentry <IceSentry@users.noreply.github.com> |
||
![]() |
1cca4f2968
|
Remove some asset examples from web showcase (#14973)
# Objective - `custom_asset_reader` and `extra_asset_source` examples are not working on web. - Fixes #14689 ## Solution - Make these examples `wasm=false` per https://github.com/bevyengine/bevy/issues/14689#issuecomment-2313064396 ## Testing |
||
![]() |
3540b87e17
|
Add bevy_picking sprite backend (#14757)
# Objective Add `bevy_picking` sprite backend as part of the `bevy_mod_picking` upstreamening (#12365). ## Solution More or less a copy/paste from `bevy_mod_picking`, with the changes [here](https://github.com/aevyrie/bevy_mod_picking/pull/354). I'm putting that link here since those changes haven't yet made it through review, so should probably be reviewed on their own. ## Testing I couldn't find any sprite-backend-specific tests in `bevy_mod_picking` and unfortunately I'm not familiar enough with Bevy's testing patterns to write tests for code that relies on windowing and input. I'm willing to break the pointer hit system into testable blocks and add some more modular tests if that's deemed important enough to block, otherwise I can open an issue for adding tests as follow-up. ## Follow-up work - More docs/tests - Ignore pick events on transparent sprite pixels with potential opt-out --------- Co-authored-by: Aevyrie <aevyrie@gmail.com> |
||
![]() |
94d40d206e
|
Replace the wgpu_trace feature with a field in bevy_render::settings::WgpuSettings (#14842)
# Objective - Remove the `wgpu_trace` feature while still making it easy/possible to record wgpu traces for debugging. - Close #14725. - Get a taste of the bevy codebase. :P ## Solution This PR performs the above objective by removing the `wgpu_trace` feature from all `Cargo.toml` files. However, wgpu traces are still useful for debugging - but to record them, you need to pass in a directory path to store the traces in. To avoid forcing users into manually creating the renderer, `bevy_render::settings::WgpuSettings` now has a `trace_path` field, so that all of Bevy's automatic initialization can happen while still allowing for tracing. ## Testing - Did you test these changes? If so, how? - I have tested these changes, but only via running `cargo run -p ci`. I am hoping the Github Actions workflows will catch anything I missed. - Are there any parts that need more testing? - I do not believe so. - How can other people (reviewers) test your changes? Is there anything specific they need to know? - If you want to test these changes, I have updated the debugging guide (`docs/debugging.md`) section on WGPU Tracing. - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? - I ran the above command on a Windows 10 64-bit (x64) machine, using the `stable-x86_64-pc-windows-msvc` toolchain. I do not have anything set up for other platforms or targets (though I can't imagine this needs testing on other platforms). --- ## Migration Guide 1. The `bevy/wgpu_trace`, `bevy_render/wgpu_trace`, and `bevy_internal/wgpu_trace` features no longer exist. Remove them from your `Cargo.toml`, CI, tooling, and what-not. 2. Follow the instructions in the updated `docs/debugging.md` file in the repository, under the WGPU Tracing section. Because of the changes made, you can now generate traces to any path, rather than the hardcoded `%WorkspaceRoot%/wgpu_trace` (where `%WorkspaceRoot%` is... the root of your crate's workspace) folder. (If WGPU hasn't restored tracing functionality...) Do note that WGPU has not yet restored tracing functionality. However, once it does, the above should be sufficient to generate new traces. --------- Co-authored-by: TrialDragon <31419708+TrialDragon@users.noreply.github.com> |
||
![]() |
510fce9af3
|
Allow fog density texture to be scrolled over time with an offset (#14868)
# Objective - The goal of this PR is to make it possible to move the density texture of a `FogVolume` over time in order to create dynamic effects like fog moving in the wind. - You could theoretically move the `FogVolume` itself, but this is not ideal, because the `FogVolume` AABB would eventually leave the area. If you want an area to remain foggy while also creating the impression that the fog is moving in the wind, a scrolling density texture is a better solution. ## Solution - The PR adds a `density_texture_offset` field to the `FogVolume` component. This offset is in the UVW coordinates of the density texture, meaning that a value of `(0.5, 0.0, 0.0)` moves the 3d texture by half along the x-axis. - Values above 1.0 are wrapped, a 1.5 offset is the same as a 0.5 offset. This makes it so that the density texture wraps around on the other side, meaning that a repeating 3d noise texture can seamlessly scroll forever. It also makes it easy to move the density texture over time by simply increasing the offset every frame. ## Testing - A `scrolling_fog` example has been added to demonstrate the feature. It uses the offset to scroll a repeating 3d noise density texture to create the impression of fog moving in the wind. - The camera is looking at a pillar with the sun peaking behind it. This highlights the effect the changing density has on the volumetric lighting interactions. - Temporal anti-aliasing combined with the `jitter` option of `VolumetricFogSettings` is used to improve the quality of the effect. --- ## Showcase https://github.com/user-attachments/assets/3aa50ebd-771c-4c99-ab5d-255c0c3be1a8 |
||
![]() |
938d810766
|
Apply unused_qualifications lint (#14828)
# Objective Fixes #14782 ## Solution Enable the lint and fix all upcoming hints (`--fix`). Also tried to figure out the false-positive (see review comment). Maybe split this PR up into multiple parts where only the last one enables the lint, so some can already be merged resulting in less many files touched / less potential for merge conflicts? Currently, there are some cases where it might be easier to read the code with the qualifier, so perhaps remove the import of it and adapt its cases? In the current stage it's just a plain adoption of the suggestions in order to have a base to discuss. ## Testing `cargo clippy` and `cargo run -p ci` are happy. |
||
![]() |
eec38004a8
|
Add example demonstrating how to enable / disable diagnostics (#14741)
# Objective fixes #14569 ## Solution added an example to the diagnostic examples and linked the code to the docs of the diagnostic library itself. ## Testing I tested locally on my laptop in a web browser. Looked fine. You are able to collapse the whole "intro" part of the doc to get to the links sooner (for those who may think that including the example code here is annoying to scroll through) I would like people to run ```cargo doc``` and go the bevy_diagnostic page to see if they have any issues or suggestions. --- ## Showcase <img width="1067" alt="Screenshot 2024-08-14 at 12 52 16" src="https://github.com/user-attachments/assets/70b6c18a-0bb9-4656-ba53-c416f62c6116"> --------- Co-authored-by: dpeke <dpekelis@funstage.com> |