Posted on November 12, 2022 by Carter Anderson
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 to try it today. It's free and open source forever! You can grab the full source code on GitHub. Check out Bevy 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.
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 #
Bevy now supports the "bloom" post processing effect, backed by a ton of internal improvements to our HDR (High Dynamic Range) render pipeline.
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, 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:
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.
Bloom is enabled by adding a
BloomSettings component to a camera with HDR textures enabled:
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:
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!
FXAA: Fast Approximate Anti-Aliasing #
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:
Bevy already has support for MSAA (multisample anti-aliasing), which does multiple samples when rendering geometry edges, which makes those edges crisper:
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 #
"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):
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:
You can enable and disable this per-camera:
Post Processing: View Target Double Buffering #
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 means 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
destination texture. It assumes that an effect will write
destination (with or without modifications).
destination will then become the new "main" texture.
let post_process = view_target.post_process_write; render_some_effect;
This reduces the complexity burden on post processing effect developers and keeps our pipeline nice and efficient. The new FXAA effect was implemented using this new system. Post processing plugin developers can use that implementation as a reference.
Improved Render Target Texture Format Handling #
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
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:
New Scene Format #
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!
// The New Bevy Scene Format
Compare that to the old format:
// The Old Bevy Scene Format
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.
// Old , // New "game::Health": ,
Simpler Primitive Serialization #
Types can now opt in to direct serde serialization, which makes primitive values much nicer to work with:
// Old "name": , // New name: "Reyna",
Nicer Enum Syntax #
Consider the enum:
Lets compare how it is serialized:
// Old , // 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 section of this blog post for details!
Nicer Tuples #
// Old // New
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).
// Old // New
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.
// Old // New
Binary Scene Formats #
Bevy Scenes can be serialized and deserialized to/from binary formats, such as
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 #
Bevy Scenes can now be constructed dynamically using the new
DynamicSceneBuilder. Previous versions of Bevy already supported writing "whole worlds" to scenes, but in some cases, users might only want to write specific entities to a scene. Bevy 0.9's
DynamicSceneBuilder makes this possible:
// Write players to a scene
extract_entities accepts any
You can also pass in specific entities:
More Scene Construction Tools #
Scenes can now be cloned:
let scene = scene.clone_with.unwrap;
let scene = from_dynamic_scene.unwrap;
Improved Entity / Component APIs #
Spawning entities with components and adding / removing them from entities just got even easier!
First some quick fundamentals: Bevy ECS uses
Components to add data and logic to entities. To make entity composition easier, Bevy ECS also has
Bundles, which define groups of components to be added together.
Just like in previous versions of Bevy, Bundles can be tuples of components:
Bundle trait can also be derived:
In Bevy 0.9,
Component types now also automatically implement the
Bundle trait, which allows us to consolidate all entity component operations under new
remove apis. Previously, we had separate variants for
spawn now takes a bundle:
// Old (variant 1) commands.spawn.insert_bundle; // Old (variant 2) commands.spawn_bundle; // New commands.spawn;
// Old commands.spawn.insert; // New commands.spawn;
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
// Old commands .spawn_bundle .insert_bundle .insert; // New commands.spawn;
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". This makes this single spawn operation much more efficient!
These principles apply to the insert apis as well:
// Old commands .insert_bundle .insert; // New commands.insert;
They also apply to the remove apis:
// Old commands . .; // New commands.;
Exclusive System Rework #
In preparation for the larger scheduler changes outlined in the newly-merged (but not yet implemented) Stageless RFC, 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:
// Old app.add_system // New app.add_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:
// Old // New
QueryState enables cached access to individual queries:
// Old // New
Local enables storing local data inside of the exclusive system:
// Old ; // New
Bevy ECS Now Uses GATS! #
Rust 1.65.0 stabilized GATs (Generic Associated Types), which enabled us to significantly simplify Bevy ECS Query internals.
For awhile now, Bevy ECS has been hacking around the lack of GATs with a complicated nest of traits (
WorldQueryGats (a "lack of real GATs hack" trait), and
In Bevy 0.9, we now have a single
WorldQuery trait! This makes Bevy ECS much easier to maintain, extend, debug, document, and understand.
Derive Resource #
Resource trait is now no longer automatically implemented for all types. It must be derived:
Resourcefor every type made it very easy to accidentally insert the "wrong" value, such as inserting the constructor function pointer instead of the value itself:
; // This inserts the constructor function pointer as a resource! // Weird and confusing! app.insert_resource; // This is how it should be done! app.insert_resource;
Resourcedocuments intent in a structured way. Without a derive, resource-ness is implicit by default.
Auto-implementing meant that plugins could use the same "common" type in conflicting ways (ex:
Vec<usize>). Not implementing by default means that plugins cannot use these common types in conflicting ways. They must create new types.
This opens the door to configuring resource types using the Rust type system (like we already do for components).
System Ambiguity Resolution API Improvements #
Bevy ECS schedules systems to run in parallel by default. It will safely schedule systems in parallel, honoring dependencies between systems and enforcing Rust's mutability rules. By default, this means that if System A reads a resource and System B writes the resource (and they have no order defined between them), then System A might execute before or after System B. We call these systems "ambiguous". In some situations this ambiguity might matter, in other situations it might not.
Bevy already has a system ambiguity detection system which enables users to detect ambiguous systems and resolve the ambiguity (either by adding ordering constraints or ignoring the ambiguity). Users could add systems to "ambiguity sets" to ignore ambiguities between systems in these sets:
; app .add_system .add_system
This was a bit hard to reason about and introduced more boilerplate than necessary.
In Bevy 0.9, we have replaced ambiguity sets with simpler
app .add_system .add_system
This builds on the existing [
SystemLabel] approach, which means you can also use labels to accomplish "set-like" ambiguity resolution:
; app .add_system .add_system .add_system
Bevy ECS Optimizations #
We had some huge performance wins in Bevy 0.9 thanks to
- The Query fetch abstraction was reworked to hoist common parts out of individual iteration, improving iterator performance on some benchmarks by ~10-20%.
Query::getperformance also saw some improvements.
- Some unnecessary branches were removed from our data access apis, improving performance across most of our ECS benchmarks by ~5-20%!
- The parallel executor now starts running systems while the
prepare_systemsstep is running, cutting out a lot of delay when there are many systems with very little work to do. This cut almost 1 millisecond from our
many_foxesanimation benchmark (~12% improvement). That is a very big deal!
- Iterators now skip empty archetypes and tables when iterating over queries, which significantly reduces per-archetype iteration overhead when the archetype is empty.
@JoJoJet also optimized
Query::get_many access by replacing
array::map with loops, optimizing
get_many by ~20-30%!
ECS Change Detection Bypass #
Bevy ECS automatically detects changes to components and resources thanks to some very fancy Rust usage.
However sometimes, a user might make a change that they don't want to be detected. In Bevy 0.9, change detection can now be bypassed:
Enum Reflection #
Bevy Reflect now has native support for Rust enums! Bevy Reflect is Bevy's "Rust reflection system", which allows us to access Rust type information about values and types dynamically at runtime.
In past versions of Bevy, we needed to hack around Bevy Reflect's lack of enum support by treating enum types as "reflected values", which required a lot more work for each type, and it provided less reflected information about the type:
// Old // New
No more magic incantations!
Just like other reflected types, Enum reflection provides a lot of new runtime functionality:
// Access variant names let value = A; assert_eq!; // Get the variant type match value.variant_type let mut value = C ; // Read/write specific fields by name *value.field_mut.unwrap = true; // Iterate over the entire collection of fields for field in value.iter_fields // Detect the value type and retrieve information about it if let Enum = value.type_info
Other Bevy Reflect Improvements #
We've made a lot of other improvements to Bevy Reflect!
"Container" Reflect traits (Map, List, Array, Tuple) can now be drained to get owned values:
let container: = Boxnew; let values: = container.drain;
Reflected fields can now opt out of serialization without also opting out of reflection as a whole:
Boxed "reflection type" traits (Struct, Enum, List, etc) can now be converted to the more generic
let list: = Boxnew; let reflect: = list.into_reflect;
It is now possible to get owned variants of reflected types:
let value: = Boxnew; if let Struct = value.reflect_owned
Arrays in the "reflection path api" can now use list syntax:
let foo = Foo ; assert_eq!;
Reflected Lists now have a pop operation:
let mut list: = Boxnew; let value: = list.pop.unwrap; assert_eq!;
Example: Gamepad Viewer #
Bevy now has a gamepad input viewer app, which can be run using
cargo run --example gamepad_viewer from the Bevy repo.
Axis and Button Settings Validation #
InputAxis] and [
ButtonSettings] now use getters and setters to ensure the integrity of the settings. Setters will return an error instead of allowing invalid state.
For example, attempting to set the "press threshold" of a button to a value lower than the "release threshold" will result in an error:
button_settings.set_release_threshold; // this is too low! assert!
ScanCode Input Resource #
Bevy 0.9 adds an
Input<ScanCode> resource, which behaves like
Input<KeyCode>, but ignores keyboard layout:
Time Shader Globals #
Bevy shaders finally have access to built-in time values, removing the need for users to calculate time values and pass them in manually. Time is very useful in shaders, as it opens the doors to animating values.
Here is a simple shader that animates between a black and red color using the time:
Bevy Shaders now have access to the following globals:
time: time since startup in seconds, wrapping to 0 after 1 hour
delta_time: time since the previous frame in seconds
frame_count: frame count since the start of the app, wrapping to 0 after reaching the max size of a
High Entity Renderer Slowdown Optimization #
Bevy's renderer synchronizes entity state between the "main world" and the "render world", which enables parallel pipelined rendering. To implement this, we clear out the render entities every frame to ensure the integrity of the extracted state.
However, it became apparent that the method we were using to clear entities each frame was incurring a per-entity cost that became notable at very high entity counts.
In Bevy 0.9, we have significantly optimized the entity clearing, which cuts the cost of clearing 5,000,000 entities from ~360 microseconds to ~120 microseconds. We are also considering a "retained state" extraction model, piggybacking on Bevy ECS's built in change detection, which would remove the need to clear entities entirely (and optimize the extraction processes more generally). Implementing that will be a much larger effort though!
Vertex Attributes Fully Optional #
In a previous release we made it possible to make vertex attributes optional by specializing on mesh vertex attributes. But we left a couple of the common attributes as required: the position and the normal. Bevy 0.9 finishes the job. All standard mesh vertex attributes are now completely optional. If your mesh doesn't need positions for some reason, Bevy won't stop you!
Expose Multi Draw Indirect #
Wgpu has opt-in support for "multi draw indirect" apis on platforms that support them, which are a key piece of implementing efficient "gpu driven rendering". Bevy now exposes these apis through its "tracked render pass" abstraction, enabling developers to build render features using these apis.
KTX2 Array / Cubemap / Cubemap Array Textures #
Bevy can now properly load KTX2 array, cubemap, and cubemap array texture assets, which opens the doors to scenarios like skyboxes:
Bevy doesn't yet have high level support for skyboxes, but we have an example that illustrates how this feature can be implemented by users
It is often desirable to convert a position "on the screen" to a ray at that position facing out from the camera. For example, if you want to click on something in a 3D scene to select it, you might cast a ray from that point in the camera's view and see if it intersect with any "colliders" in the scene.
Bevy cameras now have a
viewport_to_world function, which provides this functionality:
let ray = camera.viewport_to_world.unwrap; if let Some = physics_context.cast_ray
The following cursor-driven selection uses
viewport_to_world to calculate the ray coming "out" of the cursor, then feeds it into the
bevy_rapier physics library to detect and pick up the card under the cursor:
Multiple Directional Lights #
Bevy now supports multiple directional lights (the new limit is 10 at once). Much like we did for point lights, we will likely make this unbounded on platforms that support storage buffers in the future, but this was a nice first step that maintains compatibility on all platforms.
Sprite Rects #
Sprites can now define "rects" that select a specific area of their texture to be used as the "sprite":
This is similar to how
TextureAtlasSprite / "sprite sheets" work, but without the need to define a texture atlas.
Plugin Settings #
In past versions of Bevy, "immutable" Plugin settings were represented as normal ECS resources, which were read as part of plugin init. This presented a number of problems:
- If a user inserted the plugin settings resource after the plugin was initialized, it would be silently ignored (and use the defaults instead)
- Users could modify the plugin settings resource after the plugin had been initialized. This created a false sense of control over settings that could no longer be changed.
These were especially problematic and confusing for the
WindowDescriptor resource, but it was a general problem.
To resolve this, in Bevy 0.9 we moved plugin settings onto the plugins themselves, and created new apis for overriding the default settings:
This makes the connection between the settings and the plugin clear, and differentiates these "plugin init" settings from "runtime configurable" settings (which are still represented as ECS resources).
Plugins Are Now Unique By Default #
Plugins are now unique by default. Attempting to add a unique plugin to an app more than once will result in an error. Plugins that are not intended to be unique can override the default
Task Pool: Nested Spawns on Scope #
Bevy's Task Pools now support "nested spawns on scopes":
let results = task_pool.scope; assert!; assert!;
This enables adding new tasks to the task pool scope while performing other tasks! This was a requirement for implementing the newly merged (but not yet implemented) Stageless RFC, but it enables new patterns for anyone spawning async tasks in Bevy!
Task Pool Panic Handling #
Bevy uses its own custom async task pools to manage scheduling parallel, async tasks. In previous versions of Bevy, if a task panicked in one of these pools, it would be non-recoverable unless every scheduled task used
catch_unwind (which isn't feasible). This would also permanently kill worker threads in the global task pools.
Bevy 0.9 resolves this problem by calling
catch_unwind inside the task pool executors.
Hierarchy Query Methods #
To make navigating hierarchies easier, we've added some convenience methods to
Bevy UI: The Origin Is Now In The Top Left #
Bevy UI now considers the "top left" of the window to be the "origin" and it extends "downward" (Y-down). To illustrate, consider the following cases where a widget spawned in the "default" location (at the origin).
Top Left Origin (New) #
Bottom Left Origin (Old) #
We chose to make this change because pretty much the entire UI ecosystem uses top left as the origin (Web, Godot, GTK, GPU images, etc).
In the early days when Bevy was still in its infancy, I (
@cart) originally opted for bottom left (Y-up) for consistency with Bevy's world space 2D and 3D coordinate systems. In theory, I figured this would make everything easier to reason about. But in practice, it turns out this consistency won us nothing. And the behavior defied users' expectations when it came to UI default behaviors. UIs tend to extend downward (from the top), not upward (from the bottom), so overriding the defaults was common practice.
Fortunately, in Bevy 0.9 we're now aligned with the rest of the ecosystem!
Bevy UI: Z-Indices #
Bevy UI elements now have more control over their "z index" (whether or not they are "in front" or "behind" each other). In past versions of Bevy, this was determined entirely by hierarchy: children stack on top of parents and earlier siblings. This is a nice "default" and works for a good portion of UIs, but some types of UI need more control over element ordering.
If you are a web developer and you have ever reached for the
z-index css property, that is the problem we're discussing here.
Bevy 0.9 adds a new
ZIndex component, which is an enum with two modes:
ZIndex::Local(i32): Overrides the depth relative to its siblings.
ZIndex::Global(i32): Overrides the depth relative to the UI root. Setting this essentially allows UI elements to "escape" z-ordering relative to their parents and instead be ordered relative to the entire UI.
UI items with a higher z-level within the context (local vs global) will show up in front of UI items with a lower z-level. Ties within a z-level fall back to hierarchy order. "Later" children stack on top of "earlier" children.
To illustrate, consider the following UI:
root (green) child1 (red) child2 (blue)
By default these all have a z-index of 0. The root is at the bottom and each subsequent child stacks "on top":
If we want the blue child to stack "behind" the earlier red child, we can set its z-index to a "local" value smaller than the default of 0:
blue.z_index = Local;
If we want the blue child to stack "behind" the green root, we can set its z-index to a "global" value smaller than the default of 0:
blue.z_index = Global;
Very useful stuff!
Bevy UI Scaling #
Bevy UI's global "pixel scale" can now be set using the
// Render UI pixel units 2x bigger app.insert_resource
This allows developers to expose arbitrary scale configuration to users in cases where that flexibility is beneficial.
Audio Playback Toggling #
It is now possible to toggle audio playback, which will flip between playing and pausing:
// Old, manual toggling (still possible) if audio_sink.is_paused else // New, automatic toggling audio_sink.toggle;
Time Scaling #
The "global" time scale can now be configured on
Time, which scales the values common functions like
In cases where unscaled values are required, you can use the new "raw" variants of these functions:
// The number of seconds elapsed since the last update, with time scaling taken into account. let delta = time.delta_seconds; // The number of seconds elapsed since the last update, with time scaling ignored. let raw_delta = time.raw_delta_seconds;
Time Wrapping #
Some scenarios, such as shaders, need to represent elapsed time values as
f32, which will suffer from precision issues pretty quickly. To resolve this,
Time has been extended to support "time wrapping":
// Wrap once every hour time.wrapping_period = from_secs: // If one hour and 6 seconds have passed since the app started, // this will return 6 seconds. let wrapped = time.seconds_since_startup_wrapped_f32;
What's Next? #
Here are some of the things
- High Level Post Processing Stack: Now that we have the core post processing pipeline in place, we need to make a higher level system that makes it easier for users to select, configure, and re-order post processing effects on a per-camera basis. Additionally for performance reasons we want to combine as many post processing effects into a single pass as we can, so we need an opinionated set of post processing apis that facilitate this.
- More Post Processing Effects: More anti-aliasing options (TAA, SMAA), more tonemapping algorithm options (Ex: ACES), SSAO
- Asset Preprocessing: We will be investing heavily in our asset pipeline, with a focus on:
- Pre-processing assets to do expensive work "during development time", so Bevy Apps can be deployed with assets that are prettier, smaller, and/or faster to load.
- Enabling configuring assets with .meta files. For example, you could define a texture compression level, the filter it should use, or the target format.
- Bevy UI Improvements: We will continue improving Bevy UI's functionality and expanding its widget library, with a focus on enabling editor experiences.
- More Scene Improvements: Nested scenes, implicit defaults, and inline assets.
- Bevy Editor: We will start prototyping Bevy Editor experiences, starting with scene editor tooling.
- Stageless ECS: Now that the Stageless RFC is merged, we can start implementing stageless scheduling! See the RFC for an outline of the improvements coming. This will be a game changer!
We're also looking for experts in some key areas. Most of our current devs are focused on the efforts above, so if you have interest and experience in the following areas, we would love to hear from you!
- Animation: Animation blending, procedural animation, and higher level animation systems. Check out the issues labeled
A-Animationon GitHub and introduce yourself on the
#animation-devchannel of our Discord.
- Audio: We need more control over audio playback, especially when it comes to layering effects. Check out the issues labeled
A-Audioon GitHub and introduce yourself on the
#audio-devchannel of our Discord.
Support Bevy #
Sponsorships help make our work on Bevy sustainable. If you believe in Bevy's mission, consider sponsoring us ... every bit helps!
- Carter Anderson (@cart): Full-time lead developer, project manager, and creator of Bevy. Focused on building out core engine systems, guiding project direction, and managing the community.
- Alice Cecile (@alice-i-cecile): Technical project manager, mad scientist, and documentation lead. While she regularly leads expeditions into new domains, ECS will always be home base.
- François Mockers (@mockersf): CI whisperer. Making sure everything is running smoothly and improving Bevy one PR at a time.
- Rob Swain (@superdump): Wielder of light. Turning data into shiny with massive parallelism. Currently hobby hacking so please donate to/sponsor the rest of the team. ❤️
A huge thanks to the 159 contributors that made this release (and associated docs) possible! In random order:
Full Change Log #
- Add FXAA postprocessing
- Fix color banding by dithering image before quantization
- Plugins own their settings. Rework PluginGroup trait.
- Add global time scaling
- add globals to mesh view bind group
- Add UI scaling
- Add FromReflect for Timer
- Re-add local bool
- Add default implementation of Serialize and Deserialize to Timer and Stopwatch
- add time wrapping to Time
- Stopwatch elapsed secs f64
- Remaining fn in Timer
- Support array / cubemap / cubemap array textures in KTX2
- Add methods for silencing system-order ambiguity warnings
- bevy_dynamic_plugin: make it possible to handle loading errors
- can get the settings of a plugin from the app
- Use plugin setup for resource only used at setup time
TimeUpdateStrategyresource for manual
- dynamic scene builder
- Create a scene from a dynamic scene
- Scene example: write file in a task
- Add writing of scene data to Scene example
- can clone a scene
- Add "end of main pass post processing" render graph node
- Sprite: allow using a sub-region (Rect) of the image
- Add missing type registrations for bevy_math types
- add serialize feature to bevy_transform
- Add associated constant
- bevy_reflect: Add
- Add reflect_owned
ReflectDefaultto std types
- Add FromReflect for Visibility
- Enable Constructing ReflectComponent/Resource
- Support multiple
#[reflect_value]+ improve error messages
- Reflect Default for GlobalTransform
- Impl Reflect for PathBuf and OsString
- Reflect Default for
- Make arrays behave like lists in reflection
Debugfor dynamic types
Reflectfor all the ranges
- register missing reflect types
- bevy_reflect: Get owned fields
- bevy_reflect: Add
FromReflectto the prelude
Input<T>, some misc improvements to reflect value derive
Cow<'static, str>for reflection
- bevy_reflect: Relax bounds on
ReflectMutin favor of
- add some info from
ReflectPathErrorto the error messages
- Added reflect/from reflect impls for NonZero integer types
- bevy_reflect: Update enum derives
reflect(skip_serializing)which retains reflection but disables automatic serialization
- bevy_reflect: Reflect enums
- Disabling default features support in bevy_ecs, bevy_reflect and bevy
- expose window alpha mode
- Make bevy_window and bevy_input events serializable
- Add window resizing example
- feat: add GamepadInfo, expose gamepad names
FromReflectfor input types
- Make TouchInput and ForceTouch serializable
- Add a Gamepad Viewer tool to examples
Deserializefor events in
PartialEqfor events in both, and
Eqwhere possible in both.
- Support for additional gamepad buttons and axis
- Added keyboard scan input event
- Add methods to
Query<&Parent>to iterate over descendants and ancestors
- Expose mint feature in bevy_math/glam
- Utility methods for Val
- Register missing bevy_text types
- Add additional constructors for
UiRectto specify values for specific fields
- Add AUTO and UNDEFINED const constructors for
- Add Exponential Moving Average into diagnostics
send_eventand friends to
- Add a method for accessing the width of a
- Add iter_entities to World #6228
- Adding Debug implementations for App, Stage, Schedule, Query, QueryState, etc.
- Add a method for mapping
- implemented #[bundle(ignore)]
- Allow access to non-send resource through
- Add get_entity to Commands
- Added the ability to get or set the last change tick of a system.
- Add a module for common system
- SystemParam for the name of the system you are currently in
- Warning message for missing events
- Add a change detection bypass and manual control over change ticks
- Add into_world_mut to EntityMut
From<EntityMut>for EntityRef (fixes #5459)
- Implement IntoIterator for ECS wrapper types.
- Add CameraRenderGraph::set
- Use wgsl saturate
- Add mutating
- Add globals struct to mesh2d
- add support for .comp glsl shaders
- add Debug, Copy, Clone derives to Circle
- Add TextureFormat::Rg16Unorm support for Image and derive Resource for SpecializedComputePipelines
Projectioncomponent to prelude.
Imageconversion functions (fixes #5452)
- Macro for Loading Internal Binary Assets
- Add Eq & PartialEq to AssetPath
- Add warning when using load_folder on web
- Expose rodio's Source and Sample traits in bevy_audio
- Add a way to toggle
- separate tonemapping and upscaling passes
- Rework ViewTarget to better support post processing
- bevy_reflect: Improve serialization format even more
- bevy_reflect: Binary formats
- Unique plugins
- Support arbitrary RenderTarget texture formats
Resourcetrait opt-in, requiring
WorldQueryGatstrait with actual gats
- Change UI coordinate system to have origin at top left corner
- Move the cursor's origin back to the bottom-left
- Add z-index support with a predictable UI stack
- TaskPool Panic Handling
Bundletuples for insertion
- Spawn now takes a Bundle
- Accept Bundles for insert and remove. Deprecate insert/remove_bundle
- Exclusive Systems Now Implement
System. Flexible Exclusive System Params
- bevy_scene: Serialize entities to map
- bevy_scene: Stabilize entity order in
- bevy_scene: Replace root list with struct
- bevy_scene: Use map for scene
- Start running systems while prepare_systems is running
- Extract Resources into their own dedicated storage
- get proper texture format after the renderer is initialized, fix #3897
- Add getters and setters for
- Clean up Fetch code
- Nested spawns on scope
- Skip empty archetypes and tables when iterating over queries
- Increase the
MAX_DIRECTIONAL_LIGHTSfrom 1 to 10
- bevy_pbr: Normalize skinned normals
- remove mandatory mesh attributes
startand add new
playmethod that won't overwrite the existing animation if it's already playing
- Replace the
- improve panic messages for add_system_to_stage and add_system_set_to_stage
- Use default serde impls for Entity
- scenes: simplify return type of iter_instance_entities
- Consistently use
PIto specify angles in examples.
transform_pointand improve docs
- do not set cursor grab on window creation if not asked for
- Support monitor selection for all window modes.
Copy; do not require / return references to it in
- Update tracing-chrome to 0.6.0
- Update to ron 0.8
- Update clap requirement from 3.2 to 4.0
- Update glam 0.22, hexasphere 8.0, encase 0.4
- Update to notify 5.0 stable
- Update rodio requirement from 0.15 to 0.16
- remove copyless
- Swap out num_cpus for std::thread::available_parallelism
- Cleaning up NodeBundle, and some slight UI module re-organization
- Make the default background color of
- changed diagnostics from seconds to milliseconds
- Remove unnecesary branches/panics from Query accesses
debug_checked_unwrapshould track its caller
- Speed up
Query::get_manyand add benchmarks
- Rename system chaining to system piping
- [Fixes #6059]
Entity's “ID” should be named “index” instead
Queryfilter types must be
- Remove ambiguity sets
Sizedbounds around change detection types
- Remove ExactSizeIterator from QueryCombinationIter
- Remove Sync bound from Command
- Make most
- Avoid making
- bevy_ecs: Use 32-bit entity ID cursor on platforms without AtomicI64
- Specialize UI pipeline on "hdr-ness"
- Allow passing
glamvector types as vertex attributes
- Add multi draw indirect draw calls
- Take DirectionalLight's GlobalTransform into account when calculating shadow map volume (not just direction)
- Respect mipmap_filter when create ImageDescriptor with linear()/nearest()
- use bevy default texture format if the surface is not yet available
- log pipeline cache errors earlier
- Merge TextureAtlas::from_grid_with_padding into TextureAtlas::from_grid through option arguments
- Reconfigure surface on present mode change
- Use 3 bits of PipelineKey to store MSAA sample count
- Limit FontAtlasSets
- Make vertex colors work without textures in bevy_sprite
- use bevy_default() for texture format in post_processing
- don't render completely transparent UI nodes
- make TextLayoutInfo a Component
Handle::<T>field id private, and replace with a getter
- Rename Handle::as_weak() to cast_weak()
- Optimize rendering slow-down at high entity counts
- bevy_reflect: Fix
DynamicScenenot respecting component registrations during serialization
- fixes the types for Vec3 and Quat in scene example to remove WARN from the logs
- Fix end-of-animation index OOB
- bevy_reflect: Remove unnecessary
- bevy_reflect: Fix
- Fix outdated and badly formatted docs for
- disable window pre creation for ios
- Remove unnecessary unsafe
- Fix window centering when scale_factor is not 1.0
- fix order of exit/close window systems
- bevy_input: Fix process touch event
- fix: explicitly specify required version of async-task
- Fix inconsistent children removal behavior
- tick local executor
- Fix panic when the primary window is closed
- UI scaling fix
- Fix clipping in UI
- Fixes scroll example after inverting UI Y axis
- Fixes incorrect glyph positioning for text2d
- Clean up taffy nodes when UI node entities are removed
- Fix unsound
- Fix spawning empty bundles
- Fix query.to_readonly().get_component_mut() soundness bug
- #5817: derive_bundle macro is not hygienic
- drop old value in
- Fix lifetime bound on
mesh.wgslerror for meshes without normals
- Fix panic when using globals uniform in wasm builds
- Resolve most remaining execution-order ambiguities
mesh2d_tangent_local_to_worldwith the right arguments
- Fixes Camera not being serializable due to missing registrations in core functionality.
- fix spot dir nan bug
- use alpha mask even when unlit
Timeouterrors on Linux AMD & Intel
- adjust cluster index for viewport origin
- update camera projection if viewport changed
- Ensure 2D phase items are sorted before batching
- bevy_pbr: Fix incorrect and unnecessary normal-mapping code
- Add explicit ordering between
- bevy_pbr: Fix tangent and normal normalization
- Fix shader syntax
- Correctly use as_hsla_f32 in
AddAssign<Color>, fixes #5543
- Sync up bevy_sprite and bevy_ui shader View struct
- Fix View by adding missing fields present in ViewUniform
- Freeing memory held by visible entities vector
- Correctly parse labels with '#'