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

Retain RenderMaterialInstances and RenderMeshMaterialIds from frame to frame. #16878

Closed
wants to merge 30 commits into from

Conversation

pcwalton
Copy link
Contributor

This commit makes Bevy use change detection to only update RenderMaterialInstances and RenderMeshMaterialIds when meshes have been added, changed, or removed. extract_mesh_materials, the system that extracts these, now follows the pattern that
extract_meshes_for_gpu_building established.

This improves frame time of many_cubes from 3.9ms to approximately 3.1ms, which slightly surpasses the performance of Bevy 0.14.

Screenshot 2024-12-17 182109

@pcwalton pcwalton requested review from JMS55 and IceSentry December 18, 2024 02:22
@pcwalton pcwalton added A-Rendering Drawing game state to the screen S-Needs-Review Needs reviewer attention (from anyone!) to move forward C-Performance A change motivated by improving speed, memory usage or compile times labels Dec 18, 2024
@JMS55
Copy link
Contributor

JMS55 commented Dec 18, 2024

CI is failing

changed_meshes_query: Extract<
Query<
(Entity, &ViewVisibility, &MeshMaterial3d<M>),
Or<(Changed<ViewVisibility>, Changed<MeshMaterial3d<M>>)>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Question on this: MeshMaterial3d might not change, but the asset pointed to by its handle might change. Do we need to handle that here? I don't have the context of what extract is doing here anymore.

Copy link
Contributor Author

@pcwalton pcwalton Dec 18, 2024

Choose a reason for hiding this comment

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

We don't need to handle that here because the only thing extract_mesh_materials needs to do is to allocate within the slabs and store the resulting texture indices. If the material changes, then whatever textures (and other bindings) the material has will be updated in-place within the slabs, so the indices won't change, so this system doesn't need to do anything to handle that.

Copy link
Contributor

@tychedelia tychedelia left a comment

Choose a reason for hiding this comment

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

Would you mind updating extract_mesh_materials_2d as well to make sure these don't diverge too much?

@pcwalton
Copy link
Contributor Author

Maybe #16825 should land first, so we can make sure meshlets don't regress.

pcwalton and others added 21 commits December 25, 2024 00:56
to frame.

This commit makes Bevy use change detection to only update
`RenderMaterialInstances` and `RenderMeshMaterialIds` when meshes have
been added, changed, or removed. `extract_mesh_materials`, the system
that extracts these, now follows the pattern that
`extract_meshes_for_gpu_building` established.

This improves frame time of `many_cubes` from 3.9ms to approximately
3.1ms, which slightly surpasses the performance of Bevy 0.14.
# Objective

- To fix a tiny bug in `bevy_ecs::storage::Tables` that, in one case,
means it accidentally allocates an additional "empty" `Table`, resulting
in two "empty" `Table`s:
- The one pre-allocated empty table at index 0 whose index is designed
to match up with `TableId::empty()`
- One extra empty table, at some non-0 index, that does not match up
with `TableId::empty()`.
- This PR aims to prevent this extraneous `Table`, ensuring that
entities with no components in table-storage reliably have their
archetype's table ID be equal to `TableId::empty()`.

## Solution

### Background

The issue occurs because:

- `Tables` contains:
- `tables: Vec<Table>` - The set of all `Table`s allocated in the world.
- `table_ids: HashMap<Box<[ComponentId]>, TableId>` - An index to
rapidly lookup the `Table` in `tables` by a set of `ComponentId`s.
- When `Tables` is constructed it pre-populates the `tables` `Vec` with
an empty `Table`.
- This ensures that the first entry (index 0) is always the `Table` for
entities with no components in table storage.
- In particular, `TableId::empty()` is a utility that returns a
`TableId` of `0`.
- However, the `table_ids` map is not initialised to associate an empty
`[ComponentId]` with `TableId` `0`.
- This means, the first time a structural change tries to access a
`Table` for an archetype with 0 table components:
  - `Tables::get_id_or_insert` is used to retrieve the target `Table`
- The function attempts to lookup the entry in the `table_ids` `HashMap`
whose key is the empty `ComponentId` set
- The empty `Table` created at startup won't be found, because it was
never inserted into `table_ids`
- It will instead create a new table, insert it into the `HashMap`
(preventing further instances of this issue), and return it.

### Changes

- I considered simply initialising the `table_ids` `HashMap` to know
about the pre-allocated `Table`
- However, I ended up using the proposed solution discussed on Discord
[#ecs-dev](https://discord.com/channels/691052431525675048/749335865876021248/1320430933152759958):
- Make `Tables::get_id_or_insert` simply early-exit if the requested
`component_ids` was empty.
- This avoids unnecessarily hashing the empty slice and looking it up in
the `HashMap`.
- The `table_ids` `HashMap` is not exposed outside this struct, and is
only used within `get_id_or_insert`, so it seems wasteful to defensively
populate it with the empty `Table`.

## Testing

This is my first Bevy contribution, so I don't really know the processes
that well. That said:
- I have introduced a little test that exercises the original issue and
shows that it is now resolved.
- I have run the `bevy_ecs` tests locally, so I have reasonable
confidence I haven't broken that.
- I haven't run any further test suites, mostly as when I tried to run
test suites for the whole project it filled my entire SSD with >600GB of
target directory output 😱😱😱
Bumps [crate-ci/typos](https://github.com/crate-ci/typos) from 1.28.3 to
1.28.4.
<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.28.4</h2>
<h2>[1.28.4] - 2024-12-16</h2>
<h3>Features</h3>
<ul>
<li><code>--format sarif</code> support</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.28.4] - 2024-12-16</h2>
<h3>Features</h3>
<ul>
<li><code>--format sarif</code> support</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/crate-ci/typos/commit/9d890159570d5018df91fedfa40b4730cd4a81b1"><code>9d89015</code></a>
chore: Release</li>
<li><a
href="https://github.com/crate-ci/typos/commit/6b24563a993736342606b02dc6f98c7d86197fac"><code>6b24563</code></a>
chore: Release</li>
<li><a
href="https://github.com/crate-ci/typos/commit/bd0a2769ae8d608b6e8152aff91e91d7d2aad0f3"><code>bd0a276</code></a>
docs: Update changelog</li>
<li><a
href="https://github.com/crate-ci/typos/commit/370109dd4d88cfe9d647eb6cc9ed23e64cc75f8a"><code>370109d</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1047">#1047</a>
from Zxilly/sarif</li>
<li><a
href="https://github.com/crate-ci/typos/commit/63908449a70239a7719ed21f1caaca964c001470"><code>6390844</code></a>
feat: Implement sarif format reporter</li>
<li><a
href="https://github.com/crate-ci/typos/commit/32b96444b9239039a8977dc5fc82e46732b77844"><code>32b9644</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1169">#1169</a>
from klensy/deps</li>
<li><a
href="https://github.com/crate-ci/typos/commit/720258f60bee6e05a3307b2ef7e7574d9d19f2d9"><code>720258f</code></a>
Merge pull request <a
href="https://redirect.github.com/crate-ci/typos/issues/1176">#1176</a>
from Ghaniyyat05/master</li>
<li><a
href="https://github.com/crate-ci/typos/commit/a42904ad6e5d5533d2dc478538bf379b0189d20a"><code>a42904a</code></a>
Update README.md</li>
<li><a
href="https://github.com/crate-ci/typos/commit/0169b9b9e82ae338ebe6d8af6956ec3b6a3fcc9f"><code>0169b9b</code></a>
fix: Remove some unused deps</li>
<li>See full diff in <a
href="https://github.com/crate-ci/typos/compare/v1.28.3...v1.28.4">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.28.3&new-version=1.28.4)](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] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Revert the retry queue for stuck meshlet groups that couldn't simplify
added in bevyengine#15886.

It was a hack that didn't really work, that was intended to help solve
meshlets getting stuck and never getting simplified further. The actual
solution is a new DAG building algorithm that I have coming in a
followup PR. With that PR, there will be no need for the retry queue, as
meshlets will rarely ever get stuck (I checked, the code never gets
called). I split this off into it's own PR for easier reviewing.

Meshlet IDs during building are back to being relative to the overall
list of meshlets across all LODs, instead of starting at 0 for the first
meshlet in the simplification queue for the current LOD, regardless of
how many meshlets there are in the asset total.

Not going to bother to regenerate the bunny asset for this PR.
Noticed these were either incomplete or inconsistent, so I
fixed/augmented them.
# Objective

Fixes: bevyengine#16578

## Solution

This is a patch fix, proper fix requires a breaking change.

Added `Panic` enum variant and using is as the system meta default.
Warn once behavior can be enabled same way disabling panic (originally
disabling wans) is.

To fix an issue with the current architecture, where **all** combinator
system params get checked together,
combinator systems only check params of the first system.
This will result in old, panicking behavior on subsequent systems and
will be fixed in 0.16.

## Testing

Ran unit tests and `fallible_params` example.

---------

Co-authored-by: François Mockers <mockersf@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
We have to extract the material ID from the mesh and stuff it in the
vertex during visibility buffer resolution.
# Objective

Allow users to enable or disable layout rounding for specific UI nodes
and their descendants.

Fixes bevyengine#16731

## Solution

New component `LayoutConfig` that can be added to any UiNode entity.
Setting the `use_rounding` field of `LayoutConfig` determines if the
Node and its descendants should be given rounded or unrounded
coordinates.

## Testing

Not tested this extensively but it seems to work and it's not very
complicated.
This really basic test app returns fractional coords:

```rust
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .add_systems(Update, report)
        .run();
}

fn setup(mut commands: Commands) {
    commands.spawn(Camera2d);
    commands.spawn((
        Node {
            left: Val::Px(0.1),
            width: Val::Px(100.1),
            height: Val::Px(100.1),
            ..Default::default()
        },
        LayoutConfig { use_rounding: false },
    ));
}

fn report(node: Query<(Ref<ComputedNode>, &GlobalTransform)>) {
    for (c, g) in node.iter() {
        if c.is_changed() {
            println!("{:#?}", c);
            println!("position = {:?}", g.to_scale_rotation_translation().2);
        }
    }
}
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: UkoeHB <37489173+UkoeHB@users.noreply.github.com>
…vyengine#16910)

And add a bunch of tests to show that all the monotonic easing functions
have roughly the expected shape.

# Objective

The `EaseFunction::Exponential*` variants aren't actually smooth as
currently implemented, because they jump by about 1‰ at the
start/end/both.

- Fixes bevyengine#16676
- Subsumes bevyengine#16675

## Solution

This PR slightly tweaks the shifting and scaling of all three variants
to ensure they hit (0, 0) and (1, 1) exactly while gradually
transitioning between them.

Graph demonstration of the new easing function definitions:
<https://www.desmos.com/calculator/qoc5raus2z>

![desmos-graph](https://github.com/user-attachments/assets/c87e9fe5-47d9-4407-9c94-80135eef5908)
(Yes, they look completely identical to the previous ones at that scale.
[Here's a zoomed-in
comparison](https://www.desmos.com/calculator/ken6nk89of) between the
old and the new if you prefer.)

The approach taken was to keep the core 2¹⁰ᵗ shape, but to [ask
WolframAlpha](https://www.wolframalpha.com/input?i=solve+over+the+reals%3A+pow%282%2C+10-A%29+-+pow%282%2C+-A%29%3D+1)
what scaling factor to use such that f(1)-f(0)=1, then shift the curve
down so that goes from zero to one instead of ¹/₁₀₂₃ to ¹⁰²⁴/₁₀₂₃.

## Testing

I've included in this PR a bunch of general tests for all monotonic
easing functions to ensure they hit (0, 0) to (1, 1), that the InOut
functions hit (½, ½), and that they have the expected convexity.

You can also see by inspection that the difference is small. The change
for `exponential_in` is from `exp2(10 * t - 10)` to `exp2(10 * t -
9.99859…) - 0.0009775171…`.

The problem for `exponential_in(0)` is also simple to see without a
calculator: 2⁻¹⁰ is obviously not zero, but with the new definition
`exp2(-LOG2_1023) - FRAC_1_1023` => `1/(exp2(LOG2_1023)) - FRAC_1_1023`
=> `FRAC_1_1023 - FRAC_1_1023` => `0`.


---

## Migration Guide

This release of bevy slightly tweaked the definitions of
`EaseFunction::ExponentialIn`, `EaseFunction::ExponentialOut`, and
`EaseFunction::ExponentialInOut`. The previous definitions had small
discontinuities, while the new ones are slightly rescaled to be
continuous. For the output values that changed, that change was less
than 0.001, so visually you might not even notice the difference.

However, if you depended on them for determinism, you'll need to define
your own curves with the previous definitions.

---------

Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
# Objective

Some types like `RenderEntity` and `MainEntity` are just wrappers around
`Entity`, so they should be able to implement
`EntityBorrow`/`TrustedEntityBorrow`. This allows using them with
`EntitySet` functionality.
The `EntityRef` family are more than direct wrappers around `Entity`,
but can still benefit from being unique in a collection.

## Solution

Implement `EntityBorrow` and `TrustedEntityBorrow` for simple `Entity`
newtypes and `EntityRef` types.
These impls are an explicit decision to have the `EntityRef` types
compare like just `Entity`.
`EntityWorldMut` is omitted from this impl, because it explicitly
contains a `&mut World` as well, and we do not ever use more than one at
a time.

Add `EntityBorrow` to the `bevy_ecs` prelude.

## Migration Guide

`NormalizedWindowRef::entity` has been replaced with an
`EntityBorrow::entity` impl.
# Objective

This PR implements `FromStr` for `Val`, so developers can parse values
like `10px` and `50%`

## Testing

Added tests for this. I think they cover pretty much everything, and
it's a fairly simple unit test.

## Limitations

Currently the following float values are not parsed:
- `inf`, `-inf`, `+infinity`, `NaN`
- `2.5E10`, `2.5e10`, `2.5E-10`

For my use case this is perfectly fine but other developers might want
to support these values
…evyengine#16931)

# Objective

Now that `variadics_please` has a 1.1 release, we can re-implement the
original solution.

## Solution

Copy-paste the code from the [original
PR](bevyengine#15931) branch :)
… doesn't exist (bevyengine#16932)

Fixes a crash when using deferred rendering but disabling the default
deferred lighting plugin.

# The Issue
The `ScreenSpaceReflectionsPlugin` references
`NodePbr::DeferredLightingPass`, which hasn't been added when
`PbrPlugin::add_default_deferred_lighting_plugin` is `false`.

This yields the following crash:
```
thread 'main' panicked at /Users/marius/Documents/dev/bevy/crates/bevy_render/src/render_graph/graph.rs:155:26:
InvalidNode(DeferredLightingPass)
stack backtrace:
   0: rust_begin_unwind
             at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/std/src/panicking.rs:665:5
   1: core::panicking::panic_fmt
             at /rustc/90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf/library/core/src/panicking.rs:74:14
   2: bevy_render::render_graph::graph::RenderGraph::add_node_edges
             at /Users/marius/Documents/dev/bevy/crates/bevy_render/src/render_graph/graph.rs:155:26
   3: <bevy_app::sub_app::SubApp as bevy_render::render_graph::app::RenderGraphApp>::add_render_graph_edges
             at /Users/marius/Documents/dev/bevy/crates/bevy_render/src/render_graph/app.rs:66:13
   4: <bevy_pbr::ssr::ScreenSpaceReflectionsPlugin as bevy_app::plugin::Plugin>::finish
             at /Users/marius/Documents/dev/bevy/crates/bevy_pbr/src/ssr/mod.rs:234:9
   5: bevy_app::app::App::finish
             at /Users/marius/Documents/dev/bevy/crates/bevy_app/src/app.rs:255:13
   6: bevy_winit::state::winit_runner
             at /Users/marius/Documents/dev/bevy/crates/bevy_winit/src/state.rs:859:9
   7: core::ops::function::FnOnce::call_once
             at /Users/marius/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
   8: core::ops::function::FnOnce::call_once{{vtable.shim}}
             at /Users/marius/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
   9: <alloc::boxed::Box<F,A> as core::ops::function::FnOnce<Args>>::call_once
             at /Users/marius/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/alloc/src/boxed.rs:2454:9
  10: bevy_app::app::App::run
             at /Users/marius/Documents/dev/bevy/crates/bevy_app/src/app.rs:184:9
  11: bevy_deferred_test::main
             at ./src/main.rs:9:5
  12: core::ops::function::FnOnce::call_once
             at /Users/marius/.rustup/toolchains/stable-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/ops/function.rs:250:5
```


### Minimal reproduction example:
```rust
use bevy::core_pipeline::prepass::{DeferredPrepass, DepthPrepass};
use bevy::pbr::{DefaultOpaqueRendererMethod, PbrPlugin, ScreenSpaceReflections};
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins.set(PbrPlugin {
            add_default_deferred_lighting_plugin: false,
            ..default()
        }))
        .add_systems(Startup, setup)
        .insert_resource(DefaultOpaqueRendererMethod::deferred())
        .run();
}

/// set up a camera
fn setup(
    mut commands: Commands
) {
    // camera
    commands.spawn((
        Camera3d::default(),
        Transform::from_xyz(-2.5, 4.5, 9.0).looking_at(Vec3::ZERO, Vec3::Y),
        DepthPrepass,
        DeferredPrepass,
        ScreenSpaceReflections::default(),
    ));
}
```

# The Fix
When no node under the default lighting node's label exists, this label
isn't added to the SSR's graph node edges. It's good to keep the
SSRPlugin enabled, this way, users can plug in their own lighting
system, which I have successfully done on top of this PR.

# Workarounds

A current workaround for this issue is to re-use Bevy's
`NodePbr::DeferredLightingPass` as the label for your own custom
lighting pass node.
This PR simply exposes Bevy PBR's
`TONEMAPPING_LUT_TEXTURE_BINDING_INDEX` and
`TONEMAPPING_LUT_SAMPLER_BINDING_INDEX`.

# Objective 
Alongside bevyengine#16932, this is the last required change to be able to replace
Bevy's built-in deferred lighting pass with a custom one based on the
original logic.
…bevyengine#16936)

## Objective

I believe these started as structs, back when that was how commands had
to be implemented. Now they just hide implementation details.

## Solution

Remove the helper functions and move each implementation into its
respective method, except for the ones that actually reduce code
duplication.
)

# Objective

bevy_reflect is a big part of bevy_math's dependency footprint, and is
often not useful when using bevy_math standalone (as I often do). The
goal with this PR is to avoid pulling in those dependencies by default
without compromising the usability of bevy_math types within Bevy
proper.

## Solution

`bevy_reflect` has been removed from default features of `bevy_math`.
However, the feature is enabled by `bevy_internal`, so that
`bevy_reflect` is enabled when `bevy_math` is used through `bevy`.

Philosophically, if there were a feature flag toggling reflection on
`bevy` globally, then whether `bevy_math` enabled `bevy_reflect` itself
would depend on that, but that doesn't exist for the time being.

## Testing

It compiles :)

## Migration Guide

`bevy_reflect` has been made a non-default feature of `bevy_math`. (It
is still enabled when `bevy_math` is used through `bevy`.) You may need
to enable this feature if you are using `bevy_math` on its own and
desire for the types it exports to implement `Reflect` and other
reflection traits.
# Objective

- Fixes bevyengine#16563 
- Make sure bevy_image is available when needed

## Solution

- Add a new feature for `bevy_image`
- Also enable the `bevy_image` feature in `bevy_internal` for all
features that use `bevy_image` themselves
# Objective

- Fixes bevyengine#16568 

## Solution

- `bevy_winit` feature also enables `bevy_window`
# Objective

- Fixes bevyengine#16571

## Solution

- When position delta is zero, don't trigger `Drag` or `DragOver` events

## Testing

- tested with the code from the issue
# Objective
`SubApps` is visible within the documentation for `bevy_app`. However,
no way of accessing the `SubApps` field in `App` is currently available.

## Solution
Expose two new functions, `App::sub_apps()` and `App::sub_apps_mut()`,
which give immutable and mutable access to `SubApps` respectively.

The other solution is to hide `SubApps`, which I submitted as a PR at
<bevyengine#16953>.

## Testing
Because of the simplicity of the changes, I only tested by compiling
`bevy_app` - which compiled successfully.

Note: `SubApps`, and its corresponding field on `App`, are not used
outside of `bevy_app` - which means that compiling the other crates is
not necessary.
alice-i-cecile and others added 8 commits December 25, 2024 00:56
# Objective

With the introduction of bevy_input_focus, the uses of "focus" in
bevy_picking are quite confusing and make searching hard.

Users will intuitively think these concepts are related, but they
actually aren't.

## Solution

Rename / rephrase all uses of "focus" in bevy_picking to refer to
"hover", since this is ultimately related to creating the `HoverMap`.

## Migration Guide

Various terms related to "focus" in `bevy_picking` have been renamed to
refer to "hover" to avoid confusion with `bevy_input_focus`. In
particular:

- The `update_focus` system has been renamed to `generate_hovermap`
- `PickSet::Focus` and `PostFocus` have been renamed to `Hover` and
`PostHover`
- The `bevy_picking::focus` module has been renamed to
`bevy_picking::hover`
- The `is_focus_enabled` field on `PickingPlugin` has been renamed to
`is_hover_enabled`
- The `focus_should_run` run condition has been renamed to
`hover_should_run`
# Summary 

- I started experimenting if `TextureAtlas` and friends can be moved to
`bevy_image`. See
[Discord](https://discord.com/channels/691052431525675048/692572690833473578/1320176054911897642)
thread.
- While doing that, and moving `DynamicTextureAtlasBuilder` to
`bevy_image`, it revealed that `DynamicTextureAtlasBuilder` depends on
`bevy_render::GpuImage`, but we can't have `bevy_image` depend on
`bevy_render`.
- The reason for the dependency is an assertion introduced in [this
PR](https://github.com/bevyengine/bevy/pull/12827/files?show-viewed-files=true&file-filters%5B%5D=#diff-d9afd2170466f4aae340b244bdaa2a80aef58e979268c003878ca6c95860eb37R59).
- [It doesn't seem like there was a specific reason for that
change](https://discord.com/channels/691052431525675048/743663924229963868/1320506862067650580),
so should be safe to change it.
- So instead of the cast, just look up `asset_usage` directly on the
concrete `Image` type.
- Also update the message which referred to a non-existent variable
`atlas_texture_handle` (it was renamed during a subsequent refactor PR).

# Testing

- Checked on Discord if there was any known reason this had to stay like
this.
- CI builds it.
…ne#16957)

# Objective

Almost all of the `*InOut` easing functions are not actually smooth
(`SineInOut` is the one exception).

Because they're defined piecewise, they jump from accelerating upwards
to accelerating downwards, causing infinite jerk at t=½.

## Solution

This PR adds the well-known
[smoothstep](https://registry.khronos.org/OpenGL-Refpages/gl4/html/smoothstep.xhtml),
as well as its higher-degree version
[smootherstep](https://en.wikipedia.org/wiki/Smoothstep#Variations), as
easing functions.

Mathematically, these are the classic [Hermite
interpolation](https://en.wikipedia.org/wiki/Hermite_interpolation)
results:
- for smoothstep, the cubic with velocity zero at both ends
- for smootherstep, the quintic with velocity zero *and acceleration
zero* at both ends

And because they're simple polynomials, there's no branching and thus
they don't have the acceleration jump in the middle.

I also added some more information and cross-linking to the
documentation for these and some of the other easing functions, to help
clarify why one might want to use these over other existing ones. In
particular, I suspect that if people are willing to pay for a quintic
they might prefer `SmootherStep` to `QuinticInOut`.

For consistency with how everything else has triples, I added
`Smooth(er)Step{In,Out}` as well, in case people want to run the `In`
and `Out` versions separately for some reason. Qualitatively they're not
hugely different from `Quadratic{In,Out}` or `Cubic{In,Out}`, though, so
could be removed if you'd rather. They're low cost to keep, though, and
convenient for testing.

## Testing

These are simple polynomials, so their coefficients can be read directly
from the Horner's method implementation and compared to the reference
materials. The tests from bevyengine#16910 were updated to also test these 6 new
easing functions, ensuring basic behaviour, plus one was updated to
better check that the InOut versions of things match their rescaled In
and Out versions.

Even small changes like
```diff
-    (((2.5 + (-1.875 + 0.375*t) * t) * t) * t) * t
+    (((2.5 + (-1.85 + 0.375*t) * t) * t) * t) * t
```
are caught by multiple tests this way.

If you want to confirm them visually, here are the 6 new ones graphed:
<https://www.desmos.com/calculator/2d3ofujhry>

![smooth-and-smoother-step](https://github.com/user-attachments/assets/a114530e-e55f-4b6a-85e7-86e7abf51482)

---

## Migration Guide

This version of bevy marks `EaseFunction` as `#[non_exhaustive]` to that
future changes to add more easing functions will be non-breaking. If you
were exhaustively matching that enum -- which you probably weren't --
you'll need to add a catch-all (`_ =>`) arm to cover unknown easing
functions.
# Objective

- To fix the benches panicking on `main`

## Solution

- It appears that systems requiring access to a non-existing `Res` now
causes a panic
- Some of the benches run systems that access resources that have not
been inserted into the world
- I have made it so that those resources are inserted into the world

## Testing

- I ran all the ecs benches and they all run without panicking

Co-authored-by: Oliver Maskery <oliver@wellplayed.games>
# Objective

Make it so that users can ease between tuples of easeable values. 

## Solution

Use `variadics_please`'s `all_tuples_enumerated` macro to generate code
that creates these trait implementations. For two elements, the result
looks like this:
```rust
impl<T0: Ease, T1: Ease> Ease for (T0, T1) {
    fn interpolating_curve_unbounded(start: Self, end: Self) -> impl Curve<Self> {
        let curve_tuple = (
            <T0 as Ease>::interpolating_curve_unbounded(start.0, end.0),
            <T1 as Ease>::interpolating_curve_unbounded(start.1, end.1),
        );
        FunctionCurve::new(Interval::EVERYWHERE, move |t| {
            (
                curve_tuple.0.sample_unchecked(t),
                curve_tuple.1.sample_unchecked(t),
            )
        })
    }
}
```

## Testing

It compiles, and I futzed about with some manual examples, which seem to
work as expected.

---

## Showcase

Easing curves now support easing tuples of values that can themselves be
eased. For example:
```rust
// Easing between two `(Vec3, Quat)` values:
let easing_curve = EasingCurve::new(
    (vec3(0.0, 0.0, 0.0), Quat::from_rotation_z(-FRAC_PI_2)),
    (vec3(1.0, 1.0, 1.0), Quat::from_rotation_z(FRAC_PI_2)),
    EaseFunction::ExponentialInOut
);
```
# Objective

Fixes bevyengine#16850

## Solution

Add a new function `SubApp::take_extract()`, similar to
`Option::take()`, which allows stealing the currently installed extract
function of a sub-app, with the intent to replace it with a custom one
calling the original one via `set_extract()`.

This pattern enables registering a custom "world sync" function similar
to the existing one `entity_sync_system()`, to run custom world sync
logic with mutable access to both the main and render worlds.

## Testing

`cargo r -p ci` currently doesn't build locally, event after upgrading
rustc to latest and doing a `cargo update`.
@pcwalton pcwalton force-pushed the retained-mesh-materials branch from 4e30455 to 08ee2a9 Compare December 25, 2024 06:00
@pcwalton
Copy link
Contributor Author

I don't know what happened to this branch, but I needed to force-push to fix it, sorry.

@pcwalton
Copy link
Contributor Author

@tychedelia Done

@pcwalton pcwalton requested review from tychedelia and JMS55 December 25, 2024 06:23
@pcwalton
Copy link
Contributor Author

I'm going to close and resubmit this so that the commit history is cleaned up.

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-Performance A change motivated by improving speed, memory usage or compile times S-Needs-Review Needs reviewer attention (from anyone!) to move forward
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.