# Objective
- Build on the changes in https://github.com/bevyengine/bevy/pull/9982
- Use `ImageSamplerDescriptor` as the "public image sampler descriptor"
interface in all places (for consistency)
- Make it possible to configure textures to use the "default" sampler
(as configured in the `DefaultImageSampler` resource)
- Fix a bug introduced in #9982 that prevents configured samplers from
being used in Basis, KTX2, and DDS textures
---
## Migration Guide
- When using the `Image` API, use `ImageSamplerDescriptor` instead of
`wgpu::SamplerDescriptor`
- If writing custom wgpu renderer features that work with `Image`, call
`&image_sampler.as_wgpu()` to convert to a wgpu descriptor.
# Objective
- Folder handles are not shared. Loading the same folder multiple times
will result in different handles.
- Once folder handles are shared, they can no longer be manually
reloaded, so we should add support for hot-reloading them
## Solution
- Reuse folder handles based on their path
- Trigger a reload of a folder if a file contained in it (or a sub
folder) is added or removed
- This also covers adding/removing/moving sub folders containing files
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
- Assets v2 does not currently offer a public API to load untyped assets
## Solution
- Wrap the untyped handle in a `LoadedUntypedAsset` asset to offer a
non-blocking load for untyped assets. The user does not need to know the
actual asset type.
- Handles to `LoadedUntypedAsset` have the same path as the wrapped
asset, but their handles are shared using a label.
The user side of `load_untyped` looks like this:
```rust
use bevy::prelude::*;
use bevy_internal::asset::LoadedUntypedAsset;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.add_systems(Update, check)
.run();
}
#[derive(Resource)]
struct UntypedAsset {
handle: Handle<LoadedUntypedAsset>,
}
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
) {
let handle = asset_server.load_untyped("branding/banner.png");
commands.insert_resource(UntypedAsset { handle });
commands.spawn(Camera2dBundle::default());
}
fn check(
mut commands: Commands,
res: Option<Res<UntypedAsset>>,
assets: Res<Assets<LoadedUntypedAsset>>,
) {
if let Some(untyped_asset) = res {
if let Some(asset) = assets.get(&untyped_asset.handle) {
commands.spawn(SpriteBundle {
texture: asset.handle.clone().typed(),
..default()
});
commands.remove_resource::<UntypedAsset>();
}
}
}
```
---
## Changelog
- `load_untyped` on the asset server now returns a handle to a
`LoadedUntypedAsset` instead of an untyped handle to the asset at the
given path. The untyped handle for the given path can be retrieved from
the `LoadedUntypedAsset` once it is done loading.
## Migration Guide
Whenever possible use the typed API in order to directly get a handle to
your asset. If you do not know the type or need to use `load_untyped`
for a different reason, Bevy 0.12 introduces an additional layer of
indirection. The asset server will return a handle to a
`LoadedUntypedAsset`, which will load in the background. Once it is
loaded, the untyped handle to the asset file can be retrieved from the
`LoadedUntypedAsset`s field `handle`.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
Fixes#9395
Alternative to #9415 (See discussion here)
## Solution
Do clamping like
[`fit-content`](https://www.w3.org/TR/css-sizing-3/#column-sizing).
## Notes
I am not sure if this is a valid approach. It doesn't seem to cause any
obvious issues with our existing examples.
# Objective
- Hot reloading doesn't work the first time it is used
## Solution
- Currently, Bevy processor:
1. Create the `imported_assets` folder
2. Setup a watcher on it
3. Clear empty folders, so the `imported_assets` folder is deleted
4. Recreate the `imported_assets` folder and add all the imported assets
- On a first run without an existing `imported_assets` with some
content, hot reloading won't work as step 3 breaks the file watcher
- This PR stops the empty root folder from being deleted
- Also don't setup the processor internal asset server for file
watching, freeing up a thread
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
Fixes#9473
## Solution
Added `resolve()` method to AssetPath. This method accepts a relative
asset path string and returns a "full" path that has been resolved
relative to the current (self) path.
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
First of all, this PR took heavy inspiration from #7760 and #5715. It
intends to also fix#5569, but with a slightly different approach.
This also fixes#9335 by reexporting `DynEq`.
## Solution
The advantage of this API is that we can intern a value without
allocating for zero-sized-types and for enum variants that have no
fields. This PR does this automatically in the `SystemSet` and
`ScheduleLabel` derive macros for unit structs and fieldless enum
variants. So this should cover many internal and external use cases of
`SystemSet` and `ScheduleLabel`. In these optimal use cases, no memory
will be allocated.
- The interning returns a `Interned<dyn SystemSet>`, which is just a
wrapper around a `&'static dyn SystemSet`.
- `Hash` and `Eq` are implemented in terms of the pointer value of the
reference, similar to my first approach of anonymous system sets in
#7676.
- Therefore, `Interned<T>` does not implement `Borrow<T>`, only `Deref`.
- The debug output of `Interned<T>` is the same as the interned value.
Edit:
- `AppLabel` is now also interned and the old
`derive_label`/`define_label` macros were replaced with the new
interning implementation.
- Anonymous set ids are reused for different `Schedule`s, reducing the
amount of leaked memory.
### Pros
- `InternedSystemSet` and `InternedScheduleLabel` behave very similar to
the current `BoxedSystemSet` and `BoxedScheduleLabel`, but can be copied
without an allocation.
- Many use cases don't allocate at all.
- Very fast lookups and comparisons when using `InternedSystemSet` and
`InternedScheduleLabel`.
- The `intern` module might be usable in other areas.
- `Interned{ScheduleLabel, SystemSet, AppLabel}` does implement
`{ScheduleLabel, SystemSet, AppLabel}`, increasing ergonomics.
### Cons
- Implementors of `SystemSet` and `ScheduleLabel` still need to
implement `Hash` and `Eq` (and `Clone`) for it to work.
## Changelog
### Added
- Added `intern` module to `bevy_utils`.
- Added reexports of `DynEq` to `bevy_ecs` and `bevy_app`.
### Changed
- Replaced `BoxedSystemSet` and `BoxedScheduleLabel` with
`InternedSystemSet` and `InternedScheduleLabel`.
- Replaced `impl AsRef<dyn ScheduleLabel>` with `impl ScheduleLabel`.
- Replaced `AppLabelId` with `InternedAppLabel`.
- Changed `AppLabel` to use `Debug` for error messages.
- Changed `AppLabel` to use interning.
- Changed `define_label`/`derive_label` to use interning.
- Replaced `define_boxed_label`/`derive_boxed_label` with
`define_label`/`derive_label`.
- Changed anonymous set ids to be only unique inside a schedule, not
globally.
- Made interned label types implement their label trait.
### Removed
- Removed `define_boxed_label` and `derive_boxed_label`.
## Migration guide
- Replace `BoxedScheduleLabel` and `Box<dyn ScheduleLabel>` with
`InternedScheduleLabel` or `Interned<dyn ScheduleLabel>`.
- Replace `BoxedSystemSet` and `Box<dyn SystemSet>` with
`InternedSystemSet` or `Interned<dyn SystemSet>`.
- Replace `AppLabelId` with `InternedAppLabel` or `Interned<dyn
AppLabel>`.
- Types manually implementing `ScheduleLabel`, `AppLabel` or `SystemSet`
need to implement:
- `dyn_hash` directly instead of implementing `DynHash`
- `as_dyn_eq`
- Pass labels to `World::try_schedule_scope`, `World::schedule_scope`,
`World::try_run_schedule`. `World::run_schedule`, `Schedules::remove`,
`Schedules::remove_entry`, `Schedules::contains`, `Schedules::get` and
`Schedules::get_mut` by value instead of by reference.
---------
Co-authored-by: Joseph <21144246+JoJoJet@users.noreply.github.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
- Reduce noise to allow users to see previous asset changes and other
logs like from asset reloading
- The example file is named differently than the example
## Solution
- Only print the asset content if there are asset events
- Rename the example file to `asset_processing`
# Objective
When a mesh vertex attribute has a vertex count mismatch, a warning
message is printed with the index of the attribute which did not match.
Change to name the attribute, or fall back to the old behaviour if it
was not a known attribute.
Before:
```
MeshVertexAttributeId(2) has a different vertex count (32) than other attributes (64) in this mesh, all attributes will be truncated to match the smallest.
```
After:
```
Vertex_Uv has a different vertex count (32) than other attributes (64) in this mesh, all attributes will be truncated to match the smallest.
```
## Solution
Name the mesh attribute which had a count mismatch.
## Changelog
- If a mesh vertex attribute has a different count than other vertex
attributes, name the offending attribute using a human readable name
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Co-authored-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
# Objective
- the style of import used by bevy guarantees merge conflicts when any
file change
- This is especially true when import lists are large, such as in
`bevy_pbr`
- Merge conflicts are tricky to resolve. This bogs down rendering PRs
and makes contributing to bevy's rendering system more difficult than it
needs to
## Solution
- Use wildcard imports to replace multiline import list in `bevy_pbr`
I suspect this is controversial, but I'd like to hear alternatives.
Because this is one of many papercuts that makes developing render
features near impossible.
Closes#9946
# Objective
Add a new type mirroring `wgpu::SamplerDescriptor` for
`ImageLoaderSettings` to control how a loaded image should be sampled.
Fix issues with texture sampler descriptors not being set when loading
gltf texture from URI.
## Solution
Add a new `ImageSamplerDescriptor` and its affiliated types that mirrors
`wgpu::SamplerDescriptor`, use it in the image loader settings.
---
## Changelog
### Added
- Added new types `ImageSamplerDescriptor`, `ImageAddressMode`,
`ImageFilterMode`, `ImageCompareFunction` and `ImageSamplerBorderColor`
that mirrors the corresponding wgpu types.
- `ImageLoaderSettings` now carries an `ImageSamplerDescriptor` field
that will be used to determine how the loaded image is sampled, and will
be serialized as part of the image assets `.meta` files.
### Changed
- `Image::from_buffer` now takes the sampler descriptor to use as an
additional parameter.
### Fixed
- Sampler descriptors are set for gltf textures loaded from URI.
# Objective
- Fixes#10250
```
[Log] ERROR crates/bevy_render/src/render_resource/pipeline_cache.rs:823 failed to process shader: (wasm_example.js, line 376)
error: no definition in scope for identifier: 'bevy_pbr::pbr_deferred_functions::unpack_unorm3x4_plus_unorm_20_'
┌─ crates/bevy_pbr/src/deferred/deferred_lighting.wgsl:44:20
│
44 │ frag_coord.z = bevy_pbr::pbr_deferred_functions::unpack_unorm3x4_plus_unorm_20_(deferred_data.b).w;
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown identifier
│
= no definition in scope for identifier: 'bevy_pbr::pbr_deferred_functions::unpack_unorm3x4_plus_unorm_20_'
```
## Solution
- Fix the import path
The "gray" issue is since #9258 on macOS
... at least they're not white anymore
<img width="1294" alt="Screenshot 2023-10-25 at 00 14 11"
src="https://github.com/bevyengine/bevy/assets/8672791/df1a1138-c26c-4417-9b49-a00fbb8561d7">
Updates the requirements on
[async-io](https://github.com/smol-rs/async-io) to permit the latest
version.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/smol-rs/async-io/releases">async-io's
releases</a>.</em></p>
<blockquote>
<h2>v2.0.0</h2>
<ul>
<li><strong>Breaking:</strong> <code>Async::new()</code> now takes types
that implement <code>AsFd</code>/<code>AsSocket</code> instead of
<code>AsRawFd</code>/<code>AsRawSocket</code>, in order to implement I/O
safety. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/142">#142</a>)</li>
<li><strong>Breaking:</strong> <code>Async::get_mut()</code>,
<code>Async::read_with_mut()</code> and
<code>Async::write_with_mut()</code> are now <code>unsafe</code>. The
underlying source is technically "borrowed" by the polling
instance, so moving it out would be unsound. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/142">#142</a>)</li>
<li>Expose miscellaneous <code>kqueue</code> filters in the
<code>os::kqueue</code> module. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/112">#112</a>)</li>
<li>Expose a way to get the underlying <code>Poller</code>'s file
descriptor on Unix. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/125">#125</a>)</li>
<li>Add a new <code>Async::new_nonblocking</code> method to allow users
to avoid duplicating an already nonblocking socket. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/159">#159</a>)</li>
<li>Remove the unused <code>fastrand</code> and <code>memchr</code>
dependencies. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/131">#131</a>)</li>
<li>Use <code>tracing</code> instead of <code>log</code>. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/140">#140</a>)</li>
<li>Support ESP-IDF. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/144">#144</a>)</li>
<li>Optimize the <code>block_on</code> function to reduce allocation,
leading to a slight performance improvement. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/149">#149</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/smol-rs/async-io/blob/master/CHANGELOG.md">async-io's
changelog</a>.</em></p>
<blockquote>
<h1>Version 2.0.0</h1>
<ul>
<li><strong>Breaking:</strong> <code>Async::new()</code> now takes types
that implement <code>AsFd</code>/<code>AsSocket</code> instead of
<code>AsRawFd</code>/<code>AsRawSocket</code>, in order to implement I/O
safety. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/142">#142</a>)</li>
<li><strong>Breaking:</strong> <code>Async::get_mut()</code>,
<code>Async::read_with_mut()</code> and
<code>Async::write_with_mut()</code> are now <code>unsafe</code>. The
underlying source is technically "borrowed" by the polling
instance, so moving it out would be unsound. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/142">#142</a>)</li>
<li>Expose miscellaneous <code>kqueue</code> filters in the
<code>os::kqueue</code> module. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/112">#112</a>)</li>
<li>Expose a way to get the underlying <code>Poller</code>'s file
descriptor on Unix. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/125">#125</a>)</li>
<li>Add a new <code>Async::new_nonblocking</code> method to allow users
to avoid duplicating an already nonblocking socket. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/159">#159</a>)</li>
<li>Remove the unused <code>fastrand</code> and <code>memchr</code>
dependencies. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/131">#131</a>)</li>
<li>Use <code>tracing</code> instead of <code>log</code>. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/140">#140</a>)</li>
<li>Support ESP-IDF. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/144">#144</a>)</li>
<li>Optimize the <code>block_on</code> function to reduce allocation,
leading to a slight performance improvement. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/149">#149</a>)</li>
</ul>
<h1>Version 1.13.0</h1>
<ul>
<li>Use <a
href="https://crates.io/crates/rustix/"><code>rustix</code></a> instead
of <a href="https://crates.io/crates/libc/"><code>libc</code></a>/<a
href="https://crates.io/crates/windows-sys/"><code>windows-sys</code></a>
for system calls (<a
href="https://redirect.github.com/smol-rs/async-io/issues/76">#76</a>)</li>
<li>Add a <code>will_fire</code> method to <code>Timer</code> to test if
it will ever fire (<a
href="https://redirect.github.com/smol-rs/async-io/issues/106">#106</a>)</li>
<li>Reduce syscalls in <code>Async::new</code> (<a
href="https://redirect.github.com/smol-rs/async-io/issues/107">#107</a>)</li>
<li>Improve the drop ergonomics of <code>Readable</code> and
<code>Writable</code> (<a
href="https://redirect.github.com/smol-rs/async-io/issues/109">#109</a>)</li>
<li>Change the "<code>wepoll</code>" in documentation to
"<code>IOCP</code>" (<a
href="https://redirect.github.com/smol-rs/async-io/issues/116">#116</a>)</li>
</ul>
<h1>Version 1.12.0</h1>
<ul>
<li>Switch from <code>winapi</code> to <code>windows-sys</code> (<a
href="https://redirect.github.com/smol-rs/async-io/issues/102">#102</a>)</li>
</ul>
<h1>Version 1.11.0</h1>
<ul>
<li>Update <code>concurrent-queue</code> to v2. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/99">#99</a>)</li>
</ul>
<h1>Version 1.10.0</h1>
<ul>
<li>Remove the dependency on the <code>once_cell</code> crate to restore
the MSRV. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/95">#95</a>)</li>
</ul>
<h1>Version 1.9.0</h1>
<ul>
<li>Fix panic on very large durations. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/87">#87</a>)</li>
<li>Add <code>Timer::never</code> (<a
href="https://redirect.github.com/smol-rs/async-io/issues/87">#87</a>)</li>
</ul>
<h1>Version 1.8.0</h1>
<ul>
<li>Implement I/O safety traits on Rust 1.63+ (<a
href="https://redirect.github.com/smol-rs/async-io/issues/84">#84</a>)</li>
</ul>
<h1>Version 1.7.0</h1>
<ul>
<li>Process timers set for exactly <code>now</code>. (<a
href="https://redirect.github.com/smol-rs/async-io/issues/73">#73</a>)</li>
</ul>
<h1>Version 1.6.0</h1>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="7e89eec4d1"><code>7e89eec</code></a>
v2.0.0</li>
<li><a
href="356431754c"><code>3564317</code></a>
tests: Add test for <a
href="https://redirect.github.com/smol-rs/async-io/issues/154">#154</a></li>
<li><a
href="a5da16f072"><code>a5da16f</code></a>
Expose Async::new_nonblocking</li>
<li><a
href="0f2af634d8"><code>0f2af63</code></a>
Avoid needless set_nonblocking calls</li>
<li><a
href="62e3454f38"><code>62e3454</code></a>
Migrate to Rust 2021 (<a
href="https://redirect.github.com/smol-rs/async-io/issues/160">#160</a>)</li>
<li><a
href="59ee2ea27c"><code>59ee2ea</code></a>
Use set_nonblocking in Async::new on Windows (<a
href="https://redirect.github.com/smol-rs/async-io/issues/157">#157</a>)</li>
<li><a
href="d5bc619021"><code>d5bc619</code></a>
Remove needless as_fd/as_socket calls (<a
href="https://redirect.github.com/smol-rs/async-io/issues/158">#158</a>)</li>
<li><a
href="0b5016e567"><code>0b5016e</code></a>
m: Replace socket2 calls with rustix</li>
<li><a
href="8c3c3bd80b"><code>8c3c3bd</code></a>
m: Optimize block_on by caching Parker and Waker</li>
<li><a
href="1b1466a6c1"><code>1b1466a</code></a>
Update this crate to use the new polling breaking changes (<a
href="https://redirect.github.com/smol-rs/async-io/issues/142">#142</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/smol-rs/async-io/compare/v1.13.0...v2.0.0">compare
view</a></li>
</ul>
</details>
<br />
Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
</details>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
# Objective
A follow-up PR for https://github.com/bevyengine/bevy/pull/10221
## Changelog
Replaced usages of texture_descriptor.size with the helper methods of
`Image` through the entire engine codebase
# Objective
Reduce code duplication and improve APIs of Bevy's [global
taskpools](https://github.com/bevyengine/bevy/blob/main/crates/bevy_tasks/src/usages.rs).
## Solution
- As all three of the global taskpools have identical implementations
and only differ in their identifiers, this PR moves the implementation
into a macro to reduce code duplication.
- The `init` method is renamed to `get_or_init` to more accurately
reflect what it really does.
- Add a new `try_get` method that just returns `None` when the pool is
uninitialized, to complement the other getter methods.
- Minor documentation improvements to accompany the above changes.
---
## Changelog
- Added a new `try_get` method to the global TaskPools
- The global TaskPools' `init` method has been renamed to `get_or_init`
for clarity
- Documentation improvements
## Migration Guide
- Uses of `ComputeTaskPool::init`, `AsyncComputeTaskPool::init` and
`IoTaskPool::init` should be changed to `::get_or_init`.
# Objective
- Handle pausing audio when Android app is suspended
## Solution
- This is the start of application lifetime events. They are mostly
useful on mobile
- Next version of winit should add a few more
- When application is suspended, send an event to notify the
application, and run the schedule one last time before actually
suspending the app
- Audio is now suspended too 🎉https://github.com/bevyengine/bevy/assets/8672791/d74e2e09-ee29-4f40-adf2-36a0c064f94e
---------
Co-authored-by: Marco Buono <418473+coreh@users.noreply.github.com>
# Objective
Fog color was passed to shaders without conversion from sRGB to linear
color space. Because shaders expect colors in linear space this resulted
in wrong color being used. This is most noticeable in open scenes with
dark fog color and clear color set to the same color. In such case
background/clear color (which is properly processed) is going to be
darker than very far objects.
Example:
![image](https://github.com/bevyengine/bevy/assets/160391/89b70d97-b2d0-4bc5-80f4-c9e8b8801c4c)
[bevy-fog-color-bug.zip](https://github.com/bevyengine/bevy/files/13063718/bevy-fog-color-bug.zip)
## Solution
Add missing conversion of fog color to linear color space.
---
## Changelog
* Fixed conversion of fog color
## Migration Guide
- Colors in `FogSettings` struct (`color` and `directional_light_color`)
are now sent to the GPU in linear space. If you were using
`Color::rgb()`/`Color::rgba()` and would like to retain the previous
colors, you can quickly fix it by switching to
`Color::rgb_linear()`/`Color::rgba_linear()`.
# Objective
- After #9826, there are issues on "run once runners"
- example `without_winit` crashes:
```
2023-10-19T22:06:01.810019Z INFO bevy_render::renderer: AdapterInfo { name: "llvmpipe (LLVM 15.0.7, 256 bits)", vendor: 65541, device: 0, device_type: Cpu, driver: "llvmpipe", driver_info: "Mesa 23.2.1 - kisak-mesa PPA (LLVM 15.0.7)", backend: Vulkan }
2023-10-19T22:06:02.860331Z WARN bevy_audio::audio_output: No audio device found.
2023-10-19T22:06:03.215154Z INFO bevy_diagnostic::system_information_diagnostics_plugin::internal: SystemInfo { os: "Linux 22.04 Ubuntu", kernel: "6.2.0-1014-azure", cpu: "Intel(R) Xeon(R) CPU E5-2673 v3 @ 2.40GHz", core_count: "2", memory: "6.8 GiB" }
thread 'main' panicked at crates/bevy_render/src/pipelined_rendering.rs:91:14:
Unable to get RenderApp. Another plugin may have removed the RenderApp before PipelinedRenderingPlugin
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
- example `headless` runs the app twice with the `run_once` schedule
## Solution
- Expose a more complex state of an app than just "ready"
- Also block adding plugins to an app after it has finished or cleaned
up its plugins as that wouldn't work anyway
## Migration Guide
* `app.ready()` has been replaced by `app.plugins_state()` which will
return more details on the current state of plugins in the app
# Objective
- Replace md5 by another hasher, as suggested in
https://github.com/bevyengine/bevy/pull/8624#discussion_r1359291028
- md5 is not secure, and is slow. use something more secure and faster
## Solution
- Replace md5 by blake3
Putting this PR in the 0.12 as once it's released, changing the hash
algorithm will be a painful breaking change
# Objective
Even at `reflectance == 0.0`, our ambient and environment map light
implementations still produce fresnel/specular highlights.
Such a low `reflectance` value lies outside of the physically possible
range and is already used by our directional, point and spot light
implementations (via the `fresnel()` function) to enable artistic
control, effectively disabling the fresnel "look" for non-physically
realistic materials. Since ambient and environment lights use a
different formulation, they were not honoring this same principle.
This PR aims to bring consistency to all light types, offering the same
fresnel extinguishing control to ambient and environment lights.
Thanks to `@nathanf` for [pointing
out](https://discord.com/channels/691052431525675048/743663924229963868/1164083373514440744)
the [Filament docs section about
this](https://google.github.io/filament/Filament.md.html#lighting/occlusion/specularocclusion).
## Solution
- We use [the same
formulation](ffc572728f/crates/bevy_pbr/src/render/pbr_lighting.wgsl (L99))
already used by the `fresnel()` function in `bevy_pbr::lighting` to
modulate the F90, to modulate the specular component of Ambient and
Environment Map lights.
## Comparison
⚠️ **Modified version of the PBR example for demo purposes, that shows
reflectance (_NOT_ part of this PR)** ⚠️
Also, keep in mind this is a very subtle difference (look for the
fresnel highlights on the lower left spheres, you might need to zoom in.
### Before
<img width="1392" alt="Screenshot 2023-10-18 at 23 02 25"
src="https://github.com/bevyengine/bevy/assets/418473/ec0efb58-9a98-4377-87bc-726a1b0a3ff3">
### After
<img width="1392" alt="Screenshot 2023-10-18 at 23 01 43"
src="https://github.com/bevyengine/bevy/assets/418473/a2809325-5728-405e-af02-9b5779767843">
---
## Changelog
- Ambient and Environment Map lights will now honor values of
`reflectance` that are below the physically possible range (⪅ 0.35) by
extinguishing their fresnel highlights. (Just like point, directional
and spot lights already did.) This allows for more consistent artistic
control and for non-physically realistic looks with all light types.
## Migration Guide
- If Fresnel highlights from Ambient and Environment Map lights are no
longer visible in your materials, make sure you're using a higher,
physically plausible value of `reflectance` (⪆ 0.35).
# Objective
- I want to use the `debug_glam_assert` feature with bevy.
## Solution
- Re-export the feature flag
---
## Changelog
- Re-export `debug_glam_assert` feature flag from glam.
# Objective
Fixes#5101
Alternative to #6511
## Solution
Corrected the behavior for ignored fields in `FromReflect`, which was
previously using the incorrect field indexes.
Similarly, fields marked with `#[reflect(skip_serializing)]` no longer
break when using `FromReflect` after deserialization. This was done by
modifying `SerializationData` to store a function pointer that can later
be used to generate a default instance of the skipped field during
deserialization.
The function pointer points to a function generated by the derive macro
using the behavior designated by `#[reflect(default)]` (or just
`Default` if none provided). The entire output of the macro is now
wrapped in an [unnamed
constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant)
which keeps this behavior hygienic.
#### Rationale
The biggest downside to this approach is that it requires fields marked
`#[reflect(skip_serializing)]` to provide the ability to create a
default instance— either via a `Default` impl or by specifying a custom
one. While this isn't great, I think it might be justified by the fact
that we really need to create this value when using `FromReflect` on a
deserialized object. And we need to do this _during_ deserialization
because after that (at least for tuples and tuple structs) we lose
information about which field is which: _"is the value at index 1 in
this `DynamicTupleStruct` the actual value for index 1 or is it really
the value for index 2 since index 1 is skippable...?"_
#### Alternatives
An alternative would be to store `Option<Box<dyn Reflect>>` within
`DynamicTuple` and `DynamicTupleStruct` instead of just `Box<dyn
Reflect>`. This would allow us to insert "empty"/"missing" fields during
deserialization, thus saving the positional information of the skipped
fields. However, this may require changing the API of `Tuple` and
`TupleStruct` such that they can account for their dynamic counterparts
returning `None` for a skipped field. In practice this would probably
mean exposing the `Option`-ness of the dynamics onto implementors via
methods like `Tuple::drain` or `TupleStruct::field`.
Personally, I think requiring `Default` would be better than muddying up
the API to account for these special cases. But I'm open to trying out
this other approach if the community feels that it's better.
---
## Changelog
### Public Changes
#### Fixed
- The behaviors of `#[reflect(ignore)]` and
`#[reflect(skip_serializing)]` are no longer dependent on field order
#### Changed
- Fields marked with `#[reflect(skip_serializing)]` now need to either
implement `Default` or specify a custom default function using
`#[reflect(default = "path::to::some_func")]`
- Deserializing a type with fields marked `#[reflect(skip_serializing)]`
will now include that field initialized to its specified default value
- `SerializationData::new` now takes the new `SkippedField` struct along
with the skipped field index
- Renamed `SerializationData::is_ignored_field` to
`SerializationData::is_field_skipped`
#### Added
- Added `SkippedField` struct
- Added methods `SerializationData::generate_default` and
`SerializationData::iter_skipped`
### Internal Changes
#### Changed
- Replaced `members_to_serialization_denylist` and `BitSet<u32>` with
`SerializationDataDef`
- The `Reflect` derive is more hygienic as it now outputs within an
[unnamed
constant](https://doc.rust-lang.org/stable/reference/items/constant-items.html#unnamed-constant)
- `StructField::index` has been split up into
`StructField::declaration_index` and `StructField::reflection_index`
#### Removed
- Removed `bitset` dependency
## Migration Guide
* Fields marked `#[reflect(skip_serializing)]` now must implement
`Default` or specify a custom default function with `#[reflect(default =
"path::to::some_func")]`
```rust
#[derive(Reflect)]
struct MyStruct {
#[reflect(skip_serializing)]
#[reflect(default = "get_foo_default")]
foo: Foo, // <- `Foo` does not impl `Default` so requires a custom
function
#[reflect(skip_serializing)]
bar: Bar, // <- `Bar` impls `Default`
}
#[derive(Reflect)]
struct Foo(i32);
#[derive(Reflect, Default)]
struct Bar(i32);
fn get_foo_default() -> Foo {
Foo(123)
}
```
* `SerializationData::new` has been changed to expect an iterator of
`(usize, SkippedField)` rather than one of just `usize`
```rust
// BEFORE
SerializationData::new([0, 3].into_iter());
// AFTER
SerializationData::new([
(0, SkippedField::new(field_0_default_fn)),
(3, SkippedField::new(field_3_default_fn)),
].into_iter());
```
* `Serialization::is_ignored_field` has been renamed to
`Serialization::is_field_skipped`
* Fields marked `#[reflect(skip_serializing)]` are now included in
deserialization output. This may affect logic that expected those fields
to be absent.
# Objective
To get the width or height of an image you do:
```rust
self.texture_descriptor.size.{width, height}
```
that is quite verbose.
This PR adds some convenient methods for Image to reduce verbosity.
## Changelog
* Add a `width()` method for getting the width of an image.
* Add a `height()` method for getting the height of an image.
* Rename the `size()` method to `size_f32()`.
* Add a `size()` method for getting the size of an image as u32.
* Renamed the `aspect_2d()` method to `aspect_ratio()`.
## Migration Guide
Replace calls to the `Image::size()` method with `size_f32()`.
Replace calls to the `Image::aspect_2d()` method with `aspect_ratio()`.
# Objective
- Fix#10165
- On iOS simulator on apple silicon Macs, shader validation is going
through the host, but device limits are reported for the device. They
sometimes differ, and cause the validation to crash on something that
should work
```
-[MTLDebugRenderCommandEncoder validateCommonDrawErrors:]:5775: failed assertion `Draw Errors Validation
Fragment Function(fragment_): the offset into the buffer _naga_oil_mod_MJSXM6K7OBRHEOR2NVSXG2C7OZUWK527MJUW4ZDJNZTXG_memberfog that is bound at buffer index 6 must be a multiple of 256 but was set to 448.
```
## Solution
- Add a custom flag when building for the simulator and override the
buffer alignment
# Objective
- Closes#10049.
- Detect DDS texture containing a cubemap or a cubemap array.
## Solution
- When loading a dds texture, the header capabilities are checked for
the cubemap flag. An error is returned if not all faces are provided.
---
## Changelog
### Added
- Added a new texture error `TextureError::IncompleteCubemap`, used for
dds cubemap textures containing less than 6 faces, as that is not
supported on modern graphics APIs.
### Fixed
- DDS cubemaps are now loaded as cubemaps instead of 2D textures.
## Migration Guide
If you are matching on a `TextureError`, you will need to add a new
branch to handle `TextureError::IncompleteCubemap`.
# Objective
While reviewing #10187 I noticed some other mistakes in the UI node
docs.
## Solution
I did a quick proofreading pass and fixed a few things. And of course,
the typo from that other PR.
## Notes
I occasionally insert a period to make a section of doc self-consistent
but didn't go one way or the other on all periods in the file.
---------
Co-authored-by: Noah <noahshomette@gmail.com>
# Objective
Simplify bind group creation code. alternative to (and based on) #9476
## Solution
- Add a `BindGroupEntries` struct that can transparently be used where
`&[BindGroupEntry<'b>]` is required in BindGroupDescriptors.
Allows constructing the descriptor's entries as:
```rust
render_device.create_bind_group(
"my_bind_group",
&my_layout,
&BindGroupEntries::with_indexes((
(2, &my_sampler),
(3, my_uniform),
)),
);
```
instead of
```rust
render_device.create_bind_group(
"my_bind_group",
&my_layout,
&[
BindGroupEntry {
binding: 2,
resource: BindingResource::Sampler(&my_sampler),
},
BindGroupEntry {
binding: 3,
resource: my_uniform,
},
],
);
```
or
```rust
render_device.create_bind_group(
"my_bind_group",
&my_layout,
&BindGroupEntries::sequential((&my_sampler, my_uniform)),
);
```
instead of
```rust
render_device.create_bind_group(
"my_bind_group",
&my_layout,
&[
BindGroupEntry {
binding: 0,
resource: BindingResource::Sampler(&my_sampler),
},
BindGroupEntry {
binding: 1,
resource: my_uniform,
},
],
);
```
the structs has no user facing macros, is tuple-type-based so stack
allocated, and has no noticeable impact on compile time.
- Also adds a `DynamicBindGroupEntries` struct with a similar api that
uses a `Vec` under the hood and allows extending the entries.
- Modifies `RenderDevice::create_bind_group` to take separate arguments
`label`, `layout` and `entries` instead of a `BindGroupDescriptor`
struct. The struct can't be stored due to the internal references, and
with only 3 members arguably does not add enough context to justify
itself.
- Modify the codebase to use the new api and the `BindGroupEntries` /
`DynamicBindGroupEntries` structs where appropriate (whenever the
entries slice contains more than 1 member).
## Migration Guide
- Calls to `RenderDevice::create_bind_group({BindGroupDescriptor {
label, layout, entries })` must be amended to
`RenderDevice::create_bind_group(label, layout, entries)`.
- If `label`s have been specified as `"bind_group_name".into()`, they
need to change to just `"bind_group_name"`. `Some("bind_group_name")`
and `None` will still work, but `Some("bind_group_name")` can optionally
be simplified to just `"bind_group_name"`.
---------
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
# Objective
- bump naga_oil to 0.10
- update shader imports to use rusty syntax
## Migration Guide
naga_oil 0.10 reworks the import mechanism to support more syntax to
make it more rusty, and test for item use before importing to determine
which imports are modules and which are items, which allows:
- use rust-style imports
```
#import bevy_pbr::{
pbr_functions::{alpha_discard as discard, apply_pbr_lighting},
mesh_bindings,
}
```
- import partial paths:
```
#import part::of::path
...
path::remainder::function();
```
which will call to `part::of::path::remainder::function`
- use fully qualified paths without importing:
```
// #import bevy_pbr::pbr_functions
bevy_pbr::pbr_functions::pbr()
```
- use imported items without qualifying
```
#import bevy_pbr::pbr_functions::pbr
// for backwards compatibility the old style is still supported:
// #import bevy_pbr::pbr_functions pbr
...
pbr()
```
- allows most imported items to end with `_` and numbers (naga_oil#30).
still doesn't allow struct members to end with `_` or numbers but it's
progress.
- the vast majority of existing shader code will work without changes,
but will emit "deprecated" warnings for old-style imports. these can be
suppressed with the `allow-deprecated` feature.
- partly breaks overrides (as far as i'm aware nobody uses these yet) -
now overrides will only be applied if the overriding module is added as
an additional import in the arguments to `Composer::make_naga_module` or
`Composer::add_composable_module`. this is necessary to support
determining whether imports are modules or items.
# Objective
This PR aims to make it so that we don't accidentally go over
`MAX_TEXTURE_IMAGE_UNITS` (in WebGL) or
`maxSampledTexturesPerShaderStage` (in WebGPU), giving us some extra
leeway to add more view bind group textures.
(This PR is extracted from—and unblocks—#8015)
## Solution
- We replace the existing `view_layout` and `view_layout_multisampled`
pair with an array of 32 bind group layouts, generated ahead of time;
- For now, these layouts cover all the possible combinations of:
`multisampled`, `depth_prepass`, `normal_prepass`,
`motion_vector_prepass` and `deferred_prepass`:
- In the future, as @JMS55 pointed out, we can likely take out
`motion_vector_prepass` and `deferred_prepass`, as these are not really
needed for the mesh pipeline and can use separate pipelines. This would
bring the possible combinations down to 8;
- We can also add more "optional" textures as they become needed,
allowing the engine to scale to a wider variety of use cases in lower
end/web environments (e.g. some apps might just want normal and depth
prepasses, others might only want light probes), while still keeping a
high ceiling for high end native environments where more textures are
supported.
- While preallocating bind group layouts is relatively cheap, the number
of combinations grows exponentially, so we should likely limit ourselves
to something like at most 256–1024 total layouts until we find a better
solution (like generating them lazily)
- To make this mechanism a little bit more explicit/discoverable, so
that compatibility with WebGPU/WebGL is not broken by accident, we add a
`MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES` const and warn whenever
the number of textures in the layout crosses it.
- The warning is gated by `#[cfg(debug_assertions)]` and not issued in
release builds;
- We're counting the actual textures in the bind group layout instead of
using some roundabout metric so it should be accurate;
- Right now `MESH_PIPELINE_VIEW_LAYOUT_SAFE_MAX_TEXTURES` is set to 10
in order to leave 6 textures free for other groups;
- Currently there's no combination that would cause us to go over the
limit, but that will change once #8015 lands.
---
## Changelog
- `MeshPipeline` view bind group layouts now vary based on the current
multisampling and prepass states, saving a couple of texture binding
entries when prepasses are not in use.
## Migration Guide
- `MeshPipeline::view_layout` and
`MeshPipeline::view_layout_multisampled` have been replaced with a
private array to accomodate for variable view bind group layouts. To
obtain a view bind group layout for the current pipeline state, use the
new `MeshPipeline::get_view_layout()` or
`MeshPipeline::get_view_layout_from_key()` methods.
# Objective
Users shouldn't need to change their source code between "development
workflows" and "releasing". Currently, Bevy Asset V2 has two "processed"
asset modes `Processed` (assumes assets are already processed) and
`ProcessedDev` (starts an asset processor and processes assets). This
means that the mode must be changed _in code_ when switching from "app
dev" to "release". Very suboptimal.
We have already removed "runtime opt-in" for hot-reloading. Enabling the
`file_watcher` feature _automatically_ enables file watching in code.
This means deploying a game (without hot reloading enabled) just means
calling `cargo build --release` instead of `cargo run --features
bevy/file_watcher`.
We should adopt this pattern for asset processing.
## Solution
This adds the `asset_processor` feature, which will start the
`AssetProcessor` when an `AssetPlugin` runs in `AssetMode::Processed`.
The "asset processing workflow" is now:
1. Enable `AssetMode::Processed` on `AssetPlugin`
2. When developing, run with the `asset_processor` and `file_watcher`
features
3. When releasing, build without these features.
The `AssetMode::ProcessedDev` mode has been removed.
# Objective
I encountered a problem where I had a plugin `FooPlugin` which did
```rust
impl Plugin for FooPlugin {
fn build(&self, app: &mut App) {
app
.register_asset_source(...); // more stuff after
}
}
```
And when I tried using it, e.g.
```rust
asset_server.load("foo://data/asset.custom");
```
I got an error that `foo` was not recognized as a source.
I found that this is because asset sources must be registered _before_
`AssetPlugin` is added, and I had `FooPlugin` _after_.
## Solution
Add clarifying note about having to register sources before
`AssetPlugin` is added.
Signed-off-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
Co-authored-by: Torstein Grindvik <torstein.grindvik@muybridge.com>
# Objective
- Provides actionable feedback when users encounter the error in
https://github.com/bevyengine/bevy/issues/10162
- Complements https://github.com/bevyengine/bevy/pull/10186
## Solution
- Log an error when registering an AssetSource after the AssetPlugin has
been built (via DefaultPlugins). This will let users know that their
registration order needs changing
The outputted error message will look like this:
```rust
ERROR bevy_asset::server: 'AssetSourceId::Name(test)' must be registered before `AssetPlugin` (typically added as part of `DefaultPlugins`)
```
---------
Co-authored-by: 66OJ66 <hi0obxud@anonaddy.me>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes#10177 .
## Solution
Added a new run condition and tweaked the docs for `on_timer`.
## Changelog
### Added
- `on_real_time_timer` run condition
# Objective
- Make it possible to move the light position around in the
`shadow_biases` example
- Also support resetting the depth/normal biases to the engine defaults,
or zero.
## Solution
- The light position is displayed in the text overlay.
- The light position can be adjusted with
left/right/up/down/pgup/pgdown.
- The depth/normal biases can be reset to defaults by pressing R, or to
zero by pressing Z.
---------
Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
# Objective
- Demonstrate the different shadow PCF methods in the `shadow_biases`
example
## Solution
- Cycle through the available methods when pressing the `F` key
- Display which filter method is being used
# Objective
This PR addresses the issue where Bevy displays one or several black
frames before the scene is first rendered. This is particularly
noticeable on iOS, where the black frames disrupt the transition from
the launch screen to the game UI. I have written about my search to
solve this issue on the Bevy discord:
https://discord.com/channels/691052431525675048/1151047604520632352
While I can attest this PR works on both iOS and Linux/Wayland (and even
seems to resolve a slight flicker during startup with the latter as
well), I'm not familiar enough with Bevy to judge the full implications
of these changes. I hope a reviewer or tester can help me confirm
whether this is the right approach, or what might be a cleaner solution
to resolve this issue.
## Solution
I have moved the "startup phase" as well as the plugin finalization into
the `app.run()` function so those things finish synchronously before the
"main schedule" starts. I even move one frame forward as well, using
`app.update()`, to make sure the rendering has caught up with the state
of the finalized plugins as well.
I admit that part of this was achieved through trial-and-error, since
not doing the "startup phase" *before* `app.finish()` resulted in
panics, while not calling an extra `app.update()` didn't fully resolve
the issue.
What I *can* say, is that the iOS launch screen animation works in such
a way that the OS initiates the transition once the framework's
[`didFinishLaunching()`](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1622921-application)
returns, meaning app developers **must** finish setting up their UI
before that function returns. This is what basically led me on the path
to try to "finish stuff earlier" :)
## Changelog
### Changed
- The startup phase and the first frame are rendered synchronously when
calling `app.run()`, before the "main schedule" is started. This fixes
black frames during the iOS launch transition and possible flickering on
other platforms, but may affect initialization order in your
application.
## Migration Guide
Because of this change, the timing of the first few frames might have
changed, and I think it could be that some things one may expect to be
initialized in a system may no longer be. To be honest, I feel out of my
depth to judge the exact impact here.
# Objective
Add a way to easily compute the up-to-date `GlobalTransform` of an
entity.
## Solution
Add the `TransformHelper`(Name pending) system parameter with the
`compute_global_transform` method that takes an `Entity` and returns a
`GlobalTransform` if successful.
## Changelog
- Added the `TransformHelper` system parameter for computing the
up-to-date `GlobalTransform` of an entity.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Noah <noahshomette@gmail.com>
# Objective
- Fixes#9382
## Solution
- Added a few extra notes in regards to WebGPU experimental state and
the need of enabling unstable APIs through certain attribute flags in
`cargo_features.md` and the examples `README.md` files.
# Objective
- Add a header for contributing to make it easier for people new to
github for getting started.
- Adding links that point to issues and PRs
## Solution
- Updated the README.md to show a contributing section under the
Community header
- Added links in the section to point to issued and PRs