diff --git a/content/news/2023-07-09-bevy-0.11/2d_gizmos.png b/content/news/2023-07-09-bevy-0.11/2d_gizmos.png new file mode 100644 index 0000000000..f4434f1a86 Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/2d_gizmos.png differ diff --git a/content/news/2023-07-09-bevy-0.11/3d_gizmos.png b/content/news/2023-07-09-bevy-0.11/3d_gizmos.png new file mode 100644 index 0000000000..424e31021f Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/3d_gizmos.png differ diff --git a/content/news/2023-07-09-bevy-0.11/aa.png b/content/news/2023-07-09-bevy-0.11/aa.png new file mode 100644 index 0000000000..25d10d736d Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/aa.png differ diff --git a/content/news/2023-07-09-bevy-0.11/border-sides.png b/content/news/2023-07-09-bevy-0.11/border-sides.png new file mode 100644 index 0000000000..851f062b80 Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/border-sides.png differ diff --git a/content/news/2023-07-09-bevy-0.11/borders.png b/content/news/2023-07-09-bevy-0.11/borders.png new file mode 100644 index 0000000000..b0f8e28afe Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/borders.png differ diff --git a/content/news/2023-07-09-bevy-0.11/codespan.png b/content/news/2023-07-09-bevy-0.11/codespan.png new file mode 100644 index 0000000000..d108193cbe Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/codespan.png differ diff --git a/content/news/2023-07-09-bevy-0.11/cubic_curve.png b/content/news/2023-07-09-bevy-0.11/cubic_curve.png new file mode 100644 index 0000000000..73fc32f916 Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/cubic_curve.png differ diff --git a/content/news/2023-07-09-bevy-0.11/custom_vertex.png b/content/news/2023-07-09-bevy-0.11/custom_vertex.png new file mode 100644 index 0000000000..a1fed4cb43 Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/custom_vertex.png differ diff --git a/content/news/2023-07-09-bevy-0.11/default-pose-bw.png b/content/news/2023-07-09-bevy-0.11/default-pose-bw.png new file mode 100644 index 0000000000..7f8339ac0d Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/default-pose-bw.png differ diff --git a/content/news/2023-07-09-bevy-0.11/default_font.png b/content/news/2023-07-09-bevy-0.11/default_font.png new file mode 100644 index 0000000000..3e55c9f71c Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/default_font.png differ diff --git a/content/news/2023-07-09-bevy-0.11/display_and_visibility.png b/content/news/2023-07-09-bevy-0.11/display_and_visibility.png new file mode 100644 index 0000000000..97d70f375e Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/display_and_visibility.png differ diff --git a/content/news/2023-07-09-bevy-0.11/earth-parallax.webm b/content/news/2023-07-09-bevy-0.11/earth-parallax.webm new file mode 100644 index 0000000000..2c6a3f6dd0 Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/earth-parallax.webm differ diff --git a/content/news/2023-07-09-bevy-0.11/frown-pose-bw.png b/content/news/2023-07-09-bevy-0.11/frown-pose-bw.png new file mode 100644 index 0000000000..ab5585ffb4 Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/frown-pose-bw.png differ diff --git a/content/news/2023-07-09-bevy-0.11/grid.png b/content/news/2023-07-09-bevy-0.11/grid.png new file mode 100644 index 0000000000..bf3db61e32 Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/grid.png differ diff --git a/content/news/2023-07-09-bevy-0.11/imported_items.png b/content/news/2023-07-09-bevy-0.11/imported_items.png new file mode 100644 index 0000000000..448bbff18d Binary files /dev/null and b/content/news/2023-07-09-bevy-0.11/imported_items.png differ diff --git a/content/news/2023-07-09-bevy-0.11/index.md b/content/news/2023-07-09-bevy-0.11/index.md new file mode 100644 index 0000000000..6665b60fa8 --- /dev/null +++ b/content/news/2023-07-09-bevy-0.11/index.md @@ -0,0 +1,2149 @@ ++++ +title = "Bevy 0.11" +date = 2023-07-09 +[extra] +author = "Bevy Contributors" +image = "with_ssao.png" +show_image = true ++++ + +Thanks to **166** contributors, **522** pull requests, community reviewers, and our [**generous sponsors**](/community/donate), we're happy to announce the **Bevy 0.11** release on [crates.io](https://crates.io/crates/bevy)! + +For those who don't know, Bevy is a refreshingly simple data-driven game engine built in Rust. You can check out our [Quick Start Guide](/learn/book/getting-started/) to try it today. It's free and open source forever! You can grab the full [source code](https://github.com/bevyengine/bevy) on GitHub. Check out [Bevy Assets](https://bevyengine.org/assets) for a collection of community-developed plugins, games, and learning resources. + +To update an existing Bevy App or Plugin to **Bevy 0.11**, check out our [0.10 to 0.11 Migration Guide](/learn/migration-guides/0.10-0.11/). + +Since our last release a few months ago we've added a _ton_ of new features, bug fixes, and quality of life tweaks, but here are some of the highlights: + + + +* **Screen Space Ambient Occlusion (SSAO)**: Increase scene render quality by simulating "indirect" diffuse light +* **Temporal Anti-Aliasing (TAA)**: A popular anti-aliasing technique that blends the current frame with past frames using motion vectors to smooth out artifacts +* **Morph Targets**: Animate vertex positions on meshes between predefined states. Great for things like character customization! +* **Robust Constrast Adaptive Sharpening (RCAS)**: Intelligently sharpens renders, which pairs nicely with TAA +* **WebGPU Support**: Bevy can now render on the web faster and with more features using the modern WebGPU web API +* **Improved Shader Imports**: Bevy shaders now support granular imports and other new features +* **Parallax Mapping**: Materials now support an optional depth map, giving flat surfaces a feel of depth through parallaxing the material's textures +* **Schedule-First ECS APIs**: A simpler and more ergonomic ECS system scheduling API +* **Immediate Mode Gizmo Rendering**: Easily and efficiently render 2D and 3D shapes for debugging and editor scenarios +* **ECS Audio APIs**: A more intuitive and idiomatic way to play back audio +* **UI Borders**: UI nodes can now have configurable borders! +* **Grid UI Layout**: Bevy UI now supports CSS-style grid layout +* **UI Performance Improvements**: The UI batching algorithm was changed, yielding significant performance wins + +## Screen Space Ambient Occlusion + +
authors: @JMS55, @danchia, @superdump
+ +Drag this image to compare +
+ Without SSAO + With SSAO +
+ +**SSAO Only** +![ssao_only](ssao_only.png) + +Bevy now supports Screen Space Ambient Occlusion (SSAO). While Bevy already supported shadows from direct lights +([`DirectionalLight`], [`PointLight`], [`SpotLight`]) via shadow mapping, Bevy now supports shadows from _indirect_ diffuse lighting such as [`AmbientLight`] or [`EnvironmentMapLight`]. + +These shadows give scenes a more "grounded" feel, by estimating how much surrounding geometry blocks incoming light via the screen-space depth and normal prepasses. You can try it out in the new [SSAO example](https://github.com/bevyengine/bevy/blob/v0.11.0/examples/3d/ssao.rs). + +Note that using SSAO with the newly added Temporal Anti-Aliasing leads to a _large_ increase in quality and noise reduction. + +Platform support is currently limited - Only Vulkan, DirectX12, and Metal are currently supported. WebGPU support will come at a later date. WebGL likely won't be supported because it doesn't have compute shaders. + +Special thanks to Intel for their open source [XeGTAO](https://github.com/GameTechDev/XeGTAO) project, which was a huge help in developing this feature. + +[`DirectionalLight`]: https://docs.rs/bevy/0.11.0/bevy/pbr/struct.DirectionalLight.html +[`PointLight`]: https://docs.rs/bevy/0.11.0/bevy/pbr/struct.PointLight.html +[`SpotLight`]: https://docs.rs/bevy/0.11.0/bevy/pbr/struct.SpotLight.html +[`AmbientLight`]: https://docs.rs/bevy/0.11.0/bevy/pbr/struct.AmbientLight.html + +## Temporal Anti-Aliasing + +
authors: @JMS55, @DGriffin91
+ +![aa](aa.png) + +Alongside MSAA and FXAA, Bevy now supports Temporal Anti-aliasing (TAA) as an anti-aliasing option. + +TAA works by blending the newly rendered frame with past frames in order to smooth out aliasing artifacts in the image. TAA has become increasingly popular in the industry because of its ability to cover up so many rendering artifacts: it smooths out shadows (both global illumination and "casted" shadows), mesh edges, textures, and reduces specular aliasing of light on reflective surfaces. However because the "smoothing" effect is so apparent, some people prefer other methods. + +Here's a quick rundown of the following advantages and disadvantages of each anti-aliasing method that Bevy supports: + +* **Multi-Sample Antialiasing (MSAA)** + * Does a good job at smoothing the edges of meshes (anti geometric aliasing). Does not help with specular aliasing. Performance cost scales with triangle count, and performs very poorly on scenes with many triangles +* **Fast Approximate Antialiasing (FXAA)** + * Does a decent job of dealing with both geometric and specular aliasing. Very little performance cost in all scenes. Somewhat blurry and low quality results +* **Temporal Antialiasing (TAA)** + * Does a very good job at dealing with both geometric and specular aliasing. Does a good job at dealing with temporal aliasing, where high-frequency details flicker over time or as you move the camera around or as things animate. Performance cost is moderate, and scales only with screen resolution. Chance of "ghosting" where meshes or lighting effects may leave trails behind them that fade over time. Although TAA helps with reducing temporal aliasing, it may also introduce additional temporal aliasing, especially on thin geometry or texture detail rendered at a distance. Requires 2 view's worth of additional GPU memory, as well as enabling the motion vector and depth prepasses. Requires accurate motion vector and depth prepasses, which complicates custom materials + +TAA implementations are a series of tradeoffs and rely on heuristics that are easy to get wrong. In Bevy 0.11, TAA is marked as an experimental feature for the following reasons: + +* TAA does not currently work with the following Bevy features: skinning, morph targets, and parallax mapping +* TAA currently tends to soften the image a bit, which can be worked around via post-process sharpening +* Our TAA heuristics are not currently user-configurable (and these heuristics are likely to change and evolve) + +We will continue to improve quality, compatibility, and performance in future releases. Please report any bugs you encounter! + +You can compare all of our anti-aliasing methods in Bevy's improved [anti-aliasing example](https://github.com/bevyengine/bevy/blob/v0.11.0/examples/3d/anti_aliasing.rs). + +## Robust Contrast Adaptive Sharpening + +
authors: @Elabajaba
+ +Effects like TAA and FXAA can cause the final render to become blurry. Sharpening post processing effects can help counteract that. In **Bevy 0.11** we've added a port of AMD's Robust Constrast Adaptive Sharpening (RCAS). + +Drag this image to compare +
+ TAA + TAA+RCAS +
+ +Notice that the texture on the leather part of the helmet is much crisper! + +## Morph Targets + +
authors: @nicopap, @cart
+ +Bevy, since the 0.7 release, supports 3D animations. + +But it only supported _skeletal_ animations. Leaving on the sidewalk a common +animation type called _morph targets_ (aka blendshapes, aka keyshapes, and a slew +of other name). This is the grandparent of all 3D character animation! +[Crash Bandicoot]'s run cycle used morph targets. + + +
Character model by Samuel Rosario (© all rights reserved), used with permission. Modified by nicopap, using the Snow character texture by Demeter Dzadik for Blender Studios (🅯 CC-BY). +
+ + +Nowadays, an animation artist will typically use a skeleton rig for wide +moves and morph targets to clean up the detailed movements. + +When it comes to game assets, however, the complex skeleton rigs used by +artists for faces and hands are too heavy. Usually, the poses are +"baked" into morph poses, and facial expression transitions are handled +in the engine through morph targets. + +Morph targets is a very simple animation method. Take a model, have a base +vertex position, move the vertices around to create several poses: + +
+

Default

A wireframe rendering of a character's face with a neutral expression
+

Frown

Wireframe rendering of a frowning character
+

Smirk

Wireframe rendering of a smirking character
+
+ +Store those poses as a difference between the default base mesh and the variant +pose, then, at runtime, _mix_ each pose. Now that we have the difference with +the base mesh, we can get the variant pose by simply adding to the base +vertices positions. + +That's it, the morph target shader looks like this: + +```rust +fn morph_vertex(vertex: Vertex) { + for (var i: u32 = 0u; i < pose_count(); i++) { + let weight = weight_for_pose(i); + vertex.position += weight * get_difference(vertex.index, position_offset, i); + vertex.normal += weight * get_difference(vertex.index, normal_offset, i); + } +} +``` + +In Bevy, we store the weights per pose in the `MorphWeights` component. + +```rust +fn set_weights_system(mut morph_weights: Query<&mut MorphWeights>) { + for mut entity_weights in &mut morph_weights { + let weights = entity_weights.weights_mut(); + + weights[0] = 0.5; + weights[1] = 0.25; + } +} +``` + +Now assuming that we have two morph targets, (1) the frown pose, (2) +the smirk pose: + +
+
+

[0.0, 0.0]

+

default pose

+ Neutral face expression +
+
+

[1.0, 0.0]

+

frown only

+ Frowning +
+
+

[0.0, 1.0]

+

smirk only

+ Smirking +
+
+

[0.5, 0.0]

+

half frown

+ Slightly frowning +
+
+

[1.0, 1.0]

+

both at max

+ Making faces +
+
+

[0.5, 0.25]

+

bit of both

+ Slightly frowning/smirking +
+
+ +While conceptually simple, it requires communicating to the GPU a tremendous +amount of data. Thousand of vertices, each 288 bits, several model variations, +sometimes a hundred. + +We store the vertex data as pixels in a 3D texture. This allows morph targets to not only +run on WebGPU, but also on the WebGL2 wgpu backend. + +This could be improved in a number of ways, but it is sufficient for an +initial implementation. + + + +[Crash Bandicoot]: https://en.wikipedia.org/wiki/Crash_Bandicoot_(video_game)#Gameplay + +## Parallax Mapping + +
author: @nicopap
+ +Bevy now supports parallax mapping and depth maps. Parallax mapping puts normal +maps to shame when it comes to giving "illusion of depth" to a material. The top half of this video uses parallax mapping plus a normal map, whereas the bottom half only uses a normal map: + + +
earth view, elevation & night view by NASA (public domain)
+ +Notice how it is not merely the shading of pixels that changes, but their +actual position on screen. The mountaintops hide mountain ridges behind +themselves. High mountains move faster than coastal areas. + +Parallax mapping moves pixels according to the perspective and depth on the +surface of the geometry. Adding true 3D depth to flat surfaces. + +All of that, without adding a single vertex to the geometry. The whole globe +has exactly 648 vertices. Unlike a more primitive shader, such as displacement +mapping, parallax mapping only requires an additional grayscale image, called +the `depth_map`. + +Games often use parallax mapping for cobblestones or brick walls, so +let's make a brick wall in Bevy! First, we spawn a mesh: + +```rust +commands.spawn(PbrBundle { + mesh: meshes.add(shape::Box::new(30.0, 10.0, 1.0).into()), + material: materials.add(StandardMaterial { + base_color: Color::WHITE, + ..default() + }), + ..default() +}); +``` + +![A 3D desert scene with two flat white walls and a pebble path winding between them](parallax_mapping_none_mini.jpg) + +Of course, it's just a flat white box, we didn't add any texture. +So let's add a normal map: + +```rust +normal_map_texture: Some(assets.load("normal_map.png")), +``` + +![The same scene with normal maps](parallax_mapping_normals_mini.jpg) + +This is much better. The shading changes according to the light direction too! +However, the specular highlights on the corner are overbearing, almost noisy. + +Let's see how a depth map can help: + +```rust +depth_map: Some(assets.load("depth_map.png")), +``` + +![The same scene with a depth texture](parallax_mapping_depth_mini.jpg) + +We eliminated the noise! There is also that sweet 3D feel reminiscent of +90's games pre-rendered cinematic sequences. + +So what's going on, why does parallax mapping eliminate the ugly specular +lights on the wall? + +This is because parallax mapping insets the ridges between bricks, so that they +are occluded by the bricks themselves. + +![Illustration of the previous paragraph](ridge-light-view-1.svg) + +Since normal maps do not "move" the shaded areas, merely shade them +differently, we get those awkward specular highlights. With parallax mapping, +they are gone. + +Drag this image to compare +
+ Normal Mapping Only + Parallax & Normal Mapping +
+ +Parallax mapping in Bevy is still very limited. The most painful aspect is that +it is not a standard glTF feature, meaning that the depth texture needs to be +programmatically added to materials if they came from a GLTF file. + +Additionally, parallax mapping is incompatible with the temporal antialiasing +shader, doesn't work well on curved surfaces, and doesn't affect object's +silhouettes. + +However, those are not fundamental limitations of parallax mapping, and may be +fixed in the future. + +## Skyboxes + +
authors: @JMS55, @superdump
+ +![skybox](skybox.png) + +Bevy now has built-in support for displaying an HDRI environment as your scene background. + +Simply attach the new [`Skybox`] component to your [`Camera`]. It pairs well with the existing [`EnvironmentMapLight`], which will use the environment map to light the scene. + +We also plan to add support for built-in procedural skyboxes sometime in the future! + +[`Skybox`]: https://docs.rs/bevy/0.11.0/bevy/core_pipeline/struct.Skybox.html +[`Camera`]: https://docs.rs/bevy/0.11.0/bevy/render/camera/struct.Camera.html +[`EnvironmentMapLight`]: https://docs.rs/bevy/0.11.0/bevy/pbr/struct.EnvironmentMapLight.html + +## WebGPU Support + +
authors: @mockersf, many others throughout Bevy's development
+ +![webgpu](webgpu.svg) + +Bevy now supports WebGPU rendering on the web (in addition to WebGL 2). WebGPU support is still rolling out, but if you have [a supported web browser][webgpu-support] you can explore our new [live WebGPU examples](/examples-webgpu) page. + +### What is WebGPU? + +WebGPU is an [exciting new web standard](https://github.com/gpuweb/gpuweb) for doing modern GPU graphics and compute. It takes inspiration from Vulkan, Direct3D 12, and Metal. In fact, it is generally implemented on top of these APIs under the hood. WebGPU gives us access to more GPU features than WebGL2 (such as compute shaders) and also has the potential to be much faster. It means that more of Bevy's native renderer features are now also available on the web. It also uses the new [WGSL shader language](https://www.w3.org/TR/WGSL). We're very happy with how WGSL has evolved over time and Bevy uses it internally for our shaders. We also added usability features like imports! But with Bevy you still have the option to use GLSL if you prefer. + +### How it Works + +Bevy is built on top of the [wgpu] library, which is a modern low-level GPU API that can target pretty much every popular API: Vulkan, Direct3D 12, Metal, OpenGL, WebGL2, and WebGPU. The best backend API is selected for a given platform. It is a "native" rendering API, but it generally follows the WebGPU terminology and API design. Unlike WebGPU, it can provide direct access to the native APIs, which means Bevy [enjoys a "best of all worlds" situation](/news/bevy-webgpu/#how-it-works). + +### WebGPU Examples + +Click one of the images below to check out our live WebGPU examples (if your [browser supports it][webgpu-support]): + +[![webgpu examples](webgpu_examples.png)](examples-webgpu) + +[wgpu]: https://github.com/gfx-rs/wgpu +[webgpu-support]: https://caniuse.com/webgpu + +## Improved Shader Imports + +
authors: @robtfm
+ +Bevy's rendering engine has a lot of great options and features. For example, the PBR `StandardMaterial` pipeline supports desktop/webgpu and webgl, 6 optional mesh attributes, 4 optional textures, and a plethora of optional features like fog, skinning, and alpha blending modes, with more coming in every release. + +Many feature combos need specialized shader variants, and with over 3000 lines of shader code split over 50 files in total, the text-substitution-based shader processor was beginning to creak at the seams. + +This release we've switched to using [naga_oil](https://github.com/bevyengine/naga_oil), which gives us a module-based shader framework. It compiles each file individually to naga's IR and then combines them into a final shader on demand. This doesn't have much visible impact yet, but it does give a few immediate benefits: + +* The engine's shader code is easier to navigate and less magical. Previously there was only a single global scope, so items could be referenced even if they were only imported indirectly. This sometimes made it hard to locate the actual code behind the reference. Now items must be explicitly imported, so you can always tell where a variable or function originated just by looking at the current file:
+![imported items](imported_items.png) +* Shaders now have codespan reporting, an error will point you to the shader file and line number, preventing a lot of hair pulling in complex shader codebases:
+![codespan](codespan.png) +* naga_oil's preprocessor supports a few more conditional directives, you can use `#else if` and `#else ifndef` as well as `#else ifdef` which was previously supported +* Functions, variables and structs are all properly scoped so a shader file doesn't need to use globally unique names to avoid conflicts +* Shader defs can be added to modules directly. For example, any shader that imports `bevy_pbr::mesh_view_types` now has `MAX_DIRECTIONAL_LIGHTS` automatically defined, there's no longer a need to remember to add it for every new pipeline that uses the module. + +The future possibilities are more exciting. Using naga IR opens the door to a bunch of nice features that we hope to bring in future releases: + +* Automatic bind slot allocation will let plugins extend the core view bindgroup, which means self-contained plugins for features like lighting and shadow methods, common material properties, etc become viable. This will allow us to modularise the core pipelines to make growing the codebase - while keeping support for multiple targets - more sustainable +* "Virtual" shader functions will allow user modifications to core functions (like lighting), and potentially lead to a template-style material system, where users can provide "hooks" that will be called at the right point in the pipeline +* Language interop: mix and match glsl and wgsl, so bevy's pbr pipeline features could be accessed from your glsl material shader, or utils written for glsl could be used in wgsl code. We're hopeful that this can extend to spirv (and rust-gpu) as well +* More cool stuff we haven't thought of yet. Being able to inspect and modify shaders at runtime is very powerful and makes a lot of things possible! + +## UI Node Borders + +
authors: @ickshonpe
+ +UI nodes now draws borders, whose color can be configured with the new [`BorderColor`] component: + +![borders](borders.png) + +```rust +commands.spawn(ButtonBundle { + style: Style { + border: UiRect::all(Val::Px(5.0)), + ..default() + }, + border_color: BorderColor(Color::rgb(0.9, 0.9, 0.9)), + ..default() +}) +``` + +Each side of the border is configurable: + +![border sides](border-sides.png) + +[`BorderColor`]: https://docs.rs/bevy/0.11.0/bevy/ui/struct.BorderColor.html + +## Grid UI Layout + +
authors: @nicoburns
+ +In Bevy UI we wired up the new `grid` feature in the layout library we use ([Taffy](https://github.com/DioxusLabs/taffy)). This enables CSS-style grid layouts: + +![grid](grid.png) + +This can be configured on the [`Style`] component: + +```rust +Style { + /// Use grid layout for this node + display: Display::Grid, + /// Make the grid have a 1:1 aspect ratio + /// This means the width will adjust to match the height + aspect_ratio: Some(1.0), + // Add 24px of padding around the grid + padding: UiRect::all(Val::Px(24.0)), + /// Set the grid to have 4 columns all with sizes minmax(0, 1fr) + /// This creates 4 exactly evenly sized columns + grid_template_columns: RepeatedGridTrack::flex(4, 1.0), + /// Set the grid to have 4 rows all with sizes minmax(0, 1fr) + /// This creates 4 exactly evenly sized rows + grid_template_rows: RepeatedGridTrack::flex(4, 1.0), + /// Set a 12px gap/gutter between rows and columns + row_gap: Val::Px(12.0), + column_gap: Val::Px(12.0), + ..default() +}, +``` + +[`Style`]: https://docs.rs/bevy/0.11.0/bevy/ui/struct.Style.html + +## Schedule-First ECS APIs + +
authors: @cart
+ +In **Bevy 0.10** we introduced [ECS Schedule V3](/news/bevy-0-10/#ecs-schedule-v3), which _vastly_ improved the capabilities of Bevy ECS system scheduling: scheduler API ergonomics, system chaining, the ability to run exclusive systems and apply deferred system operations at any point in a schedule, a single unified schedule, configurable System Sets, run conditions, and a better State system. + +However it pretty quickly became clear that the new system still had some areas to improve: + +* **Base Sets were hard to understand and error prone**: What _is_ a Base Set? When do I use them? Why do they exist? Why is my ordering implicitly invalid due to incompatible Base Set ordering? Why do some schedules have a default Base Set while others don't? [Base Sets were confusing!](https://github.com/bevyengine/bevy/pull/8079#base-set-confusion) +* **There were too many ways to schedule a System**: We've accumulated too many scheduling APIs. As of Bevy **0.10**, we had [_SIX_ different ways to add a system to the "startup" schedule](https://github.com/bevyengine/bevy/pull/8079#unify-system-apis). Thats too many ways! +* **Too much implicit configuration**: There were both default Schedules and default Base Sets. In some cases systems had default schedules or default base sets, but in other cases they didn't! [A system's schedule and configuration should be explicit and clear](https://github.com/bevyengine/bevy/pull/8079#schedule-should-be-clear). +* **Adding Systems to Schedules wasn't ergonomic**: Things like `add_system(foo.in_schedule(CoreSchedule::Startup))` were not fun to type or read. We created special-case helpers, such as `add_startup_system(foo)`, but [this required more internal code, user-defined schedules didn't benefit from the special casing, and it completely hid the `CoreSchedule::Startup` symbol!](https://github.com/bevyengine/bevy/pull/8079#ergonomic-system-adding). + +### Unraveling the Complexity + +If your eyes started to glaze over as you tried to wrap your head around this, or phrases like "implicitly added to the `CoreSet::Update` Base Set" filled you with dread ... don't worry. After [a lot of careful thought](https://github.com/bevyengine/bevy/pull/8079) we've unraveled the complexity and built something clear and simple. + +In **Bevy 0.11** the "scheduling mental model" is _much_ simpler thanks to **Schedule-First ECS APIs**: + +```rust +app + .add_systems(Startup, (a, b)) + .add_systems(Update, (c, d, e)) + .add_systems(FixedUpdate, (f, g)) + .add_systems(PostUpdate, h) + .add_systems(OnEnter(AppState::Menu), enter_menu) + .add_systems(OnExit(AppState::Menu), exit_menu) +``` + +* **There is _exactly_ one way to schedule systems** + * Call `add_systems`, state the schedule name, and specify one or more systems +* **Base Sets have been entirely removed in favor of Schedules, which have friendly / short names** + * Ex: The `CoreSet::Update` Base Set has become `Update` +* **There is no implicit or implied configuration** + * Default Schedules and default Base Sets don't exist +* **The syntax is easy on the eyes and ergonomic** + * Schedules are first so they "line up" when formatted + +
+ To compare, expand this to see what it used to be! + +```rust +app + // Startup system variant 1. + // Has an implied default StartupSet::Startup base set + // Has an implied CoreSchedule::Startup schedule + .add_startup_systems((a, b)) + // Startup system variant 2. + // Has an implied default StartupSet::Startup base set + // Has an implied CoreSchedule::Startup schedule + .add_systems((a, b).on_startup()) + // Startup system variant 3. + // Has an implied default StartupSet::Startup base set + .add_systems((a, b).in_schedule(CoreSchedule::Startup)) + // Update system variant 1. + // `CoreSet::Update` base set and `CoreSchedule::Main` are implied + .add_system(c) + // Update system variant 2 (note the add_system vs add_systems difference) + // `CoreSet::Update` base set and `CoreSchedule::Main` are implied + .add_systems((d, e)) + // No implied default base set because CoreSchedule::FixedUpdate doesn't have one + .add_systems((f, g).in_schedule(CoreSchedule::FixedUpdate)) + // `CoreSchedule::Main` is implied, in_base_set overrides the default CoreSet::Update set + .add_system(h.in_base_set(CoreSet::PostUpdate)) + // This has no implied default base set + .add_systems(enter_menu.in_schedule(OnEnter(AppState::Menu))) + // This has no implied default base set + .add_systems(exit_menu.in_schedule(OnExit(AppState::Menu))) +``` + +
+ +Note that normal "system sets" still exist! You can still use sets to organize and order your systems: + +```rust +app.add_systems(Update, ( + (walk, jump).in_set(Movement), + collide.after(Movement), +)) +``` + +The `configure_set` API has also been adjusted for parity: + +```rust +// Bevy 0.10 +app.configure_set(Foo.after(Bar).in_schedule(PostUpdate)) +// Bevy 0.11 +app.configure_set(PostUpdate, Foo.after(Bar)) +``` + +## Nested System Tuples and Chaining + +
authors: @cart
+ +It is now possible to infinitely nest tuples of systems in a `.add_systems` call! + +```rust +app.add_systems(Update, ( + (a, (b, c, d, e), f), + (g, h), + i +)) +``` + +At first glance, this might not seem very useful. But in combination with per-tuple configuration, it allows you to easily and cleanly express schedules: + +```rust +app.add_systems(Update, ( + (attack, defend).in_set(Combat).before(check_health) + check_health, + (handle_death, respawn).after(check_health) +)) +``` + +`.chain()` has also been adapted to support arbitrary nesting! The ordering in the example above could be rephrased like this: + +```rust +app.add_systems(Update, + ( + (attack, defend).in_set(Combat) + check_health, + (handle_death, respawn) + ).chain() +) +``` + +This will run `attack` and `defend` first (in parallel), then `check_health`, then `handle_death` and `respawn` (in parallel). + +This allows for powerful and expressive "graph-like" ordering expressions: + +```rust +app.add_systems(Update, + ( + (a, (b, c, d).chain()), + (e, f), + ).chain() +) +``` + +This will run `a` in parallel with `b->c->d`, then after those have finished running it will run `e` and `f` in parallel. + +## Gizmos + +
authors: @devil-ira, @jannik4, @lassade, @The5-1, @Toqozz, @nicopap
+ +It is often helpful to be able to draw simple shapes and lines in 2D and 3D for things like editor controls, and debug views. Game development is a very "spatial" thing and being able to quickly draw shapes is the visual equivalent of "print line debugging". It helps answer questions like "is this ray casting in the right direction?" and "is this collider big enough?" + +In **Bevy 0.11** we've added an "immediate mode" [`Gizmos`] drawing API that makes these things easy and efficient. In 2D and 3D you can draw lines, rects, circles, arcs, spheres, cubes, line strips, and more! + +**2D Gizmos** +![2d gizmos](2d_gizmos.png) +**3D Gizmos** +![3d gizmos](3d_gizmos.png) + +From any system you can spawn shapes into existence (for both 2D and 3D): + +```rust +fn system(mut gizmos: Gizmos) { + // 2D + gizmos.line_2d(Vec2::new(0., 0.), Vec2::new(0., 10.), Color::RED); + gizmos.circle_2d(Vec2::new(0., 0.), 40., Color::BLUE); + // 3D + gizmos.circle(Vec3::ZERO, Vec3::Y, 3., Color::BLACK); + gizmos.ray(Vec3::new(0., 0., 0.), Vec3::new(5., 5., 5.), Color::BLUE); + gizmos.sphere(Vec3::ZERO, Quat::IDENTITY, 3.2, Color::BLACK) +} +``` + +Because the API is "immediate mode", gizmos will only be drawn on frames where they are "queued up", which means you don't need to worry about cleaning up gizmo state! + +Gizmos are drawn in batches, which means they are very cheap. You can have hundreds of thousands of them! + +[`Gizmos`]: https://docs.rs/bevy/0.11.0/bevy/gizmos/gizmos/struct.Gizmos.html + +## ECS Audio APIs + +
authors: @inodentry
+ +Bevy's audio playback APIs have been reworked to integrate more cleanly with Bevy's ECS. + +In previous versions of Bevy you would play back audio like this: + +```rust +#[derive(Resource)] +struct MyMusic { + sink: Handle, +} + +fn play_music( + mut commands: Commands, + asset_server: Res, + audio: Res