Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement percentage-closer soft shadows (PCSS). #13497

Merged
merged 17 commits into from
Sep 18, 2024

Conversation

pcwalton
Copy link
Contributor

@pcwalton pcwalton commented May 24, 2024

Percentage-closer soft shadows are a technique from 2004 that allow shadows to become blurrier farther from the objects that cast them. It works by introducing a blocker search step that runs before the normal shadow map sampling. The blocker search step detects the difference between the depth of the fragment being rasterized and the depth of the nearby samples in the depth buffer. Larger depth differences result in a larger penumbra and therefore a blurrier shadow.

To enable PCSS, fill in the soft_shadow_size value in DirectionalLight, PointLight, or SpotLight, as appropriate. This shadow size value represents the size of the light and should be tuned as appropriate for your scene. Higher values result in a wider penumbra (i.e. blurrier shadows).

When using PCSS, temporal shadow maps (ShadowFilteringMethod::Temporal) are recommended. If you don't use ShadowFilteringMethod::Temporal and instead use ShadowFilteringMethod::Gaussian, Bevy will use the same technique as Temporal, but the result won't vary over time. This produces a rather noisy result. Doing better would likely require downsampling the shadow map, which would be complex and slower (and would require PR #13003 to land first).

In addition to PCSS, this commit makes the near Z plane for the shadow map configurable on a per-light basis. Previously, it had been hardcoded to 0.1 meters. This change was necessary to make the point light shadow map in the example look reasonable, as otherwise the shadows appeared far too aliased.

A new example, pcss, has been added. It demonstrates the percentage-closer soft shadow technique with directional lights, point lights, spot lights, non-temporal operation, and temporal operation. The assets are my original work.

Both temporal and non-temporal shadows are rather noisy in the example, and, as mentioned before, this is unavoidable without downsampling the depth buffer, which we can't do yet. Note also that the shadows don't look particularly great for point lights; the example simply isn't an ideal scene for them. Nevertheless, I felt that the benefits of the ability to do a side-by-side comparison of directional and point lights outweighed the unsightliness of the point light shadows in that example, so I kept the point light feature in.

Fixes #3631.

Changelog

Added

  • Percentage-closer soft shadows (PCSS) are now supported, allowing shadows to become blurrier as they stretch away from objects. To use them, set the soft_shadow_size field in DirectionalLight, PointLight, or SpotLight, as applicable.

  • The near Z value for shadow maps is now customizable via the shadow_map_near_z field in DirectionalLight, PointLight, and SpotLight.

Screenshots

PCSS off:
Screenshot 2024-05-24 120012

PCSS on:
Screenshot 2024-05-24 115959

@pcwalton pcwalton requested review from IceSentry and superdump May 24, 2024 19:08
@pcwalton pcwalton added A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels May 24, 2024
@pcwalton pcwalton added this to the 0.15 milestone May 24, 2024
@pcwalton pcwalton force-pushed the pcss branch 4 times, most recently from 5167130 to 0377266 Compare May 25, 2024 08:00
[*Percentage-closer soft shadows*] are a technique from 2004 that allow
shadows to become blurrier farther from the objects that cast them. It
works by introducing a *blocker search* step that runs before the normal
shadow map sampling. The blocker search step detects the difference
between the depth of the fragment being rasterized and the depth of the
nearby samples in the depth buffer. Larger depth differences result in a
larger penumbra and therefore a blurrier shadow.

To enable PCSS, fill in the `soft_shadow_size` value in
`DirectionalLight`, `PointLight`, or `SpotLight`, as appropriate. This
shadow size value represents the size of the light and should be tuned
as appropriate for your scene.  Higher values result in a wider penumbra
(i.e. blurrier shadows).

When using PCSS, temporal shadow maps
(`ShadowFilteringMethod::Temporal`) are recommended. If you don't use
`ShadowFilteringMethod::Temporal` and instead use
`ShadowFilteringMethod::Gaussian`, Bevy will use the same technique as
`Temporal`, but the result won't vary over time. This produces a rather
noisy result. Doing better would likely require downsampling the shadow
map, which would be complex and slower (and would require PR bevyengine#13003 to
land first).

In addition to PCSS, this commit makes the near Z plane for the shadow
map configurable on a per-light basis. Previously, it had been hardcoded
to 0.1 meters. This change was necessary to make the point light shadow
map in the example look reasonable, as otherwise the shadows appeared
far too aliased.

A new example, `pcss`, has been added. It demonstrates the
percentage-closer soft shadow technique with directional lights, point
lights, spot lights, non-temporal operation, and temporal operation. The
assets are my original work.

Both temporal and non-temporal shadows are rather noisy in the example,
and, as mentioned before, this is unavoidable without downsampling the
depth buffer, which we can't do yet. Note also that the shadows don't
look particularly great for point lights; the example simply isn't an
ideal scene for them. Nevertheless, I felt that the benefits of the
ability to do a side-by-side comparison of directional and point lights
outweighed the unsightliness of the point light shadows in that example,
so I kept the point light feature in.

Fixes bevyengine#3631.

[*Percentage-closer soft shadows*]:
https://developer.download.nvidia.com/shaderlibrary/docs/shadow_PCSS.pdf
@torsteingrindvik
Copy link
Contributor

I don't know the domain well- why do the shadows here:
image

Have curve-like imperfections?

I noticed the article you linked has this image which has a different type of noise:

image

Is it related to the geometry which casts the shadow or something else?

Also I was wondering how the shadows perform when the light source is moving.
I changed the example a bit to have the light undulate.

pcss-example-undulate.patch.txt

Feel free to git apply pcss-example-undulate.patch.txt if you want to try the same or add it to the PR.

pcss-undulate.mp4

I noticed an effect that spot lights have this effect where it looks like the shadow density changes a lot, perhaps related to shadow map resolution?

@pcwalton
Copy link
Contributor Author

pcwalton commented May 25, 2024

The patterns are because of the interleaved gradient noise. This is generally considered more desirable than the white noise that it looks like your other example has.

There isn't a whole lot we can do about the noise in this patch without generating mip chains for the shadow map, which would require #13003 (and even if that were in I wouldn't want to do it in the first patch because this patch is too big as it is). When I asked in Discord I was told that PCSS in games tends to be noisy; that's just the way it is.

I think PCSS is mostly used in directional lights in practice. The results for point lights in particular just aren't as good.

@pcwalton
Copy link
Contributor Author

I considered allowing the user to move the light but I realized that this will cause problems with the Z near value, which is carefully tuned so that the palm tree makes maximum use of the shadow map. So I'm less inclined to make the light movable, though I could be convinced otherwise.

@pcwalton
Copy link
Contributor Author

I suspect what's going wrong with spot lights is that the blocker search starts missing blockers. I'm not sure if this is something that can reasonably be fixed; it's always possible that the blocker search can miss things. The solution is for artists to tweak the soft_shadow_size manually.

Copy link
Contributor

@torsteingrindvik torsteingrindvik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found out that Godot has PCSS and they have an example showcasing it: https://github.com/godotengine/godot-demo-projects/tree/master/3d/lights_and_shadows

I put the GLTF files in this PR in that project and dropped the palm tree into Godot and tried experimenting with the PCSS lights in that example.
I couldn't try the spot light (likely due to godotengine/godot#80137) but I saw similar results when using their omni light (point light) and their sun (directional light).

I learned that it's very finicky to get decent looking shadows, and I had to resort to a mix of tuning their shadow blur and their shadow opacity (not sure if we have that in Bevy yet) and only specific combos of those along with light strength and positioning yielded OK results.

I'm convinced that PCSS is hard to get right (as a user) and that this PR adds value and if we can get better noise patterns further down the line that's really great.

EDIT: When we have a Bevy editor where we can interactively tune parameters like I could in Godot it will be a lot easier to spot problems so I'm not worried about any minor issues right now.

Approving on the basis of the above, as well as:

  • Code quality to me looks great
  • Adds great docs
  • Great example

I haven't verified any math or looked in depth at the shaders- hoping rendering maintainers will do so.

@pcwalton
Copy link
Contributor Author

Yeah. Unity doesn't implement PCSS at all and in this PR I pretty much learned why. PCSS is just really hard to tune.

@theprotonfactor
Copy link

@pcwalton Unity does, in fact, implement PCSS as part of their High Definition Render Pipeline package. See the "Shadows" section on this changelog page, for example. If you ever want to know what Unity does and doesn't support then that repository is a fantastic place to search.

Copy link
Contributor

@IceSentry IceSentry left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, the code looks good to me. The new docs for the existing shadow stuff is really nice.

As mentioned on discord, the volumetric_fog and trransmission example currently crash. Once those are fixed and assuming conflicts are fixed I'll approve.

examples/3d/pcss.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@therealbnut therealbnut left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code looks good, just a small nit about clarifying some unused uncommented fields.

Comment on lines +156 to +157
pub(crate) pad_a: f32,
pub(crate) pad_b: f32,
Copy link
Contributor

@therealbnut therealbnut Jul 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Is this intended to make the structure's size a multiple of 4 x f32? If so a comment and maybe a test might be good, assuming it's important and relied upon elsewhere. Maybe something like this would also make the intention clearer and more maintainable:

Suggested change
pub(crate) pad_a: f32,
pub(crate) pad_b: f32,
pub(crate) _reserved: [f32; 2],

The test could be as simple as this:

#[cfg(test)]
const_assert_eq!(size_of::<GpuClusterableObject>() % size_of::<Vec4>(), 0);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A test isn't that necessary for that. Things break pretty quickly if the padding is wrong anyway. We have padding in a bunch of places for rendering code because of some webgl limitations.

Copy link
Contributor

@therealbnut therealbnut Jul 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool, no problem if it’s convention - although should it be commented all the same? I was thinking the test wasn't so much about ensuring it breaks, but ensuring the issue is determined statically and in the right location to fix it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For me, just the fact that it's called pad_x is enough documentation.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Righto, again no problem if it's an established convention in the codebase.

I was initially unsure whether this was perhaps something like padding from the edge of the shadow when sampling to avoid boundary conditions. It required me to check it wasn't used to understand its purpose and intention, but if I was adding a new field I may not have checked so thoroughly and just added new fields rather than removing these.

Again, it's a nit, and not a huge issue. I just saw it as something that could be made clearer. My intention if it's clearer is that more people can get across these changes, review, and contribute. Being knowledgable about graphics doesn't mean you're knowledgable about conventions in this codebase, or rust, etc. My understanding of Rust convention, for example, is that fields like this would have an underscore prefix _pad_a to indicate they're intentionally unused.

@pcwalton
Copy link
Contributor Author

pcwalton commented Jul 15, 2024

Please don't merge this yet as spot shadows are broken somehow due to merge fallout.

@pcwalton pcwalton marked this pull request as draft July 15, 2024 01:46
Comment on lines -220 to +222
4,
5,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a change for this PR, but after this is merged would a PR be welcome to replace these values with constants? and defined in the shader with defines like this:

@group(0) @binding(#TONEMAPPING_LUT_TEXTURE_BINDING_INDEX) var dt_lut_texture: texture_3d<f32>;
@group(0) @binding(#TONEMAPPING_LUT_SAMPLER_BINDING_INDEX) var dt_lut_sampler: sampler;

It might reduce merge conflict churn when there's lots of unrelated changes in a PR.

Copy link
Contributor Author

@pcwalton pcwalton Jul 16, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As I recall, non-boolean defines are kind of annoying in our PBR shaders at the moment, but sure, it could be done in the future.

@pcwalton
Copy link
Contributor Author

@alice-i-cecile I think I fixed DX12.

@alice-i-cecile alice-i-cecile added this pull request to the merge queue Sep 18, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Sep 18, 2024
@pcwalton
Copy link
Contributor Author

This failure is because directional_shadow_textures can be sampled with both linear and PCF with PCSS and WebGL 2 doesn't support that. Grr. Trying to see if there's a way I can just ifdef off all of PCSS in WebGL 2.

@pcwalton
Copy link
Contributor Author

Should be fixed again.

@alice-i-cecile
Copy link
Member

I love WebGL2 🥲 Thanks for fixing this up <3

@alice-i-cecile
Copy link
Member

Thank you to everyone involved with the authoring or reviewing of this PR! This work is relatively important and needs release notes! Head over to bevyengine/bevy-website#1688 if you'd like to help out.

pcwalton added a commit to pcwalton/bevy that referenced this pull request Oct 23, 2024
The PCSS PR bevyengine#13497 increased the size of clusterable objects from 64
bytes to 80 bytes but didn't decrease the UBO size to compensate, so we
blew past the 16kB limit on WebGL 2. This commit fixes the issue by
lowering the maximum number of clusterable objects to 204, which puts us
under the 16kB limit again.

Closes bevyengine#15998.
github-merge-queue bot pushed a commit that referenced this pull request Oct 24, 2024
The PCSS PR #13497 increased the size of clusterable objects from 64
bytes to 80 bytes but didn't decrease the UBO size to compensate, so we
blew past the 16kB limit on WebGL 2. This commit fixes the issue by
lowering the maximum number of clusterable objects to 204, which puts us
under the 16kB limit again.

Closes #15998.
mockersf pushed a commit that referenced this pull request Oct 24, 2024
The PCSS PR #13497 increased the size of clusterable objects from 64
bytes to 80 bytes but didn't decrease the UBO size to compensate, so we
blew past the 16kB limit on WebGL 2. This commit fixes the issue by
lowering the maximum number of clusterable objects to 204, which puts us
under the 16kB limit again.

Closes #15998.
grace125 added a commit to grace125/bevy that referenced this pull request Oct 28, 2024
commit 78a4bea
Author: ickshonpe <[email protected]>
Date:   Sun Oct 27 22:39:32 2024 +0000

    Move `ContentSize` requirements from `Node` to the widget defining components (bevyengine#16083)

    # Objective

    Missed this in the required components PR review. `ContentSize` isn't
    used by regular UI nodes, only those with intrinsically sized content
    that needs a measure func.

    ## Solution

    Remove `ContentSize` from `Node`'s required components and add it to the
    required components of `Text` and `UiImage`.

    ---------

    Co-authored-by: Alice Cecile <[email protected]>

commit c4c1c8f
Author: mgi388 <[email protected]>
Date:   Mon Oct 28 09:38:07 2024 +1100

    Undeprecate is_playing_animation (bevyengine#16121)

    # Objective

    - Fixes bevyengine#16098

    ## Solution

    - Undeprecate `is_playing_animation` and copy the docs from
    `animation_is_playing` to it.

    ## Testing

    - CI

    ## Migration

    https://github.com/bevyengine/bevy-website/blob/68e9a34e3068ed2e7db5ae0b4b32feac94a589dd/release-content/0.15/migration-guides/_guides.toml#L13-L17
    needs to be removed.

commit 3d72f49
Author: ickshonpe <[email protected]>
Date:   Sun Oct 27 20:08:51 2024 +0000

    Layout rounding debug example (bevyengine#16096)

    # Objective

    Simple example for debugging layout rounding errors.

    <img width="1039" height="752" alt="layout_rounding_debug"
    src="https://github.com/user-attachments/assets/12673000-e267-467e-b25b-3f8001c1347c">

    Any white lines are gaps in the layout caused by coordinate rounding
    errors.

commit 86ee8e4
Author: ickshonpe <[email protected]>
Date:   Sun Oct 27 19:14:46 2024 +0000

    Move `UiImage` from `ui_node` to the `widget::image` module (bevyengine#16084)

    # Objective

    `UiImage` isn't just a general image component now, it's the defining
    component for the image widget so it belongs in the image widget's
    module.

commit d01db9b
Author: Hexroll by Pen, Dice & Paper <[email protected]>
Date:   Sun Oct 27 19:08:34 2024 +0000

    Adding alpha_threshold to OrderIndependentTransparencySettings for user-level optimization (bevyengine#16090)

    # Objective

    Order independent transparency can filter fragment writes based on the
    alpha value and it is currently hard-coded to anything higher than 0.0.
    By making that value configurable, users can optimize fragment writes,
    potentially reducing the number of layers needed and improving
    performance in favor of some transparency quality.

    ## Solution

    This PR adds `alpha_threshold` to the
    OrderIndependentTransparencySettings component and uses the struct to
    configure a corresponding shader uniform. This uniform is then used
    instead of the hard-coded value.

    To configure OIT with a custom alpha threshold, use:

    ```rust
    fn setup(mut commands: Commands) {
        commands.spawn((
            Camera3d::default(),
            OrderIndependentTransparencySettings {
                layer_count: 8,
                alpha_threshold: 0.2,
            },
        ));
    }
    ```

    ## Testing

    I tested this change using the included OIT example, as well as with two
    additional projects.

    ## Migration Guide

    If you previously explicitly initialized
    OrderIndependentTransparencySettings with your own `layer_count`, you
    will now have to add either a `..default()` statement or an explicit
    `alpha_threshold` value:

    ```rust
    fn setup(mut commands: Commands) {
        commands.spawn((
            Camera3d::default(),
            OrderIndependentTransparencySettings {
                layer_count: 16,
                ..default()
            },
        ));
    }
    ```

    ---------

    Co-authored-by: JMS55 <[email protected]>

commit 3fc2bd7
Author: Rob Parrett <[email protected]>
Date:   Sun Oct 27 12:06:19 2024 -0700

    Cosmetic tweaks to `query_gltf_primitives` (bevyengine#16102)

    # Objective

    This example is really confusing to look at and tell at a glance whether
    it's broken or not.

    It's displaying a strange shape -- a cube with two vertices stretched in
    a couple dimensions at an odd angle, and doing its vertex position
    modification in a way where the intent isn't obvious.

    ## Solution

    - Change the gltf geometry so that the object is a recognizable regular
    shape
    - Change the vertex modification so that the entire cube top is being
    "lifted" from the cube
    - Adjust colors, lighting, and camera location so we can see what's
    going on
    - Also remove some irrelevant shadow and environment map setup

    ## Before

    ![Image](https://github.com/user-attachments/assets/e5dd5075-0480-49d4-b1ed-cf1fe6106f3c)

    ## After

    <img width="1280" alt="image"
    src="https://github.com/user-attachments/assets/59cab60d-efbc-47c3-8688-e4544b462421">

commit 7451900
Author: Miles Silberling-Cook <[email protected]>
Date:   Sun Oct 27 15:05:31 2024 -0400

    Emit picking event streams (bevyengine#16105)

    # Objective

    In `bevy_mod_picking` events are accessible through event listeners or
    `EventReader`s. When I replaced event listeners with observers, I
    removed the `EventReader` for simplicity. This adds it back.

    ## Solution

    All picking events are now properly registered, and can be accessed
    through `EventReader<Pointer<E>>`. `Pointer` now tracks the entity the
    event targeted initially, and this can also be helpful in observers
    (which don't currently do this).

    ## Testing

    The picking examples run fine. This shouldn't really change anything.

    ---------

    Co-authored-by: Aevyrie <[email protected]>

commit 54b323e
Author: Aevyrie <[email protected]>
Date:   Sun Oct 27 12:03:48 2024 -0700

    Mesh picking fixes (bevyengine#16110)

    # Objective

    - Mesh picking is noisy when a non triangle list is used
    - Mesh picking runs even when users don't need it
    - Resolve bevyengine#16065

    ## Solution

    - Don't add the mesh picking plugin by default
    - Remove error spam

commit a644ac7
Author: Tau Gärtli <[email protected]>
Date:   Sun Oct 27 20:01:50 2024 +0100

    More `#[doc(fake_variadic)]` goodness (bevyengine#16108)

    This PR adds `#[doc(fake_variadic)]` to that were previously not
    supported by rustdoc.

    Thanks to an [upstream
    contribution](rust-lang/rust#132115) by yours
    truly, `#[doc(fake_variadic)]` is now supported on impls such as `impl
    QueryData for AnyOf<(T, ...)>` 🎉
    Requires the latest nightly compiler (2024-10-25) which is already
    available on [docs.rs](https://docs.rs/about/builds).

    ![image](https://github.com/user-attachments/assets/68589c7e-f68f-44fb-9a7b-09d24ccf19c9)

    ![image](https://github.com/user-attachments/assets/f09d20d6-d89b-471b-9a81-4a72c8968178)

    This means that the impl sections for `QueryData` and `QueryFilter` are
    now nice and tidy ✨

    ---

    I also added `fake_variadic` to some impls that use
    `all_tuples_with_size`, however I'm not entirely happy because the docs
    are slightly misleading now:

    ![image](https://github.com/user-attachments/assets/fac93d08-dc02-430f-9f34-c97456256c56)

    Note that the docs say `IntoBindGroupLayoutEntryBuilderArray<1>` instead
    of
    `IntoBindGroupLayoutEntryBuilderArray<N>`.

commit 60b2c7c
Author: François Mockers <[email protected]>
Date:   Fri Oct 25 22:14:39 2024 +0200

    fix bevy_dev_tools build (bevyengine#16099)

    # Objective

    - bevy_dev_tools 0.15.0-rc.1 failed to build docs
    - it use bevy_text feature in bevy_ui but it's not enabled by default
    - https://docs.rs/crate/bevy_dev_tools/0.15.0-rc.1
    -
    ## Solution

    - enable bevy_text feature of bevy_ui

commit 7c59317
Author: BD103 <[email protected]>
Date:   Fri Oct 25 16:11:51 2024 -0400

    Fix `bevy_picking` plugin suffixes (bevyengine#16082)

    # Objective

    - `MeshPickingBackend` and `SpritePickingBackend` do not have the
    `Plugin` suffix
    - `DefaultPickingPlugins` is masquerading as a `Plugin` when in reality
    it should be a `PluginGroup`
    - Fixes bevyengine#16081.

    ## Solution

    - Rename some structures:

    |Original Name|New Name|
    |-|-|
    |`MeshPickingBackend`|`MeshPickingPlugin`|
    |`MeshPickingBackendSettings`|`MeshPickingSettings`|
    |`SpritePickingBackend`|`SpritePickingPlugin`|
    |`UiPickingBackendPlugin`|`UiPickingPlugin`|

    - Make `DefaultPickingPlugins` a `PluginGroup`.
    - Because `DefaultPickingPlugins` is within the `DefaultPlugins` plugin
    group, I also added support for nested plugin groups to the
    `plugin_group!` macro.

    ## Testing

    - I used ripgrep to ensure all references were properly renamed.
    - For the `plugin_group!` macro, I used `cargo expand` to manually
    inspect the expansion of `DefaultPlugins`.

    ---

    ## Migration Guide

    > [!NOTE]
    >
    > All 3 of the changed structures were added after 0.14, so this does
    not need to be included in the 0.14 to 0.15 migration guide.

    - `MeshPickingBackend` is now named `MeshPickingPlugin`.
    - `MeshPickingBackendSettings` is now named `MeshPickingSettings`.
    - `SpritePickingBackend` is now named `SpritePickingPlugin`.
    - `UiPickingBackendPlugin` is now named `UiPickingPlugin`.
    - `DefaultPickingPlugins` is now a a `PluginGroup` instead of a
    `Plugin`.

commit 611ba8b
Author: Ludwig DUBOS <[email protected]>
Date:   Fri Oct 25 22:08:14 2024 +0200

    Add `AsyncSeekForwardExt` trait to allows a similar API to the previous Bevy version (bevyengine#16027)

    # Objective

    This PR introduces an `AsyncSeekForwardExt` trait, which I forgot in my
    previous PR bevyengine#14194.

    This new trait is analogous to `AsyncSeekExt` and allows all
    implementors of `AsyncSeekForward` to directly use the `seek_forward`
    function in async contexts.

    ## Solution

    - Implement a new `AsyncSeekForwardExt` trait
    - Automatically implement this trait for all types that implement
    `AsyncSeekForward`

    ## Showcase

    This new trait allows a similar API to the previous Bevy version:

    ```rust
    #[derive(Default)]
    struct UniverseLoader;

    #[derive(Asset, TypePath, Debug)]
    struct JustALilAsteroid([u8; 128]);

    impl AssetLoader for UniverseLoader {
        type Asset = JustALilAsteroid;
        type Settings = ();
        type Error = std::io::Error;

        async fn load<'a>(
            &'a self,
            reader: &'a mut Reader<'a>,
            _settings: &'a Self::Settings,
            _context: &'a mut LoadContext<'_>,
        ) -> Result<Self::Asset, Self::Error> {
            // read the asteroids entry table
            let entry_offset: u64 = /* ... */;
            let current_offset: u64 = reader.seek_forward(0).await?;

            // jump to the entry
            reader.seek_forward(entry_offset - current_offset).await?;

            let mut asteroid_buf = [0; 128];
            reader.read_exact(&mut asteroid_buf).await?;

            Ok(JustALilAsteroid(asteroid_buf))
        }

        fn extensions(&self) -> &[&str] {
            &["celestial"]
        }
    }
    ```

commit c6a66a7
Author: Patrick Walton <[email protected]>
Date:   Thu Oct 24 14:16:00 2024 -0700

    Place percentage-closer soft shadows behind a feature gate to save on samplers. (bevyengine#16068)

    The two additional linear texture samplers that PCSS added caused us to
    blow past the limit on Apple Silicon macOS and WebGL. To fix the issue,
    this commit adds a `--feature pbr_pcss` feature gate that disables PCSS
    if not present.

    Closes bevyengine#15345.
    Closes bevyengine#15525.
    Closes bevyengine#15821.

    ---------

    Co-authored-by: Carter Anderson <[email protected]>
    Co-authored-by: IceSentry <[email protected]>

commit 897404e
Author: Patrick Walton <[email protected]>
Date:   Thu Oct 24 14:00:11 2024 -0700

    Reduce the clusterable object UBO size below 16384 for WebGL 2. (bevyengine#16069)

    The PCSS PR bevyengine#13497 increased the size of clusterable objects from 64
    bytes to 80 bytes but didn't decrease the UBO size to compensate, so we
    blew past the 16kB limit on WebGL 2. This commit fixes the issue by
    lowering the maximum number of clusterable objects to 204, which puts us
    under the 16kB limit again.

    Closes bevyengine#15998.

commit 9274bfe
Author: Carter Anderson <[email protected]>
Date:   Wed Oct 23 18:24:17 2024 -0500

    Move TextureAtlas into UiImage and remove impl Component for TextureAtlas (bevyengine#16072)

    # Objective

    Fixes bevyengine#16064

    ## Solution

    - Add TextureAtlas to `UiImage::texture_atlas`
    - Add `TextureAtlas::from_atlas_image` for parity with `Sprite`
    - Rename `UiImage::texture` to `UiImage::image` for parity with `Sprite`
    - Port relevant implementations and uses
    - Remove `derive(Component)` for `TextureAtlas`

    ---

    ## Migration Guide

    Before:
    ```rust
    commands.spawn((
      UiImage::new(image),
      TextureAtlas { index, layout },
    ));
    ```

    After:
    ```rust
    commands.spawn(UiImage::from_atlas_image(image, TextureAtlas { index, layout }));
    ```

    Before:
    ```rust
    commands.spawn(UiImage {
        texture: some_image,
        ..default()
    })
    ```

    After:
    ```rust
    commands.spawn(UiImage {
        image: some_image,
        ..default()
    })
    ```

commit 2cdad48
Author: Viktor Gustavsson <[email protected]>
Date:   Wed Oct 23 23:51:39 2024 +0200

    Ensure ghost nodes are skipped when getting parent clipping rect (bevyengine#16058)

    # Objective

    - Follow up on bevyengine#16044
    - `extract_uinode_borders` uses `bevy_hierarchy` directly instead of
    going through the traversal utilities, meaning it won't handle
    `GhostNode`s properly.

    ## Solution

    - Replaced the use of `bevy_hierarchy::Parent` with
    `UIChildren::get_parent`

    ## Testing

    - Ran the `overflow` example, clipping looks ok.

    ---

    ---------

    Co-authored-by: Carter Anderson <[email protected]>

commit c9a3f34
Author: ickshonpe <[email protected]>
Date:   Wed Oct 23 21:41:42 2024 +0100

    Fixes for a few minor borders and outlines bugs (bevyengine#16071)

    # Objective

    1. Nodes with `Display::None` set are removed from the layout and have
    no position or size. Outlines should not be drawn for a node with
    `Display::None` set.
    2. The outline and border colors are checked for transparency together.
    If only one of the two is transparent, both will get queued.
    3. The `node.is_empty()` check is insufficient to check if a border is
    present since a non-zero sized node can have a zero width border.

    ## Solution

    1. Add a check to `extract_uinode_borders` and ignore the node if
    `Display::None` is set.
    2. Filter the border and outline optional components by
    `is_fully_transparent`.
    3.  Check if all the border widths are zero instead.

    ## Testing

    I added dark cyan outlines around the left and right sections in the
    `display_and_visibility` example. If you run the example and set the
    outermost node to `Display::None` on the right, then you'll see the that
    the outline on the left disappears.

commit 7577895
Author: Carter Anderson <[email protected]>
Date:   Wed Oct 23 15:05:28 2024 -0500

    Use CosmicFontSystem in public bevy_text APIs and remove cosmic_text re-export (bevyengine#16063)

    # Objective

    Fixes bevyengine#16006

    ## Solution

    We currently re-export `cosmic_text`, which is seemingly motivated by
    the desire to use `cosmic_text::FontSystem` in `bevy_text` public APIs
    instead of our `CosmicFontSystem` resource wrapper type.

    This change makes `bevy_text` a "true" abstraction over `cosmic_text`
    (it in fact, was already built to be that way generally and has this one
    "leak").

    This allows us to remove the `cosmic_text` re-export, which helps clean
    up the Rust Analyzer imports and generally makes this a "cleaner" API.

commit 3fb6cef
Author: JMS55 <[email protected]>
Date:   Wed Oct 23 12:18:49 2024 -0700

    Meshlet fill cluster buffers rewritten (bevyengine#15955)

    # Objective
    - Make the meshlet fill cluster buffers pass slightly faster
    - Address bevyengine#15920 for meshlets
    - Added PreviousGlobalTransform as a required meshlet component to avoid
    extra archetype moves, slightly alleviating
    bevyengine#14681 for meshlets
    - Enforce that MeshletPlugin::cluster_buffer_slots is not greater than
    2^25 (glitches will occur otherwise). Technically this field controls
    post-lod/culling cluster count, and the issue is on pre-lod/culling
    cluster count, but it's still valid now, and in the future this will be
    more true.

    Needs to be merged after bevyengine#15846
    and bevyengine#15886

    ## Solution

    - Old pass dispatched a thread per cluster, and did a binary search over
    the instances to find which instance the cluster belongs to, and what
    meshlet index within the instance it is.
    - New pass dispatches a workgroup per instance, and has the workgroup
    loop over all meshlets in the instance in order to write out the cluster
    data.
    - Use a push constant instead of arrayLength to fix the linked bug
    - Remap 1d->2d dispatch for software raster only if actually needed to
    save on spawning excess workgroups

    ## Testing

    - Did you test these changes? If so, how?
    - Ran the meshlet example, and an example with 1041 instances of 32217
    meshlets per instance. Profiled the second scene with nsight, went from
    0.55ms -> 0.40ms. Small savings. We're pretty much VRAM bandwidth bound
    at this point.
    - How can other people (reviewers) test your changes? Is there anything
    specific they need to know?
      - Run the meshlet example

    ## Changelog (non-meshlets)
    - PreviousGlobalTransform now implements the Default trait

commit 6d42830
Author: JMS55 <[email protected]>
Date:   Wed Oct 23 09:56:50 2024 -0700

    Meshlet builder improvements redux (bevyengine#15886)

    Take a bunch more improvements from @zeux's nanite.cpp code.

    * Use position-only vertices (discard other attributes) to determine
    meshlet connectivity for grouping
    * Rather than using the lock borders flag when simplifying meshlet
    groups, provide the locked vertices ourselves. The lock borders flag
    locks the entire border of the meshlet group, but really we only want to
    lock the edges between meshlet groups - outwards facing edges are fine
    to unlock. This gives a really significant increase to the DAG quality.
    * Add back stuck meshlets (group has only a single meshlet,
    simplification failed) to the simplification queue to allow them to get
    used later on and have another attempt at simplifying
    * Target 8 meshlets per group instead of 4 (second biggest improvement
    after manual locks)
    * Provide a seed to metis for deterministic meshlet building
    * Misc other improvements

    We can remove the usage of unsafe after the next upstream meshopt
    release, but for now we need to use the ffi function directly. I'll do
    another round of improvements later, mainly attribute-aware
    simplification and using spatial weights for meshlet grouping.

    Need to merge bevyengine#15846 first.

commit 50d38f2
Author: akimakinai <[email protected]>
Date:   Wed Oct 23 08:29:58 2024 +0900

    Fix point light count limit (bevyengine#16062)

    # Objective

    - I made a mistake in bevyengine#15902, specifically [this
    diff](bevyengine@e2faedb)
    -- the `point_light_count` variable is used for all point lights, not
    just shadow mapped ones, so I cannot add `.min(max_texture_cubes)`
    there. (Despite `spot_light_count` having `.min(..)`)

    It may have broken code like this (where `index` is index of
    `point_light` vec):

    https://github.com/bevyengine/bevy/blob/9930df83ed42008f7eb2c02cc7350040f0250c2e/crates/bevy_pbr/src/render/light.rs#L848-L850

    and also causes panic here:

    https://github.com/bevyengine/bevy/blob/9930df83ed42008f7eb2c02cc7350040f0250c2e/crates/bevy_pbr/src/render/light.rs#L1173-L1174

    ## Solution

    - Adds `.min(max_texture_cubes)` directly to the loop where texture
    views for point lights are created.

    ## Testing

    - `lighting` example (with the directional light removed; original
    example doesn't crash as only 1 directional-or-spot light in total is
    shadow-mapped on webgl) no longer crashes on webgl

commit 2223f6e
Author: JMS55 <[email protected]>
Date:   Tue Oct 22 16:05:40 2024 -0700

    Meshlet fix software rasterization (bevyengine#16049)

    # Objective
    1. Prevent weird glitches with stray pixels scattered around the scene

    ![image](https://github.com/user-attachments/assets/f12adb38-5996-4dc7-bea6-bd326b7317e1)
    2. Prevent weird glitchy full-screen triangles that pop-up and destroy
    perf (SW rasterizing huge triangles is slow)

    ![image](https://github.com/user-attachments/assets/d3705427-13a5-47bc-a54b-756f0409da0b)

    ## Solution
    1. Use floating point math in the SW rasterizer bounding box calculation
    to handle negative verticss, and add backface culling
    2. Force hardware raster for clusters that clip the near plane, and let
    the hardware rasterizer handle the clipping

    I also adjusted the SW rasterizer threshold to < 64 pixels (little bit
    better perf in my test scene, but still need to do a more comprehensive
    test), and enabled backface culling for the hardware raster pipeline.

    ## Testing

    - Did you test these changes? If so, how?
      - Yes, on an example scene. Issues no longer occur.
    - Are there any parts that need more testing?
      - No.
    - How can other people (reviewers) test your changes? Is there anything
    specific they need to know?
      - Run the meshlet example.

commit fe4f44b
Author: François Mockers <[email protected]>
Date:   Wed Oct 23 00:37:04 2024 +0200

    crate publish order: bevy_animation depends on bevy_animation_derive (bevyengine#16060)

    # Objective

    - bevy_animation publication fails because of missed dependency
    - bevy_animation depends on bevy_animation_derive which is published
    after

    ## Solution

    - Reorder crates bevy_animation and bevy_animation_derive

commit fac0b34
Author: François Mockers <[email protected]>
Date:   Tue Oct 22 22:21:19 2024 +0200

    remove reference to missing file in bevy_remote cargo.toml (bevyengine#16057)

    # Objective

    - bevy_remote Cargo.toml file references a readme that doesn't exist
    - This is blocking releasing the rc

    ## Solution

    - Remove the reference

commit 9d54fe0
Author: JMS55 <[email protected]>
Date:   Tue Oct 22 13:14:30 2024 -0700

    Meshlet new error projection (bevyengine#15846)

    * New error projection code taken from @zeux's meshoptimizer nanite.cpp
    demo for determining LOD (thanks zeux!)
    * Builder: `compute_lod_group_data()`
    * Runtime: `lod_error_is_imperceptible()`

commit 9930df8
Author: ickshonpe <[email protected]>
Date:   Mon Oct 21 23:54:09 2024 +0100

    UI borders and outlines clipping fix (bevyengine#16044)

    # Objective

    fixes bevyengine#15502

    Clipped borders and outlines aren't drawn correctly.

    ### Borders aren't clipped

    Spawn two nodes with the same dimensions and border thickness, but clip
    on of the nodes so that only its top left quarter is visible:

    <img width="194" alt="clip"
    src="https://github.com/user-attachments/assets/2d3f6d28-aa20-44df-967a-677725828294">

    You can see that instead of clipping the border, instead the border is
    scaled to fit inside of the unclipped section.

    ```rust
    use bevy::color::palettes::css::BLUE;
    use bevy::prelude::*;
    use bevy::winit::WinitSettings;

    fn main() {
        App::new()
            .add_plugins(DefaultPlugins)
            .insert_resource(WinitSettings::desktop_app())
            .add_systems(Startup, setup)
            .run();
    }

    fn setup(mut commands: Commands) {
        commands.spawn(Camera2d);
        commands
            .spawn(Node {
                width: Val::Percent(100.),
                height: Val::Percent(100.),
                justify_content: JustifyContent::Center,
                align_items: AlignItems::Center,
                ..Default::default()
            })
            .with_children(|commands| {
                commands
                    .spawn(Node {
                        column_gap: Val::Px(10.),
                        ..Default::default()
                    })
                    .with_children(|commands| {
                        commands
                            .spawn(Node {
                                width: Val::Px(100.),
                                height: Val::Px(100.),
                                overflow: Overflow::clip(),
                                ..Default::default()
                            })
                            .with_child((
                                Node {
                                    position_type: PositionType::Absolute,
                                    width: Val::Px(100.),
                                    height: Val::Px(100.),
                                    border: UiRect::all(Val::Px(10.)),
                                    ..Default::default()
                                },
                                BackgroundColor(Color::WHITE),
                                BorderColor(BLUE.into()),
                            ));

                        commands
                            .spawn(Node {
                                width: Val::Px(50.),
                                height: Val::Px(50.),
                                overflow: Overflow::clip(),
                                ..Default::default()
                            })
                            .with_child((
                                Node {
                                    position_type: PositionType::Absolute,
                                    width: Val::Px(100.),
                                    height: Val::Px(100.),
                                    border: UiRect::all(Val::Px(10.)),
                                    ..Default::default()
                                },
                                BackgroundColor(Color::WHITE),
                                BorderColor(BLUE.into()),
                            ));
                    });
            });
    }
    ```

    You can also see this problem in the `overflow` example. If you hover
    over any of the clipped nodes you'll see that the outline only wraps the
    visible section of the node

    ### Outlines are clipped incorrectly

    A UI nodes Outline's are drawn outside of its bounds, so applying the
    local clipping rect to the outline doesn't make any sense.
    Instead an `Outline` should be clipped using its parent's clipping rect.

    ## Solution

    * Pass the `point` value into the vertex shader instead of calculating
    it in the shader.
    * In `extract_uinode_borders` use the parents clipping rect when
    clipping outlines.

    The extra parameter isn't a great solution I think, but I wanted to fix
    borders for the 0.15 release and this is the most minimal approach I
    could think of without replacing the whole shader and prepare function.

     ## Showcase

    <img width="149" alt="clipp"
    src="https://github.com/user-attachments/assets/19fbd3cc-e7cd-42e1-a5e0-fd92aad04dcd">

    ---------

    Co-authored-by: Alice Cecile <[email protected]>

commit d0af199
Author: Stepan Koltsov <[email protected]>
Date:   Mon Oct 21 16:57:52 2024 +0100

    Add a test for Mesh::triangles and fix for TriangleStrip (bevyengine#16026)

    # Objective

    - Illustrate behavior with a test
    - Fix a bug revealed by a test

    ## Solution

    - Add a test and fix

    ## Testing

    Test added.

commit 465d113
Author: Stepan Koltsov <[email protected]>
Date:   Mon Oct 21 03:17:59 2024 +0100

    Replace TwoIterators with Either in bevy_animation (bevyengine#16036)

    # Objective

    - Less code
    - Better iterator (implements `size_hint` for example)

    ## Solution

    - Use `either`
    - This change is free because `bevy_animation` depends on `bevy_asset`,
    which already depends on `either`

    ## Testing

    CI

# Conflicts:
#	Cargo.toml
grace125 added a commit to grace125/bevy that referenced this pull request Oct 28, 2024
commit 069291d
Author: Clar Fon <[email protected]>
Date:   Mon Oct 28 17:15:00 2024 -0400

    Reduce compile time of bevy_ptr::OwnedPtr::make function (bevyengine#15644)

    ## Methodology

    A good metric that correlates with compile time is the amount of code
    generated by the compiler itself; even if the end binary is exactly the
    same size, having more copies of the same code can really slow down
    compile time, since it has to figure out whether it needs to include
    them or not.

    The measurement for this used was the [`cargo-llvm-lines`
    crate](https://docs.rs/crate/cargo-llvm-lines) which can measure which
    functions are generating the most lines of LLVM IR, which generally
    means more code compiled. The example compiled was the `breakout` game,
    to choose something that touches a decent portion of the engine.

    ## Solution

    Based upon the measurements, `bevy_ptr::OwnedPtr::make` was taking up
    4061 lines of LLVM IR in the example code. So, I separated part of this
    function into a less-monomorphised version to reduce the amount of
    generated code. This was by far the most lines emitted by any single
    function.

    ## Results

    After this change, only 2560 lines are emitted, accounting for a 36%
    decrease. I tried timing the results and it seemed like it did decrease
    compile times a bit, but honestly, the data is really noisy and I can't
    be bothered to compile bevy for hours on end to get enough data points.

    The tweak feels like an improvement, so, I'll offer it, however small.

commit 1add4bf
Author: ickshonpe <[email protected]>
Date:   Mon Oct 28 21:05:25 2024 +0000

    Rename `ComputedNode::calculated_size` to `size` (bevyengine#16131)

    # Objective

    Remove `calculated_` from the name `ComputedNode::calculated_size` as
    redundant, It's obvious from context that it's the resolved size value
    and it's inconsistant since none of other fields of `ComputedNode` have
    a `calculated_` prefix.

    ## Alternatives

    Rename all the fields of `ComputedNode` to `calculated_*`, this seems
    worse.

commit 33c4945
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Mon Oct 28 13:01:25 2024 +0100

    Bump crate-ci/typos from 1.26.0 to 1.26.8 (bevyengine#16128)

    Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.26.0 to
    1.26.8.
    <details>
    <summary>Release notes</summary>
    <p><em>Sourced from <a
    href="https://github.com/crate-ci/typos/releases">crate-ci/typos's
    releases</a>.</em></p>
    <blockquote>
    <h2>v1.26.8</h2>
    <h2>[1.26.8] - 2024-10-24</h2>
    <h2>v1.26.3</h2>
    <h2>[1.26.3] - 2024-10-24</h2>
    <h3>Fixes</h3>
    <ul>
    <li>Accept <code>additionals</code></li>
    </ul>
    <h2>v1.26.2</h2>
    <h2>[1.26.2] - 2024-10-24</h2>
    <h3>Fixes</h3>
    <ul>
    <li>Accept <code>tesselate</code> variants</li>
    </ul>
    <h2>v1.26.1</h2>
    <h2>[1.26.1] - 2024-10-23</h2>
    <h3>Fixes</h3>
    <ul>
    <li>Respect <code>--force-exclude</code> for binary files</li>
    </ul>
    </blockquote>
    </details>
    <details>
    <summary>Changelog</summary>
    <p><em>Sourced from <a
    href="https://github.com/crate-ci/typos/blob/master/CHANGELOG.md">crate-ci/typos's
    changelog</a>.</em></p>
    <blockquote>
    <h2>[1.26.8] - 2024-10-24</h2>
    <h2>[1.26.7] - 2024-10-24</h2>
    <h2>[1.26.6] - 2024-10-24</h2>
    <h2>[1.26.5] - 2024-10-24</h2>
    <h2>[1.26.4] - 2024-10-24</h2>
    <h2>[1.26.3] - 2024-10-24</h2>
    <h3>Fixes</h3>
    <ul>
    <li>Accept <code>additionals</code></li>
    </ul>
    <h2>[1.26.2] - 2024-10-24</h2>
    <h3>Fixes</h3>
    <ul>
    <li>Accept <code>tesselate</code> variants</li>
    </ul>
    <h2>[1.26.1] - 2024-10-23</h2>
    <h3>Fixes</h3>
    <ul>
    <li>Respect <code>--force-exclude</code> for binary files</li>
    </ul>
    </blockquote>
    </details>
    <details>
    <summary>Commits</summary>
    <ul>
    <li><a
    href="https://github.com/crate-ci/typos/commit/0d9e0c2c1bd7f770f6eb90f87780848ca02fc12c"><code>0d9e0c2</code></a>
    chore: Release</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/e5385b07a020af945231c06d33ec490fb77fc7b0"><code>e5385b0</code></a>
    chore(ci): Fix new release process</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/f08d1171e28430953c39c15beb330811e20ecfe2"><code>f08d117</code></a>
    chore: Release</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/e6e172498c285b815f8cbe3ada1bf51f02fd3b9a"><code>e6e1724</code></a>
    chore(ci): Fix new release process</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/02afc59fd4633b33c1f7b14b96f46402477dcc75"><code>02afc59</code></a>
    chore: Release</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/f981a1cd200c62b7ce895f09d269b3ee688ccad9"><code>f981a1c</code></a>
    chore(ci): Fix new release process</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/afbc96c5d3760227ecd31b4ed5f80415beeaaa86"><code>afbc96c</code></a>
    chore: Release</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/d3dcaaeb2d5bb61eadbd393a8803745af7c81290"><code>d3dcaae</code></a>
    chore(ci): Fix new release process</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/fb8217bd5e6531ce9c1992dd571f7f23d8fdc9c4"><code>fb8217b</code></a>
    chore: Release</li>
    <li><a
    href="https://github.com/crate-ci/typos/commit/88ea8ea67dcd07e71f5c9e397a2669c639786dd8"><code>88ea8ea</code></a>
    chore(ci): Stage releases until done</li>
    <li>Additional commits viewable in <a
    href="https://github.com/crate-ci/typos/compare/v1.26.0...v1.26.8">compare
    view</a></li>
    </ul>
    </details>
    <br />

    [![Dependabot compatibility
    score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=crate-ci/typos&package-manager=github_actions&previous-version=1.26.0&new-version=1.26.8)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

    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] <[email protected]>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit 4b0efda
Author: mamekoro <[email protected]>
Date:   Mon Oct 28 12:26:35 2024 +0900

    Make some associated functions of `Color` const (bevyengine#16091)

    # Objective
    Make the following functions `const` that will be useful to define
    colors as constants.

    - `Color::srgb_from_array`
    - `Color::srgba_u8`
    - `Color::srgb_u8`

    The last two require Rust 1.82.0.

    ## Solution
    - Make them `const`
    - Change MSRV to 1.82.0

    ## Testing
    I tested bevy_color only. My machine does not have enough RAM capacity
    to test the whole bevy.

    `cargo test -p bevy_color`

commit 78a4bea
Author: ickshonpe <[email protected]>
Date:   Sun Oct 27 22:39:32 2024 +0000

    Move `ContentSize` requirements from `Node` to the widget defining components (bevyengine#16083)

    # Objective

    Missed this in the required components PR review. `ContentSize` isn't
    used by regular UI nodes, only those with intrinsically sized content
    that needs a measure func.

    ## Solution

    Remove `ContentSize` from `Node`'s required components and add it to the
    required components of `Text` and `UiImage`.

    ---------

    Co-authored-by: Alice Cecile <[email protected]>

commit c4c1c8f
Author: mgi388 <[email protected]>
Date:   Mon Oct 28 09:38:07 2024 +1100

    Undeprecate is_playing_animation (bevyengine#16121)

    # Objective

    - Fixes bevyengine#16098

    ## Solution

    - Undeprecate `is_playing_animation` and copy the docs from
    `animation_is_playing` to it.

    ## Testing

    - CI

    ## Migration

    https://github.com/bevyengine/bevy-website/blob/68e9a34e3068ed2e7db5ae0b4b32feac94a589dd/release-content/0.15/migration-guides/_guides.toml#L13-L17
    needs to be removed.

commit 3d72f49
Author: ickshonpe <[email protected]>
Date:   Sun Oct 27 20:08:51 2024 +0000

    Layout rounding debug example (bevyengine#16096)

    # Objective

    Simple example for debugging layout rounding errors.

    <img width="1039" height="752" alt="layout_rounding_debug"
    src="https://github.com/user-attachments/assets/12673000-e267-467e-b25b-3f8001c1347c">

    Any white lines are gaps in the layout caused by coordinate rounding
    errors.

commit 86ee8e4
Author: ickshonpe <[email protected]>
Date:   Sun Oct 27 19:14:46 2024 +0000

    Move `UiImage` from `ui_node` to the `widget::image` module (bevyengine#16084)

    # Objective

    `UiImage` isn't just a general image component now, it's the defining
    component for the image widget so it belongs in the image widget's
    module.

commit d01db9b
Author: Hexroll by Pen, Dice & Paper <[email protected]>
Date:   Sun Oct 27 19:08:34 2024 +0000

    Adding alpha_threshold to OrderIndependentTransparencySettings for user-level optimization (bevyengine#16090)

    # Objective

    Order independent transparency can filter fragment writes based on the
    alpha value and it is currently hard-coded to anything higher than 0.0.
    By making that value configurable, users can optimize fragment writes,
    potentially reducing the number of layers needed and improving
    performance in favor of some transparency quality.

    ## Solution

    This PR adds `alpha_threshold` to the
    OrderIndependentTransparencySettings component and uses the struct to
    configure a corresponding shader uniform. This uniform is then used
    instead of the hard-coded value.

    To configure OIT with a custom alpha threshold, use:

    ```rust
    fn setup(mut commands: Commands) {
        commands.spawn((
            Camera3d::default(),
            OrderIndependentTransparencySettings {
                layer_count: 8,
                alpha_threshold: 0.2,
            },
        ));
    }
    ```

    ## Testing

    I tested this change using the included OIT example, as well as with two
    additional projects.

    ## Migration Guide

    If you previously explicitly initialized
    OrderIndependentTransparencySettings with your own `layer_count`, you
    will now have to add either a `..default()` statement or an explicit
    `alpha_threshold` value:

    ```rust
    fn setup(mut commands: Commands) {
        commands.spawn((
            Camera3d::default(),
            OrderIndependentTransparencySettings {
                layer_count: 16,
                ..default()
            },
        ));
    }
    ```

    ---------

    Co-authored-by: JMS55 <[email protected]>

commit 3fc2bd7
Author: Rob Parrett <[email protected]>
Date:   Sun Oct 27 12:06:19 2024 -0700

    Cosmetic tweaks to `query_gltf_primitives` (bevyengine#16102)

    # Objective

    This example is really confusing to look at and tell at a glance whether
    it's broken or not.

    It's displaying a strange shape -- a cube with two vertices stretched in
    a couple dimensions at an odd angle, and doing its vertex position
    modification in a way where the intent isn't obvious.

    ## Solution

    - Change the gltf geometry so that the object is a recognizable regular
    shape
    - Change the vertex modification so that the entire cube top is being
    "lifted" from the cube
    - Adjust colors, lighting, and camera location so we can see what's
    going on
    - Also remove some irrelevant shadow and environment map setup

    ## Before

    ![Image](https://github.com/user-attachments/assets/e5dd5075-0480-49d4-b1ed-cf1fe6106f3c)

    ## After

    <img width="1280" alt="image"
    src="https://github.com/user-attachments/assets/59cab60d-efbc-47c3-8688-e4544b462421">

commit 7451900
Author: Miles Silberling-Cook <[email protected]>
Date:   Sun Oct 27 15:05:31 2024 -0400

    Emit picking event streams (bevyengine#16105)

    # Objective

    In `bevy_mod_picking` events are accessible through event listeners or
    `EventReader`s. When I replaced event listeners with observers, I
    removed the `EventReader` for simplicity. This adds it back.

    ## Solution

    All picking events are now properly registered, and can be accessed
    through `EventReader<Pointer<E>>`. `Pointer` now tracks the entity the
    event targeted initially, and this can also be helpful in observers
    (which don't currently do this).

    ## Testing

    The picking examples run fine. This shouldn't really change anything.

    ---------

    Co-authored-by: Aevyrie <[email protected]>

commit 54b323e
Author: Aevyrie <[email protected]>
Date:   Sun Oct 27 12:03:48 2024 -0700

    Mesh picking fixes (bevyengine#16110)

    # Objective

    - Mesh picking is noisy when a non triangle list is used
    - Mesh picking runs even when users don't need it
    - Resolve bevyengine#16065

    ## Solution

    - Don't add the mesh picking plugin by default
    - Remove error spam

commit a644ac7
Author: Tau Gärtli <[email protected]>
Date:   Sun Oct 27 20:01:50 2024 +0100

    More `#[doc(fake_variadic)]` goodness (bevyengine#16108)

    This PR adds `#[doc(fake_variadic)]` to that were previously not
    supported by rustdoc.

    Thanks to an [upstream
    contribution](rust-lang/rust#132115) by yours
    truly, `#[doc(fake_variadic)]` is now supported on impls such as `impl
    QueryData for AnyOf<(T, ...)>` 🎉
    Requires the latest nightly compiler (2024-10-25) which is already
    available on [docs.rs](https://docs.rs/about/builds).

    ![image](https://github.com/user-attachments/assets/68589c7e-f68f-44fb-9a7b-09d24ccf19c9)

    ![image](https://github.com/user-attachments/assets/f09d20d6-d89b-471b-9a81-4a72c8968178)

    This means that the impl sections for `QueryData` and `QueryFilter` are
    now nice and tidy ✨

    ---

    I also added `fake_variadic` to some impls that use
    `all_tuples_with_size`, however I'm not entirely happy because the docs
    are slightly misleading now:

    ![image](https://github.com/user-attachments/assets/fac93d08-dc02-430f-9f34-c97456256c56)

    Note that the docs say `IntoBindGroupLayoutEntryBuilderArray<1>` instead
    of
    `IntoBindGroupLayoutEntryBuilderArray<N>`.

commit 60b2c7c
Author: François Mockers <[email protected]>
Date:   Fri Oct 25 22:14:39 2024 +0200

    fix bevy_dev_tools build (bevyengine#16099)

    # Objective

    - bevy_dev_tools 0.15.0-rc.1 failed to build docs
    - it use bevy_text feature in bevy_ui but it's not enabled by default
    - https://docs.rs/crate/bevy_dev_tools/0.15.0-rc.1
    -
    ## Solution

    - enable bevy_text feature of bevy_ui

commit 7c59317
Author: BD103 <[email protected]>
Date:   Fri Oct 25 16:11:51 2024 -0400

    Fix `bevy_picking` plugin suffixes (bevyengine#16082)

    # Objective

    - `MeshPickingBackend` and `SpritePickingBackend` do not have the
    `Plugin` suffix
    - `DefaultPickingPlugins` is masquerading as a `Plugin` when in reality
    it should be a `PluginGroup`
    - Fixes bevyengine#16081.

    ## Solution

    - Rename some structures:

    |Original Name|New Name|
    |-|-|
    |`MeshPickingBackend`|`MeshPickingPlugin`|
    |`MeshPickingBackendSettings`|`MeshPickingSettings`|
    |`SpritePickingBackend`|`SpritePickingPlugin`|
    |`UiPickingBackendPlugin`|`UiPickingPlugin`|

    - Make `DefaultPickingPlugins` a `PluginGroup`.
    - Because `DefaultPickingPlugins` is within the `DefaultPlugins` plugin
    group, I also added support for nested plugin groups to the
    `plugin_group!` macro.

    ## Testing

    - I used ripgrep to ensure all references were properly renamed.
    - For the `plugin_group!` macro, I used `cargo expand` to manually
    inspect the expansion of `DefaultPlugins`.

    ---

    ## Migration Guide

    > [!NOTE]
    >
    > All 3 of the changed structures were added after 0.14, so this does
    not need to be included in the 0.14 to 0.15 migration guide.

    - `MeshPickingBackend` is now named `MeshPickingPlugin`.
    - `MeshPickingBackendSettings` is now named `MeshPickingSettings`.
    - `SpritePickingBackend` is now named `SpritePickingPlugin`.
    - `UiPickingBackendPlugin` is now named `UiPickingPlugin`.
    - `DefaultPickingPlugins` is now a a `PluginGroup` instead of a
    `Plugin`.

commit 611ba8b
Author: Ludwig DUBOS <[email protected]>
Date:   Fri Oct 25 22:08:14 2024 +0200

    Add `AsyncSeekForwardExt` trait to allows a similar API to the previous Bevy version (bevyengine#16027)

    # Objective

    This PR introduces an `AsyncSeekForwardExt` trait, which I forgot in my
    previous PR bevyengine#14194.

    This new trait is analogous to `AsyncSeekExt` and allows all
    implementors of `AsyncSeekForward` to directly use the `seek_forward`
    function in async contexts.

    ## Solution

    - Implement a new `AsyncSeekForwardExt` trait
    - Automatically implement this trait for all types that implement
    `AsyncSeekForward`

    ## Showcase

    This new trait allows a similar API to the previous Bevy version:

    ```rust
    #[derive(Default)]
    struct UniverseLoader;

    #[derive(Asset, TypePath, Debug)]
    struct JustALilAsteroid([u8; 128]);

    impl AssetLoader for UniverseLoader {
        type Asset = JustALilAsteroid;
        type Settings = ();
        type Error = std::io::Error;

        async fn load<'a>(
            &'a self,
            reader: &'a mut Reader<'a>,
            _settings: &'a Self::Settings,
            _context: &'a mut LoadContext<'_>,
        ) -> Result<Self::Asset, Self::Error> {
            // read the asteroids entry table
            let entry_offset: u64 = /* ... */;
            let current_offset: u64 = reader.seek_forward(0).await?;

            // jump to the entry
            reader.seek_forward(entry_offset - current_offset).await?;

            let mut asteroid_buf = [0; 128];
            reader.read_exact(&mut asteroid_buf).await?;

            Ok(JustALilAsteroid(asteroid_buf))
        }

        fn extensions(&self) -> &[&str] {
            &["celestial"]
        }
    }
    ```

commit c6a66a7
Author: Patrick Walton <[email protected]>
Date:   Thu Oct 24 14:16:00 2024 -0700

    Place percentage-closer soft shadows behind a feature gate to save on samplers. (bevyengine#16068)

    The two additional linear texture samplers that PCSS added caused us to
    blow past the limit on Apple Silicon macOS and WebGL. To fix the issue,
    this commit adds a `--feature pbr_pcss` feature gate that disables PCSS
    if not present.

    Closes bevyengine#15345.
    Closes bevyengine#15525.
    Closes bevyengine#15821.

    ---------

    Co-authored-by: Carter Anderson <[email protected]>
    Co-authored-by: IceSentry <[email protected]>

commit 897404e
Author: Patrick Walton <[email protected]>
Date:   Thu Oct 24 14:00:11 2024 -0700

    Reduce the clusterable object UBO size below 16384 for WebGL 2. (bevyengine#16069)

    The PCSS PR bevyengine#13497 increased the size of clusterable objects from 64
    bytes to 80 bytes but didn't decrease the UBO size to compensate, so we
    blew past the 16kB limit on WebGL 2. This commit fixes the issue by
    lowering the maximum number of clusterable objects to 204, which puts us
    under the 16kB limit again.

    Closes bevyengine#15998.

commit 9274bfe
Author: Carter Anderson <[email protected]>
Date:   Wed Oct 23 18:24:17 2024 -0500

    Move TextureAtlas into UiImage and remove impl Component for TextureAtlas (bevyengine#16072)

    # Objective

    Fixes bevyengine#16064

    ## Solution

    - Add TextureAtlas to `UiImage::texture_atlas`
    - Add `TextureAtlas::from_atlas_image` for parity with `Sprite`
    - Rename `UiImage::texture` to `UiImage::image` for parity with `Sprite`
    - Port relevant implementations and uses
    - Remove `derive(Component)` for `TextureAtlas`

    ---

    ## Migration Guide

    Before:
    ```rust
    commands.spawn((
      UiImage::new(image),
      TextureAtlas { index, layout },
    ));
    ```

    After:
    ```rust
    commands.spawn(UiImage::from_atlas_image(image, TextureAtlas { index, layout }));
    ```

    Before:
    ```rust
    commands.spawn(UiImage {
        texture: some_image,
        ..default()
    })
    ```

    After:
    ```rust
    commands.spawn(UiImage {
        image: some_image,
        ..default()
    })
    ```

commit 2cdad48
Author: Viktor Gustavsson <[email protected]>
Date:   Wed Oct 23 23:51:39 2024 +0200

    Ensure ghost nodes are skipped when getting parent clipping rect (bevyengine#16058)

    # Objective

    - Follow up on bevyengine#16044
    - `extract_uinode_borders` uses `bevy_hierarchy` directly instead of
    going through the traversal utilities, meaning it won't handle
    `GhostNode`s properly.

    ## Solution

    - Replaced the use of `bevy_hierarchy::Parent` with
    `UIChildren::get_parent`

    ## Testing

    - Ran the `overflow` example, clipping looks ok.

    ---

    ---------

    Co-authored-by: Carter Anderson <[email protected]>

commit c9a3f34
Author: ickshonpe <[email protected]>
Date:   Wed Oct 23 21:41:42 2024 +0100

    Fixes for a few minor borders and outlines bugs (bevyengine#16071)

    # Objective

    1. Nodes with `Display::None` set are removed from the layout and have
    no position or size. Outlines should not be drawn for a node with
    `Display::None` set.
    2. The outline and border colors are checked for transparency together.
    If only one of the two is transparent, both will get queued.
    3. The `node.is_empty()` check is insufficient to check if a border is
    present since a non-zero sized node can have a zero width border.

    ## Solution

    1. Add a check to `extract_uinode_borders` and ignore the node if
    `Display::None` is set.
    2. Filter the border and outline optional components by
    `is_fully_transparent`.
    3.  Check if all the border widths are zero instead.

    ## Testing

    I added dark cyan outlines around the left and right sections in the
    `display_and_visibility` example. If you run the example and set the
    outermost node to `Display::None` on the right, then you'll see the that
    the outline on the left disappears.

commit 7577895
Author: Carter Anderson <[email protected]>
Date:   Wed Oct 23 15:05:28 2024 -0500

    Use CosmicFontSystem in public bevy_text APIs and remove cosmic_text re-export (bevyengine#16063)

    # Objective

    Fixes bevyengine#16006

    ## Solution

    We currently re-export `cosmic_text`, which is seemingly motivated by
    the desire to use `cosmic_text::FontSystem` in `bevy_text` public APIs
    instead of our `CosmicFontSystem` resource wrapper type.

    This change makes `bevy_text` a "true" abstraction over `cosmic_text`
    (it in fact, was already built to be that way generally and has this one
    "leak").

    This allows us to remove the `cosmic_text` re-export, which helps clean
    up the Rust Analyzer imports and generally makes this a "cleaner" API.

commit 3fb6cef
Author: JMS55 <[email protected]>
Date:   Wed Oct 23 12:18:49 2024 -0700

    Meshlet fill cluster buffers rewritten (bevyengine#15955)

    # Objective
    - Make the meshlet fill cluster buffers pass slightly faster
    - Address bevyengine#15920 for meshlets
    - Added PreviousGlobalTransform as a required meshlet component to avoid
    extra archetype moves, slightly alleviating
    bevyengine#14681 for meshlets
    - Enforce that MeshletPlugin::cluster_buffer_slots is not greater than
    2^25 (glitches will occur otherwise). Technically this field controls
    post-lod/culling cluster count, and the issue is on pre-lod/culling
    cluster count, but it's still valid now, and in the future this will be
    more true.

    Needs to be merged after bevyengine#15846
    and bevyengine#15886

    ## Solution

    - Old pass dispatched a thread per cluster, and did a binary search over
    the instances to find which instance the cluster belongs to, and what
    meshlet index within the instance it is.
    - New pass dispatches a workgroup per instance, and has the workgroup
    loop over all meshlets in the instance in order to write out the cluster
    data.
    - Use a push constant instead of arrayLength to fix the linked bug
    - Remap 1d->2d dispatch for software raster only if actually needed to
    save on spawning excess workgroups

    ## Testing

    - Did you test these changes? If so, how?
    - Ran the meshlet example, and an example with 1041 instances of 32217
    meshlets per instance. Profiled the second scene with nsight, went from
    0.55ms -> 0.40ms. Small savings. We're pretty much VRAM bandwidth bound
    at this point.
    - How can other people (reviewers) test your changes? Is there anything
    specific they need to know?
      - Run the meshlet example

    ## Changelog (non-meshlets)
    - PreviousGlobalTransform now implements the Default trait

commit 6d42830
Author: JMS55 <[email protected]>
Date:   Wed Oct 23 09:56:50 2024 -0700

    Meshlet builder improvements redux (bevyengine#15886)

    Take a bunch more improvements from @zeux's nanite.cpp code.

    * Use position-only vertices (discard other attributes) to determine
    meshlet connectivity for grouping
    * Rather than using the lock borders flag when simplifying meshlet
    groups, provide the locked vertices ourselves. The lock borders flag
    locks the entire border of the meshlet group, but really we only want to
    lock the edges between meshlet groups - outwards facing edges are fine
    to unlock. This gives a really significant increase to the DAG quality.
    * Add back stuck meshlets (group has only a single meshlet,
    simplification failed) to the simplification queue to allow them to get
    used later on and have another attempt at simplifying
    * Target 8 meshlets per group instead of 4 (second biggest improvement
    after manual locks)
    * Provide a seed to metis for deterministic meshlet building
    * Misc other improvements

    We can remove the usage of unsafe after the next upstream meshopt
    release, but for now we need to use the ffi function directly. I'll do
    another round of improvements later, mainly attribute-aware
    simplification and using spatial weights for meshlet grouping.

    Need to merge bevyengine#15846 first.

commit 50d38f2
Author: akimakinai <[email protected]>
Date:   Wed Oct 23 08:29:58 2024 +0900

    Fix point light count limit (bevyengine#16062)

    # Objective

    - I made a mistake in bevyengine#15902, specifically [this
    diff](bevyengine@e2faedb)
    -- the `point_light_count` variable is used for all point lights, not
    just shadow mapped ones, so I cannot add `.min(max_texture_cubes)`
    there. (Despite `spot_light_count` having `.min(..)`)

    It may have broken code like this (where `index` is index of
    `point_light` vec):

    https://github.com/bevyengine/bevy/blob/9930df83ed42008f7eb2c02cc7350040f0250c2e/crates/bevy_pbr/src/render/light.rs#L848-L850

    and also causes panic here:

    https://github.com/bevyengine/bevy/blob/9930df83ed42008f7eb2c02cc7350040f0250c2e/crates/bevy_pbr/src/render/light.rs#L1173-L1174

    ## Solution

    - Adds `.min(max_texture_cubes)` directly to the loop where texture
    views for point lights are created.

    ## Testing

    - `lighting` example (with the directional light removed; original
    example doesn't crash as only 1 directional-or-spot light in total is
    shadow-mapped on webgl) no longer crashes on webgl

commit 2223f6e
Author: JMS55 <[email protected]>
Date:   Tue Oct 22 16:05:40 2024 -0700

    Meshlet fix software rasterization (bevyengine#16049)

    # Objective
    1. Prevent weird glitches with stray pixels scattered around the scene

    ![image](https://github.com/user-attachments/assets/f12adb38-5996-4dc7-bea6-bd326b7317e1)
    2. Prevent weird glitchy full-screen triangles that pop-up and destroy
    perf (SW rasterizing huge triangles is slow)

    ![image](https://github.com/user-attachments/assets/d3705427-13a5-47bc-a54b-756f0409da0b)

    ## Solution
    1. Use floating point math in the SW rasterizer bounding box calculation
    to handle negative verticss, and add backface culling
    2. Force hardware raster for clusters that clip the near plane, and let
    the hardware rasterizer handle the clipping

    I also adjusted the SW rasterizer threshold to < 64 pixels (little bit
    better perf in my test scene, but still need to do a more comprehensive
    test), and enabled backface culling for the hardware raster pipeline.

    ## Testing

    - Did you test these changes? If so, how?
      - Yes, on an example scene. Issues no longer occur.
    - Are there any parts that need more testing?
      - No.
    - How can other people (reviewers) test your changes? Is there anything
    specific they need to know?
      - Run the meshlet example.

commit fe4f44b
Author: François Mockers <[email protected]>
Date:   Wed Oct 23 00:37:04 2024 +0200

    crate publish order: bevy_animation depends on bevy_animation_derive (bevyengine#16060)

    # Objective

    - bevy_animation publication fails because of missed dependency
    - bevy_animation depends on bevy_animation_derive which is published
    after

    ## Solution

    - Reorder crates bevy_animation and bevy_animation_derive

commit fac0b34
Author: François Mockers <[email protected]>
Date:   Tue Oct 22 22:21:19 2024 +0200

    remove reference to missing file in bevy_remote cargo.toml (bevyengine#16057)

    # Objective

    - bevy_remote Cargo.toml file references a readme that doesn't exist
    - This is blocking releasing the rc

    ## Solution

    - Remove the reference

commit 9d54fe0
Author: JMS55 <[email protected]>
Date:   Tue Oct 22 13:14:30 2024 -0700

    Meshlet new error projection (bevyengine#15846)

    * New error projection code taken from @zeux's meshoptimizer nanite.cpp
    demo for determining LOD (thanks zeux!)
    * Builder: `compute_lod_group_data()`
    * Runtime: `lod_error_is_imperceptible()`

commit 9930df8
Author: ickshonpe <[email protected]>
Date:   Mon Oct 21 23:54:09 2024 +0100

    UI borders and outlines clipping fix (bevyengine#16044)

    # Objective

    fixes bevyengine#15502

    Clipped borders and outlines aren't drawn correctly.

    ### Borders aren't clipped

    Spawn two nodes with the same dimensions and border thickness, but clip
    on of the nodes so that only its top left quarter is visible:

    <img width="194" alt="clip"
    src="https://github.com/user-attachments/assets/2d3f6d28-aa20-44df-967a-677725828294">

    You can see that instead of clipping the border, instead the border is
    scaled to fit inside of the unclipped section.

    ```rust
    use bevy::color::palettes::css::BLUE;
    use bevy::prelude::*;
    use bevy::winit::WinitSettings;

    fn main() {
        App::new()
            .add_plugins(DefaultPlugins)
            .insert_resource(WinitSettings::desktop_app())
            .add_systems(Startup, setup)
            .run();
    }

    fn setup(mut commands: Commands) {
        commands.spawn(Camera2d);
        commands
            .spawn(Node {
                width: Val::Percent(100.),
                height: Val::Percent(100.),
                justify_content: JustifyContent::Center,
                align_items: AlignItems::Center,
                ..Default::default()
            })
            .with_children(|commands| {
                commands
                    .spawn(Node {
                        column_gap: Val::Px(10.),
                        ..Default::default()
                    })
                    .with_children(|commands| {
                        commands
                            .spawn(Node {
                                width: Val::Px(100.),
                                height: Val::Px(100.),
                                overflow: Overflow::clip(),
                                ..Default::default()
                            })
                            .with_child((
                                Node {
                                    position_type: PositionType::Absolute,
                                    width: Val::Px(100.),
                                    height: Val::Px(100.),
                                    border: UiRect::all(Val::Px(10.)),
                                    ..Default::default()
                                },
                                BackgroundColor(Color::WHITE),
                                BorderColor(BLUE.into()),
                            ));

                        commands
                            .spawn(Node {
                                width: Val::Px(50.),
                                height: Val::Px(50.),
                                overflow: Overflow::clip(),
                                ..Default::default()
                            })
                            .with_child((
                                Node {
                                    position_type: PositionType::Absolute,
                                    width: Val::Px(100.),
                                    height: Val::Px(100.),
                                    border: UiRect::all(Val::Px(10.)),
                                    ..Default::default()
                                },
                                BackgroundColor(Color::WHITE),
                                BorderColor(BLUE.into()),
                            ));
                    });
            });
    }
    ```

    You can also see this problem in the `overflow` example. If you hover
    over any of the clipped nodes you'll see that the outline only wraps the
    visible section of the node

    ### Outlines are clipped incorrectly

    A UI nodes Outline's are drawn outside of its bounds, so applying the
    local clipping rect to the outline doesn't make any sense.
    Instead an `Outline` should be clipped using its parent's clipping rect.

    ## Solution

    * Pass the `point` value into the vertex shader instead of calculating
    it in the shader.
    * In `extract_uinode_borders` use the parents clipping rect when
    clipping outlines.

    The extra parameter isn't a great solution I think, but I wanted to fix
    borders for the 0.15 release and this is the most minimal approach I
    could think of without replacing the whole shader and prepare function.

     ## Showcase

    <img width="149" alt="clipp"
    src="https://github.com/user-attachments/assets/19fbd3cc-e7cd-42e1-a5e0-fd92aad04dcd">

    ---------

    Co-authored-by: Alice Cecile <[email protected]>

commit d0af199
Author: Stepan Koltsov <[email protected]>
Date:   Mon Oct 21 16:57:52 2024 +0100

    Add a test for Mesh::triangles and fix for TriangleStrip (bevyengine#16026)

    # Objective

    - Illustrate behavior with a test
    - Fix a bug revealed by a test

    ## Solution

    - Add a test and fix

    ## Testing

    Test added.

commit 465d113
Author: Stepan Koltsov <[email protected]>
Date:   Mon Oct 21 03:17:59 2024 +0100

    Replace TwoIterators with Either in bevy_animation (bevyengine#16036)

    # Objective

    - Less code
    - Better iterator (implements `size_hint` for example)

    ## Solution

    - Use `either`
    - This change is free because `bevy_animation` depends on `bevy_asset`,
    which already depends on `either`

    ## Testing

    CI
coreh added a commit to coreh/bevy that referenced this pull request Dec 1, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Rendering Drawing game state to the screen C-Feature A new feature, making something new possible M-Needs-Release-Note Work that should be called out in the blog due to impact S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Percentage Closer Soft Shadows
8 participants