4fca331bb6
351 Commits
Author | SHA1 | Message | Date | |
---|---|---|---|---|
![]() |
4fca331bb6
|
Fix Formatting of Optimisation Table (#18375)
# Objective New markdown linter doesn't like this table. ## Solution Fixed it. ## Testing CI |
||
![]() |
6299e3de3b
|
Add examples/helpers/* as library examples (#18288)
# Objective Some of Bevy's examples contain boilerplate which is split out into the `helpers` folder. This allows examples to have access to common functionality without building into Bevy directly. However, these helpers are themselves quite high-quality code, and we do intend for users to read them and even use them. But, we don't list them in the examples document, and they aren't explicitly checked in CI, only transitively through examples which import them. ## Solution - Added `camera_controller` and `widgets` as library examples. ## Testing - CI --- ## Notes - Library examples are identical to any other example, just with `crate-type = ["lib"]` in the `Cargo.toml`. Since they are marked as libraries, they don't require a `main` function but do require public items to be documented. - Library examples opens the possibility of creating examples which don't need to be actual runnable applications. This may be more appropriate for certain ECS examples, and allows for adding helpers which (currently) don't have an example that needs them without them going stale. - I learned about this as a concept during research for `no_std` examples, but believe it has value for Bevy outside that specific niche. --------- Co-authored-by: mgi388 <135186256+mgi388@users.noreply.github.com> Co-authored-by: Carter Weinberg <weinbergcarter@gmail.com> |
||
![]() |
c3ff6d4136
|
Fix non-crate typos (#18219)
# Objective Correct spelling ## Solution Fix typos, specifically ones that I found in folders other than /crates ## Testing CI --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
683b08fec9
|
Respect viewport position in coordinate conversion functions (#17633)
# Objective - In `Camera::viewport_to_world_2d`, `Camera::viewport_to_world`, `Camera::world_to_viewport` and `Camera::world_to_viewport_with_depth`, the results were incorrect when the `Camera::viewport` field was configured with a viewport position that was non-zero. This PR attempts to correct that. - Fixes #16200 ## Solution - This PR now takes the viewport position into account in the functions mentioned above. - Extended `2d_viewport_to_world` example to test the functions with a dynamic viewport position and size, camera positions and zoom levels. It is probably worth discussing whether to change the example, add a new one or just completely skip touching the examples. ## Testing Used the modified example to test the functions with dynamic camera transform as well as dynamic viewport size and position. |
||
![]() |
181445c56b
|
Add support for experimental WESL shader source (#17953)
# Objective WESL's pre-MVP `0.1.0` has been [released](https://docs.rs/wesl/latest/wesl/)! Add support for WESL shader source so that we can begin playing and testing WESL, as well as aiding in their development. ## Solution Adds a `ShaderSource::WESL` that can be used to load `.wesl` shaders. Right now, we don't support mixing `naga-oil`. Additionally, WESL shaders currently need to pass through the naga frontend, which the WESL team is aware isn't great for performance (they're working on compiling into naga modules). Also, since our shaders are managed using the asset system, we don't currently support using file based imports like `super` or package scoped imports. Further work will be needed to asses how we want to support this. --- ## Showcase See the `shader_material_wesl` example. Be sure to press space to activate party mode (trigger conditional compilation)! https://github.com/user-attachments/assets/ec6ad19f-b6e4-4e9d-a00f-6f09336b08a4 |
||
![]() |
7d7c43dd62
|
Add uv_transform to ColorMaterial (#17879)
# Objective Implements and closes #17515 ## Solution Add `uv_transform` to `ColorMaterial` ## Testing Create a example similar to `repeated_texture` but for `Mesh2d` and `MeshMaterial2d<ColorMaterial>` ## Showcase  ## Migration Guide Add `uv_transform` field to constructors of `ColorMaterial` |
||
![]() |
4ecbe001d5
|
Add a custom render phase example (#16916)
# Objective - It's currently very hard for beginners and advanced users to get a full understanding of a complete render phase. ## Solution - Implement a full custom render phase - The render phase in the example is intended to show a custom stencil phase that renders the stencil in red directly on the screen --- ## Showcase <img width="1277" alt="image" src="https://github.com/user-attachments/assets/e9dc0105-4fb6-463f-ad53-0529b575fd28" /> ## Notes More docs to explain what is going on is still needed but the example works and can already help some people. We might want to consider using a batched phase and cold specialization in the future, but the example is already complex enough as it is. --------- Co-authored-by: Christopher Biscardi <chris@christopherbiscardi.com> |
||
![]() |
33e83330eb
|
Add entity disabling example (#17710)
# Objective The entity disabling / default query filter work added in #17514 and #13120 is neat, but we don't teach users how it works! We should fix that before 0.16. ## Solution Write a simple example to teach the basics of entity disabling! ## Testing `cargo run --example entity_disabling` ## Showcase  --------- Co-authored-by: Zachary Harrold <zac@harrold.com.au> |
||
![]() |
9ea9c5df00
|
Add edit_material_on_gltf example (#17677)
# Objective Create a minimal example of how to modify the material from a `Gltf`. This is frequently asked about on the help channel of the discord. ## Solution Create the example. ## Showcase  |
||
![]() |
203d0b4aae
|
Move bounding_2d example to math folder (#17523)
# Objective The bounding_2d example was originally placed in 2d_rendering because there was no folder for bounding or math, but now that this folder exist it makes no sense for it to be here. ## Solution Move the example ## Testing I ran the example |
||
![]() |
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. |
||
![]() |
1c765c9ae7
|
Add support for specular tints and maps per the KHR_materials_specular glTF extension. (#14069)
This commit allows specular highlights to be tinted with a color and for the reflectance and color tint values to vary across a model via a pair of maps. The implementation follows the [`KHR_materials_specular`] glTF extension. In order to reduce the number of samplers and textures in the default `StandardMaterial` configuration, the maps are gated behind the `pbr_specular_textures` Cargo feature. Specular tinting is currently unsupported in the deferred renderer, because I didn't want to bloat the deferred G-buffers. A possible fix for this in the future would be to make the G-buffer layout more configurable, so that specular tints could be supported on an opt-in basis. As an alternative, Bevy could force meshes with specular tints to render in forward mode. Both of these solutions require some more design, so I consider them out of scope for now. Note that the map is a *specular* map, not a *reflectance* map. In Bevy and Filament terms, the reflectance values in the specular map range from [0.0, 0.5], rather than [0.0, 1.0]. This is an unfortunate [`KHR_materials_specular`] specification requirement that stems from the fact that glTF is specified in terms of a specular strength model, not the reflectance model that Filament and Bevy use. A workaround, which is noted in the `StandardMaterial` documentation, is to set the `reflectance` value to 2.0, which spreads the specular map range from [0.0, 1.0] as normal. The glTF loader has been updated to parse the [`KHR_materials_specular`] extension. Note that, unless the non-default `pbr_specular_textures` is supplied, the maps are ignored. The `specularFactor` value is applied as usual. Note that, as with the specular map, the glTF `specularFactor` is twice Bevy's `reflectance` value. This PR adds a new example, `specular_tint`, which demonstrates the specular tint and map features. Note that this example requires the [`KHR_materials_specular`] Cargo feature. [`KHR_materials_specular`]: https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Khronos/KHR_materials_specular ## Changelog ### Added * Specular highlights can now be tinted with the `specular_tint` field in `StandardMaterial`. * Specular maps are now available in `StandardMaterial`, gated behind the `pbr_specular_textures` Cargo feature. * The `KHR_materials_specular` glTF extension is now supported, allowing for customization of specular reflectance and specular maps. Note that the latter are gated behind the `pbr_specular_textures` Cargo feature. |
||
![]() |
fc831c390d
|
Implement basic clustered decal projectors. (#17315)
This commit adds support for *decal projectors* to Bevy, allowing for textures to be projected on top of geometry. Decal projectors are clusterable objects, just as punctual lights and light probes are. This means that decals are only evaluated for objects within the conservative bounds of the projector, and they don't require a second pass. These clustered decals require support for bindless textures and as such currently don't work on WebGL 2, WebGPU, macOS, or iOS. For an alternative that doesn't require bindless, see PR #16600. I believe that both contact projective decals in #16600 and clustered decals are desirable to have in Bevy. Contact projective decals offer broader hardware and driver support, while clustered decals don't require the creation of bounding geometry. A new example, `decal_projectors`, has been added, which demonstrates multiple decals on a rotating object. The decal projectors can be scaled and rotated with the mouse. There are several limitations of this initial patch that can be addressed in follow-ups: 1. There's no way to specify the Z-index of decals. That is, the order in which multiple decals are blended on top of one another is arbitrary. A follow-up could introduce some sort of Z-index field so that artists can specify that some decals should be blended on top of others. 2. Decals don't take the normal of the surface they're projected onto into account. Most decal implementations in other engines have a feature whereby the angle between the decal projector and the normal of the surface must be within some threshold for the decal to appear. Often, artists can specify a fade-off range for a smooth transition between oblique surfaces and aligned surfaces. 3. There's no distance-based fadeoff toward the end of the projector range. Many decal implementations have this. This addresses #2401. ## Showcase  |
||
![]() |
deb135c25c
|
Proportional scaling for the sprite's texture. (#17258)
# Objective Bevy sprite image mode lacks proportional scaling for the underlying texture. In many cases, it's required. For example, if it is desired to support a wide variety of screens with a single texture, it's okay to cut off some portion of the original texture. ## Solution I added scaling of the texture during the preparation step. To fill the sprite with the original texture, I scaled UV coordinates accordingly to the sprite size aspect ratio and texture size aspect ratio. To fit texture in a sprite the original `quad` is scaled and then the additional translation is applied to place the scaled quad properly. ## Testing For testing purposes could be used `2d/sprite_scale.rs`. Also, I am thinking that it would be nice to have some tests for a `crates/bevy_sprite/src/render/mod.rs:sprite_scale`. --- ## Showcase <img width="1392" alt="image" src="https://github.com/user-attachments/assets/c2c37b96-2493-4717-825f-7810d921b4bc" /> |
||
![]() |
af3a84fc0b
|
Add many_materials stress test (#17346)
# Objective - This PR adds a new stress test called `many_materials` to benchmark the rendering performance of many animated materials. - Fixes #11588 - This PR continues the work started in the previous PR #11592, which was closed due to inactivity. ## Solution - Created a new example (`examples/stress_tests/many_materials.rs`) that renders a grid of cubes with animated materials. - The size of the grid can be configured using the `-n` command-line argument (or `--grid-size`). The default grid size is 10x10. - The materials animate by cycling through colors in the HSL color space. ## Testing - I have tested these changes locally on my Linux machine. - Reviewers can test the changes by running the example with different grid sizes and observing the performance (FPS, frame time). - I have not tested on other platforms (macOS, Windows, wasm), but I expect it to work as the code uses standard Bevy features. --- ## Showcase <details> <summary>Click to view showcase</summary>  </details> |
||
![]() |
81a25bb0c7
|
Procedural atmospheric scattering (#16314)
Implement procedural atmospheric scattering from [Sebastien Hillaire's 2020 paper](https://sebh.github.io/publications/egsr2020.pdf). This approach should scale well even down to mobile hardware, and is physically accurate. ## Co-author: @mate-h He helped massively with getting this over the finish line, ensuring everything was physically correct, correcting several places where I had misunderstood or misapplied the paper, and improving the performance in several places as well. Thanks! ## Credits @aevyrie: helped find numerous bugs and improve the example to best show off this feature :) Built off of @mtsr's original branch, which handled the transmittance lut (arguably the most important part) ## Showcase:   ## For followup - Integrate with pcwalton's volumetrics code - refactor/reorganize for better integration with other effects - have atmosphere transmittance affect directional lights - add support for generating skybox/environment map --------- Co-authored-by: Emerson Coskey <56370779+EmersonCoskey@users.noreply.github.com> Co-authored-by: atlv <email@atlasdostal.com> Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com> Co-authored-by: Emerson Coskey <coskey@emerlabs.net> Co-authored-by: Máté Homolya <mate.homolya@gmail.com> |
||
![]() |
b34833f00c
|
Add an example teaching users about custom relationships (#17443)
# Objective After #17398, Bevy now has relations! We don't teach users how to make / work with these in the examples yet though, but we definitely should. ## Solution - Add a simple abstract example that goes over defining, spawning, traversing and removing a custom relations. - ~~Add `Relationship` and `RelationshipTarget` to the prelude: the trait methods are really helpful here.~~ - this causes subtle ambiguities with method names and weird compiler errors. Not doing it here! - Clean up related documentation that I referenced when writing this example. ## Testing `cargo run --example relationships` ## Notes to reviewers 1. Yes, I know that the cycle detection code could be more efficient. I decided to reduce the caching to avoid distracting from the broader point of "here's how you traverse relationships". 2. Instead of using an `App`, I've decide to use `World::run_system_once` + system functions defined inside of `main` to do something closer to literate programming. --------- Co-authored-by: Joona Aalto <jondolf.dev@gmail.com> Co-authored-by: MinerSebas <66798382+MinerSebas@users.noreply.github.com> Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com> |
||
![]() |
e8e2426058
|
Forward decals (port of bevy_contact_projective_decals) (#16600)
# Objective - Implement ForwardDecal as outlined in https://github.com/bevyengine/bevy/issues/2401 ## Solution - Port https://github.com/naasblod/bevy_contact_projective_decals, and cleanup the API a little. ## Testing - Ran the new decal example. --- ## Showcase  ## Changelog * Added ForwardDecal and associated types * Added MaterialExtension::alpha_mode() --------- Co-authored-by: IceSentry <IceSentry@users.noreply.github.com> |
||
![]() |
0756a19f28
|
Support texture atlases in CustomCursor::Image (#17121)
# Objective - Bevy 0.15 added support for custom cursor images in https://github.com/bevyengine/bevy/pull/14284. - However, to do animated cursors using the initial support shipped in 0.15 means you'd have to animate the `Handle<Image>`: You can't use a `TextureAtlas` like you can with sprites and UI images. - For my use case, my cursors are spritesheets. To animate them, I'd have to break them down into multiple `Image` assets, but that seems less than ideal. ## Solution - Allow users to specify a `TextureAtlas` field when creating a custom cursor image. - To create parity with Bevy's `TextureAtlas` support on `Sprite`s and `ImageNode`s, this also allows users to specify `rect`, `flip_x` and `flip_y`. In fact, for my own use case, I need to `flip_y`. ## Testing - I added unit tests for `calculate_effective_rect` and `extract_and_transform_rgba_pixels`. - I added a brand new example for custom cursor images. It has controls to toggle fields on and off. I opted to add a new example because the existing cursor example (`window_settings`) would be far too messy for showcasing these custom cursor features (I did start down that path but decided to stop and make a brand new example). - The new example uses a [Kenny cursor icon] sprite sheet. I included the licence even though it's not required (and it's CC0). - I decided to make the example just loop through all cursor icons for its animation even though it's not a _realistic_ in-game animation sequence. - I ran the PNG through https://tinypng.com. Looks like it's about 35KB. - I'm open to adjusting the example spritesheet if required, but if it's fine as is, great. [Kenny cursor icon]: https://kenney-assets.itch.io/crosshair-pack --- ## Showcase https://github.com/user-attachments/assets/8f6be8d7-d1d4-42f9-b769-ef8532367749 ## Migration Guide The `CustomCursor::Image` enum variant has some new fields. Update your code to set them. Before: ```rust CustomCursor::Image { handle: asset_server.load("branding/icon.png"), hotspot: (128, 128), } ``` After: ```rust CustomCursor::Image { handle: asset_server.load("branding/icon.png"), texture_atlas: None, flip_x: false, flip_y: false, rect: None, hotspot: (128, 128), } ``` ## References - Feature request [originally raised in Discord]. [originally raised in Discord]: https://discord.com/channels/691052431525675048/692572690833473578/1319836362219847681 |
||
![]() |
c96949dabe
|
Improve the animated_mesh example (#17328)
# Objective Building upon https://github.com/bevyengine/bevy/pull/17191, improve the `animated_mesh` example by removing code, adding comments, and making the example more c&p'able. ## Solution - Split the setup function in two to clarify what the example is demonstrating. - `setup_mesh_and_animation` is the demonstration. - `setup_camera_and_environment` just sets up the example app. - Changed the animation playing to use `AnimationPlayer` directly instead of creating `AnimationTransitions`. - This appears sufficient when only playing a single animation. - Added a comment pointing users to an example of multiple animations. - Changed the animation to be the run cycle. - I think it got accidentally changed to the idle in [#17191](https://github.com/bevyengine/bevy/pull/17191), so this is reverting back to the original. - Note that we can improve it to select the animation by name if [#16529](https://github.com/bevyengine/bevy/pull/16529) lands. - Renamed `FOX_PATH` to a more neutral `GLTF_PATH`. - Updated the example descriptions to mention the fox. - This adds a little character and hints that the example involves character animation. - Removed a seemingly redundant `AnimationGraphHandle` component. - Removed an unnecessary `clone()`. - Added various comments. ## Notes - A draft of this PR was discussed on Discord: https://discord.com/channels/691052431525675048/1326910663972618302/1326920498663133348 - There was discord discussion on whether a component is "inserted onto", "inserted into" or "added to" an entity. - "Added to" is most common in code and docs, and seems best to me. But it awkwardly differs from the name of `EntityCommands::insert`. - This PR prefers "added to". - I plan to follow up this PR with similar changes to the `animated_mesh_control` and `animated_mesh_events` examples. - But I could roll them into this PR if requested. ## Testing `cargo run --example animated_mesh` --------- Co-authored-by: François Mockers <mockersf@gmail.com> |
||
![]() |
b77e3ef33a
|
Fix a few typos (#17292)
# Objective Stumbled upon a `from <-> form` transposition while reviewing a PR, thought it was interesting, and went down a bit of a rabbit hole. ## Solution Fix em |
||
![]() |
145f5f4394
|
Add a simple directional UI navigation example (#17224)
# Objective Gamepad / directional navigation needs an example, for both teaching and testing purposes. ## Solution - Add a simple grid-based example. - Fix an intermittent panic caused by a race condition with bevy_a11y - Clean up small issues noticed in bevy_input_focus  ## To do: this PR - [x] figure out why "enter" isn't doing anything - [x] change button color on interaction rather than printing - [x] add on-screen directions - [x] move to an asymmetric grid to catch bugs - [x] ~~fix colors not resetting on button press~~ lol this is mostly just a problem with hacking `Interaction` for this - [x] swap to using observers + bubbling, rather than `Interaction` ## To do: future work - when I increase the button size, such that there is no line break, the text on the buttons is no longer centered :( EDIT: this is https://github.com/bevyengine/bevy/issues/16783 - add gamepad stick navigation - add tools to find the nearest populated quadrant to make diagonal inputs work - add a `add_edges` method to `DirectionalNavigationMap` - add a `add_grid` method to `DirectionalNavigationMap` - make the example's layout more complex and realistic - add tools to automatically generate this list - add button shake on failed navigation rather than printing an error - make Pressed events easier to mock: default fields, PointerId::Focus ## Testing `cargo run --example directional_navigation` --------- Co-authored-by: Rob Parrett <robparrett@gmail.com> |
||
![]() |
6462935b32
|
Rename animated fox examples to better communicate their purpose (#17239)
Fixes #17192. Replaces "animated_fox" with "animated_mesh". I considered a few different names - should it say "skinned_mesh" to be precise? Should it mention gltf? But "animated_mesh" seems intuitive and keeps it short. ## Testing - Ran all three examples (Windows 10). |
||
![]() |
5faff84c10
|
Upstream DebugPickingPlugin from bevy_mod_picking (#17177)
# Objective The debug features (`DebugPickingPlugin`) from `bevy_mod_picking` were not upstreamed with the rest of the core changes, this PR reintroduces it for usage inside `bevy_dev_tools` ## Solution Vast majority of this code is taken as-is from `bevy_mod_picking` aside from changes to ensure compilation and code style, as such @aevyrie was added as the co-author for this change. ### Main changes * `multiselection` support - the relevant code was explicitly not included in the process of upstreaming the rest of the package, so it also has been omitted here. * `bevy_egui` support - the old package had a preference for using `bevy_egui` instead of `bevy_ui` if possible, I couldn't see a way to support this in a core crate, so this has been removed. Relevant code has been added to the `bevy_dev_tools` crate instead of `bevy_picking` as it is a better fit and requires a dependency on `bevy_ui` for drawing debug elements. ### Minor changes * Changed the debug text size from `60` to `12` as the former was so large as to be unreadable in the new example. ## Testing * `cargo run -p ci` * Added a new example in `dev_tools/picking_debug` and visually verified the in-window results and the console messages --------- Co-authored-by: Aevyrie <aevyrie@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
6f68776eac
|
Split up animated_fox example (#17191)
# Objective Our `animated_fox` example used to be a bare-bones example of how to spawn an animated gltf and play a single animation. I think that's a valuable example, and the current `animated_fox` example is doing way too much. Users who are trying to understand how our animation system are presented with an enormous amount of information that may not be immediately relevant. Over the past few releases, I've been migrating a simple app of mine where the only animation I need is a single gltf that starts playing a single animation when it is loaded. It has been a slight struggle to wade through changes to the animation system to figure out the minimal amount of things required to accomplish this. Somewhat motivated by this [recent reddit thread](https://www.reddit.com/r/rust/comments/1ht93vl/comment/m5c0nc9/?utm_source=share&utm_medium=mweb3x&utm_name=mweb3xcss&utm_term=1) where Bevy and animation got a mention. ## Solution - Split `animated_fox` into three separate examples - `animated_fox` - Loads and immediately plays a single animation - `animated_fox_control` - Shows how to control animations - `animated_fox_events` - Shows fancy particles when the fox's feet hit the ground - Some minor drive-by tidying of these examples I have created this PR after playing around with the idea and liking how it turned out, but the duplication isn't totally ideal and there's some slight overlap with other examples and inconsistencies: - `animation_events` is simplified and not specific to "loaded animated scenes" and seems valuable on its own - `animation_graph` also uses a fox I am happy to close this if there's no consensus that it's a good idea / step forward for these examples. ## Testing `cargo run --example animated_fox` `cargo run --example animated_fox_control` `cargo run --example animated_fox_events` |
||
![]() |
bed9ddf3ce
|
Refactor and simplify custom projections (#17063)
# Objective - Fixes https://github.com/bevyengine/bevy/issues/16556 - Closes https://github.com/bevyengine/bevy/issues/11807 ## Solution - Simplify custom projections by using a single source of truth - `Projection`, removing all existing generic systems and types. - Existing perspective and orthographic structs are no longer components - I could dissolve these to simplify further, but keeping them around was the fast way to implement this. - Instead of generics, introduce a third variant, with a trait object. - Do an object safety dance with an intermediate trait to allow cloning boxed camera projections. This is a normal rust polymorphism papercut. You can do this with a crate but a manual impl is short and sweet. ## Testing - Added a custom projection example --- ## Showcase - Custom projections and projection handling has been simplified. - Projection systems are no longer generic, with the potential for many different projection components on the same camera. - Instead `Projection` is now the single source of truth for camera projections, and is the only projection component. - Custom projections are still supported, and can be constructed with `Projection::custom()`. ## Migration Guide - `PerspectiveProjection` and `OrthographicProjection` are no longer components. Use `Projection` instead. - Custom projections should no longer be inserted as a component. Instead, simply set the custom projection as a value of `Projection` with `Projection::custom()`. |
||
![]() |
ad9f946201
|
Add many_text2d stress test (#16997)
# Objective Make it easier to test for `Text2d` performance regressions. Related to #16972 ## Solution Add a new `stress_test`, based on `many_sprites` and other existing stress tests. The `many-glyphs` option is inspired by https://github.com/bevyengine/bevy/issues/16901#issuecomment-2558572382. ## Testing ```bash cargo run --release --example many_text2d -- --help cargo run --release --example many_text2d cargo run --release --example many_text2d -- --many_glyphs ``` etc |
||
![]() |
5c67cfc8b7
|
Tab navigation framework for bevy_input_focus. (#16795)
# Objective This PR continues the work of `bevy_input_focus` by adding a pluggable tab navigation framework. As part of this work, `FocusKeyboardEvent` now propagates to the window after exhausting all ancestors. ## Testing Unit tests and manual tests. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> |
||
![]() |
bf3692a011
|
Introduce support for mixed lighting by allowing lights to opt out of contributing diffuse light to lightmapped objects. (#16761)
This PR adds support for *mixed lighting* to Bevy, whereby some parts of the scene are lightmapped, while others take part in real-time lighting. (Here *real-time lighting* means lighting at runtime via the PBR shader, as opposed to precomputed light using lightmaps.) It does so by adding a new field, `affects_lightmapped_meshes` to `IrradianceVolume` and `AmbientLight`, and a corresponding field `affects_lightmapped_mesh_diffuse` to `DirectionalLight`, `PointLight`, `SpotLight`, and `EnvironmentMapLight`. By default, this value is set to true; when set to false, the light contributes nothing to the diffuse irradiance component to meshes with lightmaps. Note that specular light is unaffected. This is because the correct way to bake specular lighting is *directional lightmaps*, which we have no support for yet. There are two general ways I expect this field to be used: 1. When diffuse indirect light is baked into lightmaps, irradiance volumes and reflection probes shouldn't contribute any diffuse light to the static geometry that has a lightmap. That's because the baking tool should have already accounted for it, and in a higher-quality fashion, as lightmaps typically offer a higher effective texture resolution than the light probe does. 2. When direct diffuse light is baked into a lightmap, punctual lights shouldn't contribute any diffuse light to static geometry with a lightmap, to avoid double-counting. It may seem odd to bake *direct* light into a lightmap, as opposed to indirect light. But there is a use case: in a scene with many lights, avoiding light leaks requires shadow mapping, which quickly becomes prohibitive when many lights are involved. Baking lightmaps allows light leaks to be eliminated on static geometry. A new example, `mixed_lighting`, has been added. It demonstrates a sofa (model from the [glTF Sample Assets]) that has been lightmapped offline using [Bakery]. It has four modes: 1. In *baked* mode, all objects are locked in place, and all the diffuse direct and indirect light has been calculated ahead of time. Note that the bottom of the sphere has a red tint from the sofa, illustrating that the baking tool captured indirect light for it. 2. In *mixed direct* mode, lightmaps capturing diffuse direct and indirect light have been pre-calculated for the static objects, but the dynamic sphere has real-time lighting. Note that, because the diffuse lighting has been entirely pre-calculated for the scenery, the dynamic sphere casts no shadow. In a real app, you would typically use real-time lighting for the most important light so that dynamic objects can shadow the scenery and relegate baked lighting to the less important lights for which shadows aren't as important. Also note that there is no red tint on the sphere, because there is no global illumination applied to it. In an actual game, you could fix this problem by supplementing the lightmapped objects with an irradiance volume. 3. In *mixed indirect* mode, all direct light is calculated in real-time, and the static objects have pre-calculated indirect lighting. This corresponds to the mode that most applications are expected to use. Because direct light on the scenery is computed dynamically, shadows are fully supported. As in mixed direct mode, there is no global illumination on the sphere; in a real application, irradiance volumes could be used to supplement the lightmaps. 4. In *real-time* mode, no lightmaps are used at all, and all punctual lights are rendered in real-time. No global illumination exists. In the example, you can click around to move the sphere, unless you're in baked mode, in which case the sphere must be locked in place to be lit correctly. ## Showcase Baked mode:  Mixed direct mode:  Mixed indirect mode (default):  Real-time mode:  ## Migration guide * The `AmbientLight` resource, the `IrradianceVolume` component, and the `EnvironmentMapLight` component now have `affects_lightmapped_meshes` fields. If you don't need to use that field (for example, if you aren't using lightmaps), you can safely set the field to true. * `DirectionalLight`, `PointLight`, and `SpotLight` now have `affects_lightmapped_mesh_diffuse` fields. If you don't need to use that field (for example, if you aren't using lightmaps), you can safely set the field to true. [glTF Sample Assets]: https://github.com/KhronosGroup/glTF-Sample-Assets/tree/main [Bakery]: https://geom.io/bakery/wiki/index.php?title=Bakery_-_GPU_Lightmapper |
||
![]() |
1f884de53c
|
Added stress test for large ecs worlds (#16591)
# Objective We currently have no benchmarks for large worlds with many entities, components and systems. Having a benchmark for a world with many components is especially useful for the performance improvements needed for relations. This is also a response to this [comment from cart](https://github.com/bevyengine/bevy/pull/14385#issuecomment-2311292546). > I'd like both a small bevy_ecs-scoped executor benchmark that generates thousands of components used by hundreds of systems. ## Solution I use dynamic components and components to construct a benchmark with 2000 components, 4000 systems, and 10000 entities. ## Some notes - ~I use a lot of random entities, which creates unpredictable performance, I should use a seeded PRNG.~ - Not entirely sure if everything is ran concurrently currently. And there are many conflicts, meaning there's probably a lot of first-come-first-serve going on. Not entirely sure if these benchmarks are very reproducible. - Maybe add some more safety comments - Also component_reads_and_writes() is about to be deprecated #16339, but there's no other way to currently do what I'm trying to do. --------- Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com> Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com> |
||
![]() |
0707c0717b
|
✏️ Fix typos across bevy (#16702)
# Objective Fixes typos in bevy project, following suggestion in https://github.com/bevyengine/bevy-website/pull/1912#pullrequestreview-2483499337 ## Solution I used https://github.com/crate-ci/typos to find them. I included only the ones that feel undebatable too me, but I am not in game engine so maybe some terms are expected. I left out the following typos: - `reparametrize` => `reparameterize`: There are a lot of occurences, I believe this was expected - `semicircles` => `hemicircles`: 2 occurences, may mean something specific in geometry - `invertation` => `inversion`: may mean something specific - `unparented` => `parentless`: may mean something specific - `metalness` => `metallicity`: may mean something specific ## Testing - Did you test these changes? If so, how? I did not test the changes, most changes are related to raw text. I expect the others to be tested by the CI. - Are there any parts that need more testing? I do not think - How can other people (reviewers) test your changes? Is there anything specific they need to know? To me there is nothing to test - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? --- ## Migration Guide > This section is optional. If there are no breaking changes, you can delete this section. (kept in case I include the `reparameterize` change here) - If this PR is a breaking change (relative to the last release of Bevy), describe how a user might need to migrate their code to support these changes - Simply adding new functionality is not a breaking change. - Fixing behavior that was definitely a bug, rather than a questionable design choice is not a breaking change. ## Questions - [x] Should I include the above typos? No (https://github.com/bevyengine/bevy/pull/16702#issuecomment-2525271152) - [ ] Should I add `typos` to the CI? (I will check how to configure it properly) This project looks awesome, I really enjoy reading the progress made, thanks to everyone involved. |
||
![]() |
0070514f54
|
Fallible systems (#16589)
# Objective Error handling in bevy is hard. See for reference https://github.com/bevyengine/bevy/issues/11562, https://github.com/bevyengine/bevy/issues/10874 and https://github.com/bevyengine/bevy/issues/12660. The goal of this PR is to make it better, by allowing users to optionally return `Result` from systems as outlined by Cart in <https://github.com/bevyengine/bevy/issues/14275#issuecomment-2223708314>. ## Solution This PR introduces a new `ScheuleSystem` type to represent systems that can be added to schedules. Instances of this type contain either an infallible `BoxedSystem<(), ()>` or a fallible `BoxedSystem<(), Result>`. `ScheuleSystem` implements `System<In = (), Out = Result>` and replaces all uses of `BoxedSystem` in schedules. The async executor now receives a result after executing a system, which for infallible systems is always `Ok(())`. Currently it ignores this result, but more useful error handling could also be implemented. Aliases for `Error` and `Result` have been added to the `bevy_ecs` prelude, as well as const `OK` which new users may find more friendly than `Ok(())`. ## Testing - Currently there are not actual semantics changes that really require new tests, but I added a basic one just to make sure we don't break stuff in the future. - The behavior of existing systems is totally unchanged, including logging. - All of the existing systems tests pass, and I have not noticed anything strange while playing with the examples ## Showcase The following minimal example prints "hello world" once, then completes. ```rust use bevy::prelude::*; fn main() { App::new().add_systems(Update, hello_world_system).run(); } fn hello_world_system() -> Result { println!("hello world"); Err("string")?; println!("goodbye world"); OK } ``` ## Migration Guide This change should be pretty much non-breaking, except for users who have implemented their own custom executors. Those users should use `ScheduleSystem` in place of `BoxedSystem<(), ()>` and import the `System` trait where needed. They can choose to do whatever they wish with the result. ## Current Work + [x] Fix tests & doc comments + [x] Write more tests + [x] Add examples + [X] Draft release notes ## Draft Release Notes As of this release, systems can now return results. First a bit of background: Bevy has hisotrically expected systems to return the empty type `()`. While this makes sense in the context of the ecs, it's at odds with how error handling is typically done in rust: returning `Result::Error` to indicate failure, and using the short-circuiting `?` operator to propagate that error up the call stack to where it can be properly handled. Users of functional languages will tell you this is called "monadic error handling". Not being able to return `Results` from systems left bevy users with a quandry. They could add custom error handling logic to every system, or manually pipe every system into an error handler, or perhaps sidestep the issue with some combination of fallible assignents, logging, macros, and early returns. Often, users would just litter their systems with unwraps and possible panics. While any one of these approaches might be fine for a particular user, each of them has their own drawbacks, and none makes good use of the language. Serious issues could also arrise when two different crates used by the same project made different choices about error handling. Now, by returning results, systems can defer error handling to the application itself. It looks like this: ```rust // Previous, handling internally app.add_systems(my_system) fn my_system(window: Query<&Window>) { let Ok(window) = query.get_single() else { return; }; // ... do something to the window here } // Previous, handling externally app.add_systems(my_system.pipe(my_error_handler)) fn my_system(window: Query<&Window>) -> Result<(), impl Error> { let window = query.get_single()?; // ... do something to the window here Ok(()) } // Previous, panicking app.add_systems(my_system) fn my_system(window: Query<&Window>) { let window = query.single(); // ... do something to the window here } // Now app.add_systems(my_system) fn my_system(window: Query<&Window>) -> Result { let window = query.get_single()?; // ... do something to the window here Ok(()) } ``` There are currently some limitations. Systems must either return `()` or `Result<(), Box<dyn Error + Send + Sync + 'static>>`, with no in-between. Results are also ignored by default, and though implementing a custom handler is possible, it involves writing your own custom ecs executor (which is *not* recomended). Systems should return errors when they cannot perform their normal behavior. In turn, errors returned to the executor while running the schedule will (eventually) be treated as unexpected. Users and library authors should prefer to return errors for anything that disrupts the normal expected behavior of a system, and should only handle expected cases internally. We have big plans for improving error handling further: + Allowing users to change the error handling logic of the default executors. + Adding source tracking and optional backtraces to errors. + Possibly adding tracing-levels (Error/Warn/Info/Debug/Trace) to errors. + Generally making the default error logging more helpful and inteligent. + Adding monadic system combininators for fallible systems. + Possibly removing all panicking variants from our api. --------- Co-authored-by: Zachary Harrold <zac@harrold.com.au> |
||
![]() |
a35811d088
|
Add Immutable Component Support (#16372)
# Objective - Fixes #16208 ## Solution - Added an associated type to `Component`, `Mutability`, which flags whether a component is mutable, or immutable. If `Mutability= Mutable`, the component is mutable. If `Mutability= Immutable`, the component is immutable. - Updated `derive_component` to default to mutable unless an `#[component(immutable)]` attribute is added. - Updated `ReflectComponent` to check if a component is mutable and, if not, panic when attempting to mutate. ## Testing - CI - `immutable_components` example. --- ## Showcase Users can now mark a component as `#[component(immutable)]` to prevent safe mutation of a component while it is attached to an entity: ```rust #[derive(Component)] #[component(immutable)] struct Foo { // ... } ``` This prevents creating an exclusive reference to the component while it is attached to an entity. This is particularly powerful when combined with component hooks, as you can now fully track a component's value, ensuring whatever invariants you desire are upheld. Before this would be done my making a component private, and manually creating a `QueryData` implementation which only permitted read access. <details> <summary>Using immutable components as an index</summary> ```rust /// This is an example of a component like [`Name`](bevy::prelude::Name), but immutable. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Component)] #[component( immutable, on_insert = on_insert_name, on_replace = on_replace_name, )] pub struct Name(pub &'static str); /// This index allows for O(1) lookups of an [`Entity`] by its [`Name`]. #[derive(Resource, Default)] struct NameIndex { name_to_entity: HashMap<Name, Entity>, } impl NameIndex { fn get_entity(&self, name: &'static str) -> Option<Entity> { self.name_to_entity.get(&Name(name)).copied() } } fn on_insert_name(mut world: DeferredWorld<'_>, entity: Entity, _component: ComponentId) { let Some(&name) = world.entity(entity).get::<Name>() else { unreachable!() }; let Some(mut index) = world.get_resource_mut::<NameIndex>() else { return; }; index.name_to_entity.insert(name, entity); } fn on_replace_name(mut world: DeferredWorld<'_>, entity: Entity, _component: ComponentId) { let Some(&name) = world.entity(entity).get::<Name>() else { unreachable!() }; let Some(mut index) = world.get_resource_mut::<NameIndex>() else { return; }; index.name_to_entity.remove(&name); } // Setup our name index world.init_resource::<NameIndex>(); // Spawn some entities! let alyssa = world.spawn(Name("Alyssa")).id(); let javier = world.spawn(Name("Javier")).id(); // Check our index let index = world.resource::<NameIndex>(); assert_eq!(index.get_entity("Alyssa"), Some(alyssa)); assert_eq!(index.get_entity("Javier"), Some(javier)); // Changing the name of an entity is also fully capture by our index world.entity_mut(javier).insert(Name("Steven")); // Javier changed their name to Steven let steven = javier; // Check our index let index = world.resource::<NameIndex>(); assert_eq!(index.get_entity("Javier"), None); assert_eq!(index.get_entity("Steven"), Some(steven)); ``` </details> Additionally, users can use `Component<Mutability = ...>` in trait bounds to enforce that a component _is_ mutable or _is_ immutable. When using `Component` as a trait bound without specifying `Mutability`, any component is applicable. However, methods which only work on mutable or immutable components are unavailable, since the compiler must be pessimistic about the type. ## Migration Guide - When implementing `Component` manually, you must now provide a type for `Mutability`. The type `Mutable` provides equivalent behaviour to earlier versions of `Component`: ```rust impl Component for Foo { type Mutability = Mutable; // ... } ``` - When working with generic components, you may need to specify that your generic parameter implements `Component<Mutability = Mutable>` rather than `Component` if you require mutable access to said component. - The entity entry API has had to have some changes made to minimise friction when working with immutable components. Methods which previously returned a `Mut<T>` will now typically return an `OccupiedEntry<T>` instead, requiring you to add an `into_mut()` to get the `Mut<T>` item again. ## Draft Release Notes Components can now be made immutable while stored within the ECS. Components are the fundamental unit of data within an ECS, and Bevy provides a number of ways to work with them that align with Rust's rules around ownership and borrowing. One part of this is hooks, which allow for defining custom behavior at key points in a component's lifecycle, such as addition and removal. However, there is currently no way to respond to _mutation_ of a component using hooks. The reasons for this are quite technical, but to summarize, their addition poses a significant challenge to Bevy's core promises around performance. Without mutation hooks, it's relatively trivial to modify a component in such a way that breaks invariants it intends to uphold. For example, you can use `core::mem::swap` to swap the components of two entities, bypassing the insertion and removal hooks. This means the only way to react to this modification is via change detection in a system, which then begs the question of what happens _between_ that alteration and the next run of that system? Alternatively, you could make your component private to prevent mutation, but now you need to provide commands and a custom `QueryData` implementation to allow users to interact with your component at all. Immutable components solve this problem by preventing the creation of an exclusive reference to the component entirely. Without an exclusive reference, the only way to modify an immutable component is via removal or replacement, which is fully captured by component hooks. To make a component immutable, simply add `#[component(immutable)]`: ```rust #[derive(Component)] #[component(immutable)] struct Foo { // ... } ``` When implementing `Component` manually, there is an associated type `Mutability` which controls this behavior: ```rust impl Component for Foo { type Mutability = Mutable; // ... } ``` Note that this means when working with generic components, you may need to specify that a component is mutable to gain access to certain methods: ```rust // Before fn bar<C: Component>() { // ... } // After fn bar<C: Component<Mutability = Mutable>>() { // ... } ``` With this new tool, creating index components, or caching data on an entity should be more user friendly, allowing libraries to provide APIs relying on components and hooks to uphold their invariants. ## Notes - ~~I've done my best to implement this feature, but I'm not happy with how reflection has turned out. If any reflection SMEs know a way to improve this situation I'd greatly appreciate it.~~ There is an outstanding issue around the fallibility of mutable methods on `ReflectComponent`, but the DX is largely unchanged from `main` now. - I've attempted to prevent all safe mutable access to a component that does not implement `Component<Mutability = Mutable>`, but there may still be some methods I have missed. Please indicate so and I will address them, as they are bugs. - Unsafe is an escape hatch I am _not_ attempting to prevent. Whatever you do with unsafe is between you and your compiler. - I am marking this PR as ready, but I suspect it will undergo fairly major revisions based on SME feedback. - I've marked this PR as _Uncontroversial_ based on the feature, not the implementation. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com> Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com> Co-authored-by: Nuutti Kotivuori <naked@iki.fi> |
||
![]() |
5adf831b42
|
Add a bindless mode to AsBindGroup . (#16368)
This patch adds the infrastructure necessary for Bevy to support *bindless resources*, by adding a new `#[bindless]` attribute to `AsBindGroup`. Classically, only a single texture (or sampler, or buffer) can be attached to each shader binding. This means that switching materials requires breaking a batch and issuing a new drawcall, even if the mesh is otherwise identical. This adds significant overhead not only in the driver but also in `wgpu`, as switching bind groups increases the amount of validation work that `wgpu` must do. *Bindless resources* are the typical solution to this problem. Instead of switching bindings between each texture, the renderer instead supplies a large *array* of all textures in the scene up front, and the material contains an index into that array. This pattern is repeated for buffers and samplers as well. The renderer now no longer needs to switch binding descriptor sets while drawing the scene. Unfortunately, as things currently stand, this approach won't quite work for Bevy. Two aspects of `wgpu` conspire to make this ideal approach unacceptably slow: 1. In the DX12 backend, all binding arrays (bindless resources) must have a constant size declared in the shader, and all textures in an array must be bound to actual textures. Changing the size requires a recompile. 2. Changing even one texture incurs revalidation of all textures, a process that takes time that's linear in the total size of the binding array. This means that declaring a large array of textures big enough to encompass the entire scene is presently unacceptably slow. For example, if you declare 4096 textures, then `wgpu` will have to revalidate all 4096 textures if even a single one changes. This process can take multiple frames. To work around this problem, this PR groups bindless resources into small *slabs* and maintains a free list for each. The size of each slab for the bindless arrays associated with a material is specified via the `#[bindless(N)]` attribute. For instance, consider the following declaration: ```rust #[derive(AsBindGroup)] #[bindless(16)] struct MyMaterial { #[buffer(0)] color: Vec4, #[texture(1)] #[sampler(2)] diffuse: Handle<Image>, } ``` The `#[bindless(N)]` attribute specifies that, if bindless arrays are supported on the current platform, each resource becomes a binding array of N instances of that resource. So, for `MyMaterial` above, the `color` attribute is exposed to the shader as `binding_array<vec4<f32>, 16>`, the `diffuse` texture is exposed to the shader as `binding_array<texture_2d<f32>, 16>`, and the `diffuse` sampler is exposed to the shader as `binding_array<sampler, 16>`. Inside the material's vertex and fragment shaders, the applicable index is available via the `material_bind_group_slot` field of the `Mesh` structure. So, for instance, you can access the current color like so: ```wgsl // `uniform` binding arrays are a non-sequitur, so `uniform` is automatically promoted // to `storage` in bindless mode. @group(2) @binding(0) var<storage> material_color: binding_array<Color, 4>; ... @fragment fn fragment(in: VertexOutput) -> @location(0) vec4<f32> { let color = material_color[mesh[in.instance_index].material_bind_group_slot]; ... } ``` Note that portable shader code can't guarantee that the current platform supports bindless textures. Indeed, bindless mode is only available in Vulkan and DX12. The `BINDLESS` shader definition is available for your use to determine whether you're on a bindless platform or not. Thus a portable version of the shader above would look like: ```wgsl #ifdef BINDLESS @group(2) @binding(0) var<storage> material_color: binding_array<Color, 4>; #else // BINDLESS @group(2) @binding(0) var<uniform> material_color: Color; #endif // BINDLESS ... @fragment fn fragment(in: VertexOutput) -> @location(0) vec4<f32> { #ifdef BINDLESS let color = material_color[mesh[in.instance_index].material_bind_group_slot]; #else // BINDLESS let color = material_color; #endif // BINDLESS ... } ``` Importantly, this PR *doesn't* update `StandardMaterial` to be bindless. So, for example, `scene_viewer` will currently not run any faster. I intend to update `StandardMaterial` to use bindless mode in a follow-up patch. A new example, `shaders/shader_material_bindless`, has been added to demonstrate how to use this new feature. Here's a Tracy profile of `submit_graph_commands` of this patch and an additional patch (not submitted yet) that makes `StandardMaterial` use bindless. Red is those patches; yellow is `main`. The scene was Bistro Exterior with a hack that forces all textures to opaque. You can see a 1.47x mean speedup.  ## Migration Guide * `RenderAssets::prepare_asset` now takes an `AssetId` parameter. * Bin keys now have Bevy-specific material bind group indices instead of `wgpu` material bind group IDs, as part of the bindless change. Use the new `MaterialBindGroupAllocator` to map from bind group index to bind group ID. |
||
![]() |
bb81a2cdb3
|
Simple integration testing (adopted) (#16489)
# Objective This older PR from `Wcubed` seemed well worth saving, adopted from #7314. See also tracking issue #2896 for ongoing discussion of Bevy testability. Thanks `Wcubed`! ## Solution - Updated for 0.15 - Added the `expected`/`actual` pattern - Switched to function plugin - Tweaked a bit of description ## Testing Green. --------- Co-authored-by: Wybe Westra <dev@wwestra.nl> Co-authored-by: Wybe Westra <wybe.westra@protonmail.com> |
||
![]() |
ef23f465ce
|
Do not re-check visibility or re-render shadow maps for point and spot lights for each view (#15156)
# Objective _If I understand it correctly_, we were checking mesh visibility, as well as re-rendering point and spot light shadow maps for each view. This makes it so that M views and N lights produce M x N complexity. This PR aims to fix that, as well as introduce a stress test for this specific scenario. ## Solution - Keep track of what lights have already had mesh visibility calculated and do not calculate it again; - Reuse shadow depth textures and attachments across all views, and only render shadow maps for the _first_ time a light is encountered on a view; - Directional lights remain unaltered, since their shadow map cascades are view-dependent; - Add a new `many_cameras_lights` stress test example to verify the solution ## Showcase 110% speed up on the stress test 83% reduction of memory usage in stress test ### Before (5.35 FPS on stress test) <img width="1392" alt="Screenshot 2024-09-11 at 12 25 57" src="https://github.com/user-attachments/assets/136b0785-e9a4-44df-9a22-f99cc465e126"> ### After (11.34 FPS on stress test) <img width="1392" alt="Screenshot 2024-09-11 at 12 24 35" src="https://github.com/user-attachments/assets/b8dd858f-5e19-467f-8344-2b46ca039630"> ## Testing - Did you test these changes? If so, how? - On my game project where I have two cameras, and many shadow casting lights I managed to get pretty much double the FPS. - Also included a stress test, see the comparison above - Are there any parts that need more testing? - Yes, I would like help verifying that this fix is indeed correct, and that we were really re-rendering the shadow maps by mistake and it's indeed okay to not do that - How can other people (reviewers) test your changes? Is there anything specific they need to know? - Run the `many_cameras_lights` example - On the `main` branch, cherry pick the commit with the example (`git cherry-pick --no-commit 1ed4ace01`) and run it - If relevant, what platforms did you test these changes on, and are there any important ones you can't test? - macOS --------- Co-authored-by: François Mockers <francois.mockers@vleue.com> |
||
![]() |
cdc18ee886
|
Move UI example to testbed (#16241)
# Objective UI example is quite extensive, probably not the best teaching example anymore. Closes #16230. |
||
![]() |
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]( |
||
![]() |
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. |
||
![]() |
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> |
||
![]() |
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> |
||
![]() |
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> |
||
![]() |
d0edbdac78
|
Fix cargo-ndk build command (#15648)
# Objective - Fix cargo-ndk build command documentation in readme. ```sh ❯ cargo ndk -t arm64-v8a build -o android_example/app/src/main/jniLibs Building arm64-v8a (aarch64-linux-android) error: unexpected argument '-o' found ``` ## Solution - Move "build" to the end of the command. ## Testing - With the new command order building works. ```sh ❯ cargo ndk -t arm64-v8a -o android_example/app/src/main/jniLibs build Building arm64-v8a (aarch64-linux-android) Compiling bevy_ptr v0.15.0-dev (/home/eero/repos/bevy/crates/bevy_ptr) Compiling bevy_macro_utils v0.15.0-dev (/home/eero/repos/bevy/crates/bevy_macro_utils) Compiling event-listener v5.3.1 ... rest of compilation ... ``` |
||
![]() |
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> |