Commit graph

5081 commits

Author SHA1 Message Date
Daniel Miller
692840274f
Added AstcBlock and AstcChannel to the forwarded wgpu types. (#14410)
Currently `TextureFormat::Astc` can't be programmatically constructed
without importing wgpu in addition to bevy.

# Objective

Allow programmatic construction of `TextureFormat::Astc` with no
additional imports required.

## Solution

Exported the two component enums `AstcBlock` and `AstcChannel` used in
`TextureFormat::Astc` construction.

## Testing

I did not test this, the change seemed pretty safe. :)
2024-07-22 19:14:14 +00:00
Sebastian J. Hamel
d88be59f92
feat: expose the default font bytes (#14406)
# Objective

- Enables use cases where third-party crates would want to use the
default font as well [see linebender's
use](https://github.com/linebender/bevy_vello/pull/66)

## Solution

- Uses `include_bytes` macro and make it `pub`

---------

Co-authored-by: Spencer C. Imbleau <spencer@imbleau.com>
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
2024-07-22 19:09:39 +00:00
John
d1f4262d7d
Only propagate transforms entities with GlobalTransforms. (#14384)
# Objective
Fixes a performance issue when you have 1000s of entities in a bevy
hierarchy without transforms.

This was prominently happening in `bevy_ecs_tilemap`.

## Solution

Filter out entities that don't have a global transform.

## Testing

CI
We should test some other way...

## Migration Guide

- To avoid surprising performance pitfalls, `Transform` /
`GlobalTransform` propagation is no longer performed down through
hierarchies where intermediate parent are missing a `GlobalTransform`.
To restore the previous behavior, add `GlobalTransform::default` to
intermediate entities.
2024-07-22 19:07:21 +00:00
Coder-Joe458
8f5345573c
Remove manual --cfg docsrs (#14376)
# Objective

- Fixes #14132 

## Solution

- Remove the cfg docsrs
2024-07-22 18:58:04 +00:00
Patrick Walton
d235d41af1
Fix the example regressions from packed growable buffers. (#14375)
The "uberbuffers" PR #14257 caused some examples to fail intermittently
for different reasons:

1. `morph_targets` could fail because vertex displacements for morph
targets are keyed off the vertex index. With buffer packing, the vertex
index can vary based on the position in the buffer, which caused the
morph targets to be potentially incorrect. The solution is to include
the first vertex index with the `MeshUniform` (and `MeshInputUniform` if
GPU preprocessing is in use), so that the shader can calculate the true
vertex index before performing the morph operation. This results in
wasted space in `MeshUniform`, which is unfortunate, but we'll soon be
filling in the padding with the ID of the material when bindless
textures land, so this had to happen sooner or later anyhow.

Including the vertex index in the `MeshInputUniform` caused an ordering
problem. The `MeshInputUniform` was created during the extraction phase,
before the allocations occurred, so the extraction logic didn't know
where the mesh vertex data was going to end up. The solution is to move
the `MeshInputUniform` creation (the `collect_meshes_for_gpu_building`
system) to after the allocations phase. This should be better for
parallelism anyhow, because it allows the extraction phase to finish
quicker. It's also something we'll have to do for bindless in any event.

2. The `lines` and `fog_volumes` examples could fail because their
custom drawing nodes weren't updated to supply the vertex and index
offsets in their `draw_indexed` and `draw` calls. This commit fixes this
oversight.

Fixes #14366.
2024-07-22 18:55:51 +00:00
Rostyslav Toch
d30391b583
Optimize transform propagation (#14373)
# Objective

- Optimize the `propagate_recursive` function in the transform system to
reduce CPU usage.
- Addresses performance bottleneck in transform propagation, especially
for scenes with complex hierarchies.

## Solution

- Avoided unnecessary cloning of `global_transform` when creating the
tuple in the `propagate_recursive` function.
- Used `as_ref()` method on `Mut<GlobalTransform>` when passing it to
the recursive call, avoiding an extra dereference.
- These changes significantly reduced the CPU usage of this function
from 4.91% to 1.16% of self function time.

## Testing

- Performance testing was conducted using the Hotspot GUI tool,
comparing CPU usage before and after the changes.
- `cargo run --release --example many_foxes`
- Tested on Fedora Linux.
---

## Showcase

Here are the PERF GUI results showing the improvement in CPU usage:

### Before

![image](https://github.com/user-attachments/assets/b5c52800-710b-4793-bf75-33e3eb1d2083)

### After

![image](https://github.com/user-attachments/assets/654a4feb-924c-41c8-8ff9-3a1027bd28b9)

As we can see, the CPU usage for the `propagate_recursive` function has
been reduced from 4.91% to 1.16%, resulting in a significant performance
improvement.

## Migration Guide

This change does not introduce any breaking changes. Users of the Bevy
engine will automatically benefit from this performance improvement
without needing to modify their code.
2024-07-22 18:53:16 +00:00
Sludge
4ea8c66321
Unignore Camera.target field for reflection (#14367)
# Objective

- The `RenderTarget` type wasn't being registered, and the `target`
field of `Camera` was marked as ignored, so it wasn't inspectable by
editors.

## Solution

- Remove `#[reflect(ignore)]` from the field
- I've also reordered the `Default` impl of `RenderTarget` because it
looked like it belonged to a different type
2024-07-22 18:46:40 +00:00
Al M.
e06f4d4083
Fix single keyframe animations. (#14344)
# Objective

For clips with more than one curve, only the first was being applied if
there is only one keyframe in it.

## Solution

Continue!
2024-07-22 18:44:27 +00:00
IQuick 143
420f7f72dc
Fast renormalize (#14316)
# Objective

- Addresses part of #14302 .

## Solution

- Add a fast_remormalize method to Dir2/Dir3/Dir3A and Rot2.

## Testing

- Added tests too

---------

Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-07-22 18:42:48 +00:00
charlotte
03fd1b46ef
Move Msaa to component (#14273)
Switches `Msaa` from being a globally configured resource to a per
camera view component.

Closes #7194

# Objective

Allow individual views to describe their own MSAA settings. For example,
when rendering to different windows or to different parts of the same
view.

## Solution

Make `Msaa` a component that is required on all camera bundles.

## Testing

Ran a variety of examples to ensure that nothing broke.

TODO:
- [ ] Make sure android still works per previous comment in
`extract_windows`.

---

## Migration Guide

`Msaa` is no longer configured as a global resource, and should be
specified on each spawned camera if a non-default setting is desired.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-07-22 18:28:23 +00:00
Sou1gh0st
462da1e49d
Fix incorrect function calls to hsv_to_rgb in render debug code. (#14260)
# Objective

- Fixes https://github.com/bevyengine/bevy/issues/14139

## Solution

- correct the input parameters at these call sites.

## Testing

1. Use a 3D scene example with PBR lighting and shadows enabled, such as
the `shadow_caster_receiver` and `load_gltf` example, for testing.
2. Enable relevant shader defines in crates/bevy_pbr/src/pbr_material.rs
for the StandardMaterial.
```rust
impl Material for StandardMaterial {
    // ...
    fn specialize(
            _pipeline: &MaterialPipeline<Self>,
            descriptor: &mut RenderPipelineDescriptor,
            _layout: &MeshVertexBufferLayoutRef,
            key: MaterialPipelineKey<Self>,
        ) -> Result<(), SpecializedMeshPipelineError> {
            // ...
            // shader_defs.push("CLUSTERED_FORWARD_DEBUG_Z_SLICES".into());
            // shader_defs.push("CLUSTERED_FORWARD_DEBUG_CLUSTER_COHERENCY".into());
            shader_defs.push("DIRECTIONAL_LIGHT_SHADOW_MAP_DEBUG_CASCADES".into());
            // ...
    }
}
``` 

## Showcase
### CLUSTERED_FORWARD_DEBUG_Z_SLICES
- example: examples/3d/shadow_caster_receiver.rs

![Screenshot2024_07_10_143150](https://github.com/bevyengine/bevy/assets/6300263/fbd12712-5cb9-489d-a7d1-ed55f72fb234)

### CLUSTERED_FORWARD_DEBUG_CLUSTER_COHERENCY
- example: examples/3d/shadow_caster_receiver.rs

![Screenshot2024_07_10_143312](https://github.com/bevyengine/bevy/assets/6300263/8eca5d7a-27b6-4ff5-9f8d-d10b49b3f990)

### DIRECTIONAL_LIGHT_SHADOW_MAP_DEBUG_CASCADES
For this one, we need to use a large scene and modity the
`CascadeShadowConfigBuilder`, here is a simple patch for the `load_gltf`
example:
```
diff --git a/examples/3d/load_gltf.rs b/examples/3d/load_gltf.rs
index 358446238..9403aa288 100644
--- a/examples/3d/load_gltf.rs
+++ b/examples/3d/load_gltf.rs
@@ -18,7 +18,7 @@ fn main() {
 fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
     commands.spawn((
         Camera3dBundle {
-            transform: Transform::from_xyz(0.7, 0.7, 1.0)
+            transform: Transform::from_xyz(0.7, 0.7, 2.0)
                 .looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y),
             ..default()
         },
@@ -39,30 +39,40 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
         // We also adjusted the shadow map to be larger since we're
         // only using a single cascade.
         cascade_shadow_config: CascadeShadowConfigBuilder {
-            num_cascades: 1,
-            maximum_distance: 1.6,
+            num_cascades: 5,
+            maximum_distance: 20.0,
             ..default()
         }
         .into(),
         ..default()
     });
+
     commands.spawn(SceneBundle {
         scene: asset_server
             .load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
         ..default()
     });
+
+    for i in 1..=10 {
+        commands.spawn(SceneBundle {
+            scene: asset_server
+                .load(GltfAssetLabel::Scene(0).from_asset("models/FlightHelmet/FlightHelmet.gltf")),
+            transform: Transform::from_xyz(i as f32 * 0.5, 0.0, i as f32 * -2.0),
+            ..default()
+        });
+    }
 }
 
 fn animate_light_direction(
     time: Res<Time>,
     mut query: Query<&mut Transform, With<DirectionalLight>>,
 ) {
-    for mut transform in &mut query {
-        transform.rotation = Quat::from_euler(
-            EulerRot::ZYX,
-            0.0,
-            time.elapsed_seconds() * PI / 5.0,
-            -FRAC_PI_4,
-        );
-    }
+    // for mut transform in &mut query {
+    //     transform.rotation = Quat::from_euler(
+    //         EulerRot::ZYX,
+    //         0.0,
+    //         time.elapsed_seconds() * PI / 5.0,
+    //         -FRAC_PI_4,
+    //     );
+    // }
 }
``` 

![Screenshot2024_07_10_145737](https://github.com/bevyengine/bevy/assets/6300263/c5c71894-f9f7-45fa-9b4f-598e324b42d0)

---------

Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2024-07-22 18:25:54 +00:00
Peter Hayman
b8416b3043
Add some missing reflect attributes (#14259)
# Objective

- Some types are missing reflection attributes, which means we can't use
them in scene serialization etc.
- Effected types
   - `BorderRadius`
   - `AnimationTransitions`
   - `OnAdd`
   - `OnInsert`
   - `OnRemove`
- My use-case for `OnAdd` etc to derive reflect is 'Serializable
Observer Components'. Add the component, save the scene, then the
observer is re-added on scene load.

```rust
#[derive(Reflect)]
struct MySerializeableObserver<T: Event>(#[reflect(ignore)]PhantomData<T>);

impl<T: Event> Component for MySerializeableObserver<T> {
  const STORAGE_TYPE: StorageType  = StorageType::Table;
    fn register_component_hooks(hooks: &mut ComponentHooks) {
      hooks.on_add(|mut world, entity, _| {
        world
          .commands()
          .entity(entity)
          .observe(|_trigger: Trigger<T>| {
            println!("it triggered etc.");
          });
    });
  }
}
```

## Solution

- Add the missing traits

---
2024-07-22 18:24:10 +00:00
ickshonpe
453e0e4fc1
Prevent division by zero in HWBA to HSVA conversions (#14256)
# Problem

Division by zero in `crates/bevy_color/src/hsva.rs` when `blackness` is
`1`:

```rust
impl From<Hwba> for Hsva {
    fn from(
        Hwba {
            hue,
            whiteness,
            blackness,
            alpha,
        }: Hwba,
    ) -> Self {
        // Based on https://en.wikipedia.org/wiki/HWB_color_model#Conversion
        let value = 1. - blackness;
        let saturation = 1. - (whiteness / value);

        Hsva::new(hue, saturation, value, alpha)
    }
}
```

## Solution
With `Hsva` colors if the `value` component is set to `0.` the output
will be pure black regardless of the values of the `hue` or `saturation`
components.

So if `value` is `0`, we don't need to calculate a `saturation` value
and can just set it to `0`:

```rust
impl From<Hwba> for Hsva {
    fn from(
        Hwba {
            hue,
            whiteness,
            blackness,
            alpha,
        }: Hwba,
    ) -> Self {
        // Based on https://en.wikipedia.org/wiki/HWB_color_model#Conversion
        let value = 1. - blackness;
        let saturation = if value != 0. {
            1. - (whiteness / value)
        } else {
            0.
        };

        Hsva::new(hue, saturation, value, alpha)
    }
}

```

---------

Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
2024-07-22 18:22:26 +00:00
Vic
bc36b4e561
implement DoubleEndedIterator for QueryManyIter (#14128)
# Objective

We currently cannot iterate from the back of `QueryManyIter`.

## Solution

Implement `DoubleEndedIterator` for `QueryManyIter` and add a
`fetch_next_back` method. These impls are bounded on the underlying
`entity_iter` implementing `DoubleEndedIterator`.

## Changelog

Added `DoubleEndedIterator` implementation for `QueryManyIter`.
Added the `fetch_next_back` method to `QueryManyIter`.
2024-07-22 18:21:42 +00:00
charlotte
08d3497d87
Fix breaking image 0.25.2 release. (#14421)
Deprecated item breaking ci:
https://github.com/image-rs/image/releases/tag/v0.25.2. See
https://github.com/bevyengine/bevy/actions/runs/10030764981/job/27720434072?pr=14419
for example.
2024-07-21 21:27:07 +00:00
Sunil Thunga
2158f3d91f
Using Cas instead of CAS #14341 (#14357)
# Objective

- Replacing CAS with Cas in CASPlugin
- Closes #14341

## Solution

- Simple replace

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Co-authored-by: François Mockers <mockersf@gmail.com>
2024-07-20 18:12:24 +00:00
François Mockers
c0b35d07f3
fix building cargo_gltf with feature dds (#14360)
# Objective

- Building bevy_gltf with feature dds fails:
```
> cargo build -p bevy_gltf --features dds
   Compiling bevy_core_pipeline v0.15.0-dev (crates/bevy_core_pipeline)
error[E0061]: this function takes 7 arguments but 6 arguments were supplied
   --> crates/bevy_core_pipeline/src/tonemapping/mod.rs:442:5
    |
442 |     Image::from_buffer(
    |     ^^^^^^^^^^^^^^^^^^
...
445 |         bytes,
    |         ----- an argument of type `std::string::String` is missing
    |
note: associated function defined here
   --> crates/bevy_render/src/texture/image.rs:709:12
    |
709 |     pub fn from_buffer(
    |            ^^^^^^^^^^^
help: provide the argument
    |
442 |     Image::from_buffer(/* std::string::String */, bytes, image_type, CompressedImageFormats::NONE, false, image_sampler, RenderAssetUsages::RENDER_WORLD)
    |                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For more information about this error, try `rustc --explain E0061`.
error: could not compile `bevy_core_pipeline` (lib) due to 1 previous error
```
- If you're fixing a specific issue, say "Fixes #X".

## Solution

- enable dds feature in bevy_core_pipeline

## Testing

- `cargo build -p bevy_gltf --features dds`
2024-07-20 17:55:25 +00:00
charlotte
3aa525885b
Set scissor on upscale to match camera viewport (#14287)
# Objective

When the user renders multiple cameras to the same output texture, it
can sometimes be confusing what `ClearColorConfig` is necessary for each
camera to avoid overwriting the previous camera's output. This is
particular true in cases where the user uses mixed HDR cameras, which
means that their scene is being rendered to different internal textures.

## Solution

When a view has a configured viewport, set the GPU scissor in the
upscaling node so we don't overwrite areas that were written to by other
cameras.

## Testing

Ran the `split_screen` example.
2024-07-20 16:45:04 +00:00
Sludge
c0cebfef45
Make Viewport::default() return a 1x1 viewport (#14372)
# Objective

- The current default viewport crashes bevy due to a wgpu validation
error, this PR fixes that
- Fixes https://github.com/bevyengine/bevy/issues/14355

## Solution

- `Viewport::default()` now returns a 1x1 viewport

## Testing

- I modified the `3d_viewport_to_world` example to use
`Viewport::default()`, and it works as expected (only the top-left pixel
is rendered)
2024-07-20 14:18:12 +00:00
Sou1gh0st
9da18cce2a
Add support for environment map transformation (#14290)
# Objective

- Fixes: https://github.com/bevyengine/bevy/issues/14036

## Solution

- Add a world space transformation for the environment sample direction.

## Testing

- I have tested the newly added `transform` field using the newly added
`rotate_environment_map` example.


https://github.com/user-attachments/assets/2de77c65-14bc-48ee-b76a-fb4e9782dbdb


## Migration Guide

- Since we have added a new filed to the `EnvironmentMapLight` struct,
users will need to include `..default()` or some rotation value in their
initialization code.
2024-07-19 15:00:50 +00:00
Abe
d8d49fdd13
Deprecate is_playing_animation (#14387)
# Objective

Fixes #14386

## Solution

- Added the `#[deprecate]` attribute to the `is_playing_animation`
function.

## Testing

The project successfully builds.

---

## Migration Guide

The user will just need to replace functions named
`is_playing_animation` with `animation_is_playing`.
2024-07-19 11:27:43 +00:00
Patrick Walton
2a6dd3e2e0
Make the GltfNode::children links actually point to children. (#14390)
Due to a bug in `load_gltf`, the `GltfNode::children` links of each node
actually point to the node itself, rather than to the node's children.
This commit fixes that bug.

Note that this didn't affect the scene hierarchy of the instantiated
glTF, only the hierarchy as present in the `GltfNode` assets. This is
likely why the bug was never noticed until now.
2024-07-19 11:24:06 +00:00
re0312
e5bf59d712
Recalibrated observe benchmark (#14381)
# Objective

- The event propagation benchmark is largely derived from
bevy_eventlistener. However, it doesn't accurately reflect performance
of bevy side, as our event bubble propagation is based on observer.


## Solution

- added several new benchmarks that focuse on observer itself rather
than event bubble
2024-07-18 18:25:33 +00:00
Lars Frost
dcbd30200e
Make names of closure systems changable (#14369)
# Objective

When using tracing or
[`bevy_mod_debugdump`](https://github.com/jakobhellermann/bevy_mod_debugdump),
the names of function systems produced by closures are either ambiguous
(like `game::mainapp::{closure}` when tracing) or too long
(`bevy_mod_debugdump` includes full type signature if no name given),
which makes debugging with tracing difficult.

## Solution
Add a function `with_name` to rename a system. The proposed API can be
used in the following way:
```rust
app
    .add_systems(Startup, IntoSystem::into_system(|name: SystemName| {
        println!("System name: {}", name.name().to_owned());
    }).with_name("print_test_system"));
```

## Testing
- There is a test in
`bevy_ecs::system:system_name::test_closure_system_name_regular_param`
2024-07-18 18:07:47 +00:00
Thierry Berger
26fc4c7198
Test for ambiguous system ordering in CI (#13950)
Progress towards https://github.com/bevyengine/bevy/issues/7386.

Following discussion
https://discord.com/channels/691052431525675048/1253260494538539048/1253387942311886960

This Pull Request adds an example to detect system order ambiguities,
and also asserts none exist.

A lot of schedules are ignored in ordered to have the test passing, we
should thrive to make them pass, but in other pull requests.

<details><summary>example output <b>summary</b>, without ignored
schedules</summary>
<p>

```txt
$ cargo run --example ambiguity_detection 2>&1 | grep -C 1 "pairs of syst"
2024-06-21T13:17:55.776585Z  WARN bevy_ecs::schedule::schedule: Schedule First has ambiguities.
1 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_time::time_system (in set TimeSystem) and bevy_ecs::event::event_update_system (in set EventUpdates)
--
2024-06-21T13:17:55.782265Z  WARN bevy_ecs::schedule::schedule: Schedule PreUpdate has ambiguities.
11 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_pbr::prepass::update_mesh_previous_global_transforms and bevy_asset::server::handle_internal_asset_events
--
2024-06-21T13:17:55.809516Z  WARN bevy_ecs::schedule::schedule: Schedule PostUpdate has ambiguities.
63 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_ui::accessibility::image_changed and bevy_ecs::schedule::executor::apply_deferred
--
2024-06-21T13:17:55.816287Z  WARN bevy_ecs::schedule::schedule: Schedule Last has ambiguities.
3 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_gizmos::update_gizmo_meshes<bevy_gizmos::aabb::AabbGizmoConfigGroup> (in set UpdateGizmoMeshes) and bevy_gizmos::update_gizmo_meshes<bevy_gizmos::light::LightGizmoConfigGroup> (in set UpdateGizmoMeshes)
--
2024-06-21T13:17:55.831074Z  WARN bevy_ecs::schedule::schedule: Schedule ExtractSchedule has ambiguities.
296 pairs of systems with conflicting data access have indeterminate execution order. Consider adding `before`, `after`, or `ambiguous_with` relationships between these:
 -- bevy_render::extract_component::extract_components<bevy_sprite::SpriteSource> and bevy_render::render_asset::extract_render_asset<bevy_sprite::mesh2d::material::PreparedMaterial2d<bevy_sprite::mesh2d::color_material::ColorMaterial>>
```

</p>
</details> 

To try locally: 
```sh
CI_TESTING_CONFIG="./.github/example-run/ambiguity_detection.ron" cargo run --example ambiguity_detection --features "bevy_ci_testing,trace,trace_chrome"
```

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2024-07-17 21:05:48 +00:00
Sludge
fa855f7974
Derive and reflect Debug for CameraRenderGraph (#14364)
# Objective

- `CameraRenderGraph` is not inspectable via reflection, but should be
(the name of the configured render graph should be visible in editors,
etc.)

## Solution

- Derive and reflect `Debug` for `CameraRenderGraph`
2024-07-17 19:41:31 +00:00
Matty
3484bd916f
Cyclic splines (#14106)
# Objective

Fill a gap in the functionality of our curve constructions by allowing
users to easily build cyclic curves from control data.

## Solution

Here I opted for something lightweight and discoverable. There is a new
`CyclicCubicGenerator` trait with a method `to_curve_cyclic` which uses
splines' control data to create curves that are cyclic. For now, its
signature is exactly like that of `CubicGenerator` — `to_curve_cyclic`
just yields a `CubicCurve`:
```rust
/// Implement this on cubic splines that can generate a cyclic cubic curve from their spline parameters.
///
/// This makes sense only when the control data can be interpreted cyclically.
pub trait CyclicCubicGenerator<P: VectorSpace> {
    /// Build a cyclic [`CubicCurve`] by computing the interpolation coefficients for each curve segment.
    fn to_curve_cyclic(&self) -> CubicCurve<P>;
}
```

This trait has been implemented for `CubicHermite`,
`CubicCardinalSpline`, `CubicBSpline`, and `LinearSpline`:

<img width="753" alt="Screenshot 2024-07-01 at 8 58 27 PM"
src="https://github.com/bevyengine/bevy/assets/2975848/69ae0802-3b78-4fb9-b73a-6f842cf3b33c">
<img width="628" alt="Screenshot 2024-07-01 at 9 00 14 PM"
src="https://github.com/bevyengine/bevy/assets/2975848/2992175a-a96c-40fc-b1a1-5206c3572cde">
<img width="606" alt="Screenshot 2024-07-01 at 8 59 36 PM"
src="https://github.com/bevyengine/bevy/assets/2975848/9e99eb3a-dbe6-42da-886c-3d3e00410d03">
<img width="603" alt="Screenshot 2024-07-01 at 8 59 01 PM"
src="https://github.com/bevyengine/bevy/assets/2975848/d037bc0c-396a-43af-ab5c-fad9a29417ef">

(Each type pictured respectively with the control points rendered as
green spheres; tangents not pictured in the case of the Hermite spline.)

These curves are all parametrized so that the output of `to_curve` and
the output of `to_curve_cyclic` are similar. For instance, in
`CubicCardinalSpline`, the first output segment is a curve segment
joining the first and second control points in each, although it is
constructed differently. In the other cases, the segments from
`to_curve` are a subset of those in `to_curve_cyclic`, with the new
segments appearing at the end.

## Testing

I rendered cyclic splines from control data and made sure they looked
reasonable. Existing tests are intact for splines where previous code
was modified. (Note that the coefficient computation for cyclic spline
segments is almost verbatim identical to that of their non-cyclic
counterparts.)

The Bezier benchmarks also look fine.

---

## Changelog

- Added `CyclicCubicGenerator` trait to `bevy_math::cubic_splines` for
creating cyclic curves from control data.
- Implemented `CyclicCubicGenerator` for `CubicHermite`,
`CubicCardinalSpline`, `CubicBSpline`, and `LinearSpline`.
- `bevy_math` now depends on `itertools`.

---

## Discussion

### Design decisions

The biggest thing here is just the approach taken in the first place:
namely, the cyclic constructions use new methods on the same old
structs. This choice was made to reduce friction and increase
discoverability but also because creating new ones just seemed
unnecessary: the underlying data would have been the same, so creating
something like "`CyclicCubicBSpline`" whose internally-held control data
is regarded as cyclic in nature doesn't really accomplish much — the end
result for the user is basically the same either way.

Similarly, I don't presently see a pressing need for `to_curve_cyclic`
to output something other than a `CubicCurve`, although changing this in
the future may be useful. See below.

A notable omission here is that `CyclicCubicGenerator` is not
implemented for `CubicBezier`. This is not a gap waiting to be filled —
`CubicBezier` just doesn't have enough data to join its start with its
end without just making up the requisite control points wholesale. In
all the cases where `CyclicCubicGenerator` has been implemented here,
the fashion in which the ends are connected is quite natural and follows
the semantics of the associated spline construction.

### Future direction

There are two main things here:
1. We should investigate whether we should do something similar for
NURBS. I just don't know that much about NURBS at the moment, so I
regarded this as out of scope for the PR.
2. We may eventually want to change the output type of
`CyclicCubicGenerator::to_curve_cyclic` to a type which reifies the
cyclic nature of the curve output. This wasn't done in this PR because
I'm unsure how much value a type-level guarantee of cyclicity actually
has, but if some useful features make sense only in the case of cyclic
curves, this might be worth pursuing.
2024-07-17 13:02:31 +00:00
Martín Maita
72e7a4fed2
Update trigger_observers to operate over slices of data (#14354)
# Objective

- Fixes #14333 

## Solution

- Updated `trigger_observers` signature to operate over a slice instead
of an `Iterator`.
- Updated calls to `trigger_observers` to match the new signature.

---

## Migration Guide

- TBD
2024-07-17 13:01:52 +00:00
Patrick Walton
bc34216929
Pack multiple vertex and index arrays together into growable buffers. (#14257)
This commit uses the [`offset-allocator`] crate to combine vertex and
index arrays from different meshes into single buffers. Since the
primary source of `wgpu` overhead is from validation and synchronization
when switching buffers, this significantly improves Bevy's rendering
performance on many scenes.

This patch is a more flexible version of #13218, which also used slabs.
Unlike #13218, which used slabs of a fixed size, this commit implements
slabs that start small and can grow. In addition to reducing memory
usage, supporting slab growth reduces the number of vertex and index
buffer switches that need to happen during rendering, leading to
improved performance. To prevent pathological fragmentation behavior,
slabs are capped to a maximum size, and mesh arrays that are too large
get their own dedicated slabs.

As an additional improvement over #13218, this commit allows the
application to customize all allocator heuristics. The
`MeshAllocatorSettings` resource contains values that adjust the minimum
and maximum slab sizes, the cutoff point at which meshes get their own
dedicated slabs, and the rate at which slabs grow. Hopefully-sensible
defaults have been chosen for each value.

Unfortunately, WebGL 2 doesn't support the *base vertex* feature, which
is necessary to pack vertex arrays from different meshes into the same
buffer. `wgpu` represents this restriction as the downlevel flag
`BASE_VERTEX`. This patch detects that bit and ensures that all vertex
buffers get dedicated slabs on that platform. Even on WebGL 2, though,
we can combine all *index* arrays into single buffers to reduce buffer
changes, and we do so.

The following measurements are on Bistro:

Overall frame time improves from 8.74 ms to 5.53 ms (1.58x speedup):
![Screenshot 2024-07-09
163521](https://github.com/bevyengine/bevy/assets/157897/5d83c824-c0ee-434c-bbaf-218ff7212c48)

Render system time improves from 6.57 ms to 3.54 ms (1.86x speedup):
![Screenshot 2024-07-09
163559](https://github.com/bevyengine/bevy/assets/157897/d94e2273-c3a0-496a-9f88-20d394129610)

Opaque pass time improves from 4.64 ms to 2.33 ms (1.99x speedup):
![Screenshot 2024-07-09
163536](https://github.com/bevyengine/bevy/assets/157897/e4ef6e48-d60e-44ae-9a71-b9a731c99d9a)

## Migration Guide

### Changed

* Vertex and index buffers for meshes may now be packed alongside other
buffers, for performance.
* `GpuMesh` has been renamed to `RenderMesh`, to reflect the fact that
it no longer directly stores handles to GPU objects.
* Because meshes no longer have their own vertex and index buffers, the
responsibility for the buffers has moved from `GpuMesh` (now called
`RenderMesh`) to the `MeshAllocator` resource. To access the vertex data
for a mesh, use `MeshAllocator::mesh_vertex_slice`. To access the index
data for a mesh, use `MeshAllocator::mesh_index_slice`.

[`offset-allocator`]: https://github.com/pcwalton/offset-allocator
2024-07-16 20:33:15 +00:00
Gino Valente
af865e76a3
bevy_reflect: Improve DynamicFunction ergonomics (#14201)
# Objective

Many functions can be converted to `DynamicFunction` using
`IntoFunction`. Unfortunately, we are limited by Rust itself and the
implementations are far from exhaustive. For example, we can't convert
functions with more than 16 arguments. Additionally, we can't handle
returns with lifetimes not tied to the lifetime of the first argument.

In such cases, users will have to create their `DynamicFunction`
manually.

Let's take the following function:

```rust
fn get(index: usize, list: &Vec<String>) -> &String {
    &list[index]
}
```

This function cannot be converted to a `DynamicFunction` via
`IntoFunction` due to the lifetime of the return value being tied to the
second argument. Therefore, we need to construct the `DynamicFunction`
manually:

```rust
DynamicFunction::new(
    |mut args, info| {
        let list = args
            .pop()
            .unwrap()
            .take_ref::<Vec<String>>(&info.args()[1])?;
        let index = args.pop().unwrap().take_owned::<usize>(&info.args()[0])?;
        Ok(Return::Ref(get(index, list)))
    },
    FunctionInfo::new()
        .with_name("get")
        .with_args(vec![
            ArgInfo:🆕:<usize>(0).with_name("index"),
            ArgInfo:🆕:<&Vec<String>>(1).with_name("list"),
        ])
        .with_return_info(ReturnInfo:🆕:<&String>()),
);
```

While still a small and straightforward snippet, there's a decent amount
going on here. There's a lot of room for improvements when it comes to
ergonomics and readability.

The goal of this PR is to address those issues.

## Solution

Improve the ergonomics and readability of manually created
`DynamicFunction`s.

Some of the major changes:
1. Removed the need for `&ArgInfo` when reifying arguments (i.e. the
`&info.args()[1]` calls)
2. Added additional `pop` methods on `ArgList` to handle both popping
and casting
3. Added `take` methods on `ArgList` for taking the arguments out in
order
4. Removed the need for `&FunctionInfo` in the internal closure (Change
1 made it no longer necessary)
5. Added methods to automatically handle generating `ArgInfo` and
`ReturnInfo`

With all these changes in place, we get something a lot nicer to both
write and look at:

```rust
DynamicFunction::new(
    |mut args| {
        let index = args.take::<usize>()?;
        let list = args.take::<&Vec<String>>()?;
        Ok(Return::Ref(get(index, list)))
    },
    FunctionInfo::new()
        .with_name("get")
        .with_arg::<usize>("index")
        .with_arg::<&Vec<String>>("list")
        .with_return::<&String>(),
);
```

Alternatively, to rely on type inference for taking arguments, you could
do:

```rust
DynamicFunction::new(
    |mut args| {
        let index = args.take_owned()?;
        let list = args.take_ref()?;
        Ok(Return::Ref(get(index, list)))
    },
    FunctionInfo::new()
        .with_name("get")
        .with_arg::<usize>("index")
        .with_arg::<&Vec<String>>("list")
        .with_return::<&String>(),
);
```

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect
```

---

## Changelog

- Removed `&ArgInfo` argument from `FromArg::from_arg` trait method
- Removed `&ArgInfo` argument from `Arg::take_***` methods
- Added `ArgValue`
- `Arg` is now a struct containing an `ArgValue` and an argument `index`
- `Arg::take_***` methods now require `T` is also `TypePath`
- Added `Arg::new`, `Arg::index`, `Arg::value`, `Arg::take_value`, and
`Arg::take` methods
- Replaced `ArgId` in `ArgError` with just the argument `index`
- Added `ArgError::EmptyArgList`
- Renamed `ArgList::push` to `ArgList::push_arg`
- Added `ArgList::pop_arg`, `ArgList::pop_owned`, `ArgList::pop_ref`,
and `ArgList::pop_mut`
- Added `ArgList::take_arg`, `ArgList::take_owned`, `ArgList::take_ref`,
`ArgList::take_mut`, and `ArgList::take`
- `ArgList::pop` is now generic
- Renamed `FunctionError::InvalidArgCount` to
`FunctionError::ArgCountMismatch`
- The closure given to `DynamicFunction::new` no longer has a
`&FunctionInfo` argument
- Added `FunctionInfo::with_arg`
- Added `FunctionInfo::with_return`

## Internal Migration Guide

> [!important]
> Function reflection was introduced as part of the 0.15 dev cycle. This
migration guide was written for developers relying on `main` during this
cycle, and is not a breaking change coming from 0.14.

* The `FromArg::from_arg` trait method and the `Arg::take_***` methods
no longer take a `&ArgInfo` argument.
* What used to be `Arg` is now `ArgValue`. `Arg` is now a struct which
contains an `ArgValue`.
* `Arg::take_***` methods now require `T` is also `TypePath`
* Instances of `id: ArgId` in `ArgError` have been replaced with `index:
usize`
* `ArgList::push` is now `ArgList::push_arg`. It also takes the new
`ArgValue` type.
* `ArgList::pop` has become `ArgList::pop_arg` and now returns
`ArgValue`. `Arg::pop` now takes a generic type and downcasts to that
type. It's recommended to use `ArgList::take` and friends instead since
they allow removing the arguments from the list in the order they were
pushed (rather than reverse order).
* `FunctionError::InvalidArgCount` is now
`FunctionError::ArgCountMismatch`
* The closure given to `DynamicFunction::new` no longer has a
`&FunctionInfo` argument. This argument can be removed.
2024-07-16 13:01:52 +00:00
Steve Frampton
0e13b1ca5e
Added new method to Cone 3D primitive (#14325)
Reference to #14299.

# Objective
- Ensuring consistent practice of instantiating 3D primitive shapes in
Bevy.

## Solution

- Add `new` method, containing `radius` and `height` arguments, to Cone
3D primitive shape.

## Testing

- Instantiated cone using same values (radius is `2.` and height is
`5.`), using the current method and the added `new` method.
- Basic setup of Bevy Default Plugins and `3DCameraBundle`.


---

## Showcase

<details>
  <summary>Click to view showcase</summary>

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

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

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    let new_cone = meshes.add(Cone::new(2., 5.));
    commands.spawn(PbrBundle {
        mesh: new_cone,
        ..default()
    });

    let old_cone = meshes.add(Cone {
        radius: 2.,
        height: 5.,
    });
    commands.spawn(PbrBundle {
        mesh: old_cone,
        material: materials.add(Color::WHITE),
        transform: Transform::from_xyz(10., 0., 0.),
        ..default()
    });

    commands.spawn(Camera3dBundle {
        transform: Transform::from_xyz(20., 20., 20.).looking_at(Vec3::ZERO, Dir3::Y),
        ..default()
    });
}
```

</details>


![image](https://github.com/user-attachments/assets/267f8124-8734-4c20-8840-fcf35375a778)


- Pink Cone is created using the `new` method.
- Black Cone is created using the existing method.

## Migration Guide
- Addition of `new` method to the 3D primitive Cone struct.
2024-07-16 12:59:26 +00:00
Mike
cfcb56f5b9
Remove need for EventLoopProxy to be NonSend (#14198)
# Objective

- Continue to pare down the uses on NonSend resources in the engine. In
this case, EventLoopProxy used to be `!Sync`, but is now `Sync` in the
latest version of winit.

## Solution

- New type `EventLoopProxy` as `EventLoopProxyWrapper` to make it into a
normal resource.
- Update the `custom_user_event` example as it no longer needs to
indirectly access the `EventLoopProxy` through a static variable
anymore.

## Testing

- Ran the example. The resource exists just for users to use, so there
aren't any in engine uses for it currently.

---

## Changelog

- make EventLoopProxy into a regular resource. 

## Migration Guide

`EventLoopProxy` has been renamed to `EventLoopProxyWrapper` and is now
`Send`, making it an ordinary resource.

Before:
```rust
event_loop_system(event_loop: NonSend<EventLoopProxy<MyEvent>>) {
    event_loop.send_event(MyEvent);
}
```

After:
```rust
event_loop_system(event_loop: Res<EventLoopProxy<MyEvent>>) {
    event_loop.send_event(MyEvent);
}
```
2024-07-16 06:59:01 +00:00
Gino Valente
1042f09c2e
bevy_reflect: Add DynamicClosure and DynamicClosureMut (#14141)
# Objective

As mentioned in
[this](https://github.com/bevyengine/bevy/pull/13152#issuecomment-2198387297)
comment, creating a function registry (see #14098) is a bit difficult
due to the requirements of `DynamicFunction`. Internally, a
`DynamicFunction` contains a `Box<dyn FnMut>` (the function that reifies
reflected arguments and calls the actual function), which requires `&mut
self` in order to be called.

This means that users would require a mutable reference to the function
registry for it to be useful— which isn't great. And they can't clone
the `DynamicFunction` either because cloning an `FnMut` isn't really
feasible (wrapping it in an `Arc` would allow it to be cloned but we
wouldn't be able to call the clone since we need a mutable reference to
the `FnMut`, which we can't get with multiple `Arc`s still alive,
requiring us to also slap in a `Mutex`, which adds additional overhead).

And we don't want to just replace the `dyn FnMut` with `dyn Fn` as that
would prevent reflecting closures that mutate their environment.

Instead, we need to introduce a new type to split the requirements of
`DynamicFunction`.

## Solution

Introduce new types for representing closures.

Specifically, this PR introduces `DynamicClosure` and
`DynamicClosureMut`. Similar to how `IntoFunction` exists for
`DynamicFunction`, two new traits were introduced: `IntoClosure` and
`IntoClosureMut`.

Now `DynamicFunction` stores a `dyn Fn` with a `'static` lifetime.
`DynamicClosure` also uses a `dyn Fn` but has a lifetime, `'env`, tied
to its environment. `DynamicClosureMut` is most like the old
`DynamicFunction`, keeping the `dyn FnMut` and also typing its lifetime,
`'env`, to the environment

Here are some comparison tables:

|   | `DynamicFunction` | `DynamicClosure` | `DynamicClosureMut` |
| - | ----------------- | ---------------- | ------------------- |
| Callable with `&self` |  |  |  |
| Callable with `&mut self` |  |  |  |
| Allows for non-`'static` lifetimes |  |  |  |

|   | `IntoFunction` | `IntoClosure` | `IntoClosureMut` |
| - | -------------- | ------------- | ---------------- |
| Convert `fn` functions |  |  |  |
| Convert `fn` methods |  |  |  |
| Convert anonymous functions |  |  |  |
| Convert closures that capture immutable references |  |  |  |
| Convert closures that capture mutable references |  |  |  |
| Convert closures that capture owned values | [^1] |  |  |

[^1]: Due to limitations in Rust, `IntoFunction` can't be implemented
for just functions (unless we forced users to manually coerce them to
function pointers first). So closures that meet the trait requirements
_can technically_ be converted into a `DynamicFunction` as well. To both
future-proof and reduce confusion, though, we'll just pretend like this
isn't a thing.

```rust
let mut list: Vec<i32> = vec![1, 2, 3];

// `replace` is a closure that captures a mutable reference to `list`
let mut replace = |index: usize, value: i32| -> i32 {
  let old_value = list[index];
  list[index] = value;
  old_value
};

// Convert the closure into a dynamic closure using `IntoClosureMut::into_closure_mut`
let mut func: DynamicClosureMut = replace.into_closure_mut();

// Dynamically call the closure:
let args = ArgList::default().push_owned(1_usize).push_owned(-2_i32);
let value = func.call_once(args).unwrap().unwrap_owned();

// Check the result:
assert_eq!(value.take::<i32>().unwrap(), 2);
assert_eq!(list, vec![1, -2, 3]);
```

### `ReflectFn`/`ReflectFnMut`

To make extending the function reflection system easier (the blanket
impls for `IntoFunction`, `IntoClosure`, and `IntoClosureMut` are all
incredibly short), this PR generalizes callables with two new traits:
`ReflectFn` and `ReflectFnMut`.

These traits mimic `Fn` and `FnMut` but allow for being called via
reflection. In fact, their blanket implementations are identical save
for `ReflectFn` being implemented over `Fn` types and `ReflectFnMut`
being implemented over `FnMut` types.

And just as `Fn` is a subtrait of `FnMut`, `ReflectFn` is a subtrait of
`ReflectFnMut`. So anywhere that expects a `ReflectFnMut` can also be
given a `ReflectFn`.

To reiterate, these traits aren't 100% necessary. They were added in
purely for extensibility. If we decide to split things up differently or
add new traits/types in the future, then those changes should be much
simpler to implement.

### `TypedFunction`

Because of the split into `ReflectFn` and `ReflectFnMut`, we needed a
new way to access the function type information. This PR moves that
concept over into `TypedFunction`.

Much like `Typed`, this provides a way to access a function's
`FunctionInfo`.

By splitting this trait out, it helps to ensure the other traits are
focused on a single responsibility.

### Internal Macros

The original function PR (#13152) implemented `IntoFunction` using a
macro which was passed into an `all_tuples!` macro invocation. Because
we needed the same functionality for these new traits, this PR has
copy+pasted that code for `ReflectFn`, `ReflectFnMut`, and
`TypedFunction`— albeit with some differences between them.

Originally, I was going to try and macro-ify the impls and where clauses
such that we wouldn't have to straight up duplicate a lot of this logic.
However, aside from being more complex in general, autocomplete just
does not play nice with such heavily nested macros (tried in both
RustRover and VSCode). And both of those problems told me that it just
wasn't worth it: we need to ensure the crate is easily maintainable,
even at the cost of duplicating code.

So instead, I made sure to simplify the macro code by removing all
fully-qualified syntax and cutting the where clauses down to the bare
essentials, which helps to clean up a lot of the visual noise. I also
tried my best to document the macro logic in certain areas (I may even
add a bit more) to help with maintainability for future devs.

### Documentation

Documentation for this module was a bit difficult for me. So many of
these traits and types are very interconnected. And each trait/type has
subtle differences that make documenting it in a single place, like at
the module level, difficult to do cleanly. Describing the valid
signatures is also challenging to do well.

Hopefully what I have here is okay. I think I did an okay job, but let
me know if there any thoughts on ways to improve it. We can also move
such a task to a followup PR for more focused discussion.

## Testing

You can test locally by running:

```
cargo test --package bevy_reflect
```

---

## Changelog

- Added `DynamicClosure` struct
- Added `DynamicClosureMut` struct
- Added `IntoClosure` trait
- Added `IntoClosureMut` trait
- Added `ReflectFn` trait
- Added `ReflectFnMut` trait
- Added `TypedFunction` trait
- `IntoFunction` now only works for standard Rust functions
- `IntoFunction` no longer takes a lifetime parameter
- `DynamicFunction::call` now only requires `&self`
- Removed `DynamicFunction::call_once`
- Changed the `IntoReturn::into_return` signature to include a where
clause

## Internal Migration Guide

> [!important]
> Function reflection was introduced as part of the 0.15 dev cycle. This
migration guide was written for developers relying on `main` during this
cycle, and is not a breaking change coming from 0.14.

### `IntoClosure`

`IntoFunction` now only works for standard Rust functions. Calling
`IntoFunction::into_function` on a closure that captures references to
its environment (either mutable or immutable), will no longer compile.

Instead, you will need to use either `IntoClosure::into_closure` to
create a `DynamicClosure` or `IntoClosureMut::into_closure_mut` to
create a `DynamicClosureMut`, depending on your needs:

```rust
let punct = String::from("!");
let print = |value: String| {
    println!("{value}{punct}");
};

// BEFORE
let func: DynamicFunction = print.into_function();

// AFTER
let func: DynamicClosure = print.into_closure();
```

### `IntoFunction` lifetime

Additionally, `IntoFunction` no longer takes a lifetime parameter as it
always expects a `'static` lifetime. Usages will need to remove any
lifetime parameters:

```rust
// BEFORE
fn execute<'env, F: IntoFunction<'env, Marker>, Marker>(f: F) {/* ... */}

// AFTER
fn execute<F: IntoFunction<Marker>, Marker>(f: F) {/* ... */}
```

### `IntoReturn`

`IntoReturn::into_return` now has a where clause. Any manual
implementors will need to add this where clause to their implementation.
2024-07-16 03:22:43 +00:00
Patrick Walton
20c6bcdba4
Allow volumetric fog to be localized to specific, optionally voxelized, regions. (#14099)
Currently, volumetric fog is global and affects the entire scene
uniformly. This is inadequate for many use cases, such as local smoke
effects. To address this problem, this commit introduces *fog volumes*,
which are axis-aligned bounding boxes (AABBs) that specify fog
parameters inside their boundaries. Such volumes can also specify a
*density texture*, a 3D texture of voxels that specifies the density of
the fog at each point.

To create a fog volume, add a `FogVolume` component to an entity (which
is included in the new `FogVolumeBundle` convenience bundle). Like light
probes, a fog volume is conceptually a 1×1×1 cube centered on the
origin; a transform can be used to position and resize this region. Many
of the fields on the existing `VolumetricFogSettings` have migrated to
the new `FogVolume` component. `VolumetricFogSettings` on a camera is
still needed to enable volumetric fog. However, by itself
`VolumetricFogSettings` is no longer sufficient to enable volumetric
fog; a `FogVolume` must be present. Applications that wish to retain the
old global fog behavior can simply surround the scene with a large fog
volume.

By way of implementation, this commit converts the volumetric fog shader
from a full-screen shader to one applied to a mesh. The strategy is
different depending on whether the camera is inside or outside the fog
volume. If the camera is inside the fog volume, the mesh is simply a
plane scaled to the viewport, effectively falling back to a full-screen
pass. If the camera is outside the fog volume, the mesh is a cube
transformed to coincide with the boundaries of the fog volume's AABB.
Importantly, in the latter case, only the front faces of the cuboid are
rendered. Instead of treating the boundaries of the fog as a sphere
centered on the camera position, as we did prior to this patch, we
raytrace the far planes of the AABB to determine the portion of each ray
contained within the fog volume. We then raymarch in shadow map space as
usual. If a density texture is present, we modulate the fixed density
value with the trilinearly-interpolated value from that texture.

Furthermore, this patch introduces optional jitter to fog volumes,
intended for use with TAA. This modifies the position of the ray from
frame to frame using interleaved gradient noise, in order to reduce
aliasing artifacts. Many implementations of volumetric fog in games use
this technique. Note that this patch makes no attempt to write a motion
vector; this is because when a view ray intersects multiple voxels
there's no single direction of motion. Consequently, fog volumes can
have ghosting artifacts, but because fog is "ghostly" by its nature,
these artifacts are less objectionable than they would be for opaque
objects.

A new example, `fog_volumes`, has been added. It demonstrates a single
fog volume containing a voxelized representation of the Stanford bunny.
The existing `volumetric_fog` example has been updated to use the new
local volumetrics API.

## Changelog

### Added

* Local `FogVolume`s are now supported, to localize fog to specific
regions. They can optionally have 3D density voxel textures for precise
control over the distribution of the fog.

### Changed

* `VolumetricFogSettings` on a camera no longer enables volumetric fog;
instead, it simply enables the processing of `FogVolume`s within the
scene.

## Migration Guide

* A `FogVolume` is now necessary in order to enable volumetric fog, in
addition to `VolumetricFogSettings` on the camera. Existing uses of
volumetric fog can be migrated by placing a large `FogVolume`
surrounding the scene.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
2024-07-16 03:14:12 +00:00
Joseph
ee15be8549
Make Tasks functional on WASM (#13889)
# Objective

Right not bevy's task pool abstraction is kind of useless on wasm, since
it returns a `FakeTask` which can't be interacted with. This is only
good for fire-and-forget it tasks, and isn't even that useful since it's
just a thin wrapper around `wasm-bindgen-futures::spawn_local`

## Solution

Add a simple `Task<T>` handler type to wasm targets that allow waiting
for a task's output or periodically checking for its completion. This PR
aims to give the wasm version of these tasks feature parity with the
native, multi-threaded version of the task

## Testing

- Did you test these changes? *Not yet*

---------

Co-authored-by: Periwink <charlesbour@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
2024-07-16 01:15:03 +00:00
BD103
c3057d4353
plugin_group! macro (adopted) (#14339)
# Objective

- Adopted from #11460.
- Closes #7332.
- The documentation for `DefaultPlugins` and `MinimalPlugins` frequently
goes out of date because it is not .

## Solution

- Create a macro, `plugin_group!`, to automatically create
`PluginGroup`s and document them.

## Testing

- Run `cargo-expand` on the generated code for `DefaultPlugins` and
`MinimalPlugins`.
- Try creating a custom plugin group with the macro.

---

## Showcase

- You can now define custom `PluginGroup`s using the `plugin_group!`
macro.

```rust
plugin_group! {
    /// My really cool plugic group!
    pub struct MyPluginGroup {
        physics:::PhysicsPlugin,
        rendering:::RenderingPlugin,
        ui:::UiPlugin,
    }
}
```

<details>
  <summary>Expanded output</summary>

```rust
/// My really cool plugic group!
///
/// - [`PhysicsPlugin`](physics::PhysicsPlugin)
/// - [`RenderingPlugin`](rendering::RenderingPlugin)
/// - [`UiPlugin`](ui::UiPlugin)
pub struct MyPluginGroup;
impl ::bevy_app::PluginGroup for MyPluginGroup {
    fn build(self) -> ::bevy_app::PluginGroupBuilder {
        let mut group = ::bevy_app::PluginGroupBuilder::start::<Self>();
        {
            const _: () = {
                const fn check_default<T: Default>() {}
                check_default::<physics::PhysicsPlugin>();
            };
            group = group.add(<physics::PhysicsPlugin>::default());
        }
        {
            const _: () = {
                const fn check_default<T: Default>() {}
                check_default::<rendering::RenderingPlugin>();
            };
            group = group.add(<rendering::RenderingPlugin>::default());
        }
        {
            const _: () = {
                const fn check_default<T: Default>() {}
                check_default::<ui::UiPlugin>();
            };
            group = group.add(<ui::UiPlugin>::default());
        }
        group
    }
}
```

</details>

---------

Co-authored-by: Doonv <58695417+doonv@users.noreply.github.com>
Co-authored-by: Mateusz Wachowiak <mateusz_wachowiak@outlook.com>
2024-07-16 01:14:33 +00:00
Lura
9a1a84dd22
Fix error/typo in SMAA shader (#14338)
# Objective

- Actually use the value assigned to `d_xz`, like in [the original SMAA
implementation](https://github.com/iryoku/smaa/blob/master/SMAA.hlsl#L960).
This not already being the case was likely a mistake when converting
from HLSL to WGSL

## Solution

- Use `d_xz.x` and `d_xz.y` instead of `d.x` and `d.z`

## Testing

- Quickly tested on Windows 11, `x86_64-pc-windows-gnu` `1.79.0` with
the latest NVIDIA drivers. App runs with SMAA enabled and everything
seems to work as intended
- I didn't observe any major visual difference between this and the
previous version, though this should be more correct as it matches the
original SMAA implementation
2024-07-15 23:40:39 +00:00
Jonathan Chan Kwan Yin
e66cd484a7
Add insert_by_id and try_insert_by_id to EntityCommands (#14283)
# Objective

- Allow queuing insertion of dynamic components to an existing entity

## Solution

- Add `insert_by_id<T: Send + 'static>(commands: &mut EntityCommands,
component_id: ComponentId, value: T)` and the `try_insert_by_id`
counterpart

## Testing

TODO

- Did you test these changes? If so, how?
- Are there any parts that need more testing?
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?

## Alternatives

This PR is not feature-complete for dynamic components. In particular,
it
- only supports one component
- only supports adding components with a known, sized type

These were not implemented because doing so would require enhancing
`CommandQueue` to support pushing unsized commands (or equivalently,
pushing commands with a buffer of data). Even so, the cost would not be
transparent compared to the implementation in this PR, which simply
captures the `ComponentId` and `value: T` into the command closure and
can be easily memcpy'ed to the stack during execution. For example, to
efficiently pass `&[ComponentId]` from the caller to the world, we would
need to:

1. Update `CommandQueue.bytes` from `Vec<MaybeUninit<u8>>` to
`Vec<MaybeUninit<usize>>` so that it has the same alignment as
`ComponentId` (which probably needs to be made `#[repr(transparent)]`
too)
2. After pushing the Command metadata, push padding bytes until the vec
len is a multiple of `size_of::<usize>()`
3. Store `components.len()` in the data
4. memcpy the user-provided `&[ComponentId]` to `CommandQueue.bytes`
5. During execution, round up the data pointer behind the `Command` to
skip padding, then cast the pointer and consume it as a `&[ComponentId]`

The effort here seems unnecessarily high, unless someone else has such a
requirement. At least for the use case I am working with, I only need a
single known type, and if we need multiple components, we could always
enhance this function to accept a `[ComponentId; N]`.

I recommend enhancing the `Bundle` API in the long term to achieve this
goal more elegantly.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Felix Rath <felixm.rath@gmail.com>
2024-07-15 23:29:13 +00:00
BD103
5ea88895e9
Remove unused default feature from bevy_window (#14313)
# Objective

- Extracted from #14298.
- `bevy_window` has an empty `default` feature that does not enable
anything, which is equivalent to not having any default features.

## Solution

- Remove it :)
- This is technically a breaking change, but specifying `features =
["default"]` manually in `Cargo.toml` is highly discouraged, so the
impact is low.

---

## Migration Guide

`bevy_window` had an empty default feature flag that did not do
anything, so it was removed. You may have to remove any references to it
if you specified it manually.

```toml
# 0.14
[dependencies]
bevy_window = { version = "0.14", default-features = false, features = ["default"] }

# 0.15
[dependencies]
bevy_window = { version = "0.15", default-features = false }
```
2024-07-15 16:49:00 +00:00
Brezak
6522795889
Specify test group names in github summary for compile fail tests (#14330)
# Objective

The github action summary titles every compile test group as
`compile_fail_utils`.


![image](https://github.com/user-attachments/assets/9d00a113-6772-430c-8da9-bffe6a60a8f8)

## Solution

Manually specify group names for compile fail tests.

## Testing

- Wait for compile fail tests to run.
- Observe the generated summary.
2024-07-15 16:13:03 +00:00
SpecificProtagonist
d276525350
Allow non-static trigger targets (#14327)
# Objective

`TriggerTargets` can not be borrowed for use in `World::trigger_targets`

## Solution

Drop `'static` bound on `TriggerEvent`, keep it for `Command` impl.

## Testing

n/a
2024-07-15 16:10:57 +00:00
Joona Aalto
cf1b7fa4cc
Implement Bounded2d for Annulus (#14326)
# Objective

`Annulus` is missing `Bounded2d` even though the implementation is
trivial.

## Solution

Implement `Bounded2d` for `Annulus`.

## Testing

There is a basic test to verify that the produced bounding volumes are
correct.
2024-07-15 16:08:35 +00:00
Joona Aalto
36b521d069
Improve isometry docs (#14318)
# Objective

Fixes #14308.

#14269 added the `Isometry2d` and `Isometry3d` types, but they don't
have usage examples or much documentation on what the types actually
represent or what they may be useful for.

In addition, their module is public and the types are not re-exported at
the crate root, unlike all the other core math types like Glam's types,
direction types, and `Rot2`.

## Solution

Improve the documentation of `Isometry2d` and `Isometry3d`, explaining
what they represent and can be useful for, along with doc examples on
common high-level usage. I also made the way the types are exported
consistent with other core math types.

This does add some duplication, but I personally think having good docs
for this is valuable, and people are also less likely to look at the
module-level docs than type-level docs.
2024-07-15 16:05:33 +00:00
Torstein Grindvik
ee0a85766d
Clearer spatial bundle pub const docs (#14293)
# Objective

The docs on SpatialBundle's pub const constructors mention that one is
"visible" when it's actually inherited, which afaik means it's
conditional on its parent's visibility.

I feel it's more correct like this.

_Also I'm seeing how making a PR from github.dev works hopefully nothing
weird happens_
2024-07-15 16:03:09 +00:00
BD103
b6f61b3ac6
Fix bevy_window failing with serialize feature (#14298)
# Objective

- [`flag-frenzy`](https://github.com/TheBevyFlock/flag-frenzy) found an
issue where `bevy_window` would fail to build when its `serialize`
feature is enabled.
- See
[here](https://github.com/TheBevyFlock/flag-frenzy/actions/runs/9924187577/job/27415224405)
for the specific log.

## Solution

- Turns out it was failing because the `bevy_ecs/serialize` feature was
not enabled. This error can be fixed by adding the flag as a dependency.

## Testing

```bash
cargo check -p bevy_window -F serialize
# Or if you're very cool...
flag-frenzy --manifest-path path/to/bevy/Cargo.toml --config config -p bevy_window
```
2024-07-15 16:00:49 +00:00
masonk
d2bf052515
Clarify GlobalTransform::transform_point (#14292)
The existing doc comment for GlobalTransform::transform_point is
unclear, or, arguably, incorrect.
https://github.com/bevyengine/bevy/discussions/8501 also mentions this.

Additionally, a user reading the doc for transform_point might be
looking for one of the three other transforms that I mentioned in this
doc comment.

---------

Co-authored-by: Mason Kramer <mason@masonkramer.net>
Co-authored-by: Pascal Hertleif <killercup@gmail.com>
2024-07-15 15:59:29 +00:00
Ben Frankel
7cb97852a5
Remove second generic from .add_before, .add_after (#14285)
# Objective

```rust
// Currently:
builder.add_after::<FooPlugin, _>(BarPlugin);
// After this PR:
builder.add_after::<FooPlugin>(BarPlugin);
```

This removes some weirdness and better parallels the rest of the
`PluginGroupBuilder` API.

## Solution

Define a helper method `type_id_of_val` to use in `.add_before` and
`.add_after` instead of `TypeId::of::<T>` (which requires the plugin
type to be nameable, preventing `impl Plugin` from being used).

## Testing

Ran `cargo run -p ci lints` successfully.

## Migration Guide

Removed second generic from `PluginGroupBuilder` methods: `add_before`
and `add_after`.

```rust
// Before:
DefaultPlugins
    .build()
    .add_before::<WindowPlugin, _>(FooPlugin)
    .add_after::<WindowPlugin, _>(BarPlugin)

// After:
DefaultPlugins
    .build()
    .add_before::<WindowPlugin>(FooPlugin)
    .add_after::<WindowPlugin>(BarPlugin)
```

---------

Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
2024-07-15 15:58:14 +00:00
Sou1gh0st
65aae92127
Add support for skybox transformation (#14267)
# Objective

- Fixes https://github.com/bevyengine/bevy/issues/14036

## Solution

- Add a view space transformation for the skybox

## Testing

- I have tested the newly added `transform` field using the `skybox`
example.
```
diff --git a/examples/3d/skybox.rs b/examples/3d/skybox.rs
index beaf5b268..d16cbe988 100644
--- a/examples/3d/skybox.rs
+++ b/examples/3d/skybox.rs
@@ -81,6 +81,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
         Skybox {
             image: skybox_handle.clone(),
             brightness: 1000.0,
+            rotation: Quat::from_rotation_x(PI * -0.5),
         },
     ));
```
<img width="1280" alt="image"
src="https://github.com/bevyengine/bevy/assets/6300263/1230a608-58ea-492d-a811-90c54c3b43ef">


## Migration Guide
- Since we have added a new filed to the Skybox struct, users will need
to include `..Default::default()` or some rotation value in their
initialization code.
2024-07-15 15:53:20 +00:00
Alix Bott
a79df7b124
Fix overflow in RenderLayers::iter_layers (#14264)
# Objective

- Fixes overflow when calling `RenderLayers::iter_layers` on layers of
the form `k * 64 - 1`
- Causes a panic in debug mode, and an infinite iterator in release mode

## Solution

- Use `u64::checked_shr` instead of `>>=`

## Testing

- Added a test case for this: `render_layer_iter_no_overflow`
2024-07-15 15:50:36 +00:00
SpecificProtagonist
ab255aefc6
Implement FromIterator/IntoIterator for dynamic types (#14250)
# Objective

Implement FromIterator/IntoIterator for dynamic types where missing

Note:
- can't impl `IntoIterator` for `&Array` & co because of orphan rules
- `into_iter().collect()` is a no-op for `Vec`s because of
specialization

---

## Migration Guide

- Change `DynamicArray::from_vec` to `DynamicArray::from_iter`
2024-07-15 15:38:11 +00:00