diff --git a/content/news/2022-11-12-bevy-0.9/2d_bloom.png b/content/news/2022-11-12-bevy-0.9/2d_bloom.png new file mode 100644 index 0000000000..740a82a772 Binary files /dev/null and b/content/news/2022-11-12-bevy-0.9/2d_bloom.png differ diff --git a/content/news/2022-11-12-bevy-0.9/banding.png b/content/news/2022-11-12-bevy-0.9/banding.png new file mode 100644 index 0000000000..fd755ab1ae Binary files /dev/null and b/content/news/2022-11-12-bevy-0.9/banding.png differ diff --git a/content/news/2022-11-12-bevy-0.9/blinking_cube.mp4 b/content/news/2022-11-12-bevy-0.9/blinking_cube.mp4 new file mode 100644 index 0000000000..072395866f Binary files /dev/null and b/content/news/2022-11-12-bevy-0.9/blinking_cube.mp4 differ diff --git a/content/news/2022-11-12-bevy-0.9/bloom.png b/content/news/2022-11-12-bevy-0.9/bloom.png new file mode 100644 index 0000000000..169fe93436 Binary files /dev/null and b/content/news/2022-11-12-bevy-0.9/bloom.png differ diff --git a/content/news/2022-11-12-bevy-0.9/bloom_lion.png b/content/news/2022-11-12-bevy-0.9/bloom_lion.png new file mode 100644 index 0000000000..7e798d577d Binary files /dev/null and b/content/news/2022-11-12-bevy-0.9/bloom_lion.png differ diff --git a/content/news/2022-11-12-bevy-0.9/debanding.png b/content/news/2022-11-12-bevy-0.9/debanding.png new file mode 100644 index 0000000000..a90c3a005b Binary files /dev/null and b/content/news/2022-11-12-bevy-0.9/debanding.png differ diff --git a/content/news/2022-11-12-bevy-0.9/fxaa.png b/content/news/2022-11-12-bevy-0.9/fxaa.png new file mode 100644 index 0000000000..c671692747 Binary files /dev/null and b/content/news/2022-11-12-bevy-0.9/fxaa.png differ diff --git a/content/news/2022-11-12-bevy-0.9/gamepad.mp4 b/content/news/2022-11-12-bevy-0.9/gamepad.mp4 new file mode 100644 index 0000000000..21c1354182 Binary files /dev/null and b/content/news/2022-11-12-bevy-0.9/gamepad.mp4 differ diff --git a/content/news/2022-11-12-bevy-0.9/index.md b/content/news/2022-11-12-bevy-0.9/index.md new file mode 100644 index 0000000000..b342f6dedb --- /dev/null +++ b/content/news/2022-11-12-bevy-0.9/index.md @@ -0,0 +1,2037 @@ ++++ +title = "Bevy 0.9" +date = 2022-11-12 +[extra] +author = "Carter Anderson" +twitter = "cart_cart" +github = "cart" +youtube = "cartdev" +image = "bloom_lion.png" +show_image = true ++++ + +Thanks to **159** contributors, **430** pull requests, community reviewers, and our [**generous sponsors**](https://github.com/sponsors/cart), I'm happy to announce the **Bevy 0.9** 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.9**, check out our [0.8 to 0.9 Migration Guide](/learn/book/migration-guides/0.8-0.9/). + +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: + + + +* **HDR Post Processing, Tonemapping, and Bloom**: Bevy has a new HDR post processing and tonemapping pipeline, which we used to implement the "bloom" post processing effect! +* **FXAA**: Fast approximate anti-aliasing was added, which gives users a new cheap option for screen space anti-aliasing. +* **Deband Dithering**: Hide gradient precision errors with this new post processing effect! +* **Other Post Processing Improvements**: View target double buffering and automatic render target format handling. +* **New Scene Format**: Bevy's new scene format is smaller, simpler to compose manually, and easier to read. Comes in both "human readable" and "binary" variants! +* **Code Driven Scene Construction**: Build scenes dynamically from an existing app using queries and specific entity references. +* **Improved Entity/Component APIs**: Spawning entities with components is now simpler and more ergonomic than ever! +* **Exclusive System Rework**: Exclusive systems (systems with unique ECS World access) are now just "normal" systems with significantly improved usability. +* **Enum Reflection**: Bevy Reflect can now reflect enum types, which exposes them to Bevy's scene system and opens doors to editor tooling for enums. +* **Time Shader Globals**: Time is now passed to shaders as a global, making time-driven animation in custom shaders easy! +* **Plugin Settings**: Plugins can now have settings, which can be overridden in plugin groups, simplifying the plugin configuration story. +* **Bevy UI Z-Indices**: Control how UI elements stack on top of each other using local and global z-indices + +## HDR Post Processing, Tonemapping, and Bloom + +
authors: @ChangeCaps, @jakobhellermann, @cart, @JMS55
+ +Bevy now supports the "bloom" post processing effect, backed by a ton of internal improvements to our HDR (High Dynamic Range) render pipeline. + +![bloom](bloom.png) + +Bloom creates a "blurred" effect around bright lights, which emulates how cameras (and our eyes) often perceive light in the real world. High quality bloom builds on top of HDR render pipelines, which represents light and color using more than the standard 8 bits per channel (rgba) used elsewhere. In previous releases Bevy already did [HDR lighting internally in its PBR shader](/news/bevy-0-5/#physically-based-rendering-pbr), but because we were rendering to a "normal" (low dynamic range) texture, we had to lose the extra high dynamic range information when we mapped the HDR lighting to the LDR texture (using a process called tonemapping). + +In **Bevy 0.9**, you can now configure cameras to render to HDR textures, which will preserve the high dynamic range information after the "main pass" is finished rendering: + +```rust +Camera { + // Currently this defaults to false, but we will likely + // switch this to true by default in future releases + hdr: true, + ..default() +} +``` + +This enables post processing effects, such as bloom, to have access to the raw HDR information. When HDR textures are enabled, we delay "tonemapping" until after "HDR post processing effects" have run in our [Render Graph](/news/bevy-0-6/#render-graphs-and-sub-graphs). + +Bloom is enabled by adding a [`BloomSettings`] component to a camera with HDR textures enabled: + +```rust +commands.spawn(( + Camera3dBundle { + camera: Camera { + hdr: true, + ..default() + }, + ..default() + }, + BloomSettings::default(), +)); +``` + +The bloom effect can be overbearing if misconfigured. [`BloomSettings`] has a number of options to tune it, but the most relevant is `intensity`, which can (and should) be used to adjust how much the effect is applied. + +Seriously ... this effect can be obnoxious: + +![too much bloom](too_much_bloom.png) + +In most cases, it is best to err on the side of subtlety. + +HDR rendering is also available in 2D, which means you can also use bloom effects in 2D! + +![2D bloom](2d_bloom.png) + +[`BloomSettings`]: https://docs.rs/bevy/0.9.0/bevy/core_pipeline/bloom/struct.BloomSettings.html + +## FXAA: Fast Approximate Anti-Aliasing + +
authors: @DGriffin91, @cart
+ +**Bevy 0.9** adds support for FXAA (fast approximate anti-aliasing). FXAA is a popular (and cheap!) anti-aliasing approach that uses luminance data contrast to identify edges and blur them: + +![no_aa](no_aa.png) +![fxaa](fxaa.png) + +Bevy already has support for MSAA (multisample anti-aliasing), which does multiple samples when rendering geometry edges, which makes those edges crisper: + +![msaa](msaa.png) + +Picking an anti-aliasing implementation is all about tradeoffs: + +* **MSAA**: Crisp, high quality geometry edges. Leaves other parts of the image (such as textures and shadows) untouched, which can be a pro (crisper outputs) or a con (more aliasing). More expensive than FXAA. +* **FXAA**: Considers the entire image when blurring, including textures, which can be a pro (textures and shadows get anti-aliased) or a con (the image gets blurrier as a whole). Cheap to run (a good choice for mobile or web AA). + +Now that our post processing pipeline is maturing, we plan on adding even more anti-aliasing options in future Bevy releases. We already have TAA (temporal anti-aliasing) and SMAA (subpixel morphological anti-aliasing) implementations in the works! + +## Deband Dithering + +
authors: @aevyrie
+ +"Color banding" is a known limitation when using 8 bit color channels (which are required by pretty much every device / screen). + +This is most visible when trying to render smooth gradients for low noise textures (ex: the lighting on a "pure green" material): + +![banding](banding.png) + +If you look closely at the green plane _or_ the tan cube, you will notice distinct bands for each shade of color. A popular solution to this problem is to "dither" the final image. + +**Bevy 0.9** now performs "deband dithering" by default in the tonemapping stage: + +![debanding](debanding.png) + +You can enable and disable this per-camera: + +```rust + commands.spawn(Camera3dBundle { + tonemapping: Tonemapping::Enabled { + deband_dither: true, + }, + ..default() + }); +``` + +## Post Processing: View Target Double Buffering + +
authors: @cart
+ +Rendering post processing effects requires both an input texture (containing the "current" render) and an output texture (the "new" render with the effect applied). Previous versions of Bevy only had one main "view target" image. This meant that naively, post processing effects would need to manage and render to their own "intermediate" texture, then write it _back_ to the main target. This is clearly inefficient, as we have a new texture allocation for each effect _and_ we have the extra work of copying the intermediate texture back to the main texture. + +To solve this, in **Bevy 0.9** we now "double buffer" our view target textures, which mean we have two copies of them that we flip between. At a given moment in time, one is the current "main" texture and the other is the "next" main texture. Post processing effect developers can now trigger a "post process write", which returns a `source` and `destination` texture. It assumes that an effect will write `source` to `destination` (with or without modifications). `destination` will then become the new "main" texture. + +```rust +let post_process = view_target.post_process_write(); +render_some_effect(render_context, post_process.source, post_process.destination); +``` + +This reduces the complexity burden on post processing effect developers and keeps our pipeline nice and efficient. The new [FXAA effect](/news/bevy-0-9/#fxaa-fast-approximate-anti-aliasing) was implemented using this new system. Post processing plugin developers can use that implementation as a reference. + +## Improved Render Target Texture Format Handling + +
authors: @VitalyAnkh, @cart
+ +**Bevy 0.9** now detects and uses each window's / surface's preferred [`TextureFormat`], rather than using hard-coded compile-time-selected per-platform formats. This means that we automatically support uncommon platforms and configurations. Additionally, Bevy's main passes and post processing passes now render to stable / consistent [`TextureFormats`][`TextureFormat`] (ex: `Rgba16Float` for HDR). We do a final blit from these "standard" textures to the final render target's preferred format. This simplifies render pipeline construction, allows for render pipeline re-use across render targets (even if their formats don't match), and provides consistent and predictable render pipeline behaviors. + +This also means that when rendering to a texture, the texture format no longer needs to match the surface's texture format. For example, you can now render to a texture that only has a red channel: + +![render to texture red](render_to_texture_red.png) + +[`TextureFormat`]: https://docs.rs/bevy/0.9.0/bevy/render/render_resource/enum.TextureFormat.html + +## New Scene Format + +
authors: @MrGVSV
+ +**Bevy 0.9** introduces a _much_ improved scene format, which makes scenes smaller, simpler to compose manually, and easier to read. This is backed by a ton of improvements to Bevy Reflect (Bevy's Rust runtime reflection system). Most of the improvements to the Bevy Scene Format are actually generic improvements to all Bevy Reflect serialization! + +```rust +// The New Bevy Scene Format +( + entities: { + 0: ( + components: { + "game::Player": ( + name: "Reyna", + position: ( + x: 0.0, + y: 0.0, + ), + ), + "game::Health": ( + current: 5, + max: 10, + ), + "game::Team": A, + }, + ), + 1: ( + components: { + "game::Player": ( + name: "Sova", + position: ( + x: 10.0, + y: 0.0, + ), + ), + "game::Health": ( + current: 10, + max: 10, + ), + "game::Team": B, + }, + ), + }, +) +``` + +Compare that to the old format: + +```rust +// The Old Bevy Scene Format +[ + ( + entity: 0, + components: [ + { + "type": "game::Player", + "struct": { + "name": { + "type": "alloc::string::String", + "value": "Reyna", + }, + "position": { + "type": "glam::f32::vec2::Vec2", + "struct": { + "x": { + "type": "f32", + "value": 0.0, + }, + "y": { + "type": "f32", + "value": 0.0, + }, + }, + }, + }, + }, + { + "type": "game::Health", + "struct": { + "current": { + "type": "usize", + "value": 5, + }, + "max": { + "type": "usize", + "value": 10, + }, + }, + }, + { + "type": "game::Team", + "value": A, + }, + ], + ), + ( + entity: 1, + components: [ + { + "type": "game::Player", + "struct": { + "name": { + "type": "alloc::string::String", + "value": "Sova", + }, + "position": { + "type": "glam::f32::vec2::Vec2", + "struct": { + "x": { + "type": "f32", + "value": 10.0, + }, + "y": { + "type": "f32", + "value": 0.0, + }, + }, + }, + }, + }, + { + "type": "game::Health", + "struct": { + "current": { + "type": "usize", + "value": 10, + }, + "max": { + "type": "usize", + "value": 10, + }, + }, + }, + { + "type": "game::Team", + "value": B, + }, + ], + ), +] +``` + +There are so many improvements that it might be hard to pick them all out! + +### Simpler Struct Syntax + +Structs now use struct-style formatting instead of complicated map-based representations. + +```rust +// Old +{ + "type": "game::Health", + "struct": { + "current": { + "type": "usize", + "value": 5, + }, + "max": { + "type": "usize", + "value": 10, + }, + }, +}, + +// New +"game::Health": ( + current: 5, + max: 10, +), +``` + +### Simpler Primitive Serialization + +Types can now opt in to direct serde serialization, which makes primitive values much nicer to work with: + +```rust +// Old +"name": { + "type": "alloc::string::String", + "value": "Reyna", +}, + +// New +name: "Reyna", +``` + +### Nicer Enum Syntax + +Consider the enum: + +```rust +pub enum Team { + A, + B, +} +``` + +Lets compare how it is serialized: + +```rust +// Old +{ + "type": "game::Team", + "value": A, +}, + +// New +"game::Team": A, +``` + +Also note that Bevy Reflect didn't even directly support enums until **Bevy 0.9**. Older versions of Bevy required using `#[reflect_value]` in combination with normal serde for enums, which was much more complicated. See the [Enum Reflection](#enum-reflection) section of this blog post for details! + +### Nicer Tuples + +```rust +// Old +{ + "type": "(f32, f32)", + "tuple": [ + { + "type": "f32", + "value": 1.0 + }, + { + "type": "f32", + "value": 2.0 + } + ] +} + +// New +{ + "(f32, f32)": (1.0, 2.0) +} +``` + +### Top Level Struct + +Bevy Scenes now have a top level struct, which allows us to add additional values and metadata to the Bevy Scene format in the future (such as version numbers, ECS Resources, assets, etc). + +```rust +// Old +[ + /* entities here */ +] + +// New +( + entities: ( + /* entities here */ + ) +) +``` + +### Use Maps Where Appropriate + +Entity IDs and Component values must be unique in Bevy ECS. To better represent that, we now use map syntax instead of a list. + +```rust +// Old +[ + ( + entity: 0, + components: [ ], + ), + ( + entity: 1, + components: [ ], + ), +] + +// New +( + entities: { + 0: ( + components: { }, + ), + 1: ( + components: { }, + ), + }, +) +``` + +## Binary Scene Formats + +
authors: @MrGVSV
+ +Bevy Scenes can be serialized and deserialized to/from binary formats, such as [`bincode`](https://crates.io/crates/bincode/2.0.0-rc.1), [`postcard`](https://crates.io/crates/postcard), and [`rmp_serde`](https://crates.io/crates/rmp-serde). This required adding support for "non-self-describing" formats to the new scene format. + +In the case of postcard, this can be almost 5x smaller (4.53x for the scene above)! Very useful if you are trying to keep the size of the scene small on disk, or send the scene over the network. + +## Dynamic Scene Builder + +
authors: @mockersf
+ +Bevy Scenes can now be constructed dynamically using the new [`DynamicSceneBuilder`]. Previous versions of Bevy already supported [writing "whole worlds" to scenes](https://github.com/bevyengine/bevy/blob/v0.8.1/examples/scene/scene.rs#L78), but in some cases, users might only want to write _specific_ entities to a scene. **Bevy 0.9**'s [`DynamicSceneBuilder`] makes this possible: + +```rust +// Write players to a scene +fn system(world: &World, players: Query>) { + let builder = DynamicSceneBuilder::from_world(world); + builder.extract_entities(players.iter()); + let dynamic_scene = builder.build(); +} +``` + +`extract_entities` accepts any `Entity` iterator. + +You can also pass in specific entities: + +```rust +builder.extract_entity(entity); +``` + +[`DynamicSceneBuilder`]: https://docs.rs/bevy/0.9.0/bevy/scene/struct.DynamicSceneBuilder.html + +## More Scene Construction Tools + +
authors: @mockersf
+ +[`Scenes`][`Scene`] can now be cloned: + +```rust +let scene scene.clone_with(type_registry).unwrap(); +``` + +[`DynamicScenes`][`DynamicScene`] can now be converted to [`Scenes`][`Scene`]: + +```rust +let scene = Scene::from_dynamic_scene(dynamic_scene, type_registry).unwrap(); +``` + +[`Scene`]: https://docs.rs/bevy/0.9.0/bevy/scene/struct.Scene.html +[`DynamicScene`]: https://docs.rs/bevy/0.9.0/bevy/scene/struct.DynamicScene.html + +## Improved Entity / Component APIs + +
authors: @DJMcNab, @cart
+ +Spawning entities with components and adding / removing them from entities just got even easier! + +First some quick fundamentals: Bevy ECS uses [`Components`][`Component`] to add data and logic to entities. To make entity composition easier, Bevy ECS also has [`Bundles`][`Bundle`], which define groups of components to be added together. + +Just like in previous versions of Bevy, Bundles can be tuples of components: + +```rust +(Player { name: "Sova" }, Health::new(10), Team::A) +``` + +The [`Bundle`] trait can also be derived: + +```rust +#[derive(Bundle)] +struct PlayerBundle { + player: Player, + health: Health, + team: Team, +} +``` + +In **Bevy 0.9**, [`Component`] types now _also_ automatically implement the [`Bundle`] trait, which allows us to consolidate all entity component operations under new `spawn`, `insert`, and `remove` apis. Previously, we had separate variants for [`Bundle`] (ex: `insert_bundle(SomeBundle)`) and [`Component`] (ex: `.insert(SomeComponent)`). + +The [`Bundle`] trait is now also implemented for tuples of [`Bundles`][`Bundle`] instead of just tuples of [`Components`][`Component`]. The value of this will be made clear in a moment. + +First, `spawn` now takes a bundle: + +```rust +// Old (variant 1) +commands.spawn().insert_bundle(SpriteBundle::default()); + +// Old (variant 2) +commands.spawn_bundle(SpriteBundle::default()); + +// New +commands.spawn(SpriteBundle::default()); +``` + +Already we've saved some characters, but we're just getting started! Because [`Component`] implements [`Bundle`], we can now also pass in single components into `spawn`: + +```rust +// Old +commands.spawn().insert(Player { name: "Sova" }); + +// New +commands.spawn(Player { name: "Sova" }); +``` + +Things get even more interesting when we introduce [`Bundle`] tuples into the mix, which allow us to combine many operations (covering both components and bundles) into a single `spawn` call: + +```rust +// Old +commands + .spawn_bundle(PlayerBundle::default()) + .insert_bundle(TransformBundle::default()) + .insert(ActivePlayer); + +// New +commands.spawn(( + PlayerBundle::default(), + TransformBundle::default(), + ActivePlayer, +)); +``` + +This is _much_ easier to type and read. And on top of that, from the perspective of Bevy ECS this is a single "bundle spawn" instead of multiple operations, which cuts down on ["archetype moves"](/news/bevy-0-5/#component-storage-the-problem). This makes this single spawn operation much more efficient! + +These principles apply to the insert apis as well: + +```rust +// Old +commands + .insert_bundle(PlayerBundle::default()) + .insert(ActivePlayer); + +// New +commands.insert((PlayerBundle::default(), ActivePlayer)); +``` + +They also apply to the remove apis: + +```rust +// Old +commands + .remove_bundle::() + .remove::(); + +// New +commands.remove::<(PlayerBundle, ActivePlayer)>(); +``` + +[`Bundle`]: https://docs.rs/bevy/0.9.0/bevy/ecs/bundle/trait.Bundle.html +[`Component`]: https://docs.rs/bevy/0.9.0/bevy/ecs/component/trait.Component.html + +## Exclusive System Rework + +
authors: @cart, @maniwani
+ +In preparation for the larger scheduler changes outlined in the newly-merged (but not yet implemented) [Stageless RFC](https://github.com/bevyengine/rfcs/pull/45), we've started blurring the lines between "exclusive systems" (systems with "exclusive" full mutable access to the ECS [`World`]) and normal systems, which historically have been separate types with strict lines between them. + +In **Bevy 0.9**, exclusive systems now implement the normal [`System`] trait! This will ultimately have even larger implications, but in **Bevy 0.9** this means that you no longer need to call `.exclusive_system()` when adding exclusive systems to your schedule: + +```rust +fn some_exclusive_system(world: &mut World) { } + +// Old +app.add_system(some_exclusive_system.exclusive_system()) + +// New +app.add_system(some_exclusive_system) +``` + +We've also expanded exclusive systems to support more system parameters, which vastly improves the user experience of writing exclusive systems and makes them more efficient by caching state across executions. + +[`SystemState`] enables using "normal" system parameters from inside an exclusive system: + +```rust +// Old +fn some_system(world: &mut World) { + let mut state: SystemState<(Res