Bevy 0.9
Posted on November 12, 2022 by Carter Anderson ( @cart @cart_cart cartdev )
Thanks to 159 contributors, 430 pull requests, community reviewers, and our generous sponsors, I'm happy to announce the Bevy 0.9 release on crates.io!
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:
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.
Bloom is enabled by adding a BloomSettings
component to a camera with HDR textures enabled:
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:
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:
commands.spawn(Camera3dBundle {
tonemapping: Tonemapping::Enabled {
deband_dither: true,
},
..default()
});
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 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.
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 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 TextureFormats
(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:
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
(
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:
// 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.
// 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:
// Old
"name": {
"type": "alloc::string::String",
"value": "Reyna",
},
// New
name: "Reyna",
Nicer Enum Syntax #
Consider the enum:
pub enum Team {
A,
B,
}
Lets compare how it is serialized:
// 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 section of this blog post for details!
Nicer Tuples #
// 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).
// 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.
// Old
[
(
entity: 0,
components: [ ],
),
(
entity: 1,
components: [ ],
),
]
// New
(
entities: {
0: (
components: { },
),
1: (
components: { },
),
},
)
Binary Scene Formats #
Bevy Scenes can be serialized and deserialized to/from binary formats, such as bincode
, postcard
, and 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
fn system(world: &World, players: Query<Entity, With<Player>>) {
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:
builder.extract_entity(entity);
More Scene Construction Tools #
Scenes
can now be cloned:
let scene = scene.clone_with(type_registry).unwrap();
DynamicScenes
can now be converted to Scenes
:
let scene = Scene::from_dynamic_scene(dynamic_scene, type_registry).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:
(Player { name: "Sova" }, Health::new(10), Team::A)
The Bundle
trait can also be derived:
#[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
instead of just tuples of Components
. The value of this will be made clear in a moment.
First, spawn
now takes a bundle:
// 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
:
// 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:
// 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". This makes this single spawn operation much more efficient!
These principles apply to the insert APIs as well:
// Old
commands
.insert_bundle(PlayerBundle::default())
.insert(ActivePlayer);
// New
commands.insert((PlayerBundle::default(), ActivePlayer));
They also apply to the remove APIs:
// Old
commands
.remove_bundle::<PlayerBundle>()
.remove::<ActivePlayer>();
// New
commands.remove::<(PlayerBundle, ActivePlayer)>();
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:
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:
// Old
fn some_system(world: &mut World) {
let mut state: SystemState<(Res<Time>, Query<&mut Transform>)> =
SystemState::new(&mut world);
let (time, mut transforms) = state.get_mut(world);
}
// New
fn some_system(world: &mut World, state: &mut SystemState<(Res<Time>, Query<&mut Transform>)>) {
let (time, mut transforms) = state.get_mut(world);
}
QueryState
enables cached access to individual queries:
// Old
fn some_system(world: &mut World) {
let mut transforms = world.query::<&Transform>();
for transform in transforms.iter(world) {
}
}
// New
fn some_system(world: &mut World, transforms: &mut QueryState<&Transform>) {
for transform in transforms.iter(world) {
}
}
Local
enables storing local data inside of the exclusive system:
// Old
#[derive(Resource)]
struct Counter(usize);
fn some_system(world: &mut World) {
let mut counter = world.resource_mut::<Counter>();
counter.0 += 1;
}
// New
fn some_system(world: &mut World, mut counter: Local<usize>) {
*counter += 1;
}
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 (WorldQuery
, WorldQueryGats
(a "lack of real GATs hack" trait), and Fetch
).
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 #
The Resource
trait is now no longer automatically implemented for all types. It must be derived:
#[derive(Resource)]
struct Counter(usize);
This change was made on the tail of making the same decision for Component
types. In short:
Auto-implementing
Resource
for every type made it very easy to accidentally insert the "wrong" value, such as inserting the constructor function pointer instead of the value itself:struct Counter(usize); // This inserts the constructor function pointer as a resource! // Weird and confusing! app.insert_resource(Counter); // This is how it should be done! app.insert_resource(Counter(0));
Deriving
Resource
documents 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:
std
types likeVec<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:
#[derive(AmbiguitySet)]
struct AmbiguousSystems;
app
.add_system(a.in_ambiguity_set(AmbiguousSystems))
.add_system(b.in_ambiguity_set(AmbiguousSystems))
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 ambiguous_with
calls:
app
.add_system(a)
.add_system(b.ambiguous_with(a))
This builds on the existing [SystemLabel
] approach, which means you can also use labels to accomplish "set-like" ambiguity resolution:
#[derive(SystemLabel)]
struct Foo;
app
.add_system(a.label(Foo))
.add_system(b.label(Foo))
.add_system(b.ambiguous_with(Foo))
Bevy ECS Optimizations #
We had some huge performance wins in Bevy 0.9 thanks to @james7132
:
- The Query fetch abstraction was reworked to hoist common parts out of individual iteration, improving iterator performance on some benchmarks by ~10-20%.
Query::get
performance 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_systems
step 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 ourmany_foxes
animation 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:
fn system(mut transforms: Query<&mut Transform>) {
for transform in &mut transforms {
transform.bypass_change_detection().translation.x = 1.0;
}
}
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
#[derive(Copy, Clone, PartialEq, Debug, Default, Serialize, Deserialize, Reflect)]
#[reflect_value(PartialEq, Serialize, Deserialize)]
enum SomeEnum {
A,
B(usize),
C {
foo: f32,
bar: bool,
},
}
// New
#[derive(Reflect)]
enum SomeEnum {
A,
B(usize),
C {
foo: f32,
bar: bool,
},
}
No more magic incantations!
Just like other reflected types, Enum reflection provides a lot of new runtime functionality:
// Access variant names
let value = SomeEnum::A;
assert_eq!("A", value.variant_name());
// Get the variant type
match value.variant_type() {
VariantType::Unit => {},
VariantType::Struct => {},
VariantType::Tuple => {},
}
let mut value = SomeEnum::C {
foo: 1.23,
bar: false
};
// Read/write specific fields by name
*value.field_mut("bar").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 TypeInfo::Enum(info) = value.type_info() {
if let VariantInfo::Struct(struct_info) = value.variant("C") {
let first_field = struct_info.field_at(0).unwrap();
assert_eq!(first_field.name(), "foo");
}
}
Deriving Reflect
on enums also automatically adds support for "reflect-based serialization", which as of Bevy 0.9 now has a much nicer syntax.
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: Box<dyn List> = Box::new(vec![1.0, 2.0]);
let values: Vec<Box<dyn Reflect>> = container.drain();
Reflected fields can now opt out of serialization without also opting out of reflection as a whole:
#[derive(Reflect)]
struct Foo {
a: i32,
// fully invisible to reflection, including serialization
#[reflect(ignore)]
b: i32,
// can still be reflected, but will be skipped when serializing
#[reflect(skip_serializing)]
c: i32,
}
Boxed "reflection type" traits (Struct, Enum, List, etc) can now be converted to the more generic Box<dyn Reflect>
:
let list: Box<dyn List> = Box::new(vec![1.0, 2.0]);
let reflect: Box<dyn Reflect> = list.into_reflect();
It is now possible to get owned variants of reflected types:
let value: Box<Sprite> = Box::new(Sprite::default());
if let ReflectOwned::Struct(owned) = value.reflect_owned() {
// owned is a Box<dyn Struct>
}
Arrays in the "reflection path API" can now use list syntax:
#[derive(Reflect)]
struct Foo {
bar: [u8; 3],
}
let foo = Foo {
bar: [10, 20, 30],
};
assert_eq!(*foo.get_path("bar[1]").unwrap(), 20);
Reflected Lists now have a pop operation:
let mut list: Box<dyn List> = Box::new(vec![1u8, 2u8]);
let value: Box<dyn Reflect> = list.pop().unwrap();
assert_eq!(*value.downcast::<u8>().unwrap(), 2u8);
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(0.65);
// this is too low!
assert!(button_settings.try_set_press_threshold(0.6).is_err())
ScanCode Input Resource #
Bevy 0.9 adds an Input<ScanCode>
resource, which behaves like Input<KeyCode>
, but ignores keyboard layout:
fn system(scan_code: Res<Input<ScanCode>>, key_code: Res<Input<KeyCode>>) {
// 33 is the scan code for F on a physical keyboard
if scan_code.pressed(ScanCode(33)) {
log!("The physical F key is pressed on the keyboard");
}
if keycode.pressed(KeyCode::F) {
log!("The logical F key is pressed on the keyboard, taking layout into account.");
}
}
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:
@fragment
fn fragment(in: FragmentInput) -> @location(0) vec4<f32> {
return vec4<f32>(sin(globals.time * 10.0), 0.0, 0.0, 1.0);
}
Bevy Shaders now have access to the following globals:
time
: time since startup in seconds, wrapping to 0 after 1 hourdelta_time
: time since the previous frame in secondsframe_count
: frame count since the start of the app, wrapping to 0 after reaching the max size of au32
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
Camera::viewport_to_world #
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(transform, cursor_position).unwrap();
if let Some(entity) = physics_context.cast_ray(ray.origin, ray.direction) {
// select entity
}
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":
Sprite {
rect: Some(Rect {
min: Vec2::new(100.0, 0.0),
max: Vec2::new(200.0, 100.0),
}),
..default()
}
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:
app.add_plugins(DefaultPlugins
.set(AssetPlugin {
watch_for_changes: true,
..default()
})
.set(WindowPlugin {
window: WindowDescriptor {
width: 400.0,
..default()
},
..default()
})
)
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 is_unique
method:
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app.add_system(some_system);
}
fn is_unique(&self) -> bool {
false
}
}
Task Pool: Nested Spawns on Scope #
Bevy's Task Pools now support "nested spawns on scopes":
let results = task_pool.scope(|scope| {
scope.spawn(async move {
scope.spawn(async move { 1 });
2
});
});
assert!(results.contains(&1));
assert!(results.contains(&2));
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 Query<&Children>
and Query<&Parent>
:
#[derive(Resource)]
struct SomeEntity(Entity);
fn system(children: Query<&Children>, some_entity: Res<SomeEntity>) {
// iterate all descendents of some_entity
for entity in children.iter_descendants(some_entity.0) {
}
}
fn other_system(parents: Query<&Parent>, some_entity: Res<SomeEntity>) {
// iterate all ancestors of some_entity
for entity in parents.iter_ancestors(some_entity.0) {
}
}
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 = ZIndex::Local(-1);
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 = ZIndex::Global(-1);
Very useful stuff!
Bevy UI Scaling #
Bevy UI's global "pixel scale" can now be set using the UiScale
resource:
// Render UI pixel units 2x bigger
app.insert_resource(UiScale { scale: 2.0 })
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() {
audio_sink.play();
} else {
audio_sink.pause();
}
// 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 Time::delta_seconds()
return.
time.set_relative_speed(2.0);
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 = Duration::from_secs(60 * 60):
// 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-Animation
on GitHub and introduce yourself on the#animation-dev
channel of our Discord. - Audio: We need more control over audio playback, especially when it comes to layering effects. Check out the issues labeled
A-Audio
on GitHub and introduce yourself on the#audio-dev
channel 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. ❤️
Contributors #
A huge thanks to the 159 contributors that made this release (and associated docs) possible! In random order:
- @Edwox
- @targrub
- @fvacek
- @xtr3m3nerd
- @timokoesters
- @Suficio
- @Sergi-Ferrez
- @hymm
- @MrGVSV
- @SleepySwords
- @nicopap
- @Vrixyz
- @McSpidey
- @VitalyAnkh
- @ramirezmike
- @jiftoo
- @TheNeikos
- @ManevilleF
- @KDecay
- @Zearin
- @marlyx
- @StarArawn
- @Ixentus
- @hmeine
- @emersonmx
- @gilescope
- @inodentry
- @robtfm
- @yrns
- @Lucidus115
- @kurtkuehnert
- @zmarlon
- @leereilly
- @galkowskit
- @DGriffin91
- @Ptrskay3
- @strattonbrazil
- @Pand9
- @PROMETHIA-27
- @zicklag
- @lewiszlw
- @contagnas
- @EMachad0
- @SpecificProtagonist
- @BoxyUwU
- @jkb0o
- @xgbwei
- @andresovela
- @0x182d4454fb211940
- @TehPers
- @pcone
- @CleanCut
- @makspll
- @64kramsystem
- @Wandalen
- @coreh
- @Fracey
- @Azervu
- @SyamaMishra
- @BeastLe9enD
- @Weibye
- @Pietrek14
- @NiklasEi
- @TheRawMeatball
- @jgoday
- @7flash
- @light4
- @Ian-Yy
- @Carter0
- @slyedoc
- @devil-ira
- @MDeiml
- @NathanSWard
- @robem
- @Bleb1k
- @bzm3r
- @anchpop
- @aevyrie
- @amiani
- @x3ro
- @NoahShomette
- @bjorn3
- @djeedai
- @bwhitt7
- @oceantume
- @micron-mushroom
- @JMS55
- @asherkin
- @afonsolage
- @shuoli84
- @harudagondi
- @Demiu
- @TimJentzsch
- @gak
- @dataphract
- @raffimolero
- @Moulberry
- @james7132
- @torsteingrindvik
- @jakobhellermann
- @hakolao
- @themasch
- @CatThingy
- @Metadorius
- @merelymyself
- @SludgePhD
- @CGMossa
- @sullyj3
- @ian-h-chamberlain
- @lain-dono
- @mwcz
- @thebluefish
- @manokara
- @mirkoRainer
- @hankjordan
- @cryscan
- @WaffleLapkin
- @mahulst
- @AlexOkafor
- @Davier
- @jwagner
- @CAD97
- @alice-i-cecile
- @james-j-obrien
- @rparrett
- @tguichaoua
- @YohDeadfall
- @msvbg
- @komadori
- @maniwani
- @Shatur
- @LarsDu
- @DJMcNab
- @JoJoJet
- @polarvoid
- @KirmesBude
- @Aceeri
- @ottah
- @IceSentry
- @Piturnah
- @lovelymono
- @maxwellodri
- @oledfish
- @BorisBoutillier
- @mockersf
- @Nilirad
- @elbertronnie
- @maccesch
- @vertesians
- @superdump
- @wanderrful
- @Neo-Zhixing
- @rustui
- @cart
- @JohnTheCoolingFan
- @pascualex
- @fishykins
- @Carlrs
- @leath-dub
Full Change Log #
Added #
- Bloom
- 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
has_received_time
intime_system
- 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
- Add
TimeUpdateStrategy
resource for manualTime
updating - 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
- Add
Camera::viewport_to_world
- Sprite: allow using a sub-region (Rect) of the image
- Add missing type registrations for bevy_math types
- Add
serialize
feature tobevy_core
- add serialize feature to bevy_transform
- Add associated constant
IDENTITY
toTransform
and friends. - bevy_reflect: Add
Reflect::into_reflect
- Add reflect_owned
Reflect
forTonemapping
andClusterConfig
- add
ReflectDefault
to std types - Add FromReflect for Visibility
- Register
RenderLayers
type inCameraPlugin
- Enable Constructing ReflectComponent/Resource
- Support multiple
#[reflect]
/#[reflect_value]
+ improve error messages - Reflect Default for GlobalTransform
- Impl Reflect for PathBuf and OsString
- Reflect Default for
ComputedVisibility
andHandle<T>
- Register
Wireframe
type - Derive
FromReflect
forTransform
andGlobalTransform
- Make arrays behave like lists in reflection
- Implement
Debug
for dynamic types - Implemented
Reflect
for all the ranges - Add
pop
method forList
trait. - bevy_reflect:
GetTypeRegistration
forSmallVec<T>
- register missing reflect types
- bevy_reflect: Get owned fields
- bevy_reflect: Add
FromReflect
to the prelude - implement
Reflect
forInput<T>
, some misc improvements to reflect value derive - register
Cow<'static, str>
for reflection - bevy_reflect: Relax bounds on
Option<T>
- remove
ReflectMut
in favor ofMut<dyn Reflect>
- add some info from
ReflectPathError
to the error messages - Added reflect/from reflect impls for NonZero integer types
- bevy_reflect: Update enum derives
- Add
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
- Derive
Reflect
+FromReflect
for input types - Make TouchInput and ForceTouch serializable
- Add a Gamepad Viewer tool to examples
- Derived
Copy
trait forbevy_input
events,Serialize
/Deserialize
for events inbevy_input
andbevy_windows
,PartialEq
for events in both, andEq
where possible in both. - Support for additional gamepad buttons and axis
- Added keyboard scan input event
- Add
set_parent
andremove_parent
toEntityCommands
- Add methods to
Query<&Children>
andQuery<&Parent>
to iterate over descendants and ancestors - Add
is_finished
toTask<T>
- Expose mint feature in bevy_math/glam
- Utility methods for Val
- Register missing bevy_text types
- Add additional constructors for
UiRect
to specify values for specific fields - Add AUTO and UNDEFINED const constructors for
Size
- Add Exponential Moving Average into diagnostics
- Add
send_event
and friends toWorldCell
- Add a method for accessing the width of a
Table
- Add iter_entities to World #6228
- Adding Debug implementations for App, Stage, Schedule, Query, QueryState, etc.
- Add a method for mapping
Mut<T>
->Mut<U>
- implemented #[bundle(ignore)]
- Allow access to non-send resource through
World::resource_scope
- 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
chain
/pipe
adapters - 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
- Add
FromWorld
bound toT
inLocal<T>
- Add
From<EntityMut>
for EntityRef (fixes #5459) - Implement IntoIterator for ECS wrapper types.
- add
Res::clone
- Add CameraRenderGraph::set
- Use wgsl saturate
- Add mutating
toggle
method toVisibility
component - Add globals struct to mesh2d
- add support for .comp glsl shaders
- Implement
IntoIterator
for&Extract<P>
- add Debug, Copy, Clone derives to Circle
- Add TextureFormat::Rg16Unorm support for Image and derive Resource for SpecializedComputePipelines
- Add
bevy_render::texture::ImageSettings
to prelude - Add
Projection
component to prelude. - Expose
Image
conversion functions (fixes #5452) - Macro for Loading Internal Binary Assets
- Add
From<String>
forAssetPath<'a>
- Add Eq & PartialEq to AssetPath
- add
ReflectAsset
andReflectHandle
- Add warning when using load_folder on web
- Expose rodio's Source and Sample traits in bevy_audio
- Add a way to toggle
AudioSink
Changed #
- 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
- Make
Resource
trait opt-in, requiring#[derive(Resource)]
V2 - Replace
WorldQueryGats
trait 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
- Implement
Bundle
forComponent
. UseBundle
tuples for insertion - Spawn now takes a Bundle
- make
WorldQuery
very flat - 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
DynamicSceneBuilder
- bevy_scene: Replace root list with struct
- bevy_scene: Use map for scene
components
- 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
InputAxis
andButtonSettings
- Clean up Fetch code
- Nested spawns on scope
- Skip empty archetypes and tables when iterating over queries
- Increase the
MAX_DIRECTIONAL_LIGHTS
from 1 to 10 - bevy_pbr: Normalize skinned normals
- remove mandatory mesh attributes
- Rename
play
tostart
and add newplay
method that won't overwrite the existing animation if it's already playing - Replace the
bool
argument ofTimer
withTimerMode
- 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
PI
to specify angles in examples. - Remove
Transform::apply_non_uniform_scale
- Rename
Transform::mul_vec3
totransform_point
and improve docs - make
register
onTypeRegistry
idempotent - do not set cursor grab on window creation if not asked for
- Make
raw_window_handle
field inWindow
andExtractedWindow
anOption
. - Support monitor selection for all window modes.
Gamepad
type isCopy
; do not require / return references to it inGamepads
API- 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
wgpu
to 0.14.0,naga
to0.10.0
,winit
to 0.27.4,raw-window-handle
to 0.5.0,ndk
to 0.7 - Update to notify 5.0 stable
- Update rodio requirement from 0.15 to 0.16
- remove copyless
- Mark
Task
as#[must_use]
- 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
NodeBundle
transparent - Rename
UiColor
toBackgroundColor
- changed diagnostics from seconds to milliseconds
- Remove unnecesary branches/panics from Query accesses
debug_checked_unwrap
should track its caller- Speed up
Query::get_many
and add benchmarks - Rename system chaining to system piping
- [Fixes #6059]
Entity
's “ID” should be named “index” instead Query
filter types must beReadOnlyWorldQuery
- Remove ambiguity sets
- relax
Sized
bounds around change detection types - Remove ExactSizeIterator from QueryCombinationIter
- Remove Sync bound from Command
- Make most
Entity
methodsconst
- Remove
insert_resource_with_id
- Avoid making
Fetch
sClone
- Remove
Sync
bound fromLocal
- Replace
many_for_each_mut
withiter_many_mut
. - bevy_ecs: Use 32-bit entity ID cursor on platforms without AtomicI64
- Specialize UI pipeline on "hdr-ness"
- Allow passing
glam
vector 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
- Move
sprite::Rect
intobevy_math
- 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
- make
Handle::<T>
field id private, and replace with a getter - Remove
AssetServer::watch_for_changes()
- Rename Handle::as_weak() to cast_weak()
- Remove
Sync
requirement inDecodable::Decoder
Fixed #
- Optimize rendering slow-down at high entity counts
- bevy_reflect: Fix
DynamicScene
not 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
Clone
bounds - bevy_reflect: Fix
apply
method forOption<T>
- Fix outdated and badly formatted docs for
WindowDescriptor::transparent
- disable window pre creation for ios
- Remove unnecessary unsafe
Send
andSync
impl forWinitWindows
on wasm. - 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
clippy::iter_with_drain
- Use
cbrt()
instead ofpowf(1./3.)
- Fix
RemoveChildren
command - 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
EntityMut::remove_children
. AddEntityMut::world_scope
- Fix spawning empty bundles
- Fix query.to_readonly().get_component_mut() soundness bug
- #5817: derive_bundle macro is not hygienic
- drop old value in
insert_resource_by_id
if exists - Fix lifetime bound on
From
impl forNonSendMut
->Mut
- Fix
mesh.wgsl
error for meshes without normals - Fix panic when using globals uniform in wasm builds
- Resolve most remaining execution-order ambiguities
- Call
mesh2d_tangent_local_to_world
with 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
- Ignore
Timeout
errors 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
update_frusta
andcamera_system
- bevy_pbr: Fix tangent and normal normalization
- Fix shader syntax
- Correctly use as_hsla_f32 in
Add<Color>
andAddAssign<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 '#'