Bevy 0.10
Posted on March 6, 2023 by Bevy Contributors
Thanks to 173 contributors, 689 pull requests, community reviewers, and our generous sponsors, we're happy to announce the Bevy 0.10 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.10, check out our 0.9 to 0.10 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:
- ECS Schedule v3: Bevy now has much simpler, more flexible scheduling. Systems are now stored in a unified schedule, commands can be applied explicitly via
apply_system_buffers
, and a whole lot of quality of life and bug fixes. - Cascaded Shadow Maps: Higher quality shadow maps that cover larger distances, where the quality follows the camera.
- Environment Map Lighting: 360 degree ambient image based lighting that can cheaply and drastically improve the visual quality of a scene.
- Depth and Normal Prepass: Render depth and normal textures for a scene prior to the main pass, enabling new effects and (in some cases) improved performance. Shadow mapping uses the prepass shaders, which enables transparent textures to cast shadows.
- Smooth Skeletal Animation Transitions: Smoothly transition between two skeletal animations playing at the same time!
- Improved Android Support: Bevy now works out of the box on more Android devices (with a couple of caveats)
- Revamped Bloom: Bloom now looks better, is easier to control, and has fewer visual artifacts.
- Distance and Atmospheric Fog: Add depth and ambiance to your scene with 3D distance and atmospheric fog effects!
- StandardMaterial Blend Modes: Achieve a variety of interesting effects with more PBR material blend modes.
- More Tonemapping Choices: Choose one of 7 popular tonemapping algorithms for your HDR scenes to achieve the visual style you are looking for.
- Color Grading: Control per-camera exposure, gamma, "pre-tonemapping saturation", and "post-tonemapping saturation".
- Parallel Pipelined Rendering: App logic and render logic now run in parallel automatically, yielding significant performance wins.
- Windows as Entities: Windows are now represented as entities instead of resources, improving the user experience and unlocking new scenarios.
- Renderer Optimizations: We spent a ton of effort optimizing the renderer this cycle. Bevy's renderer is snappier than ever!
- ECS Optimizations: Likewise, we've turbocharged many common ECS operations. Bevy apps get a nice speed boost!
ECS Schedule v3 #
Thanks to the fantastic work of our ECS team, the hotly awaited "stageless" scheduling RFC has been implemented!
Schedule v3 is the culmination of significant design and implementation work. Scheduling APIs are a central and defining part of the Bevy developer experience, so we had to be very thoughtful and meticulous about this next evolution of the API. In addition to the RFC PR, the initial implementation PR by @maniwani
and the Bevy Engine internals port PR by @alice-i-cecile
are great places to start if you would like a view into our process and rationale. As we all know, plans and implementations are two different things. Our final implementation is a bit different from the initial RFC (in a good way).
There are a ton of changes, but we've put a lot of care into ensuring the migration path for existing applications is relatively straightforward. Don't sweat it!
Let's take a look at what shipped in 0.10!
A Single Unified Schedule #
Have you ever wanted to specify that system_a
runs before system_b
, only to be met with confusing warnings that system_b
isn't found because it's in a different stage?
No more! All systems within a single Schedule
are now stored in a single data structure with a global awareness of what's going on.
This simplifies our internal logic, makes your code more robust to refactoring, and allows plugin authors to specify high-level invariants (e.g. "movement must occur before collision checking") without locking themselves into an exact schedule location.
This diagram made with @jakobhellermann's bevy_mod_debugdump
crate shows a simplified version of Bevy's default schedule.
Adding Systems #
Systems
(which are just normal Rust functions!) are how you define game logic in Bevy ECS. With Schedule v3, you can add systems to your App
just like you did in previous versions:
app.add_system(gravity)
However Schedule v3 has some new tricks up its sleeve! You can now add multiple systems at once:
app.add_systems((apply_acceleration, apply_velocity))
By default, Bevy runs systems in parallel to each other. In previous versions of Bevy, you ordered systems like this:
app
.add_system(walk.before(jump))
.add_system(jump)
.add_system(collide.after(jump))
You can still do that! But you can now compress this using add_systems
:
// much cleaner!
app.add_systems((
walk.before(jump),
jump,
collide.after(jump),
))
before()
and after()
are definitely useful tools! However, thanks to the new chain()
function, it is now much easier to run systems in a specific order:
// This is equivalent to the previous example
app.add_systems((walk, jump, collide).chain())
chain()
will run the systems in the order they were defined. Chaining also pairs with per-system configuration:
app.add_systems((walk.after(input), jump, collide).chain())
Configurable System Sets #
In Schedule v3, the idea of the "system set" has been redefined to support more natural and flexible control over how systems are run and scheduled. The old "system label" concept has been combined with the "set" concept, resulting in one straightforward but powerful abstraction.
SystemSets
are named collections of systems that share system configuration across all of their members. Ordering systems relative to a SystemSet
applies that ordering to all systems in that set, in addition to any configuration on each individual system.
Let's jump right into what this would look like. You define SystemSets
like this:
#[derive(SystemSet, Debug, Hash, PartialEq, Eq, Clone)]
enum PhysicsSet {
Movement,
CollisionDetection,
}
You can add systems to sets by calling the in_set
method:
app.add_system(gravity.in_set(PhysicsSet::Movement))
You can combine this with the new system features mentioned above:
app.add_systems(
(apply_acceleration, apply_velocity)
.chain()
.in_set(PhysicsSet::Movement)
)
Systems can belong to any number of sets:
app.add_system(
move_player
.in_set(MoveSet::Player)
.in_set(PhysicsSet::Movement)
)
Configuration is added to sets like this:
app.configure_set(
// Run systems in the Movement set before systems in the CollisionDetection set
PhysicsSet::Movement.before(PhysicsSet::CollisionDetection)
)
Sets can be nested inside other sets, which will cause them to inherit the configuration of their parent set:
app.configure_set(MoveSet::Enemy.in_set(PhysicsSet::Movement))
Sets can be configured multiple times:
// In PlayerPlugin:
app.configure_set(MoveSet::Player.before(MoveSet::Enemy))
// In PlayerTeleportPlugin
app.configure_set(MoveSet::Player.after(PortalSet::Teleport))
Crucially system configuration is strictly additive: you cannot remove rules added elsewhere. This is both an "anti-spaghetti" and "plugin privacy" consideration. When this rule is combined with Rust's robust type privacy rules, plugin authors can make careful decisions about which exact invariants need to be upheld, and reorganize code and systems internally without breaking consumers.
Configuration rules must be compatible with each other: any paradoxes (like a system set inside of itself, a system that must run both before and after a set, order cycles, etc) will result in a runtime panic with a helpful error message.
Directly Schedule Exclusive Systems #
"Exclusive systems" are Systems
that have mutable direct access to the entire ECS World
. For this reason, they cannot be run in parallel with other Systems
.
Since Bevy's inception, Bevy devs have wanted to schedule exclusive systems (and flush commands) relative to normal systems.
Now you can! Exclusive systems can now be scheduled and ordered like any other system.
app
.add_system(ordinary_system)
// This works!
.add_system(exclusive_system.after(ordinary_system))
This is particularly powerful, as command flushes (which apply queued-up Commands
added in systems to do things like spawn and despawn entities) are now simply performed in the apply_system_buffers
exclusive system.
app.add_systems(
(
// This system produces some commands
system_a,
// This will apply the queued commands from system_a
apply_system_buffers,
// This system will have access to the results of
// system_a's commands
system_b,
// This chain ensures the systems above run in the order
// they are defined
).chain()
)
Do be careful with this pattern though: it's easy to quickly end up with many poorly ordered exclusive systems, creating bottlenecks and chaos.
What will you do with this much power? We're keen to find out!
Managing Complex Control Flow with Schedules #
But what if you want to do something weird with your Schedule
? Something non-linear, branching, or looping. What should you reach for?
It turns out, Bevy already had a great tool for this: schedules that run inside of an exclusive system. The idea is pretty simple:
- Construct a schedule, that stores whatever complex logic you want to run.
- Store that schedule inside of a resource.
- In an exclusive system, perform any arbitrary Rust logic you want to decide if and how your schedule runs.
- Temporarily take the schedule out of the
World
, run it on the rest of the world to mutate both the schedule and the world, and then put it back in.
With the addition of the new Schedules
resource and the world.run_schedule()
API it's more ✨ ergonomic ✨ than ever.
// A Schedule!
let mut my_schedule = Schedule::new();
schedule.add_system(my_system);
// A label for our new Schedule!
#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone)]
struct MySchedule;
// An exclusive system to run this schedule
fn run_my_schedule(world: &mut World) {
while very_complex_logic() {
world.run_schedule(MySchedule);
}
}
// Behold the ergonomics!
app
.add_schedule(MySchedule, my_schedule)
.add_system(run_my_schedule);
Bevy uses this pattern for five rather different things in Bevy 0.10:
- Startup systems: these now live in their own schedule, which is run once at the start of the app.
- Fixed timestep systems: another schedule?! The exclusive system that runs this schedule accumulates time, running a while loop that repeatedly runs
CoreSchedule::FixedUpdate
until all of the accumulated time has been spent. - Entering and exiting states: a bonanza of schedules. Each collection of systems that runs logic to enter and exit a state variant is stored in its own schedule, which is called based on the change in state in the
apply_state_transitions::<S>
exclusive system. - Rendering: all rendering logic is stored in its own schedule to allow it to run asynchronously relative to gameplay logic.
- Controlling the outermost loop: in order to handle the "startup schedule first, then main schedule" logic, we wrap it all up in a minimal overhead
CoreSchedule::Outer
and then run our schedules as the sole exclusive system there.
Follow the breadcrumbs starting at CoreSchedule
for more info.
Run Conditions #
Systems
can have any number of run conditions, which are "just" systems that return a bool
. If the bool
s returned by all of a system's run conditions are true
, the system will run. Otherwise the system will be skipped for the current run of the schedule:
// Let's make our own run condition
fn game_win_condition(query: Query<&Player>, score: Res<Score>) -> bool {
let player = query.single();
player.is_alive() && score.0 > 9000
}
app.add_system(win_game.run_if(game_win_condition));
Run conditions also have a number of "combinator" operations, thanks to @JoJoJet and @Shatur:
They can be negated with not()
:
app.add_system(continue_game.run_if(not(game_win_condition)))
They can also be combined with and_then
and or_else
:
app.add_system(move_player.run_if(is_alive.or_else(is_zombie)))
Bevy 0.10 is shipping with a lovely collection of built-in common run conditions. You can easily run systems if there are events to process, timers that elapsed, resources that changed, input state changes, states that changed, and more (thanks to @maniwani
, @inodentry
, @jakobhellermann
, and @jabuwu
).
Run conditions can also serve as a lightweight optimization tool. Run conditions are evaluated on the main thread, and each run criteria is evaluated exactly once each schedule update, at the time of the first system in the set that relies on it. Systems disabled by run conditions don't spawn a task, which can add up across many systems. Like always though: benchmark!
Run conditions have replaced the "run criteria" in previous versions of Bevy. We can finally get rid of the dreaded "looping run criteria"! ShouldRun::YesAndCheckAgain
was not exactly straightforward to reason about, either for engine devs or users. It's always a bad sign when your bool-like enums have four possible values. If you crave more complex control flow: use the "schedules in exclusive systems" pattern in the section above. For the other 99% of use cases, enjoy the simpler bool
-based run conditions!
Simpler States #
Schedule v3 adds a new, much simpler "state system". States
allow you to easily configure different App
logic to run based on the current "state" of the App
.
You define States
like this:
#[derive(States, PartialEq, Eq, Debug, Clone, Hash, Default)]
enum AppState {
#[default]
MainMenu,
InGame,
}
Each variant of the enum corresponds to a different state the App
can be in.
You add States
to your App
like this:
app.add_state::<AppState>()
This will setup your App
to use the given state. It adds the State
resource, which can be used to find the current state the App
is in:
fn check_state(state: Res<State<AppState>>) {
info!("We are in the {} state", state.0);
}
Additionally, add_state
will create an OnUpdate
set for each possible value, which you can then add your systems to. These sets run as part of the normal app update, but only when the app is in a given state:
app
.add_systems(
(main_menu, start_game)
.in_set(OnUpdate(AppState::MainMenu))
)
.add_system(fun_gameplay.in_set(OnUpdate(AppState::InGame)));
It will also create OnEnter
and OnExit
schedules for each state, which will only run when transitioning from one state to another:
app
.add_system(load_main_menu.in_schedule(OnEnter(AppState::MainMenu)))
.add_system(cleanup_main_menu.in_schedule(OnExit(AppState::MainMenu)))
add_state
also adds the NextState
resource, which can be used to queue a state change:
fn start_game(
button_query: Query<&Interaction, With<StartGameButton>>,
mut next_state: ResMut<NextState<AppState>>,
){
if button_query.single() == Interaction::Pressed {
next_state.set(AppState::InGame);
}
}
This replaces Bevy's previous state system, which was very hard to deal with. It had state stacks, elaborate queued transitions, and error handling (that most people just unwrapped). The state stack was very complex to learn, very prone to exasperating bugs, and mostly ignored.
As a result, in Bevy 0.10 states are now "stackless": only one queued state of each type at a time. After lots of alpha testing, we're reasonably confident that this shouldn't be too bad to migrate away from. If you were relying on the state stack, you have plenty of options:
- Build the "stack" logic on top of the core state system
- Split your state into multiple states, which capture orthogonal elements of your app's status
- Build your own state stack abstraction using the same patterns as Bevy's first-party version. None of the new state logic is hard coded! If you build something, let the rest of the community know so you can collaborate!
Base Sets: Getting Default Behavior Right #
An astute reader may point out that:
- Bevy automatically runs its systems in parallel.
- The order of systems is nondeterministic unless there is an explicit ordering relationship between them
- All of the systems are now stored in a single
Schedule
object with no barriers between them - Systems can belong to any number of system sets, each of which can add their own behavior
- Bevy is a powerful engine with many internal systems.
Won't this lead to utter chaos and tedious spaghetti-flavored work to resolve every last ordering ambiguity? Many users liked stages, they were helpful for understanding the structure of an App
!
Well, we're glad you asked, rhetorical skeptic. To reduce this chaos (and ease migration), Bevy 0.10 comes with a brand new collection of system sets provided by DefaultPlugins
: CoreSet
, StartupSet
, and RenderSet
. The similarity of their names to the old CoreStage
, StartupStage
, and RenderStage
is not a coincidence. Much like stages, there are command flush points between each set, and existing systems have been migrated directly.
Some parts of the stage-centric architecture were appealing: a clear high-level structure, coordination on flush points (to reduce excessive bottlenecks), and good default behavior. To keep those bits (while excising the frustrating ones), we've introduced the concept of Base Sets (added by @cart). Base Sets are just normal SystemSets
, except:
- Every system can belong to at most one base set.
- Systems that do not specify a base set will be added to the default base set for the schedule (if the schedule has one).
// You define base sets exactly like normal sets, with the
// addition of the system_set(base) attribute
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
#[system_set(base)]
enum MyBaseSet {
Early,
Late,
}
app
// This ends up in CoreSet::Update by default
.add_system(no_explicit_base_set)
// You must use .in_base_set rather than .in_set for explicitness
// This is a high-impact decision!
.add_system(post_update.in_base_set(CoreSet::PostUpdate))
// Look, it works!
.add_system(custom_base_set.in_base_set(MyBaseSet::Early))
// Ordering your base sets relative to CoreSet is probably wise
.configure_set(MyBaseSet::Early.before(CoreSet::Update))
.configure_set(MyBaseSet::Late.after(CoreSet::Update));
Let me tell you a story, set in a world without Base Sets:
- A new user adds the
make_player_run
system to their app. - Sometimes this system runs before input handling, leading to randomly dropped inputs. Sometimes it runs after rendering, leading to strange flickers.
- After much frustration, the user discovers that these are due to "system execution order ambiguities".
- The user runs a specialized detection tool, digs into the source code of the engine, figures out what order their system should run in relative to the engine's system sets, and then continues on their merry way, doing this for each new system.
- Bevy (or one of their third-party plugins) updates, breaking all of our poor users system ordering once again.
The clear problem this illustrates is that most gameplay systems should not need to know or care about "internal systems".
We've found that in practice, there are three broad classes of systems: gameplay logic (the majority of all end user systems), stuff that needs to happen before gameplay logic (like event cleanup and input handling), and stuff that needs to happen after gameplay logic (like rendering and audio).
By broadly ordering the schedule via Base Sets, Bevy apps can have good default behavior and clear high-level structure without compromising on the scheduling flexibility and explicitness that advanced users crave. Let us know how it works out for you!
Improved System Ambiguity Detection #
When multiple systems interact with an ECS resource in conflicting ways, but don't have an ordering constraint between them, we call this an "ambiguity". If your App
has ambiguities, this can cause bugs. We've significantly improved our ambiguity reporting, which can be configured in the new ScheduleBuildSettings
. Check out the docs for more info. If you haven't tried this out on your app yet: you should take a look!
Single Threaded Execution #
You can now easily switch a Schedule
to single-threaded evaluation via the SingleThreadedExecutor
for users who don't want or need parallelism.
schedule.set_executor_kind(ExecutorKind::SingleThreaded);
Cascaded Shadow Maps #
Bevy uses "shadow maps" to cast shadows for lights / objects. Previous versions of Bevy used a simple but limited shadow map implementation for directional light sources. For a given light, you would define the resolution of the shadow map and a manual "view projection" that would determine how the shadow is cast. This had a number of downsides:
- The resolution of the shadow map was fixed. You had to choose something between "cover a large area, but have a lower resolution" and "cover a smaller area, but have a higher resolution".
- The resolution didn't adapt to camera positioning. Shadows might look great in one position, but terrible in another position.
- The "shadow projection" had to be manually defined. This made it hard and unapproachable to configure shadows to match a given scene.
Bevy 0.10 adds "cascaded shadow maps", which breaks up the camera's view frustum into a series of configurable "cascades", which each have their own shadow map. This enables shadows in the cascade "close to the camera" to be highly detailed, while allowing shadows "far from the camera" to cover a wider area with less detail. Because it uses the camera's view frustum to define the shadow projections, the shadow quality remains consistent as the camera moves through the scene. This also means that users don't need to manually configure shadow projections anymore. They are automatically calculated!
Notice how the nearby shadows are highly detailed whereas the shadows in the distance become less detailed as they get farther away (which doesn't matter as much because they are far away).
While shadow cascades solve important problems, they also introduce new ones. How many cascades should you use? What is the minimum and maximum distance from the camera where shadows should appear? How much overlap should there be between cascades? Be sure to dial in these parameters to fit your scenes.
Environment Map Lighting #
Environment maps are a popular and computationally cheap way to significantly improve the quality of a scene's lighting. It uses a cube map texture to provide 360 degree lighting "from all directions". This is especially apparent for reflective surfaces, but it applies to all lit materials.
This is what the PBR material looks like without environment map lighting:
And this is what the PBR material looks like with environment map lighting:
For scenes that need constant lighting (especially outdoor scenes), environment maps are a great solution. And because environment maps are arbitrary images, artists have a lot of control over the character of the scene's lighting.
Depth and Normal Prepass #
This effect uses the depth from the prepass to find the intersection between the ground and the force field
Bevy now has the ability to run a depth and/or normal prepass. This means the depth and normal textures will be generated in a render pass that runs before the main pass and can therefore be used during the main pass. This enables various special effects like Screen Space Ambient Occlusion, Temporal Anti Aliasing, and many more. These are currently being worked on and should be available in the next release of Bevy.
In the image on the right, green lines are edges detected in the normal texture and blue lines are edges detected in the depth texture
The depth and normal textures generated by the prepass
Using the prepass essentially means rendering everything twice. The prepass itself is much faster since it does a lot less work than the main pass. The result of the prepass can be used to reduce overdraw in the main pass, but if your scene didn't already suffer from overdraw then enabling the prepass will negatively affect performance. There are many things that can be done to improve this and we will keep working towards this goal. Like with anything performance related, make sure to measure it for your use case and see if it helps or not.
The prepass is still very useful when working on special effects that require a depth or normal texture, so if you want to use it you can simply add the DepthPrepass
or NormalPrepass
components to your camera.
Shadow Mapping using Prepass Shaders #
Previously, the shader used for shadow mapping was hard-coded and had no knowledge of the material, only meshes. Now in Bevy 0.10, a Material
's depth prepass shaders are used for shadow mapping. This means that the shaders used to do the shadow mapping for a Material
are customizable!
As a bonus, the availability of Material
information during shadow mapping means that we could instantly enable alpha mask shadows allowing foliage to cast shadows according to the alpha values in their texture rather than only based on their geometry.
Smooth Skeletal Animation Transitions #
You can now smoothly transition between two (or more) skeletal animations!
With the new play_with_transition
method on the AnimationPlayer
component, you can now specify a transition duration during which the new animation will be linearly blended with the currently playing animation, whose weight will decrease during that duration until it reaches 0.0
.
#[derive(Component, Default)]
struct ActionTimer(Timer);
#[derive(Component)]
struct Animations {
run: Handle<AnimationClip>,
attack: Handle<AnimationClip>,
}
fn run_or_attack(
mut query: Query<(&mut AnimationPlayer, &mut ActionTimer, &Animations)>,
keyboard_input: Res<Input<KeyCode>>,
animation_clips: Res<Assets<AnimationClip>>,
time: Res<Time>,
) {
for (mut animation_player, mut timer, animations) in query.iter_mut() {
// Trigger the attack animation when pressing <space>
if keyboard_input.just_pressed(KeyCode::Space) {
let clip = animation_clips.get(&animations.attack).unwrap();
// Set a timer for when to restart the run animation
timer.0 = Timer::new(
Duration::from_secs_f32(clip.duration() - 0.5),
TimerMode::Once,
);
// Will transition over half a second to the attack animation
animation_player
.play_with_transition(animations.attack.clone(), Duration::from_secs_f32(0.5));
}
if timer.0.tick(time.delta()).just_finished() {
// Once the attack animation is finished, restart the run animation
animation_player
.play_with_transition(animations.run.clone(), Duration::from_secs_f32(0.5))
.repeat();
}
}
}
Improved Android Support #
Bevy now runs out of the box on Android on more devices. This was unlocked by waiting for the Resumed
event to create the window instead of doing it on startup, matching the onResume()
callback on Android.
To follow the recommendations on the Suspended
event, Bevy will now exit on receiving that event. This is a temporary solution until Bevy is able to recreate rendering resources when being resumed.
Please test on your devices and report successes or issues you may encounter! There is a known issue around touch position on some devices with software buttons, as winit doesn't expose (yet) the inset size, only the inner size.
As this brings Bevy closer to full support of Android, there isn't a need anymore for separate examples for Android and iOS. They have been regrouped in one "mobile" example, and the instructions updated (for Android and for iOS).
Here is the same example running on iOS!
Revamped Bloom #
Bloom has undergone some major changes and now looks better, is easier to control, and has fewer visual artifacts. In combination with the new tonemapping options, bloom has been much improved since the previous release!
- In Bevy 0.9, bloom looked like this.
- Switching the tonemapper to something like
AcesFitted
is already a big improvement. - In Bevy 0.10, bloom now looks like this. It's much more controlled and less overbearing.
- To make the bloom stronger, rather than raise the
BloomSettings
intensity, let's double theemissive
value of each cube. - Finally, if you want more extreme bloom similar to the old algorithm, you can change
BloomSettings::composite_mode
fromBloomCompositeMode::EnergyConserving
toBloomCompositeMode::Additive
. - Explore the new bloom settings in an interactive playground using the new
bloom_3d
(andbloom_2d
) examples.
Distance and Atmospheric Fog #
Bevy can now render distance and atmospheric fog effects, bringing a heightened sense of depth and ambiance to your scenes by making objects appear dimmer the further away they are from view.
Fog is controllable per camera via the new FogSettings
component. Special care has been put into exposing several knobs to give you full artistic control over the look of your fog, including the ability to fade the fog in and out by controlling the alpha channel of the fog color.
commands.spawn((
Camera3dBundle::default(),
FogSettings {
color: Color::rgba(0.1, 0.2, 0.4, 1.0),
falloff: FogFalloff::Linear { start: 50.0, end: 100.0 },
},
));
Exactly how fog behaves with regard to distance is controlled via the FogFalloff
enum. All of the “traditional” fog falloff modes from the fixed-function OpenGL 1.x / DirectX 7 days are supported:
FogFalloff::Linear
increases in intensity linearly from 0 to 1 between start
and end
parameters. (This example uses values of 0.8 and 2.2, respectively.)
FogFalloff::Exponential
increases according to an (inverse) exponential formula, controlled by a density
parameter.
FogFalloff::ExponentialSquared
grows according to a slightly modified (inverse) exponential square formula, also controlled by a density
parameter.
Additionally, a more sophisticated FogFalloff::Atmospheric
mode is available which provides more physically accurate results by taking light extinction
and inscattering
into account separately.
DirectionalLight
influence is also supported for all fog modes via the directional_light_color
and directional_light_exponent
parameters, mimicking the light dispersion effect seen in sunny outdoor environments.
Since directly controlling the non-linear fog falloff parameters “by hand” can be tricky to get right, a number of helper functions based on meteorological visibility are available, such as FogFalloff::from_visibility()
:
FogSettings {
// objects retain visibility (>= 5% contrast) for up to 15 units
falloff: FogFalloff::from_visibility(15.0),
..default()
}
Fog is applied “forward rendering-style” on the PBR fragment shader, instead of as a post-processing effect, which allows it to properly handle semi-transparent meshes.
The atmospheric fog implementation is largely based on this great article by Inigo Quilez, Shadertoy co-creator, and computer graphics legend. Thanks for the great write up and inspiration!
StandardMaterial Blend Modes #
The AlphaMode
enum has been extended in Bevy 0.10, bringing support for additive and multiplicative blending to the StandardMaterial
. These two blend modes are staples of the “classic” (non physically-based) computer graphics toolbelt, and are commonly used to achieve a variety of effects.
Demo showcasing the use of blend modes to create stained glass and fire effects. (Source Code)
Additionally, support for semi-transparent textures with premultiplied alpha has been added, via a dedicated alpha mode.
Here's a high-level overview of the new modes:
AlphaMode::Add
— Combines the colors of the fragments with the colors behind them in an additive process, (i.e. like light) producing brighter results. Useful for effects like fire, holograms, ghosts, lasers and other energy beams. Also known as Linear Dodge in graphics software.AlphaMode::Multiply
— Combines the colors of the fragments with the colors behind them in a multiplicative process, (i.e. like pigments) producing darker results. Useful for effects approximating partial light transmission like stained glass, window tint film and some colored liquids.AlphaMode::Premultiplied
— Behaves very similarly toAlphaMode::Blend
, but assumes the color channels have premultiplied alpha. Can be used to avoid discolored “outline” artifacts that can occur when using plain alpha-blended textures, or to cleverly create materials that combine additive and regular alpha blending in a single texture, thanks to the fact that for otherwise constant RGB values,Premultiplied
behaves more likeBlend
for alpha values closer to 1.0, and more likeAdd
for alpha values closer to 0.0.
Note: Meshes using the new blend modes are drawn on the existing Transparent3d
render phase, and therefore the same z-sorting considerations/limitations from AlphaMode::Blend
apply.
More Tonemapping Choices #
Tonemapping is the process of transforming raw High Dynamic Range (HDR) information into actual "screen colors" using a "display rendering transform" (DRT). In previous versions of Bevy you had exactly two tonemapping options: Reinhard Luminance or none at all. In Bevy 0.10 we've added a ton of choices!
No Tonemapping #
This is generally not recommended as HDR lighting is not intended to be used as color.
Reinhard #
A simple method that adapts to the color in a scene: r = color / (1.0 + color)
. Lots of hue shifting, brights don't desaturate naturally. Bright primaries and secondaries don't desaturate at all.
Reinhard Luminance #
A popular method similar to normal Reinhard that incorporates luminance. It adapts to the amount of light in a scene. This is what we had in previous versions of Bevy. It is still our default algorithm, but this will likely change in the future. Hues shift. Brights don't desaturate much at all across the spectrum.
ACES Fitted #
An extremely popular algorithm used in film and industry (ex: ACES is the default Unreal tonemapping algorithm). When people say "filmic", this is often what they mean.
Not neutral, has a very specific aesthetic, intentional and dramatic hue shifting. Bright greens and reds turn orange. Bright blues turn magenta. Significantly increased contrast. Brights desaturate across the spectrum.
AgX #
Very neutral. Image is somewhat desaturated when compared to other transforms. Little to no hue shifting. Subtle Abney shifting. Created by Troy Sobotka
Somewhat Boring Display Transform #
Has little hue shifting in the darks and mids, but lots in the brights. Brights desaturate across the spectrum. Is sort of between Reinhard and Reinhard Luminance. Conceptually similar to reinhard-jodie. Designed as a compromise if you want e.g. decent skin tones in low light, but can't afford to re-do your VFX to look good without hue shifting. Created by Tomasz Stachowiak.
TonyMcMapface #
Very neutral. Subtle but intentional hue shifting. Brights desaturate across the spectrum.
From the author: Tony is a display transform intended for real-time applications such as games. It is intentionally boring, does not increase contrast or saturation, and stays close to the input stimulus where compression isn't necessary. Brightness-equivalent luminance of the input stimulus is compressed. The non-linearity resembles Reinhard. Color hues are preserved during compression, except for a deliberate Bezold–Brücke shift. To avoid posterization, selective desaturation is employed, with care to avoid the Abney effect. Created by Tomasz Stachowiak
Blender Filmic #
Default Filmic Display Transform from Blender. Somewhat neutral. Hues shift. Brights desaturate across the spectrum.
Color Grading Control #
We've added some basic control over color grading parameters such as exposure, gamma, "pre-tonemapping saturation", and "post-tonemapping saturation". These can be configured per camera using the new ColorGrading
component.
0.5 Exposure #
2.25 Exposure #
Parallel Pipelined Rendering #
On multithreaded platforms, Bevy 0.10 will now run significantly faster by running simulation and rendering in parallel. The renderer was rearchitected in Bevy 0.6 to enable this, but the final step of actually running them in parallel was not done until now. There was a bit of tricky work to figure out. The render world has a system that has to run on the main thread, but the task pool only had the ability to run on the world's thread. So, when we send the render world to another thread we need to accommodate still running render systems on the main thread. To accomplish this, we added the ability to spawn tasks onto the main thread in addition to the world's thread.
In testing different Bevy examples, the gains were typically in the 10% to 30% range. As seen in the above histogram, the mean frame time of the "many foxes" stress test is 1.8ms faster than before.
To use pipelined rendering, you just need to add the PipelinedRenderingPlugin
. If you're using DefaultPlugins
then it will automatically be added for you on all platforms except wasm. Bevy does not currently support multithreading on wasm which is needed for this feature to work. If you are not using DefaultPlugins
you can add the plugin manually.
Windows as Entities #
In previous versions of Bevy, Window
was represented as an ECS resource (contained in the Windows
resource). In Bevy 0.10 Window
is now a component (and therefore windows are represented as entities).
This accomplishes a number of goals:
- It opens the doors to representing Windows in Bevy's scene system
- It exposes
Windows
to Bevy's powerful ECS queries - It provides granular per-window change detection
- Improves the readability/discoverability of creating, using, and closing windows
- Changing the properties of a window is the same for both initializing and modifying. No more
WindowDescriptor
fuss! - It allows Bevy developers and users to easily attach new component data to windows
fn create_window(mut commands: Commands) {
commands.spawn(Window {
title: "My window :D".to_string(),
..default()
});
}
fn modify_windows(mut windows: Query<&mut Window>) {
for window in &mut windows {
window.title = "My changed window! :D".to_string();
}
}
fn close_windows(mut commands: Commands, windows: Query<Entity, With<Window>>) {
for entity in &windows {
commands.entity(entity).despawn();
}
}
Renderer Optimizations #
Bevy's renderer was ripe for optimization. So we optimized it!
The biggest bottleneck when rendering anything in Bevy is the final render stage, where we collect all of the data in the render world to issue draw calls to the GPU. The core loops here are extremely hot and any extra overhead is noticeable. In Bevy 0.10, we've thrown the kitchen sink at this problem and have attacked it from every angle. Overall, these following optimizations should make the render stage 2-3 times faster than it was in 0.9:
- In #7639 by @danchia, we found that even disabled logging has a strong impact on hot loops, netting us 20-50% speedups in the stage.
- In #6944 by @james7132, we shrank the core data structures involved in the stage, reducing memory fetches and netting us 9% speedups.
- In #6885 by @james7132, we rearchitected our
PhaseItem
andRenderCommand
infrastructure to combine common operations when fetching component data from theWorld
, netting us a 7% speedup. - In #7053 by @james7132, we changed
TrackedRenderPass
's allocation patterns to minimize branching within these loops, netting a 6% speedup. - In #7084 by @james7132, we altered how we're fetching resources from the World to minimize the use of atomics in the stage, netting a 2% speedup.
- In #6988 by @kurtkuehnert, we changed our internal resource IDs to use atomically incremented counters instead of UUIDs, reducing the comparison cost of some of the branches in the stage.
One other ongoing development is enabling the render stage to properly parallelize command encoding across multiple threads. Following #7248 by @james7132, we now support ingesting externally created CommandBuffer
s into the render graph, which should allow users to encode GPU commands in parallel and import them into the render graph. This is currently blocked by wgpu, which locks the GPU device when encoding render passes, but we should be able to support parallel command encoding as soon as that's addressed.
On a similar note, we've made steps to enable higher parallelism in other stages of the rendering pipeline. PipelineCache
has been a resource that almost every Queue stage system needed to access mutably, but also only rarely needed to be written to. In #7205, @danchia changed this to use internal mutability to allow for these systems to parallelize. This doesn't fully allow every system in this stage to parallelize just yet, as there still remain a few common blockers, but it should allow non-conflicting render phases to queue commands at the same time.
Optimization isn't all about CPU time! We've also improved memory usage, compile times, and GPU performance as well!
- We've also reduced the memory usage of
ComputedVisibility
by 50% thanks to @james7132. This was done by replacing the internal storage with a set of bitflags instead of multiple booleans. - @robfm also used type erasure as a work-around a rustc performance regression to ensure that rendering related crates have better compile times, with some of the crates compiling up to 60% faster! Full details can be seen in #5950.
- In #7069, Rob Swain (@superdump) reduced the number of active registers used on the GPU to prevent register spilling, significantly improving GPU-side performance.
Finally, we have made some improvements on specific usage scenarios:
- In #6833, @james7132 improved the extraction of bones for mesh skinning by 40-50% by omitting an unnecessary buffer copy.
- In #7311, @james7132 improved UI extraction by 33% by lifting a common computation out of a hot loop.
Parallelized Transform Propagation and Animation Kinematics #
Transform propagation is one of the core systems of any game engine. If you move a parent entity, you expect its children to move in worldspace. Bevy's transform propagation system happens to be one of the largest bottlenecks for multiple systems: rendering, UI, physics, animation, etc. cannot run until it's complete. It's imperative that transform propagation is fast to avoid blocking all of these systems. In Bevy 0.9 and before, transform propagation has always been single-threaded and always requires a full hierarchy traversal. As worlds got larger, so did the time spent in this key bottleneck. In Bevy 0.10, transform propagation leverages the structure of a well-formed hierarchy to fully run over multiple threads. The full performance benefits entirely depend on how the hierarchy is structured and how many CPU cores are available. In our testing, this has made transform propagation in our many_foxes
benchmark 4 times faster on our testing hardware.
If transform propagation can be parallelized, so can forward kinematics for animation. We leveraged the same guaranteed structure of well formed hierarchies to fully parallelize playing skeletal animations. We also enabled a basic entity-path cache lookup to reduce the extra lookups the system was doing. Altogether, we were able to make the animation player system on the same many_foxes
benchmark 10 times faster.
Combined with all of the other optimizations seen in this release, our tests on the many_foxes
benchmark has sped up from ~10ms per frame (~100 FPS) to ~2.3ms per frame (~434 FPS), a near 5x speedup!
ECS Optimizations #
ECS underlies the entire engine, so eliminating overhead in the ECS results in engine-wide speedups. In Bevy 0.10, we've found quite a few areas where we were able to massively reduce the overhead and improve CPU utilization for the entire engine.
In #6547, we enabled autovectorization when using Query::for_each
, and its parallel variants. Depending on the target architecture the engine is being compiled for, this can result in a 50-87.5% speed up in query iteration time. In 0.11, we may be extending this optimization to all iterator combinators based on Iterator::fold
, such as Iterator::count
. See this PR for more details.
In #6681, by tightly packing entity location metadata and avoiding extra memory lookups, we've significantly reduced the overhead when making random query lookups via Query::get
, seeing up to a 43% reduction in the overhead spent in Query::get
and World::get
.
In #6800 and #6902, we've found that rustc can optimize out compile-time constant branches across function boundaries, moving the branch from runtime to compile time, has resulted in up to a 50% reduction in overhead when using EntityRef::get
, EntityMut::insert
, EntityMut::remove
, and their variants.
In #6391, we've reworked CommandQueue
's internals to be more CPU-cache friendly, which has shown up to a 37% speedup when encoding and applying commands.
SystemParam
Improvements #
Central to Bevy's ECS are SystemParam
s: these types, such as Query
and Res
, dictate what a system can and can't do. Previously, manually creating one required implementing a family of four inseparable traits. In Bevy 0.10, we've used generic associated types to reduce this to just two traits: SystemParam
and ReadOnlySystemParam
.
Additionally, the #[derive(SystemParam)]
macro has received a host of miscellaneous usability improvements:
- More Flexible: you are no longer forced to declare lifetimes you don't use. Tuple structs are now allowed, and const generics don't break things.
- Encapsulated: a long-standing bug has been fixed that leaked the types of private fields. Now,
SystemParam
s can properly encapsulate private world data. - Limitless: the 16-field limit has been lifted, so you can make your params as ridiculously complex as you want. This is most useful for generated code.
Deferred World Mutations #
You probably know that when you send a Command
, it doesn't mutate the world right away. The command gets stored in the system and applied later on in the schedule. Deferring mutations in this way has a few benefits:
- Minimizing world accesses: unlike mutable queries (and resources), deferred mutations are free from data access conflicts, which affords greater parallelizability to systems using this pattern.
- Order independence: when performing idempotent operations (like setting a global flag), deferred mutations allow you to not worry about system execution order.
- Structural mutations: deferred mutations are able to change the structure of the world in ways that
Query
andResMut
cannot, such as adding components or spawning and despawning entities.
Bevy 0.10 adds first-class support for this pattern via the Deferred
system parameter, which accepts a SystemBuffer
trait impl. This lets you create systems with custom deferred mutation behavior while skipping the overhead associated with Commands
!
/// Sends events with a delay, but can run in parallel with other event writers.
pub struct EventBuffer<E>(Vec<E>);
// The `SystemBuffer` trait controls how deferred mutations get applied to the world.
impl<E> SystemBuffer for EventBuffer<E> { ... }
fn my_system(mut events: Deferred<EventBuffer<MyEvent>>) {
// Queue up an event to get sent when commands are applied.
events.0.push(MyEvent);
}
Note that this feature should be used with care -- despite the potential performance benefits, inappropriate usage can actually worsen performance. Any time you perform an optimization, make sure you check that it actually speeds things up!
Ref<T> Queries #
Since Bevy 0.1, Mut<T>
has been used to enable change detection (along with related types like ResMut<T>
). It's a simple wrapper type that provides mutable access to a component alongside its change tick metadata, automatically marking a change when the value is mutated.
In Bevy 0.10, the change detection family has grown with Ref<T>
, the immutable variant of Mut<T>
. Like its mutable sibling, it allows you to react to changes made outside of the current system.
use bevy::prelude::*;
fn inspect_changes_system<T: Component + Debug>(q: Query<Ref<T>>) {
// Iterate over each component of type `T` and log its changed status.
for val in &q {
if val.is_changed() {
println!("Value `{val:?}` was last changed at tick {}.", val.last_changed());
} else {
println!("Value `{val:?}` is unchanged.");
}
}
}
We are also deprecating ChangeTrackers<T>
, which is the old way of inspecting a component's change ticks. This type will be removed in the next version of Bevy.
Cubic Curves #
This video shows four kinds of cubic curves being smoothly animated with bezier easing. The curve itself is white, green is velocity, red is acceleration, and blue are the control points that determine the shape of the curve.
In preparation for UI animation and hand-tweaked animation curves, cubic curves have been added to bevy_math
. The implementation provides multiple curves out of the box, useful in various applications:
Bezier
: user-drawn splines, and cubic-bezier animation easing for UI - helper methods are provided for cubic animation easing as demonstrated in the above video.Hermite
: smooth interpolation between two points in time where you know both the position and velocity, such as network prediction.Cardinal
: easy interpolation between any number of control points, automatically computing tangents; Catmull-Rom is a type of Cardinal spline.B-Spline
: acceleration-continuous motion, particularly useful for camera paths where a smooth change in velocity (acceleration) is important to prevent harsh jerking motion.
The CubicGenerator
trait is public, allowing you to define your own custom splines that generate CubicCurve
s!
Performance #
The position, velocity, and acceleration of a CubicCurve
can be evaluated at any point. These evaluations all have the same performance cost, regardless of the type of cubic curve being used. On a modern CPU, these evaluations take 1-2 ns, and animation easing - which is an iterative process - takes 15-20 ns.
AccessKit integration into bevy_ui
#
Games are for everyone: and the way they're built should reflect that. Accessible games are rare, and proper support is often an afterthought, both at an engine and a game level. By building our UI solution with accessibility in mind, we hope to fix that.
Bevy has joined egui
in making the first steps towards cross-platform accessibility-by-default, with the help of the outstanding AccessKit crate. To our knowledge, this makes Bevy the first general purpose game engine with first-party accessibility support.
We've exposed Bevy's UI hierarchy and text elements to screen readers and other assistive devices, managed by the new on-by-default bevy_a11y
crate. This is ultimately powered by the new AccessibilityNode
component, which combines with the existing hierarchy to expose this information directly to AccessKit and the Focus
resource, which stores the entity that has keyboard focus.
There's still a lot more to be done here: integrating the focus system with a gamepad-driven UI controls solution, cleaning up the data model to make sure "accessible by default" is a reality), and adding support for remaining features in AccessKit.
Special thanks to @mwcampbell
, the lead author of AccessKit, for reviewing our integration and working with us to reduce the number of dependencies upstream, substantially improving both compile times and final executable size. This is still a serious challenge on Linux, and so the accesskit_unix
feature flag is disabled by default for now.
Spatial Audio #
The library Bevy uses for audio, rodio
, contains support for spatial audio. Bevy 0.10 exposes basic spatial audio. There are still a few caveats, like no HRTF and no first class support for Emitter
and Listener
components.
Interestingly, during the development of this specific feature, @harudagondi
found a bug where the audio channels reverse when running the app in either debug or release mode. This turns out to be a rodio
issue, and this also affects previous versions of Bevy. Thanks to @dis-da-moe
, the bug has been fixed upstream. See the linked PR for interesting details about audio programming quirks and performance issues.
You can now have spatial audio in your game! Clone the bevy
repository and invoke cargo run --example spatial_audio_3d --release
in the command line for a showcase of 3D spatial audio in Bevy.
Custom Audio Sources #
Bevy supports custom audio sources through the Decodable
trait, but the way to register to the bevy app is very boilerplatey and sparsely documented. In Bevy 0.10, a new extension trait for App
is added and the documentation for Decodable
has vastly improved.
As such, instead of doing this:
struct MyCustomAudioSource { /* ... */ }
app.add_asset::<MyCustomAudioSource>()
.init_resource::<Audio<MyCustomAudioSource>>()
.init_resource::<AudioOutput<MyCustomAudioSource>>()
.add_system(play_queued_audio_system::<MyCustomAudioSource>.in_base_set(CoreSet::PostUpdate))
You only have to do this:
app.add_audio_source::<MyCustomAudioSource>()
Much cleaner!
ShaderDef Values #
Bevy's shader processor now supports ShaderDefs with values, using the new ShaderDefVal
. This allows developers to pass constant values into their shaders:
let shader_defs = vec![
ShaderDefVal::Int("MAX_DIRECTIONAL_LIGHTS".to_string(), 10),
];
These can be used in #if
statements to selectively enable shader code based on the value:
#if MAX_DIRECTIONAL_LIGHTS >= 10
let color = vec4<f32>(1.0, 0.0, 0.0, 1.0);
#else
let color = vec4<f32>(0.0, 1.0, 0.0, 1.0);
#endif
ShaderDef values can be inlined into shaders:
for (var i: u32 = 0u; i < #{MAX_DIRECTIONAL_LIGHTS}; i = i + 1u) {
}
They can also be defined inline in shaders:
#define MAX_DIRECTIONAL_LIGHTS 10
ShaderDefs defined in shaders override values passed in from Bevy.
#else ifdef
Chains in Shaders #
Bevy's shader processor now also supports #else ifdef
chains like this:
#ifdef FOO
// foo code
#else ifdef BAR
// bar code
#else ifdef BAZ
// baz code
#else
// fallback code
#endif
New Shader Imports: Global and View #
The Global
and View
structs are now importable in shaders using #import bevy_render::globals
and #import bevy_render::view
. Bevy's internal shaders now use these imports (saving a lot of redundancy). Previously you either needed to re-define in each shader or import the larger bevy_pbr::mesh_view_types
(which wasn't always what was needed).
Previously this was needed:
struct View {
view_proj: mat4x4<f32>,
inverse_view_proj: mat4x4<f32>,
view: mat4x4<f32>,
inverse_view: mat4x4<f32>,
projection: mat4x4<f32>,
inverse_projection: mat4x4<f32>,
world_position: vec3<f32>,
// viewport(x_origin, y_origin, width, height)
viewport: vec4<f32>,
};
Now you can just do this!
#import bevy_render::view
Adaptive Batching for Parallel Query Iteration #
Query::par_for_each
has been the tool everyone reaches for when their queries get too big to run single-threaded. Got 100,000 entities running around on your screen? No problem, Query::par_for_each
chunks it up into smaller batches and distributes the workload over multiple threads. However, in Bevy 0.9 and before, Query::par_for_each
required callers to provide a batch size to help tune these batches for maximum performance. This rather opaque knob often resulted in users just randomly picking a value and rolling with it, or fine tuning the value based on their development machines. Unfortunately, the most effective value is dependent on the runtime environment (i.e. how many logical cores does a player's computer have) and the state of the ECS World (i.e. how many entities are matched?). Ultimately most users of the API just chose a flat number and lived with the results, good or bad.
// 0.9
const QUERY_BATCH_SIZE: usize = 32;
query.par_for_each(QUERY_BATCH_SIZE, |mut component| {
// ...
});
In 0.10, you no longer need to provide a batch size! If you use Query::par_iter
, Bevy will automatically evaluate the state of the World and task pools and select a batch size using a heuristic to ensure sufficient parallelism, without incurring too much overhead. This makes parallel queries as easy to use as normal single-threaded queries! While great for most typical use cases, these heuristics may not be suitable for every workload, so we've provided an escape hatch for those who need finer control over the workload distribution. In the future, we may further tune the backing heuristics to try to get the default to be closer to optimal in these workloads.
// 0.10
query.par_iter().for_each(|component| {
// ...
});
// Fairly easy to convert from a single-threaded for_each. Just change iter to par_iter!
query.iter().for_each(|component| {
// ...
});
You can also use BatchingStrategy
for more control over batching:
query
.par_iter_mut()
// run with batches of 100
.batching_strategy(BatchingStrategy::fixed(100))
.for_each(|mut component| { /* ... */ });
See the BatchingStrategy
docs for more info.
UnsafeWorldCell
and UnsafeEntityCell
#
UnsafeWorldCell
and UnsafeEntityCell
allow shared mutable access to parts of the world via unsafe code. It serves a similar purpose as UnsafeCell
, allowing people to build interior mutability abstractions such as Cell
Mutex
Channel
etc. In bevy UnsafeWorldCell
will be used to support the scheduler and system param implementations as these are interior mutability abstractions for World
, it also currently is used to implement WorldCell
. We're planning to use UnsafeEntityCell
to implement versions of EntityRef
/EntityMut
that only have access to the components on the entity rather than the entire world.
These abstractions were introduced in #6404, #7381 and #7568.
Cylinder Shape #
The cylinder shape primitive has joined our zoo of built-in shapes!
Subdividable Plane Shape #
Bevy's Plane
shape can now be subdivided any number of times.
Camera Output Modes #
The camera-driven post-processing features added in Bevy 0.9 add intuitive control over post-processing across multiple cameras in a scene, but there were a few corner cases that didn't quite fit into the hard-coded camera output model. And there were some bugs and limitations related to double-buffered target texture sources of truth being incorrect across cameras and MSAA's sampled texture not containing what it should under some circumstances.
Bevy 0.10 adds a CameraOutputMode
field to Camera
, which gives Bevy app developers the ability to manually configure exactly how (and if) a Camera
's render results should be written to the final output texture:
// Configure the camera to write to the final output texture
camera.output_mode = CameraOutputMode::Write {
// Do not blend with the current state of the output texture
blend_state: None,
// Clear the output texture
color_attachment_load_op: LoadOp::Clear(Default::default()),
};
// Configure the camera to skip writing to the final output texture
// This can save a pass when there are multiple cameras, and can be useful for
// some post-processing situations
camera.output_mode = CameraOutputMode::Skip;
Most single-camera and multi-camera setups will not need to touch this setting at all. But if you need it, it will be waiting for you!
MSAA requires an extra intermediate "multisampled" texture, which gets resolved to the "actual" unsampled texture. In some corner case multi-camera setups that render to the same texture, this can create weird / inconsistent results based on whether or not MSAA is enabled or disabled. We've added a new Camera::msaa_writeback
bool
field which (when enabled) will write the current state of the unsampled texture to the intermediate MSAA texture (if a previous camera has already rendered to the target on a given frame). This ensures that the state is consistent regardless of MSAA configuration. This defaults to true, so you only need to think about this if you have a multi-camera setup and you don't want MSAA writeback.
Configurable Visibility Component #
The Visibility
component controls whether or not an Entity
should be rendered. Bevy 0.10 reworked the type definition: rather than having a single is_visible: bool
field, we now use an enum with an additional mode:
pub enum Visibility {
Hidden, // unconditionally hidden
Visible, // unconditionally visible
Inherited, // inherit visibility from parent
}
Much easier to understand! In previous Bevy versions, "inherited visibility" and "hidden" were essentially the only two options. Now entities can opt to be visible, even if their parent is hidden!
AsBindGroup
Storage Buffers #
AsBindGroup
is a useful Bevy trait that makes it very easy to pass data into shaders.
Bevy 0.10 expands this with support for "storage buffer bindings", which are very useful when passing in large / unbounded chunks of data:
#[derive(AsBindGroup)]
struct CoolMaterial {
#[uniform(0)]
color: Color,
#[texture(1)]
#[sampler(2)]
color_texture: Handle<Image>,
#[storage(3)]
values: Vec<f32>,
#[storage(4, read_only, buffer)]
buffer: Buffer,
}
ExtractComponent
Derive #
To pass component data from the "main app" to the "render app" for pipelined rendering, we run an "extract step". The ExtractComponent
trait is used to copy data over. In previous versions of Bevy, you had to implement it manually, but now you can derive it!
#[derive(Component, Clone, ExtractComponent)]
pub struct Car {
pub wheels: usize,
}
This expands to this:
impl ExtractComponent for Car
{
type Query = &'static Self;
type Filter = ();
type Out = Self;
fn extract_component(item: QueryItem<'_, Self::Query>) -> Option<Self::Out> {
Some(item.clone())
}
}
It also supports filters!
#[derive(Component, Clone, ExtractComponent)]
#[extract_component_filter(With<Fuel>)]
pub struct Car {
pub wheels: usize,
}
Upgraded wgpu to 0.15 #
Bevy 0.10 now uses the latest and greatest wgpu
(our choice of low level graphics layer). In addition to a number of nice API improvements and bug fixes, wgpu
now uses the DXC shader compiler for DX12, which is faster, less buggy, and allows for new features.
Enabled OpenGL Backend by Default #
Bevy has supported wgpu
's OpenGL backend for a while now, but it was opt-in. This caused Bevy to fail to start up on some machines that don't support modern apis like Vulkan. In Bevy 0.10 the OpenGL backend is enabled by default, which means machines will automatically fall back to OpenGL if no other API is available.
Exposed Non-Uniform Indexing Support (Bindless) #
Bevy 0.10 wired up initial support for non-uniform indexing of textures and storage buffers. This is an important step toward modern "bindless / gpu-driven rendering", which can unlock significant performance on platforms that support it. Note that this is just making the feature available to render plugin developers. Bevy's core rendering features do not (yet) use the bindless approach.
We've added a new example illustrating how to use this feature:
Gamepad API Improvements #
The GamepadEventRaw
type has been removed in favor of separate GamepadConnectionEvent
, GamepadAxisChangedEvent
, and GamepadButtonChangedEvent
, and the internals have been reworked to accommodate this.
This allows for simpler, more granular event access without filtering down the general GamepadEvent
type. Nice!
fn system(mut events: EventReader<GamepadConnectionEvent>)
for event in events.iter() {
}
}
Input Method Editor (IME) Support #
Window
can now configure IME support using ime_enabled
and ime_position
, which enables the use of "dead keys", which add support for French, Pinyin, etc:
Reflection Paths: Enums and Tuples #
Bevy's "reflection paths" enable navigating Rust values using a simple (and dynamic) string syntax. Bevy 0.10 expands this system by adding support for tuples and enums in reflect paths:
#[derive(Reflect)]
struct MyStruct {
data: Data,
some_tuple: (u32, u32),
}
#[derive(Reflect)]
enum Data {
Foo(u32, u32),
Bar(bool)
}
let x = MyStruct {
data: Data::Foo(123),
some_tuple: (10, 20),
};
assert_eq!(*x.path::<u32>("data.1").unwrap(), 123);
assert_eq!(*x.path::<u32>("some_tuple.0").unwrap(), 10);
Pre-Parsed Reflection Paths #
Reflection paths enable a lot of interesting and dynamic editor scenarios, but they do have a downside: calling path()
requires parsing strings every time. To solve this problem we added ParsedPath
, which enables pre-parsing paths and then reusing those results on each access:
let parsed_path = ParsedPath::parse("foo.bar[0]").unwrap();
let element = parsed_path.element::<usize>(&some_value);
Much more suitable for repeated access, such as doing the same lookup every frame!
ReflectFromReflect
#
When using Bevy's Rust reflection system, we sometimes end up in a scenario where we have a "dynamic reflect value" representing a certain type MyType
(even though under the hood, it isn't really that type). Such scenarios happen when we call Reflect::clone_value
, use the reflection deserializers, or create the dynamic value ourselves. Unfortunately, we can't just call MyType::from_reflect
as we do not have knowledge of the concrete MyType
at runtime.
ReflectFromReflect
is a new "type data" struct in the TypeRegistry
that enables FromReflect
trait operations without any concrete references to a given type. Very cool!
#[derive(Reflect, FromReflect)]
#[reflect(FromReflect)] // <- Register `ReflectFromReflect`
struct MyStruct(String);
let type_id = TypeId::of::<MyStruct>();
// Register our type
let mut registry = TypeRegistry::default();
registry.register::<MyStruct>();
// Create a concrete instance
let my_struct = MyStruct("Hello world".to_string());
// `Reflect::clone_value` will generate a `DynamicTupleStruct` for tuple struct types
// Note that this is _not_ a MyStruct instance
let dynamic_value: Box<dyn Reflect> = my_struct.clone_value();
// Get the `ReflectFromReflect` type data from the registry
let rfr: &ReflectFromReflect = registry
.get_type_data::<ReflectFromReflect>(type_id)
.unwrap();
// Call `FromReflect::from_reflect` on our Dynamic value
let concrete_value: Box<dyn Reflect> = rfr.from_reflect(&dynamic_value);
assert!(concrete_value.is::<MyStruct>());
Other Reflection Improvements #
Reflect
is now implemented forstd::collections::VecDeque
- Reflected
List
types now haveinsert
andremove
operations - Reflected
Map
types now have theremove
operation - Reflected generic types now automatically implement
Reflect
if the generics also implement Reflect. No need to add manualT: Reflect
bounds! - Component Reflection now uses
EntityRef
/EntityMut
instead of bothWorld
andEntity
, which allows it to be used in more scenarios - The Reflection deserializer now avoids unnecessarily cloning strings in some scenarios!
Upgraded Taffy To 0.3 #
Taffy is the library we use to compute layouts for bevy_ui
. Taffy 0.2 significantly improves the performance of nested UIs (our many_buttons
example is now 8% faster and more deeply nested UIs should see even bigger gains!). It also brings support for the gap property which makes it easier to creates UI with evenly spaced items. Taffy 0.3 adds some nice API tweaks (and also a grid layout feature, which we have disabled for now as it still needs some integration work).
Relative Cursor Position #
We've added a new RelativeCursorPosition
UI component, which when added to a UI entity tracks the cursor position relative to the node. Some((0, 0))
represents the top-left corner of the node, Some((1,1))
represents the bottom-right corner of the node, and None
represents the cursor being "outside of the node".
commands.spawn((
NodeBundle::default(),
RelativeCursorPosition::default(),
));
Const Bevy UI Defaults #
Bevy uses the Default
trait a lot to make it easy to construct types. Bevy UI types generally implement Default
. However, it has one downside (which is fundamental to Rust): Default
cannot be used in const
contexts (yet!). To enable UI layout config to be defined as constants, we've added DEFAULT
associated constants to most of the Bevy UI types. For example, you can use Style::DEFAULT
to define a const style:
const COOL_STYLE: Style = Style {
size: Size::width(Val::Px(200.0)),
border: UiRect::all(Val::Px(2.0)),
..Style::DEFAULT
};
Iterating through a World's Entities #
In Bevy 0.9, World::iter_entities
allows users to get an iterator over all of the entities in the World
in Entity
form. In Bevy 0.10, this has been changed to be an iterator over EntityRef
, which gives full read-only access to all of the entity's components instead of just getting its ID. Its new implementation should also be significantly faster than fetching the EntityRef
by hand (though note that a Query
will still be faster if you know the exact components you're looking for). This gives users free rein to arbitrarily read any entity data from the World, and may see use in scripting language integrations and reflection-heavy workflows.
// Bevy 0.9
for entity in world.iter_entities() {
if let Some(entity_ref) = world.get_entity(entity) {
if let Some(component) = entity_ref.get::<MyComponent>() {
...
}
}
}
// Bevy 0.10
for entity_ref in world.iter_entities() {
if let Some(component) = entity_ref.get::<MyComponent>() {
...
}
}
In the future, we may have a World::iter_entities_mut
that exposes this functionality, but gives arbitrary mutable access to all entities in the World
. We avoided implementing this for now due to the potential safety concerns of returning an iterator of EntityMut
. For more details, see this GitHub issue.
LCH Color Space #
Bevy's Color
type now supports the LCH color space (Lightness, Chroma, Hue). LCH has a lot of arguments for it, including that it provides access to about 50% more colors over sRGB. Check out this article for more information.
Color::Lcha {
lightness: 1.0,
chroma: 0.5,
hue: 200.0,
alpha: 1.0,
}
Optimized Color::hex
Performance #
Color::hex
is now a const
function, which brought the runtime of hex
from ~14ns to ~4ns!
Split Up CorePlugin
#
CorePlugin
has historically been a bit of a "kitchen sink plugin". "Core" things that didn't fit anywhere else ended up there. This isn't a great organizational strategy, so we broke it up into individual pieces: TaskPoolPlugin
, TypeRegistrationPlugin
, and FrameCountPlugin
.
EntityCommand
s #
Commands
are "deferred ECS" operations. They enable developers to define custom ECS operations that are applied after a parallel system has finished running. Many Commands
ran on individual entities, but this pattern was a bit cumbersome:
struct MyCustomCommand(Entity);
impl Command for MyCustomCommand {
fn write(self, world: &mut World) {
// do something with the entity at self.0
}
}
let id = commands.spawn(SpriteBundle::default()).id();
commands.add(MyCustomCommand(id));
To solve this, in Bevy 0.10 we added the EntityCommand
trait. This allows the command to be ergonomically applied to spawned entities:
struct MyCustomCommand;
impl EntityCommand for MyCustomCommand {
fn write(self, id: Entity, world: &mut World) {
// do something with the given entity id
}
}
commands.spawn(SpriteBundle::default()).add(MyCustomCommand);
Pixel Perfect Example #
We now have a new "pixel perfect" example that illustrates how to set up pixel-perfect sprites. It uses a cute new Bevy logo sprite!
UI Text Layout Example #
We've added a nice "text layout" example that illustrates the various Bevy UI text layout settings:
CI Improvements #
We take CI pretty seriously in Bevy land and we're always on the lookout for new ways to make our lives better. We made a number of nice improvements this cycle:
- We now set an MSRV (minimum supported Rust version) for the
bevy
crate and we have a CI job that checks the MSRV - CI gives new contributors a friendly welcome message!
- CI now asks for a migration guide when a PR is labeled as a breaking change and no migration guide is present
The First Subject Matter Expert Release #
This was our first release using our new Subject Matter Expert (SME) system. We merged an absolutely massive amount of changes, and this was despite our Project Lead @cart
being away for about a month for Christmas and snowboarding vacations. We maintained a high quality bar and built amazing things. Suffice it to say the future is looking bright (and sustainable)! Stay tuned for more SME appointments in more areas.
What's Next? #
- Asset System Evolution: We've made good progress on the next iteration of the Bevy Asset System, which will add the ability to preprocess assets and improve the flexibility and usability of the asset system.
- Kicking off the Bevy Editor Effort: We are ready to start shifting our focus to building out the Bevy Editor! We've started gathering requirements and would like to start the initial design phase in the Bevy 0.11 cycle.
- Temporal Anti-Aliasing (TAA): We've largely implemented TAA, which uses motion vectors and time to produce a very popular screen space anti-aliasing effect.
- Screen Space Ambient Occlusion (SSAO): This is a popular, relatively cheap illumination technique that can make scenes look much more natural. It builds on the Depth Prepass work.
- Automated Render Batching and Instancing: Automatically cut down draw calls by combining geometry or using instancing. This will enable Bevy to render hundreds of thousands of objects without grinding to a halt. We technically already support this, but it must be implemented manually outside of our standard pipeline. This will bring batching and instancing wins "for free" in our built-in render pipeline.
- One-shot systems: Run arbitrary systems in a push-based fashion via commands, and store them as callback components for ultra-flexible behavior customization.
- Better plugins: Clearer and more standardized tools for adapting third-party plugins to your app's unique architecture, eliminating order-dependence in their initialization and defining dependencies between them.
- Pull
!Send
data out of theWorld
: storing non thread-safe data in a structure designed to be sent across threads has caused us no end of headaches. We plan on pulling these out into theApp
, resolving a major blocker for a first-class multiple worlds design. - Timestamp window and input events: As discussed in #5984, tracking the exact timing of input events is essential to ensuring that event ordering and timing can be precisely reconstructed.
- Opt-out change detection: improve performance for tiny components by turning off change detection at compile or run-time.
- Comprehensive Animation Composition: Supporting non-transitional animation composition (i.e. arbitrary weighted blending of animations). For more complete information, see the RFC.
Check out the Bevy 0.11 Milestone for an up-to-date list of current work being considered for Bevy 0.11.
Support Bevy #
Sponsorships help make our work on Bevy sustainable. If you believe in Bevy's mission, consider sponsoring us ... every bit helps!
Contributors #
Bevy is made by a large group of people. A huge thanks to the 173 contributors that made this release (and associated docs) possible! In random order:
- @killercup
- @torsteingrindvik
- @utilForever
- @garychia
- @lewiszlw
- @myreprise1
- @tomaspecl
- @jinleili
- @nicopap
- @edgarssilva
- @aevyrie
- @laundmo
- @AxiomaticSemantics
- @polygon
- @SkiFire13
- @SludgePhD
- @abnormalbrain
- @Testare
- @ldubos
- @SpeedRoll
- @rodolphito
- @hymm
- @rdbo
- @AndrewB330
- @13ros27
- @lupan
- @iwek7
- @ErickMVdO
- @kerkmann
- @davidhof
- @Pietrek14
- @Guvante
- @lidong63
- @Tirthnp
- @x-52
- @Suficio
- @pascualex
- @xgbwei
- @BoxyUwU
- @superdump
- @TheRawMeatball
- @wackbyte
- @StarLederer
- @MrGunflame
- @akimakinai
- @doup
- @komadori
- @darthdeus
- @phuocthanhdo
- @DanielJin21
- @LiamGallagher737
- @oliviacrain
- @IceSentry
- @Vrixyz
- @johanhelsing
- @Dessix
- @woodroww
- @SDesya74
- @alphastrata
- @wyhaya
- @foxzool
- @DasLixou
- @nakedible
- @soqb
- @Dorumin
- @maniwani
- @Elabajaba
- @geieredgar
- @stephenmartindale
- @TimJentzsch
- @holyfight6
- @targrub
- @smessmer
- @redwarp
- @LoopyAshy
- @mareq
- @bjrnt
- @slyedoc
- @kurtkuehnert
- @Charles Bournhonesque
- @cryscan
- @A-Walrus
- @JMS55
- @cBournhonesque
- @SpecificProtagonist
- @Shatur
- @VitalyAnkh
- @aktaboot
- @dis-da-moe
- @chrisjuchem
- @wilk10
- @2ne1ugly
- @zeroacez
- @jabuwu
- @Aceeri
- @coreh
- @SuperSodaSea
- @DGriffin91
- @DanielHZhang
- @mnmaita
- @elbertronnie
- @Zeenobit
- @oCaioOliveira
- @Sjael
- @JonahPlusPlus
- @devmitch
- @alice-i-cecile
- @remiCzn
- @Sasy00
- @sQu1rr
- @Ptipiak
- @zardini123
- @alradish
- @adam-shih
- @LinusKall
- @jakobhellermann
- @Andrii Borziak
- @figsoda
- @james7132
- @l1npengtul
- @danchia
- @AjaxGb
- @VVishion
- @CatThingy
- @zxygentoo
- @nfagerlund
- @silvestrpredko
- @ameknite
- @shuoli84
- @CrystaLamb
- @Nanox19435
- @james-j-obrien
- @mockersf
- @R2Boyo25
- @NeoRaider
- @MrGVSV
- @GuillaumeGomez
- @wangling12
- @AndrewJakubowicz
- @rick68
- @RedMachete
- @tbillington
- @ndarilek
- @Ian-Yy
- @Edwox
- @DevinLeamy
- @TehPers
- @cart
- @mvlabat
- @NiklasEi
- @ItsDoot
- @JayPavlina
- @ickk
- @Molot2032
- @devil-ira
- @inodentry
- @MinerSebas
- @JoJoJet
- @Neo-Zhixing
- @rparrett
- @djeedai
- @Pixelstormer
- @iiYese
- @harudagondi
- @1e1001
- @ickshonpe
- @rezural
- @arewerage
- @ld000
- @imustend
- @robtfm
- @frewsxcv
Full Changelog #
Added #
- Accessibility: Added
Label
for marking text specifically as a label for UI controls. - Accessibility: Integrate with and expose AccessKit accessibility.
- App:
App::setup
- App:
SubApp::new
- App: Bevy apps will now log system information on startup by default
- Audio Expose symphonia features from rodio in bevy_audio and bevy
- Audio: Basic spatial audio
- ECS:
bevy_ptr::dangling_with_align
: creates a well-aligned dangling pointer to a type whose alignment is not known at compile time. - ECS:
Column::get_added_ticks
- ECS:
Column::get_column_ticks
- ECS:
DetectChanges::set_if_neq
: triggering change detection when the new and previous values are equal. This will work on both components and resources. - ECS:
SparseSet::get_added_ticks
- ECS:
SparseSet::get_column_ticks
- ECS:
Tick
, a wrapper around a single change detection tick. - ECS:
UnsafeWorldCell::world_mut
now exists and can be used to get a&mut World
out ofUnsafeWorldCell
- ECS:
WorldId
now implements theFromWorld
trait. - ECS: A
core::fmt::Pointer
impl toPtr
,PtrMut
andOwnedPtr
. - ECS: Add
bevy_ecs::schedule_v3
module - ECS: Add
EntityMap::iter()
- ECS: Add
Ref
to the prelude - ECS: Add
report_sets
option toScheduleBuildSettings
- ECS: add
Resources::iter
to iterate over all resource IDs - ECS: add
UnsafeWorldCell
abstraction - ECS: Add
World::clear_resources
&World::clear_all
- ECS: Add a basic example for system ordering
- ECS: Add a missing impl of
ReadOnlySystemParam
forOption<NonSend<>>
- ECS: add a spawn_on_external method to allow spawning on the scope’s thread or an external thread
- ECS: Add const
Entity::PLACEHOLDER
- ECS: Add example to show how to use
apply_system_buffers
- ECS: Add logging variants of system piping
- ECS: Add safe constructors for untyped pointers
Ptr
andPtrMut
- ECS: Add unit test with system that panics
- ECS: Add wrapping_add to change_tick
- ECS: Added “base sets” and ported CoreSet to use them.
- ECS: Added
as_mut
andas_ref
methods toMutUntyped
. - ECS: Added
bevy::ecs::system::assert_is_read_only_system
. - ECS: Added
Components::resource_id
. - ECS: Added
DebugName
world query for more human friendly debug names of entities. - ECS: Added
distributive_run_if
toIntoSystemConfigs
to enable adding a run condition to each system when usingadd_systems
. - ECS: Added
EntityLocation::table_id
- ECS: Added
EntityLocation::table_row
. - ECS: Added
IntoIterator
implementation forEventReader
so you can now do&mut reader
instead ofreader.iter()
for events. - ECS: Added
len
,is_empty
,iter
methods on SparseSets. - ECS: Added
ManualEventReader::clear()
- ECS: Added
MutUntyped::with_type
which allows converting into aMut<T>
- ECS: Added
new_for_test
onComponentInfo
to make test code easy. - ECS: Added
not
condition. - ECS: Added
on_timer
andon_fixed_timer
run conditions - ECS: Added
OwningPtr::read_unaligned
. - ECS: Added
ReadOnlySystem
, which is implemented for anySystem
type whose parameters all implementReadOnlySystemParam
. - ECS: Added
Ref
which allows inspecting change detection flags in an immutable way - ECS: Added
shrink
andas_ref
methods toPtrMut
. - ECS: Added
SystemMeta::name
- ECS: Added
SystemState::get_manual_mut
- ECS: Added
SystemState::get_manual
- ECS: Added
SystemState::update_archetypes
- ECS: Added a large number of methods on
App
to work with schedules ergonomically - ECS: Added conversions from
Ptr
,PtrMut
, andOwningPtr
toNonNull<u8>
. - ECS: Added rore common run conditions:
on_event
, resource change detection,state_changed
,any_with_component
- ECS: Added support for variants of
bevy_ptr
types that do not require being correctly aligned for the pointee type. - ECS: Added the
CoreSchedule
enum - ECS: Added the
SystemParam
typeDeferred<T>
, which can be used to deferWorld
mutations. Powered by the new traitSystemBuffer
. - ECS: Added the extension methods
.and_then(...)
and.or_else(...)
to run conditions, which allows combining run conditions with short-circuiting behavior. - ECS: Added the marker trait
BaseSystemSet
, which is distinguished from aFreeSystemSet
. These are both subtraits ofSystemSet
. - ECS: Added the method
reborrow
toMut
,ResMut
,NonSendMut
, andMutUntyped
. - ECS: Added the private
prepare_view_uniforms
system now has a public system set for scheduling purposes, calledViewSet::PrepareUniforms
- ECS: Added the trait
Combine
, which can be used with the newCombinatorSystem
to create system combinators with custom behavior. - ECS: Added the trait
EntityCommand
. This is a counterpart ofCommand
for types that execute code for a single entity. - ECS: introduce EntityLocation::INVALID const and adjust Entities::get comment
- ECS: States derive macro
- ECS: support for tuple structs and unit structs to the
SystemParam
derive macro. - Hierarchy: Add
Transform::look_to
- Hierarchy: Added
add_child
,set_parent
andremove_parent
toEntityMut
- Hierarchy: Added
clear_children(&mut self) -> &mut Self
andreplace_children(&mut self, children: &[Entity]) -> &mut Self
function inBuildChildren
trait - Hierarchy: Added
ClearChildren
andReplaceChildren
struct - Hierarchy: Added
push_and_replace_children_commands
andpush_and_clear_children_commands
test - Hierarchy: Added the
BuildChildrenTransformExt
trait - Input: add Input Method Editor support
- Input: Added
Axis<T>::devices
- INput: Added common run conditions for
bevy_input
- Macro: add helper for macro to get either bevy::x or bevy_x depending on how it was imported
- Math:
CubicBezier2d
,CubicBezier3d
,QuadraticBezier2d
, andQuadraticBezier3d
types with methods for sampling position, velocity, and acceleration. The genericBezier
type is also available, and generic over any degree of Bezier curve. - Math:
CubicBezierEasing
, with additional methods to allow for smooth easing animations. - Math: Added a generic cubic curve trait, and implementation for Cardinal splines (including Catmull-Rom), B-Splines, Beziers, and Hermite Splines. 2D cubic curve segments also implement easing functionality for animation.
- New reflection path syntax: struct field access by index (example syntax:
foo#1
) - Reflect
State
generics other than justRandomState
can now be reflected for bothhashbrown::HashMap
andcollections::HashMap
- Reflect:
Aabb
now implementsFromReflect
. - Reflect:
derive(Reflect)
now supports structs and enums that contain generic types - Reflect:
ParsedPath
for cached reflection paths - Reflect:
std::collections::HashMap
can now be reflected - Reflect:
std::collections::VecDeque
now implementsReflect
and all relevant traits. - Reflect: Add reflection path support for
Tuple
types - Reflect: Added
ArrayIter::new
. - Reflect: Added
FromReflect::take_from_reflect
- Reflect: Added
List::insert
andList::remove
. - Reflect: Added
Map::remove
- Reflect: Added
ReflectFromReflect
- Reflect: Added
TypeRegistrationDeserializer
, which simplifies getting a&TypeRegistration
while deserializing a string. - Reflect: Added methods to
List
that were previously provided byArray
- Reflect: Added support for enums in reflection paths
- Reflect: Added the
bevy_reflect_compile_fail_tests
crate for testing compilation errors - Reflect: bevy_reflect: Add missing primitive registrations
- Reflect: impl
Reflect
for&'static Path
- Reflect: implement
Reflect
forFxaa
- Reflect: implement
TypeUuid
for primitives and fix multiple-parameter generics having the sameTypeUuid
- Reflect: Implemented
Reflect
+FromReflect
for window events and related types. These types are automatically registered when adding theWindowPlugin
. - Reflect: Register Hash for glam types
- Reflect: Register missing reflected types for
bevy_render
- Render: A pub field
extras
toGltfNode
/GltfMesh
/GltfPrimitive
which store extras - Render: A pub field
material_extras
toGltfPrimitive
which store material extras - Render: Add 'Color::as_lcha' function (#7757)
- Render: Add
Camera::viewport_to_world_2d
- Render: Add a more familiar hex color entry
- Render: add ambient lighting hook
- Render: Add bevy logo to the lighting example to demo alpha mask shadows
- Render: Add Box::from_corners method
- Render: add OpenGL and DX11 backends
- Render: Add orthographic camera support back to directional shadows
- Render: add standard material depth bias to pipeline
- Render: Add support for Rgb9e5Ufloat textures
- Render: Added buffer usage field to buffers
- Render: can define a value from inside a shader
- Render: EnvironmentMapLight support for WebGL2
- Render: Implement
ReadOnlySystemParam
forExtract<>
- Render: Initial tonemapping options
- Render: ShaderDefVal: add an
UInt
option - Render: Support raw buffers in AsBindGroup macro
- Rendering:
Aabb
now implementsCopy
. - Rendering:
ExtractComponent
can specify output type, and outputting is optional. - Rendering:
Mssaa::samples
- Rendering: Add
#else ifdef
to shader preprocessing. - Rendering: Add a field
push_constant_ranges
to RenderPipelineDescriptor and ComputePipelineDescriptor - Rendering: Added
Material::prepass_vertex_shader()
andMaterial::prepass_fragment_shader()
to control the prepass from theMaterial
- Rendering: Added
BloomSettings:lf_boost
,BloomSettings:lf_boost_curvature
,BloomSettings::high_pass_frequency
andBloomSettings::composite_mode
. - Rendering: Added
BufferVec::extend
- Rendering: Added
BufferVec::truncate
- Rendering: Added
Camera::msaa_writeback
which can enable and disable msaa writeback. - Rendering: Added
CascadeShadowConfigBuilder
to help with creatingCascadeShadowConfig
- Rendering: Added
DepthPrepass
andNormalPrepass
component to control which textures will be created by the prepass and available in later passes. - Rendering: Added
Draw<T>::prepare
optional trait function. - Rendering: Added
DrawFunctionsInternals::id()
- Rendering: Added
FallbackImageCubemap
. - Rendering: Added
FogFalloff
enum for selecting between three widely used “traditional” fog falloff modes:Linear
,Exponential
andExponentialSquared
, as well as a more advancedAtmospheric
fog; - Rendering: Added
get_input_node
- Rendering: Added
Lcha
member tobevy_render::color::Color
enum - Rendering: Added
MainTaret::main_texture_other
- Rendering: Added
PhaseItem::entity
- Rendering: Added
prepass_enabled
flag to theMaterialPlugin
that will control if a material uses the prepass or not. - Rendering: Added
prepass_enabled
flag to thePbrPlugin
to control if the StandardMaterial uses the prepass. Currently defaults to false. - Rendering: Added
PrepassNode
that runs before the main pass - Rendering: Added
PrepassPlugin
to extract/prepare/queue the necessary data - Rendering: Added
RenderCommand::ItemorldQuery
associated type. - Rendering: Added
RenderCommand::ViewWorldQuery
associated type. - Rendering: Added
RenderContext::add_command_buffer
- Rendering: Added
RenderContext::begin_tracked_render_pass
. - Rendering: Added
RenderContext::finish
- Rendering: Added
RenderContext::new
- Rendering: Added
SortedCameras
, exposing information that was previously internal to the camera driver node. - Rendering: Added
try_add_node_edge
- Rendering: Added
try_add_slot_edge
- Rendering: Added
with_r
,with_g
,with_b
, andwith_a
toColor
. - Rendering: Added 2x and 8x sample counts for MSAA.
- Rendering: Added a
#[storage(index)]
attribute to the deriveAsBindGroup
macro. - Rendering: Added an
EnvironmentMapLight
camera component that adds additional ambient light to a scene. - Rendering: Added argument to
ScalingMode::WindowSize
that specifies the number of pixels that equals one world unit. - Rendering: Added cylinder shape
- Rendering: Added example
shaders/texture_binding_array
. - Rendering: Added new capabilities for shader validation.
- Rendering: Added specializable
BlitPipeline
and ported the upscaling node to use this. - Rendering: Added subdivisions field to shape::Plane
- Rendering: Added support for additive and multiplicative blend modes in the PBR
StandardMaterial
, viaAlphaMode::Add
andAlphaMode::Multiply
; - Rendering: Added support for distance-based fog effects for PBR materials, controllable per-camera via the new
FogSettings
component; - Rendering: Added support for KTX2
R8_SRGB
,R8_UNORM
,R8G8_SRGB
,R8G8_UNORM
,R8G8B8_SRGB
,R8G8B8_UNORM
formats by converting to supported wgpu formats as appropriate - Rendering: Added support for premultiplied alpha in the PBR
StandardMaterial
, viaAlphaMode::Premultiplied
; - Rendering: Added the ability to
#[derive(ExtractComponent)]
with an optional filter. - Rendering: Added:
bevy_render::color::LchRepresentation
struct - Rendering: Clone impl for MaterialPipeline
- Rendering: Implemented
Clone
for all pipeline types. - Rendering: Smooth Transition between Animations
- Support optional env variable
BEVY_ASSET_ROOT
to explicitly specify root assets directory. - Task: Add thread create/destroy callbacks to TaskPool
- Tasks: Added
ThreadExecutor
that can only be ticked on one thread. - the extension methods
in_schedule(label)
andon_startup()
for configuring the schedule a system belongs to. - Transform: Added
GlobalTransform::reparented_to
- UI:
Size::new
is nowconst
- UI: Add const to methods and const defaults to bevy_ui
- UI: Added
all
,width
andheight
functions toSize
. - UI: Added
Anchor
component toText2dBundle
- UI: Added
CalculatedSize::preserve_aspect_ratio
- UI: Added
Component
derive toAnchor
- UI: Added
RelativeCursorPosition
, and an example showcasing it - UI: Added
Text::with_linebreak_behaviour
- UI: Added
TextBundle::with_linebreak_behaviour
- UI: Added a
BackgroundColor
component toTextBundle
. - UI: Added a helper method
with_background_color
toTextBundle
. - UI: Added the
SpaceEvenly
variant toAlignContent
. - UI: Added the
Start
andEnd
variants toAlignItems
,AlignSelf
,AlignContent
andJustifyContent
. - UI: Adds
flip_x
andflip_y
fields toExtractedUiNode
. - Utils: Added
SyncCell::read
, which allows shared access to values that already implement theSync
trait. - Utils: Added the guard type
bevy_utils::OnDrop
. - Window: Add
Windows::get_focused(_mut)
- Window: add span to winit event handler
- Window: Transparent window on macos
- Windowing:
WindowDescriptor
renamed toWindow
. - Windowing: Added
hittest
toWindowAttributes
- Windowing: Added
Window::prevent_default_event_handling
. This allows bevy apps to not override default browser behavior on hotkeys like F5, F12, Ctrl+R etc. - Windowing: Added
WindowDescriptor.always_on_top
which configures a window to stay on top. - Windowing: Added an example
cargo run --example fallthrough
- Windowing: Added the
hittest
’s setters/getters - Windowing: Modifed the
WindowDescriptor
’sDefault
impl. - Windowing: Modified the
WindowBuilder
Changed #
- Animation:
AnimationPlayer
that are on a child or descendant of another entity with another player will no longer be run. - Animation: Animation sampling now runs fully multi-threaded using threads from
ComputeTaskPool
. - App: Adapt path type of dynamically_load_plugin
- App: Break CorePlugin into TaskPoolPlugin, TypeRegistrationPlugin, FrameCountPlugin.
- App: Increment FrameCount in CoreStage::Last.
- App::run() will now panic when called from Plugin::build()
- Asset:
AssetIo::watch_path_for_changes
allows watched path and path to reload to differ - Asset: make HandleUntyped::id private
- Audio:
AudioOutput
is now aResource
. It's no longer!Send
- Audio: AudioOutput is actually a normal resource now, not a non-send resource
- ECS:
.label(SystemLabel)
is now referred to as.in_set(SystemSet)
- ECS:
App::add_default_labels
is nowApp::add_default_sets
- ECS:
App::add_system_set
was renamed toApp::add_systems
- ECS:
Archetype
indices andTable
rows have been newtyped asArchetypeRow
andTableRow
. - ECS:
ArchetypeGeneration
now implementsOrd
andPartialOrd
. - ECS:
bevy_pbr::add_clusters
is no longer an exclusive system - ECS:
Bundle::get_components
now takes aFnMut(StorageType, OwningPtr)
. The provided storage type must be correct for the component being fetched. - ECS:
ChangeTrackers<T>
has been deprecated. It will be removed in Bevy 0.11. - ECS:
Command
closures no longer need to implement the marker traitstd::marker::Sync
. - ECS:
CoreStage
andStartupStage
enums are nowCoreSet
andStartupSet
- ECS:
EntityMut::world_scope
now allows returning a value from the immediately-computed closure. - ECS:
EntityMut
: renameremove_intersection
toremove
andremove
totake
- ECS:
EventReader::clear
now takes a mutable reference instead of consuming the event reader. - ECS:
EventWriter::send_batch
will only log a TRACE level log if the batch is non-empty. - ECS:
oldest_id
andget_event
convenience methods added toEvents<T>
. - ECS:
OwningPtr::drop_as
will now panic in debug builds if the pointer is not aligned. - ECS:
OwningPtr::read
will now panic in debug builds if the pointer is not aligned. - ECS:
Ptr::deref
will now panic in debug builds if the pointer is not aligned. - ECS:
PtrMut::deref_mut
will now panic in debug builds if the pointer is not aligned. - ECS:
Query::par_for_each(_mut)
has been changed toQuery::par_iter(_mut)
and will now automatically try to produce a batch size for callers based on the currentWorld
state. - ECS:
RemovedComponents
now internally uses anEvents<RemovedComponentsEntity>
instead of anEvents<Entity>
- ECS:
SceneSpawnerSystem
now runs underCoreSet::Update
, rather thanCoreStage::PreUpdate.at_end()
. - ECS:
StartupSet
is now a base set - ECS:
System::default_labels
is nowSystem::default_system_sets
. - ECS:
SystemLabel
trait was replaced bySystemSet
- ECS:
SystemParamState::apply
now takes a&SystemMeta
parameter in addition to the provided&mut World
. - ECS:
SystemTypeIdLabel<T>
was replaced bySystemSetType<T>
- ECS:
tick_global_task_pools_on_main_thread
is no longer run as an exclusive system. Instead, it has been replaced bytick_global_task_pools
, which uses aNonSend
resource to force running on the main thread. - ECS:
Tick::is_older_than
was renamed toTick::is_newer_than
. This is not a functional change, since that was what was always being calculated, despite the wrong name. - ECS:
UnsafeWorldCell::world
is now used to get immutable access to the whole world instead of just the metadata which can now be done viaUnsafeWorldCell::world_metadata
- ECS:
World::init_non_send_resource
now returns the generatedComponentId
. - ECS:
World::init_resource
now returns the generatedComponentId
. - ECS:
World::iter_entities
now returns an iterator ofEntityRef
instead ofEntity
. - ECS:
World
s can now only hold a maximum of 2^32 - 1 tables. - ECS:
World
s can now only hold a maximum of 2^32- 1 archetypes. - ECS:
WorldId
now implementsSystemParam
and will return the id of the world the system is running in - ECS: Adding rendering extraction systems now panics rather than silently failing if no subapp with the
RenderApp
label is found. - ECS: Allow adding systems to multiple sets that share the same base set
- ECS: change
is_system_type() -> bool
tosystem_type() -> Option<TypeId>
- ECS: changed some
UnsafeWorldCell
methods to takeself
instead of&self
/&mut self
since there is literally no point to them doing that - ECS: Changed:
Query::for_each(_mut)
,QueryParIter
will now leverage autovectorization to speed up query iteration where possible. - ECS: Default to using ExecutorKind::SingleThreaded on wasm32
- ECS: Ensure
Query
does not use the wrongWorld
- ECS: Exclusive systems may now be used with system piping.
- ECS: expose
ScheduleGraph
for use in third party tools - ECS: extract topsort logic to a new method, one pass to detect cycles and …
- ECS: Fixed time steps now use a schedule (
CoreSchedule::FixedTimeStep
) rather than a run criteria. - ECS: for disconnected, use Vec instead of HashSet to reduce insert overhead
- ECS: Implement
SparseSetIndex
forWorldId
- ECS: Improve the panic message for schedule build errors
- ECS: Lift the 16-field limit from the
SystemParam
derive - ECS: Make
EntityRef::new
unsafe - ECS: Make
Query
fields private - ECS: make
ScheduleGraph::initialize
public - ECS: Make boxed conditions read-only
- ECS: Make RemovedComponents mirror EventReaders API surface
- ECS: Mark TableRow and TableId as repr(transparent)
- ECS: Most APIs returning
&UnsafeCell<ComponentTicks>
now returnsTickCells
instead, which contains two separate&UnsafeCell<Tick>
for either component ticks. - ECS: Move MainThreadExecutor for stageless migration.
- ECS: Move safe operations out of
unsafe
blocks inQuery
- ECS: Optimize
.nth()
and.last()
for event iterators - ECS: Optimize
Iterator::count
for event iterators - ECS: Provide public
EntityRef::get_change_ticks_by_id
that takesComponentId
- ECS: refactor: move internals from
entity_ref
toWorld
, addSAFETY
comments - ECS: Rename
EntityId
toEntityIndex
- ECS: Rename
UnsafeWorldCellEntityRef
toUnsafeEntityCell
- ECS: Rename schedule v3 to schedule
- ECS: Rename state_equals condition to in_state
- ECS: Replace
World::read_change_ticks
withWorld::change_ticks
withinbevy_ecs
crate - ECS: Replaced the trait
ReadOnlySystemParamFetch
withReadOnlySystemParam
. - ECS: Simplified the
SystemParamFunction
andExclusiveSystemParamFunction
traits. - ECS: Speed up
CommandQueue
by storing commands more densely - ECS: Stageless: move final apply outside of spawned executor
- ECS: Stageless: prettier cycle reporting
- ECS: Systems without
Commands
andParallelCommands
will no longer show asystem_commands
span when profiling. - ECS: The
ReportHierarchyIssue
resource now has a public constructor (new
), and implementsPartialEq
- ECS: The
StartupSchedule
label is now defined as part of theCoreSchedules
enum - ECS: The
SystemParam
derive is now more flexible, allowing you to omit unused lifetime parameters. - ECS: the top level
bevy_ecs::schedule
module was replaced withbevy_ecs::scheduling
- ECS: Use
World
helper methods for sendingHierarchyEvent
s - ECS: Use a bounded channel in the multithreaded executor
- ECS: Use a default implementation for
set_if_neq
- ECS: Use consistent names for marker generics
- ECS: Use correct terminology for a
NonSend
run condition panic - ECS: Use default-implemented methods for
IntoSystemConfig<>
- ECS: use try_send to replace send.await, unbounded channel should always b…
- General: The MSRV of the engine is now 1.67.
- Input: Bump gilrs version to 0.10
- IOS, Android... same thing
- Math: Update
glam
to0.23
- Math: use
Mul<f32>
to double the value ofVec3
- Reflect: bevy_reflect now uses a fixed state for its hasher, which means the output of
Reflect::reflect_hash
is now deterministic across processes. - Reflect: Changed function signatures of
ReflectComponent
methods,apply
,remove
,contains
, andreflect
. - Reflect: Changed the
List::push
andList::pop
to have default implementations. - Reflect: Registered
SmallVec<[Entity; 8]>
in the type registry - Renamed methods on
GetPath
:path
->reflect_path
path_mut
->reflect_path_mut
get_path
->path
get_path_mut
->path_mut
- Render: Allow prepass in webgl
- Render: bevy_pbr: Avoid copying structs and using registers in shaders
- Render: bevy_pbr: Clear fog DynamicUniformBuffer before populating each frame
- Render: bevy_render: Run calculate_bounds in the end-of-update exclusive systems
- Render: Change the glTF loader to use
Camera3dBundle
- Render: Changed &mut PipelineCache to &PipelineCache
- Render: Intepret glTF colors as linear instead of sRGB
- Render: Move 'startup' Resource
WgpuSettings
into theRenderPlugin
- Render: Move prepass functions to prepass_utils
- Render: Only compute sprite color once per quad
- Render: Only execute
#define
if current scope is accepting lines - Render: Pipelined Rendering
- Render: Refactor Globals and View structs into separate shaders
- Render: Replace UUID based IDs with a atomic-counted ones
- Render: run clear trackers on render world
- Render: set cull mode: None for Mesh2d
- Render: Shader defs can now have a value
- Render: Shrink ComputedVisibility
- Render: Use prepass shaders for shadows
- Rendering:
add_node_edge
is now infallible (panics on error) - Rendering:
add_slot_edge
is now infallible (panics on error) - Rendering:
AsBindGroup
is now object-safe. - Rendering:
BloomSettings::knee
renamed toBloomPrefilterSettings::softness
. - Rendering:
BloomSettings::threshold
renamed toBloomPrefilterSettings::threshold
. - Rendering:
HexColorError::Hex
has been renamed toHexColorError::Char
- Rendering:
input_node
now panics onNone
- Rendering:
ktx2
andzstd
are now part of bevy’s default enabled features - Rendering:
Msaa
is now enum - Rendering:
PipelineCache
no longer requires mutable access in order to queue render / compute pipelines. - Rendering:
RenderContext::command_encoder
is now private. Use the accessorRenderContext::command_encoder()
instead. - Rendering:
RenderContext::render_device
is now private. Use the accessorRenderContext::render_device()
instead. - Rendering:
RenderContext
now supports adding externalCommandBuffer
s for inclusion into the render graphs. These buffers can be encoded outside of the render graph (i.e. in a system). - Rendering:
scale
is now applied before updatingarea
. Reading from it will takescale
into account. - Rendering:
SkinnedMeshJoints::build
now takes a&mut BufferVec
instead of a&mut Vec
as a parameter. - Rendering:
StandardMaterial
now defaults to a dielectric material (0.0metallic
) with 0.5perceptual_roughness
. - Rendering:
TrackedRenderPass
now requires a&RenderDevice
on construction. - Rendering:
Visibility
is now an enum - Rendering: Bloom now looks different.
- Rendering: Directional lights now use cascaded shadow maps for improved shadow quality.
- Rendering: ExtractedMaterials, extract_materials and prepare_materials are now public
- Rendering: For performance reasons, some detailed renderer trace logs now require the use of cargo feature
detailed_trace
in addition to setting the log level toTRACE
in order to be shown. - Rendering: Made cameras with the same target share the same
main_texture
tracker, which ensures continuity across cameras. - Rendering: Renamed
ScalingMode::Auto
toScalingMode::AutoMin
. - Rendering: Renamed
ScalingMode::None
toScalingMode::Fixed
- Rendering: Renamed
window_origin
toviewport_origin
- Rendering: Renamed the
priority
field onCamera
toorder
. - Rendering: Replaced
left
,right
,bottom
, andtop
fields with a singlearea: Rect
- Rendering: StandardMaterials will now appear brighter and more saturated at high roughness, due to internal material changes. This is more physically correct.
- Rendering: The
layout
field ofRenderPipelineDescriptor
andComputePipelineDescriptor
is now mandatory. - Rendering: The
rangefinder
module has been moved into therender_phase
module. - Rendering: The bloom example has been renamed to bloom_3d and improved. A bloom_2d example was added.
- Rendering: the SubApp Extract stage has been separated from running the sub app schedule.
- Rendering: To enable multiple
RenderPhases
to share the sameTrackedRenderPass
, theRenderPhase::render
signature has changed. - Rendering: update its
Transform
in order to preserve itsGlobalTransform
after the parent change - Rendering: Updated to wgpu 0.15, wgpu-hal 0.15.1, and naga 0.11
- Rendering: Users can now use the DirectX Shader Compiler (DXC) on Windows with DX12 for faster shader compilation and ShaderModel 6.0+ support (requires
dxcompiler.dll
anddxil.dll
) - Rendering: You can now set up the rendering code of a
RenderPhase
directly using theRenderPhase::render
method, instead of implementing it manually in your render graph node. - Scenes:
SceneSpawner::spawn_dynamic
now returnsInstanceId
instead of()
. - Shape: Change
From<Icosphere>
toTryFrom<Icosphere>
- Tasks:
Scope
now usesFallibleTask
to await the cancellation of all remaining tasks when it’s dropped. - Time:
Time::set_relative_speed_fXX
now allows a relative speed of -0.0. - UI:
FocusPolicy
default has changed fromFocusPolicy::Block
toFocusPolicy::Pass
- UI:
TextPipeline::queue_text
andGlyphBrush::compute_glyphs
now need a TextLineBreakBehaviour argument, in order to pass through the new field. - UI:
update_image_calculated_size_system
setspreserve_aspect_ratio
to true for nodes with images. - UI: Added
Changed<Node>
to the change detection query oftext_system
. This ensures that any change in the size of a text node will cause any text it contains to be recomputed. - UI: Changed
Size::height
so it sets thewidth
toVal::AUTO
. - UI: Changed
Size::width
so it sets theheight
toVal::AUTO
. - UI: Changed
TextAlignment
into an enum withLeft
,Center
, andRight
variants. - UI: Changed extract_uinodes to extract the flip_x and flip_y values from UiImage.
- UI: Changed prepare_uinodes to swap the UV coordinates as required.
- UI: Changed Taffy version to 0.3.3 and disabled its
grid
feature. - UI: Changed the
Size
width
andheight
default values toVal::Auto
- UI: Changed the
size
field ofCalculatedSize
to a Vec2. - UI: Changed UiImage derefs to texture field accesses.
- UI: Changed UiImage to a struct with texture, flip_x, and flip_y fields.
- UI: Modified the
text2d
example to show both linebreaking behaviours. - UI: Renamed
image_node_system
toupdate_image_calculated_size_system
- UI: Renamed the
background_color
field ofExtractedUiNode
tocolor
. - UI: Simplified the UI examples. Replaced numeric values with the Flex property enums or elided them where possible, and removed the remaining use of auto margins.
- UI: The
MeasureFunc
only preserves the aspect ratio whenpreserve_aspect_ratio
is true. - UI: Updated
from_style
for Taffy 0.3.3. - UI: Upgraded to Taffy 0.2, improving UI layout performance significantly and adding the flexbox
gap
property andAlignContent::SpaceEvenly
. - UI: Use
f32::INFINITY
instead off32::MAX
to represent unbounded text in Text2dBounds - Window: expose cursor position with scale
- Window: Make WindowId::primary() const
- Window: revert stage changed for window closing
- Windowing:
WindowId
is nowEntity
. - Windowing: Moved
changed_window
anddespawn_window
systems toCoreStage::Last
to avoid systems making changes to theWindow
betweenchanged_window
and the end of the frame as they would be ignored. - Windowing: Requesting maximization/minimization is done on the [
Window::state
] field. - Windowing: Width/height consolidated into a
WindowResolution
component.
Removed #
- App: Removed
App::add_sub_app
- App: Rename dynamic feature
- ECS: Remove .on_update method to improve API consistency and clarity
- ECS: Remove
BuildWorldChildren
impl fromWorldChildBuilder
- ECS: Remove a duplicate lookup in
apply_state_transitions
- ECS: Remove an incorrect impl of
ReadOnlySystemParam
forNonSendMut
- ECS: Remove APIs deprecated in 0.9
- ECS: Remove broken
DoubleEndedIterator
impls on event iterators - ECS: Remove duplicate lookups from
Resource
initialization - ECS: Remove useless access to archetype in
UnsafeWorldCell::fetch_table
- ECS: Removed
AddBundle
.Edges::get_add_bundle
now returnsOption<ArchetypeId>
- ECS: Removed
Archetype::new
andArchetype::is_empty
. - ECS: Removed
ArchetypeComponentId::new
andArchetypeComponentId::value
. - ECS: Removed
ArchetypeGeneration::value
- ECS: Removed
ArchetypeId::new
andArchetypeId::value
. - ECS: Removed
ArchetypeIdentity
. - ECS: Removed
Archetypes
’sDefault
implementation. - ECS: Removed
AsSystemLabel
trait - ECS: Removed
Entities::alloc_at_without_replacement
andAllocAtWithoutReplacement
. - ECS: Removed
Entities
’sDefault
implementation. - ECS: Removed
EntityMeta
- ECS: Removed
on_hierarchy_reports_enabled
run criteria (now just uses an ad hoc resource checking run condition) - ECS: Removed
RunCriteriaLabel
- ECS: Removed
RunCriteriaLabel
- ECS: Removed
SystemParamFetch
, its functionality has been moved toSystemParamState
. - ECS: Removed
Table::component_capacity
- ECS: Removed
transform_propagate_system_set
: this was a nonstandard pattern that didn’t actually provide enough control. The systems are alreadypub
: the docs have been updated to ensure that the third-party usage is clear. - ECS: removed
UnsafeWorldCell::storages
since that is probably unsound since storages contains the actual component/resource data not just metadata - ECS: Removed stages, and all code that mentions stages
- ECS: Removed states have been dramatically simplified, and no longer use a stack
- ECS: Removed systems in
RenderSet/Stage::Extract
no longer warn when they do not read data from the main world - ECS: Removed the bound
T: Sync
fromLocal<T>
when used as anExclusiveSystemParam
. - ECS: Removed the method
ExclusiveSystemParamState::apply
. - ECS: Removed the trait
ExclusiveSystemParamState
, merging its functionality intoExclusiveSystemParam
. - ECS: Removed the trait
SystemParamState
, merging its functionality intoSystemParam
. - ECS: Support
SystemParam
types with const generics - ECS: Use T::Storage::STORAGE_TYPE to optimize out unused branches
- Hierarchy: Expose transform propagate systems
- Hierarchy: Make adding children idempotent
- Hierarchy: Remove
EntityCommands::add_children
- Input: Gamepad events refactor
- Reflect: Make proc macros hygienic in bevy_reflect_derive
- Reflect: Removed
#[module]
helper attribute forReflect
derives (this is not currently used) - Reflect: Removed
Array
as supertrait ofList
- Reflect: Removed
PixelInfo
and getpixel_size
from wgpu - Reflect: Removed
ReflectSerialize
andReflectDeserialize
registrations from most glam types - Remove unnecessary
Default
impl of HandleType - Remove warning about missed events due to false positives
- Render: Make Core Pipeline Graph Nodes Public
- Render: Optimize color computation in prepare_uinodes
- Render: Organized scene_viewer into plugins for reuse and organization
- Render: put
update_frusta::<Projection>
inUpdateProjectionFrusta
set - Render: Remove dependency on the mesh struct in the pbr function
- Render: remove potential ub in render_resource_wrapper
- Render: Remove redundant bitwise OR
TEXTURE_ADAPTER_SPECIFIC_FORMAT_FEATURES
- Render: Remove the early exit to make sure the prepass textures are cleared
- Render: remove the image loaded check for nodes without images in extract_uinodes
- Render: Remove unnecessary alternate create_texture path in prepare_asset for Image
- Render: remove unused var in fxaa shader
- Render: set AVAILABLE_STORAGE_BUFFER_BINDINGS to the actual number of buffers available
- Render: Use
Time
resource
instead ofExtract
ingTime
- Render: use better set inheritance in render systems
- Render: use blendstate blend for alphamode::blend
- Render: Use Image::default for 1 pixel white texture directly
- Rendering: Removed
bevy_render::render_phase::DrawState
. It was not usable in any form outside ofbevy_render
. - Rendering: Removed
BloomSettings::scale
. - Rendering: Removed
EntityPhaseItem
trait - Rendering: Removed
ExtractedJoints
. - Rendering: Removed
SetShadowViewBindGroup
,queue_shadow_view_bind_group()
, andLightMeta::shadow_view_bind_group
in favor of reusing the prepass view bind group. - Rendering: Removed the
render
feature group. - Scene: scene viewer: can select a scene from the asset path
- Text: Warn instead of erroring when max_font_atlases is exceeded
- Transform: Removed
GlobalTransform::translation_mut
- UI: Re-enable taffy send+sync assert
- UI: Remove
TextError::ExceedMaxTextAtlases(usize)
variant - UI: Remove needless manual default impl of ButtonBundle
- UI: Removed
HorizontalAlign
andVerticalAlign
. - UI: Removed
ImageMode
. - UI: Removed
QueuedText
- UI: Removed the
image_mode
field fromImageBundle
- UI: Removed the
Val
<->f32
conversion forCalculatedSize
. - Update toml_edit to 0.18
- Update tracing-chrome requirement from 0.6.0 to 0.7.0
- Window: Remove unnecessary windows.rs file
- Windowing:
window.always_on_top
has been removed, you can now usewindow.window_level
- Windowing: Removed
ModifiesWindows
system label.
Fixed #
- Asset: Fix asset_debug_server hang. There should be at most one ThreadExecut…
- Asset: fix load_internal_binary_asset with debug_asset_server
- Assets: Hot reloading for
LoadContext::read_asset_bytes
- Diagnostics: Console log messages now show when the
trace_tracy
feature was enabled. - ECS: Fix
last_changed()
andset_last_changed()
forMutUntyped
- ECS: Fix a miscompilation with
#[derive(SystemParam)]
- ECS: Fix get_unchecked_manual using archetype index instead of table row.
- ECS: Fix ignored lifetimes in
#[derive(SystemParam)]
- ECS: Fix init_non_send_resource overwriting previous values
- ECS: fix mutable aliases for a very short time if
WorldCell
is already borrowed - ECS: Fix partially consumed
QueryIter
andQueryCombinationIter
having invalidsize_hint
- ECS: Fix PipeSystem panicking with exclusive systems
- ECS: Fix soundness bug with
World: Send
. Dropping aWorld
that contains a!Send
resource on the wrong thread will now panic. - ECS: Fix Sparse Change Detection
- ECS: Fix trait bounds for run conditions
- ECS: Fix unsoundnes in
insert
remove
anddespawn
- ECS: Fix unsoundness in
EntityMut::world_scope
- ECS: Fixed
DetectChanges::last_changed
returning the wrong value. - ECS: Fixed
DetectChangesMut::set_last_changed
not actually updating thechanged
tick. - ECS: Fixed
Res
andQuery
parameter never being mutually exclusive. - ECS: Fixed a bug that caused
#[derive(SystemParam)]
to leak the types of private fields. - ECS: schedule_v3: fix default set for systems not being applied
- ECS: Stageless: close the finish channel so executor doesn't deadlock
- ECS: Stageless: fix unapplied systems
- Hierarchy: don't error when sending HierarchyEvents when Event type not registered
- Hierarchy: Fix unsoundness for
propagate_recursive
- Hierarchy: Fixed missing
ChildAdded
events - Input: Avoid triggering change detection for inputs
- Input: Fix
AxisSettings::new
only accepting invalid bounds - Input: Fix incorrect behavior of
just_pressed
andjust_released
inInput<GamepadButton>
- Input: Removed Mobile Touch event y-axis flip
- Reflect: bevy_reflect: Fix misplaced impls
- Reflect: Fix bug where deserializing unit structs would fail for non-self-describing formats
- Reflect: Fix bug where scene deserialization using certain readers could fail (e.g.
BufReader
,File
, etc.) - Reflect: fix typo in bevy_reflect::impls::std GetTypeRegistration for vec like…
- Reflect: Retain
::
after>
,)
or bracket when shortening type names - Render: bevy_core_pipeline: Fix prepass sort orders
- Render: Cam scale cluster fix
- Render: fix ambiguities in render schedule
- Render: fix bloom viewport
- Render: Fix dependency of shadow mapping on the optional
PrepassPlugin
- Render: Fix feature gating in texture_binding_array example
- Render: Fix material alpha_mode in example global_vs_local_translation
- Render: fix regex for shader define: must have at least one whitespace
- Render: fix shader_instancing
- Render: fix spot dir nan again
- Render: Recreate tonemapping bind group if view uniforms buffer has changed
- Render: Shadow render phase - pass the correct view entity
- Render: Text2d doesn't recompute text on changes to the text's bounds
- Render: wasm: pad globals uniform also in 2d
- Rendering: Emission strength is now correctly interpreted by the
StandardMaterial
as linear instead of sRGB. - Rendering: Fix deband dithering intensity for non-HDR pipelines.
- Rendering: Fixed StandardMaterial occlusion being incorrectly applied to direct lighting.
- Rendering: Fixed the alpha channel of the
image::DynamicImage::ImageRgb32F
tobevy_render::texture::Image
conversion inbevy_render::texture::Image::from_dynamic()
. - Scene: Cleanup dynamic scene before building
- Task: Fix panicking on another scope
- UI:
Size::height
setswidth
notheight
- UI: Don't ignore UI scale for text
- UI: Fix
bevy_ui
compile error withoutbevy_text
- UI: Fix overflow scaling for images
- UI: fix upsert_leaf not setting a MeasureFunc for new leaf nodes
- Window: Apply
WindowDescriptor
settings in all modes - Window: break feedback loop when moving cursor
- Window: create window as soon as possible
- Window: Fix a typo on
Window::set_minimized
- Window: Fix closing window does not exit app in desktop_app mode
- Window: fix cursor grab issue
- Window: Fix set_cursor_grab_mode to try an alternative mode before giving an error