Commit graph

148 commits

Author SHA1 Message Date
Giacomo Stevanato
71c5f1e3e4
Generate links to definition in source code pages on docs.rs and dev-docs.bevyengine.org (#12965)
# Objective

- Fix issue #2611

## Solution

- Add `--generate-link-to-definition` to all the `rustdoc-args` arrays
in the `Cargo.toml`s (for docs.rs)
- Add `--generate-link-to-definition` to the `RUSTDOCFLAGS` environment
variable in the docs workflow (for dev-docs.bevyengine.org)
- Document all the workspace crates in the docs workflow (needed because
otherwise only the source code of the `bevy` package will be included,
making the argument useless)
- I think this also fixes #3662, since it fixes the bug on
dev-docs.bevyengine.org, while on docs.rs it has been fixed for a while
on their side.

---

## Changelog

- The source code viewer on docs.rs now includes links to the
definitions.
2024-07-29 23:10:16 +00:00
IceSentry
3faca1e549
Don't ignore draw errors (#13240)
# Objective

- It's possible to have errors in a draw command, but these errors are
ignored

## Solution

- Return a result with the error

## Changelog

Renamed `RenderCommandResult::Failure` to `RenderCommandResult::Skip`
Added a `reason` string parameter to `RenderCommandResult::Failure`

## Migration Guide
If you were using `RenderCommandResult::Failure` to just ignore an error
and retry later, use `RenderCommandResult::Skip` instead.

This wasn't intentional, but this PR should also help with
https://github.com/bevyengine/bevy/issues/12660 since we can turn a few
unwraps into error messages now.

---------

Co-authored-by: Charlotte McElwain <charlotte.c.mcelwain@gmail.com>
2024-07-22 19:22:30 +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
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
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
Giacomo Stevanato
d7080369a7
Fix intra-doc links and make CI test them (#14076)
# Objective

- Bevy currently has lot of invalid intra-doc links, let's fix them!
- Also make CI test them, to avoid future regressions.
- Helps with #1983 (but doesn't fix it, as there could still be explicit
links to docs.rs that are broken)

## Solution

- Make `cargo r -p ci -- doc-check` check fail on warnings (could also
be changed to just some specific lints)
- Manually fix all the warnings (note that in some cases it was unclear
to me what the fix should have been, I'll try to highlight them in a
self-review)
2024-07-11 13:08:31 +00:00
github-actions[bot]
8df10d2713
Bump Version after Release (#14219)
Bump version after release
This PR has been auto-generated

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François Mockers <mockersf@gmail.com>
2024-07-08 12:54:08 +00:00
NiseVoid
eddb006a8a
Use u32 for all resolution/subdivision fields in bevy_gizmos (#13927)
# Objective

- Make gizmos behavior consistent across platforms

## Solution

- Use `u32` instead of `usize` for resolution/subdivisions/segments/etc
fields

---

## Changelog

- Change resolutions in gizmos from `usize` to  `u32`

## Migration Guide

- All gizmos now take `u32` instead of `usize` for their
resolution/subdivision/segment counts
2024-06-19 17:28:10 +00:00
NiseVoid
524dce7505
Use a well defined type for sides in RegularPolygon (#13837)
# Objective

- Primitives should not use poorly defined types like `usize`,
especially since they are serializable

## Solution

- Use `u32` instead of `usize`
- The generic array types do not need to be changed because this size is
not actually stored or serialized anywhere

---

## Migration Guide

- `RegularPolygon` now uses `u32` instead of `usize` for the number of
sides
2024-06-19 15:43:40 +00:00
Jan Hohenheim
6273227e09
Fix lints introduced in Rust beta 1.80 (#13899)
Resolves #13895

Mostly just involves being more explicit about which parts of the docs
belong to a list and which begin a new paragraph.
- found a few docs that were malformed because of exactly this, so I
fixed that by introducing a paragraph
- added indentation to nearly all multiline lists
- fixed a few minor typos
- added `#[allow(dead_code)]` to types that are needed to test
annotations but are never constructed
([here](https://github.com/bevyengine/bevy/pull/13899/files#diff-b02b63604e569c8577c491e7a2030d456886d8f6716eeccd46b11df8aac75dafR1514)
and
[here](https://github.com/bevyengine/bevy/pull/13899/files#diff-b02b63604e569c8577c491e7a2030d456886d8f6716eeccd46b11df8aac75dafR1523))
- verified that  `cargo +beta run -p ci -- lints` passes
- verified that `cargo +beta run -p ci -- test` passes
2024-06-17 17:22:01 +00:00
Ľubomír Kurčák
4b3246af40
Add cross gizmos (#13883)
# Objective

Add `cross` and `cross_2d` gizmos in accordance with #13868.

## Solution

Extend `Gizmos` to provide these functions.

## Testing

Tested in `2d_gizmos` and `3d_gizmos` examples, and external projects.


![image](https://github.com/bevyengine/bevy/assets/29227697/d13067e1-d7eb-46c5-9b73-6c2d70417889)


![image](https://github.com/bevyengine/bevy/assets/29227697/0a8eba48-fbb3-4b3e-abe1-4e250222f94b)
2024-06-17 15:45:32 +00:00
Chris Biscardi
b9e67bc3c3
view.inverse_clip_from_world should be world_from_clip (#13756)
As per the other changes in
https://github.com/bevyengine/bevy/pull/13489
`view.inverse_clip_from_world` should be `world_from_clip`.



# Objective

fixes #13749

## Solution

Modified lines.wgsl to use the right name as the current name does not
exist.

## Testing

I ran the 3d_gizmos example and pressed "p".

![screenshot-2024-06-08-at-13 21
22@2x](https://github.com/bevyengine/bevy/assets/551247/b8bfd3db-8273-4606-9dae-040764339883)

![screenshot-2024-06-08-at-13 21
26@2x](https://github.com/bevyengine/bevy/assets/551247/2619f1ae-ce83-44d7-a9fc-07e686950887)
2024-06-09 14:40:14 +00:00
Alice Cecile
2165f2218f
Rename Rotation2d to Rot2 (#13694)
# Objective

- `Rotation2d` is a very long name for a commonly used type.

## Solution

- Rename it to `Rot2` to match `glam`'s naming convention (e.g. `Vec2`)

I ran a poll, and `Rot2` was the favorite of the candidate names.

This is not actually a breaking change, since `Rotation2d` has not been
shipped yet.

---------

Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
2024-06-05 21:51:13 +00:00
Bennett Lambert
37cc8ea33b
Add axes_2d gizmo. (#12334)
# Objective

This PR addresses #12222 (Fixes #12222). Simple addition to add a 2D
axes gizmo.

## Solution

- Add a new method axes_2d which takes a transform and a case length and
then draws two arrows in the XY plane.

The only thing I'm not sure about here is taking a 3D transform as an
argument. It says in the transform comments that for 2D the z-axis is
used for ordering, so I figured I'd keep it that way?

---

## Changelog

- Add method axes_2d.
- Update arrow_2d to also calculate the tip length depending on arrow
length as in arrow.
- Add axes_2d to examples 2d_gizmos.

---------

Co-authored-by: Ben Lambert <bennett-spencer.lambert@pierer-innovation.com>
2024-06-04 00:02:38 +00:00
Ricky Taylor
9b9d3d81cb
Normalise matrix naming (#13489)
# Objective
- Fixes #10909
- Fixes #8492

## Solution
- Name all matrices `x_from_y`, for example `world_from_view`.

## Testing
- I've tested most of the 3D examples. The `lighting` example
particularly should hit a lot of the changes and appears to run fine.

---

## Changelog
- Renamed matrices across the engine to follow a `y_from_x` naming,
making the space conversion more obvious.

## Migration Guide
- `Frustum`'s `from_view_projection`, `from_view_projection_custom_far`
and `from_view_projection_no_far` were renamed to
`from_clip_from_world`, `from_clip_from_world_custom_far` and
`from_clip_from_world_no_far`.
- `ComputedCameraValues::projection_matrix` was renamed to
`clip_from_view`.
- `CameraProjection::get_projection_matrix` was renamed to
`get_clip_from_view` (this affects implementations on `Projection`,
`PerspectiveProjection` and `OrthographicProjection`).
- `ViewRangefinder3d::from_view_matrix` was renamed to
`from_world_from_view`.
- `PreviousViewData`'s members were renamed to `view_from_world` and
`clip_from_world`.
- `ExtractedView`'s `projection`, `transform` and `view_projection` were
renamed to `clip_from_view`, `world_from_view` and `clip_from_world`.
- `ViewUniform`'s `view_proj`, `unjittered_view_proj`,
`inverse_view_proj`, `view`, `inverse_view`, `projection` and
`inverse_projection` were renamed to `clip_from_world`,
`unjittered_clip_from_world`, `world_from_clip`, `world_from_view`,
`view_from_world`, `clip_from_view` and `view_from_clip`.
- `GpuDirectionalCascade::view_projection` was renamed to
`clip_from_world`.
- `MeshTransforms`' `transform` and `previous_transform` were renamed to
`world_from_local` and `previous_world_from_local`.
- `MeshUniform`'s `transform`, `previous_transform`,
`inverse_transpose_model_a` and `inverse_transpose_model_b` were renamed
to `world_from_local`, `previous_world_from_local`,
`local_from_world_transpose_a` and `local_from_world_transpose_b` (the
`Mesh` type in WGSL mirrors this, however `transform` and
`previous_transform` were named `model` and `previous_model`).
- `Mesh2dTransforms::transform` was renamed to `world_from_local`.
- `Mesh2dUniform`'s `transform`, `inverse_transpose_model_a` and
`inverse_transpose_model_b` were renamed to `world_from_local`,
`local_from_world_transpose_a` and `local_from_world_transpose_b` (the
`Mesh2d` type in WGSL mirrors this).
- In WGSL, in `bevy_pbr::mesh_functions`, `get_model_matrix` and
`get_previous_model_matrix` were renamed to `get_world_from_local` and
`get_previous_world_from_local`.
- In WGSL, `bevy_sprite::mesh2d_functions::get_model_matrix` was renamed
to `get_world_from_local`.
2024-06-03 16:56:53 +00:00
Lynn
e6a0f75a63
More gizmos builders (#13261)
# Objective

- Add GizmoBuilders for some primitives as discussed in #13233

## Solution

- `gizmos.primitive_2d(CIRCLE)` and `gizmos.primitive_2d(ELLIPSE)` now
return `Ellipse2dBuilder` aswell.
- `gizmos.primitive_3d(SPHERE)` and `gizmos.sphere()` now return the
same `SphereBuilder`.
- the `.circle_segments` method on the `SphereBuilder` that used to be
returned by `.sphere()` is now called `.segments`
  - the sphere primitive gizmo now matches the `gizmos.sphere` gizmo
- `gizmos.primitive_2d(ANNULUS)` now returns a `Annulus2dBuilder`
allowing the configuration of the `segments`
- gizmos cylinders and capsules now have only 1 line per axis, similar
to `gizmos.sphere`

## Migration Guide

- Some `gizmos.primitive_nd` methods now return some or different
builders. You may need to adjust types and match statements
- Replace any calls to `circle_segments()` with `.segments()`

---------

Co-authored-by: Raphael Büttgenbach <62256001+solis-lumine-vorago@users.noreply.github.com>
2024-06-03 16:10:14 +00:00
Olle Lukowski
4b996c75ab
Implemented GizmoPrimitive2d for Arc2d, CircularSegment, CircularSector, and make arc_2d use counter-clockwise angle. (#13610)
# Objective

Fixes #13606.
Also Fixes #13614.

## Solution

Added the missing trait impls, and made `gizmos.arc_2d()` work with a
counter-clockwise angle.
## Testing

- Updated the render_primitives example, and it works.
2024-06-01 12:30:34 +00:00
Olle Lukowski
cf4baf8fbf
Make gizmos take primitives by ref (#13534)
# Objective

Fixes #13427.

## Solution

I changed the traits, and updated all usages.

## Testing

The `render_primitives` example still works perfectly.

---

## Changelog

- Made `gizmos.primitive_2d()` and `gizmos.primitive_3d()` take the
primitives by ref.

## Migration Guide

- Any usages of `gizmos.primitive_2d()` and/or `gizmos.primitive_3d()`
need to be updated to pass the primitive in by reference.
2024-05-27 13:48:47 +00:00
Salvador Carvalhinho
7d843e0c08
Implement Rhombus 2D primitive. (#13501)
# Objective

- Create a new 2D primitive, Rhombus, also knows as "Diamond Shape"
- Simplify the creation and handling of isometric projections
- Extend Bevy's arsenal of 2D primitives

## Testing

- New unit tests created in bevy_math/ primitives and bev_math/ bounding
- Tested translations, rotations, wireframe, bounding sphere, aabb and
creation parameters

---------

Co-authored-by: Luís Figueiredo <luispcfigueiredo@tecnico.ulisboa.pt>
2024-05-26 15:27:57 +00:00
Matty
3561467f5a
Add Triangle3d / Tetrahedron to render_primitives example (#13504)
# Objective

This is just cleanup; we've got some more renderable gizmos and
primitives now that hadn't been added to this example, so let's add
them.

## Solution

In the `render_primitives` example:
- Added `Triangle3d` mesh
- Wrote `primitive_3d` gizmo impl for `Triangle3d` and added the gizmo
- Added `Tetrahedron` mesh and gizmo

I also made the 2d triangle bigger, since it was really small.

## Testing

You can just run the example to see that everything turned out all
right.

## Other

Feel free to let me know if there are other primitives that I missed;
I'm happy to tack them onto this PR.
2024-05-25 13:20:58 +00:00
Lynn
9ef9f3b3a4
Inconsistent segments/resolution naming (#13438)
# Objective

- Fixes #13412

## Solution

- Renamed `segments` in `bevy_gizmos` to `resolution` and adjusted
examples

## Migration Guide

- When working with gizmos, replace all calls to `.segments(...)` with
`.resolution(...)`
2024-05-21 18:42:59 +00:00
Patrick Walton
9da0b2a0ec
Make render phases render world resources instead of components. (#13277)
This commit makes us stop using the render world ECS for
`BinnedRenderPhase` and `SortedRenderPhase` and instead use resources
with `EntityHashMap`s inside. There are three reasons to do this:

1. We can use `clear()` to clear out the render phase collections
instead of recreating the components from scratch, allowing us to reuse
allocations.

2. This is a prerequisite for retained bins, because components can't be
retained from frame to frame in the render world, but resources can.

3. We want to move away from storing anything in components in the
render world ECS, and this is a step in that direction.

This patch results in a small performance benefit, due to point (1)
above.

## Changelog

### Changed

* The `BinnedRenderPhase` and `SortedRenderPhase` render world
components have been replaced with `ViewBinnedRenderPhases` and
`ViewSortedRenderPhases` resources.

## Migration Guide

* The `BinnedRenderPhase` and `SortedRenderPhase` render world
components have been replaced with `ViewBinnedRenderPhases` and
`ViewSortedRenderPhases` resources. Instead of querying for the
components, look the camera entity up in the
`ViewBinnedRenderPhases`/`ViewSortedRenderPhases` tables.
2024-05-21 18:23:04 +00:00
IceSentry
aa907d5437
Remove unnecessary .view_layouts (#13394)
# Objective

- The volumetric fog PR originally needed to be modified to use
`.view_layouts` but that was changed in another PR. The merge with main
still kept those around.

## Solution

- Remove them because they aren't necessary
2024-05-16 19:12:36 +00:00
Patrick Walton
19bfa41768
Implement volumetric fog and volumetric lighting, also known as light shafts or god rays. (#13057)
This commit implements a more physically-accurate, but slower, form of
fog than the `bevy_pbr::fog` module does. Notably, this *volumetric fog*
allows for light beams from directional lights to shine through,
creating what is known as *light shafts* or *god rays*.

To add volumetric fog to a scene, add `VolumetricFogSettings` to the
camera, and add `VolumetricLight` to directional lights that you wish to
be volumetric. `VolumetricFogSettings` has numerous settings that allow
you to define the accuracy of the simulation, as well as the look of the
fog. Currently, only interaction with directional lights that have
shadow maps is supported. Note that the overhead of the effect scales
directly with the number of directional lights in use, so apply
`VolumetricLight` sparingly for the best results.

The overall algorithm, which is implemented as a postprocessing effect,
is a combination of the techniques described in [Scratchapixel] and
[this blog post]. It uses raymarching in screen space, transformed into
shadow map space for sampling and combined with physically-based
modeling of absorption and scattering. Bevy employs the widely-used
[Henyey-Greenstein phase function] to model asymmetry; this essentially
allows light shafts to fade into and out of existence as the user views
them.

Volumetric rendering is a huge subject, and I deliberately kept the
scope of this commit small. Possible follow-ups include:

1. Raymarching at a lower resolution.

2. A post-processing blur (especially useful when combined with (1)).

3. Supporting point lights and spot lights.

4. Supporting lights with no shadow maps.

5. Supporting irradiance volumes and reflection probes.

6. Voxel components that reuse the volumetric fog code to create voxel
shapes.

7. *Horizon: Zero Dawn*-style clouds.

These are all useful, but out of scope of this patch for now, to keep
things tidy and easy to review.

A new example, `volumetric_fog`, has been added to demonstrate the
effect.

## Changelog

### Added

* A new component, `VolumetricFog`, is available, to allow for a more
physically-accurate, but more resource-intensive, form of fog.

* A new component, `VolumetricLight`, can be placed on directional
lights to make them interact with `VolumetricFog`. Notably, this allows
such lights to emit light shafts/god rays.

![Screenshot 2024-04-21
162808](https://github.com/bevyengine/bevy/assets/157897/7a1fc81d-eed5-4735-9419-286c496391a9)

![Screenshot 2024-04-21
132005](https://github.com/bevyengine/bevy/assets/157897/e6d3b5ca-8f59-488d-a3de-15e95aaf4995)

[Scratchapixel]:
https://www.scratchapixel.com/lessons/3d-basic-rendering/volume-rendering-for-developers/intro-volume-rendering.html

[this blog post]: https://www.alexandre-pestana.com/volumetric-lights/

[Henyey-Greenstein phase function]:
https://www.pbr-book.org/4ed/Volume_Scattering/Phase_Functions#TheHenyeyndashGreensteinPhaseFunction
2024-05-16 17:13:18 +00:00
charlotte
4c3b7679ec
#12502 Remove limit on RenderLayers. (#13317)
# Objective

Remove the limit of `RenderLayer` by using a growable mask using
`SmallVec`.

Changes adopted from @UkoeHB's initial PR here
https://github.com/bevyengine/bevy/pull/12502 that contained additional
changes related to propagating render layers.

Changes

## Solution

The main thing needed to unblock this is removing `RenderLayers` from
our shader code. This primarily affects `DirectionalLight`. We are now
computing a `skip` field on the CPU that is then used to skip the light
in the shader.

## Testing

Checked a variety of examples and did a quick benchmark on `many_cubes`.
There were some existing problems identified during the development of
the original pr (see:
https://discord.com/channels/691052431525675048/1220477928605749340/1221190112939872347).
This PR shouldn't change any existing behavior besides removing the
layer limit (sans the comment in migration about `all` layers no longer
being possible).

---

## Changelog

Removed the limit on `RenderLayers` by using a growable bitset that only
allocates when layers greater than 64 are used.

## Migration Guide

- `RenderLayers::all()` no longer exists. Entities expecting to be
visible on all layers, e.g. lights, should compute the active layers
that are in use.

---------

Co-authored-by: robtfm <50659922+robtfm@users.noreply.github.com>
2024-05-16 16:15:47 +00:00
Lynn
05e2552a68
Add Rounded box gizmos (#11948)
# Objective

- Implement rounded cuboids and rectangles, suggestion of #9400 

## Solution

- Added `Gizmos::rounded_cuboid`, `Gizmos::rounded_rect` and
`Gizmos::rounded_rect_2d`.
- All of these return builders that allow configuring of the corner/edge
radius using `.corner_radius(...)` or `.edge_radius(...)` as well as the
line segments of each arc using `.arc_segments(...)`.

---

## Changelog

- Added a new `rounded_box` module to `bevy_gizmos` containing all of
the above methods and builders.
- Updated the examples `2d_gizmos` and `3d_gizmos`

## Additional information

The 3d example now looks like this:

<img width="1440" alt="Screenshot 2024-02-28 at 01 47 28"
src="https://github.com/bevyengine/bevy/assets/62256001/654e30ca-c091-4f14-a402-90138e95c71b">

And this is the updated 2d example showcasing negative corner radius:

<img width="1440" alt="Screenshot 2024-02-28 at 01 59 37"
src="https://github.com/bevyengine/bevy/assets/62256001/3904697a-5462-4ee7-abd9-3e893ca07082">
<img width="1440" alt="Screenshot 2024-02-28 at 01 59 47"
src="https://github.com/bevyengine/bevy/assets/62256001/a8892cfd-3aad-4c0c-87eb-559c17c8864c">

---------

Co-authored-by: JMS55 <47158642+JMS55@users.noreply.github.com>
Co-authored-by: James Gayfer <10660608+jgayfer@users.noreply.github.com>
2024-05-16 16:13:49 +00:00
François Mockers
443ce9a62b
gizmos: take normal of normal on plane 3d before rotation (#13326)
# Objective

- Example `render_primitives` is painful to look at for the plane in 3d,
the gizmo seems to have extra rotations


https://github.com/bevyengine/bevy/assets/8672791/08509624-14ac-4f00-a758-9a14233ef1a9

## Solution

- Take the normal of the normal before rotation, then rotate it

## Testing

- Run the example, rotations are more in sync


https://github.com/bevyengine/bevy/assets/8672791/91c26ce4-4b7b-4575-ba32-7c32026e4596
2024-05-11 19:32:31 +00:00
Matty
4da11fda77
Add AXES iterators for Dir types (#13305)
# Objective

Sometimes it's nice to iterate over all the coordinate axes using
something like `Vec3::AXES`. This was not available for the
corresponding `Dir` types and now it is.

## Solution

We already have things like `Dir2::X`, `Dir3::Z` and so on, so I just
threw them in an array like the vector types do it. I also slightly
refactored the sphere gizmo code to use `Dir3::AXES` and operate on
directions instead of using `Dir3::new_unchecked`.

## Testing

I looked at the sphere in the `3d_gizmos` example and it seems to work,
so I assume I didn't break anything.
2024-05-09 23:30:44 +00:00
Lynn
89cd5f54f8
Add Annulus-gizmos (#13233)
# Objective

- Add support for drawing `Annulus`-gizmos using
`gizmos.primitive_2d(...)`

## Changelog

- Updated the example `math/render_primitives`
2024-05-05 22:23:32 +00:00
BD103
e357b63448
Add README.md to all crates (#13184)
# Objective

- `README.md` is a common file that usually gives an overview of the
folder it is in.
- When on <https://crates.io>, `README.md` is rendered as the main
description.
- Many crates in this repository are lacking `README.md` files, which
makes it more difficult to understand their purpose.

<img width="1552" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/78ebf91d-b0c4-4b18-9874-365d6310640f">

- There are also a few inconsistencies with `README.md` files that this
PR and its follow-ups intend to fix.

## Solution

- Create a `README.md` file for all crates that do not have one.
- This file only contains the title of the crate (underscores removed,
proper capitalization, acronyms expanded) and the <https://shields.io>
badges.
- Remove the `readme` field in `Cargo.toml` for `bevy` and
`bevy_reflect`.
- This field is redundant because [Cargo automatically detects
`README.md`
files](https://doc.rust-lang.org/cargo/reference/manifest.html#the-readme-field).
The field is only there if you name it something else, like `INFO.md`.
- Fix capitalization of `bevy_utils`'s `README.md`.
- It was originally `Readme.md`, which is inconsistent with the rest of
the project.
- I created two commits renaming it to `README.md`, because Git appears
to be case-insensitive.
- Expand acronyms in title of `bevy_ptr` and `bevy_utils`.
- In the commit where I created all the new `README.md` files, I
preferred using expanded acronyms in the titles. (E.g. "Bevy Developer
Tools" instead of "Bevy Dev Tools".)
- This commit changes the title of existing `README.md` files to follow
the same scheme.
- I do not feel strongly about this change, please comment if you
disagree and I can revert it.
- Add <https://shields.io> badges to `bevy_time` and `bevy_transform`,
which are the only crates currently lacking them.

---

## Changelog

- Added `README.md` files to all crates missing it.
2024-05-02 18:56:00 +00:00
Patrick Walton
16531fb3e3
Implement GPU frustum culling. (#12889)
This commit implements opt-in GPU frustum culling, built on top of the
infrastructure in https://github.com/bevyengine/bevy/pull/12773. To
enable it on a camera, add the `GpuCulling` component to it. To
additionally disable CPU frustum culling, add the `NoCpuCulling`
component. Note that adding `GpuCulling` without `NoCpuCulling`
*currently* does nothing useful. The reason why `GpuCulling` doesn't
automatically imply `NoCpuCulling` is that I intend to follow this patch
up with GPU two-phase occlusion culling, and CPU frustum culling plus
GPU occlusion culling seems like a very commonly-desired mode.

Adding the `GpuCulling` component to a view puts that view into
*indirect mode*. This mode makes all drawcalls indirect, relying on the
mesh preprocessing shader to allocate instances dynamically. In indirect
mode, the `PreprocessWorkItem` `output_index` points not to a
`MeshUniform` instance slot but instead to a set of `wgpu`
`IndirectParameters`, from which it allocates an instance slot
dynamically if frustum culling succeeds. Batch building has been updated
to allocate and track indirect parameter slots, and the AABBs are now
supplied to the GPU as `MeshCullingData`.

A small amount of code relating to the frustum culling has been borrowed
from meshlets and moved into `maths.wgsl`. Note that standard Bevy
frustum culling uses AABBs, while meshlets use bounding spheres; this
means that not as much code can be shared as one might think.

This patch doesn't provide any way to perform GPU culling on shadow
maps, to avoid making this patch bigger than it already is. That can be
a followup.

## Changelog

### Added

* Frustum culling can now optionally be done on the GPU. To enable it,
add the `GpuCulling` component to a camera.
* To disable CPU frustum culling, add `NoCpuCulling` to a camera. Note
that `GpuCulling` doesn't automatically imply `NoCpuCulling`.
2024-04-28 12:50:00 +00:00
Aceeri
b1ab036329
Contextually clearing gizmos (#10973)
# Objective
Allow `Gizmos` to work in `FixedUpdate` without any changes needed. This
changes `Gizmos` from being a purely immediate mode api, but allows the
user to use it as if it were an immediate mode API regardless of
schedule context.

Also allows for extending by other custom schedules by adding their own
`GizmoStorage<Clear>` and the requisite systems:
- `propagate_gizmos::<Clear>` before `update_gizmo_meshes`
- `stash_default_gizmos` when starting a clear context
- `pop_default_gizmos` when ending a clear context
- `collect_default_gizmos` when grabbing the requested gizmos 
- `clear_gizmos` for clearing the context's gizmos

## Solution
Adds a generic to `Gizmos` that defaults to `Update` (the current way
gizmos works). When entering a new clear context the default `Gizmos`
gets swapped out for that context's duration so the context can collect
the gizmos requested.

Prior work: https://github.com/bevyengine/bevy/pull/9153

## To do
- [x] `FixedUpdate` should probably get its own First, Pre, Update,
Post, Last system sets for this. Otherwise users will need to make sure
to order their systems before `clear_gizmos`. This could alternatively
be fixed by moving the setup of this to `bevy_time::fixed`?
   PR to fix this issue: https://github.com/bevyengine/bevy/pull/10977
- [x] use mem::take internally for the swaps?
- [x] Better name for the `Context` generic on gizmos? `Clear`?

---

## Changelog
- Gizmos drawn in `FixedMain` now last until the next `FixedMain`
iteration runs.
2024-04-23 00:16:12 +00:00
James Liu
54456b7ea6
Make SystemParam::new_archetype and QueryState::new_archetype unsafe functions (#13044)
# Objective
Fix #2128. Both `Query::new_archetype` and `SystemParam::new_archetype`
do not check if the `Archetype` comes from the same World the state is
initialized from. This could result in unsoundness via invalid accesses
if called incorrectly.

## Solution
Make them `unsafe` functions and lift the invariant to the caller. This
also caught one instance of us not validating the World in
`SystemState::update_archetypes_unsafe_world_cell`'s implementation.

---

## Changelog
Changed: `QueryState::new_archetype` is now an unsafe function.
Changed: `SystemParam::new_archetype` is now an unsafe function.

## Migration Guide
`QueryState::new_archetype` and `SystemParam::new_archetype` are now an
unsafe functions that must be sure that the provided `Archetype` is from
the same `World` that the state was initialized from. Callers may need
to add additional assertions or propagate the safety invariant upwards
through the callstack to ensure safety.
2024-04-21 02:49:42 +00:00
targrub
8316166622
Fix uses of "it's" vs "its". (#13033)
Grammar changes only.
2024-04-19 18:17:31 +00:00
andristarr
2b3e3341d6
separating finite and infinite 3d planes (#12426)
# Objective

Fixes #12388

## Solution

- Removing the plane3d and adding rect3d primitive mesh
2024-04-18 14:13:22 +00:00
Pablo Reinhardt
6b0e3fa572
Add double end arrow to gizmos (#11890)
# Objective

- Implement double ended arrows, suggestion of #9400

## Solution

- Creation of new field and method to the `ArrowBuilder`

---

## Changelog

### Added
- New field `ArrowBuilder::double_ended`
- New method `ArrowBuilder::with_double_end` to redefine the
double_ended field

## Additional

I added this in the 3d_gizmos example, that's the result:


![image](https://github.com/bevyengine/bevy/assets/126117294/2f8a93eb-4952-401a-b600-b1454cf898a9)

I added this arrow in the 2d_gizmos example too:


![image](https://github.com/bevyengine/bevy/assets/126117294/c46b4871-8acf-4711-9ca8-c2df36c0464b)

---------

Co-authored-by: Afonso Lage <lage.afonso@gmail.com>
Co-authored-by: Pablo Reinhardt <pabloreinhardt@gmail.com>
2024-04-16 01:34:22 +00:00
BD103
a362c278bb
Fix crates not building individually (#12948)
# Objective

- `cargo check --workspace` appears to merge features and dependencies
together, so it does not catch some issues where dependencies are not
properly feature-gated.
- The issues **are** caught, though, by running `cd $crate && cargo
check`.

## Solution

- Manually check each crate for issues.

```shell
# Script used
for i in crates/bevy_* do
    pushd $i
    cargo check
    popd
done
```

- `bevy_color` had an issue where it used `#[derive(Pod, Zeroable)]`
without using `bytemuck`'s `derive` feature.
- The `FpsOverlayPlugin` in `bevy_dev_tools` uses `bevy_ui`'s
`bevy_text` integration without properly enabling `bevy_text` as a
feature.
- `bevy_gizmos`'s `light` module was not properly feature-gated behind
`bevy_pbr`.
- ~~Lights appear to only be implemented in `bevy_pbr` and not
`bevy_sprite`, so I think this is the right call. Can I get a
confirmation by a gizmos person?~~ Confirmed :)
- `bevy_gltf` imported `SmallVec`, but only used it if `bevy_animation`
was enabled.
- There was another issue, but it was more challenging to solve than the
`smallvec` one. Run `cargo check -p bevy_gltf` and it will raise an
issue about `animation_roots`.

<details>
  <summary><code>bevy_gltf</code> errors</summary>

```shell
error[E0425]: cannot find value `animation_roots` in this scope
   --> crates/bevy_gltf/src/loader.rs:608:26
    |
608 |                         &animation_roots,
    |                          ^^^^^^^^^^^^^^^ not found in this scope

warning: variable does not need to be mutable
    --> crates/bevy_gltf/src/loader.rs:1015:5
     |
1015 |     mut animation_context: Option<AnimationContext>,
     |     ----^^^^^^^^^^^^^^^^^
     |     |
     |     help: remove this `mut`
     |
     = note: `#[warn(unused_mut)]` on by default

For more information about this error, try `rustc --explain E0425`.
warning: `bevy_gltf` (lib) generated 1 warning
error: could not compile `bevy_gltf` (lib) due to 1 previous error; 1 warning emitted
```

</details> 

---

## Changelog

- Fixed `bevy_color`, `bevy_dev_tools`, and `bevy_gizmos` so they can
now compile by themselves.
2024-04-14 00:06:03 +00:00
Lynn
597799a979
Add tetrahedron gizmos (#12914)
# Objective

- Adds tetrahedron gizmos, suggestion of #9400

## Solution

- Implement tetrahedron gizmos as a `gizmos.primitive_3d`

## Additional info

Here is a short video of the default tetrahedron :)


https://github.com/bevyengine/bevy/assets/62256001/a6f31b6f-78bc-4dc2-8f46-2ebd04ed8a0e

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-04-10 17:59:58 +00:00
Lynn
2f0b5b9c5a
Use impl Into<Color> for gizmos.primitive_3d(...) (#12915)
# Objective

- All gizmos APIs besides `gizmos.primitive_3d` use `impl Into<Color>`
as their type for `color`.

## Solution

- This PR changes `primitive_3d()` to use `impl Into<Color>` aswell.
2024-04-09 17:33:34 +00:00
Robert Swain
ab7cbfa8fc
Consolidate Render(Ui)Materials(2d) into RenderAssets (#12827)
# Objective

- Replace `RenderMaterials` / `RenderMaterials2d` / `RenderUiMaterials`
with `RenderAssets` to enable implementing changes to one thing,
`RenderAssets`, that applies to all use cases rather than duplicating
changes everywhere for multiple things that should be one thing.
- Adopts #8149 

## Solution

- Make RenderAsset generic over the destination type rather than the
source type as in #8149
- Use `RenderAssets<PreparedMaterial<M>>` etc for render materials

---

## Changelog

- Changed:
- The `RenderAsset` trait is now implemented on the destination type.
Its `SourceAsset` associated type refers to the type of the source
asset.
- `RenderMaterials`, `RenderMaterials2d`, and `RenderUiMaterials` have
been replaced by `RenderAssets<PreparedMaterial<M>>` and similar.

## Migration Guide

- `RenderAsset` is now implemented for the destination type rather that
the source asset type. The source asset type is now the `RenderAsset`
trait's `SourceAsset` associated type.
2024-04-09 13:26:34 +00:00
Stephen Turley
257df3af5f
Changed the order of arguments for the Arc gizmo docs (#12854)
Just updating docs for the arc gizmo so that the argument documentation
matches the order of the function arguments.
Also added docs for the color argument.

# Objective

- Improve docs

## Solution

- Moved the radius argument to the end of the argument list to match the
function

---

## Changelog

> N/A

## Migration Guide

> N/A

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-04-03 01:46:20 +00:00
Cameron
01649f13e2
Refactor App and SubApp internals for better separation (#9202)
# Objective

This is a necessary precursor to #9122 (this was split from that PR to
reduce the amount of code to review all at once).

Moving `!Send` resource ownership to `App` will make it unambiguously
`!Send`. `SubApp` must be `Send`, so it can't wrap `App`.

## Solution

Refactor `App` and `SubApp` to not have a recursive relationship. Since
`SubApp` no longer wraps `App`, once `!Send` resources are moved out of
`World` and into `App`, `SubApp` will become unambiguously `Send`.

There could be less code duplication between `App` and `SubApp`, but
that would break `App` method chaining.

## Changelog

- `SubApp` no longer wraps `App`.
- `App` fields are no longer publicly accessible.
- `App` can no longer be converted into a `SubApp`.
- Various methods now return references to a `SubApp` instead of an
`App`.
## Migration Guide

- To construct a sub-app, use `SubApp::new()`. `App` can no longer
convert into `SubApp`.
- If you implemented a trait for `App`, you may want to implement it for
`SubApp` as well.
- If you're accessing `app.world` directly, you now have to use
`app.world()` and `app.world_mut()`.
- `App::sub_app` now returns `&SubApp`.
- `App::sub_app_mut`  now returns `&mut SubApp`.
- `App::get_sub_app` now returns `Option<&SubApp>.`
- `App::get_sub_app_mut` now returns `Option<&mut SubApp>.`
2024-03-31 03:16:10 +00:00
Patrick Walton
4dadebd9c4
Improve performance by binning together opaque items instead of sorting them. (#12453)
Today, we sort all entities added to all phases, even the phases that
don't strictly need sorting, such as the opaque and shadow phases. This
results in a performance loss because our `PhaseItem`s are rather large
in memory, so sorting is slow. Additionally, determining the boundaries
of batches is an O(n) process.

This commit makes Bevy instead applicable place phase items into *bins*
keyed by *bin keys*, which have the invariant that everything in the
same bin is potentially batchable. This makes determining batch
boundaries O(1), because everything in the same bin can be batched.
Instead of sorting each entity, we now sort only the bin keys. This
drops the sorting time to near-zero on workloads with few bins like
`many_cubes --no-frustum-culling`. Memory usage is improved too, with
batch boundaries and dynamic indices now implicit instead of explicit.
The improved memory usage results in a significant win even on
unbatchable workloads like `many_cubes --no-frustum-culling
--vary-material-data-per-instance`, presumably due to cache effects.

Not all phases can be binned; some, such as transparent and transmissive
phases, must still be sorted. To handle this, this commit splits
`PhaseItem` into `BinnedPhaseItem` and `SortedPhaseItem`. Most of the
logic that today deals with `PhaseItem`s has been moved to
`SortedPhaseItem`. `BinnedPhaseItem` has the new logic.

Frame time results (in ms/frame) are as follows:

| Benchmark                | `binning` | `main`  | Speedup |
| ------------------------ | --------- | ------- | ------- |
| `many_cubes -nfc -vpi` | 232.179     | 312.123   | 34.43%  |
| `many_cubes -nfc`        | 25.874 | 30.117 | 16.40%  |
| `many_foxes`             | 3.276 | 3.515 | 7.30%   |

(`-nfc` is short for `--no-frustum-culling`; `-vpi` is short for
`--vary-per-instance`.)

---

## Changelog

### Changed

* Render phases have been split into binned and sorted phases. Binned
phases, such as the common opaque phase, achieve improved CPU
performance by avoiding the sorting step.

## Migration Guide

- `PhaseItem` has been split into `BinnedPhaseItem` and
`SortedPhaseItem`. If your code has custom `PhaseItem`s, you will need
to migrate them to one of these two types. `SortedPhaseItem` requires
the fewest code changes, but you may want to pick `BinnedPhaseItem` if
your phase doesn't require sorting, as that enables higher performance.

## Tracy graphs

`many-cubes --no-frustum-culling`, `main` branch:
<img width="1064" alt="Screenshot 2024-03-12 180037"
src="https://github.com/bevyengine/bevy/assets/157897/e1180ce8-8e89-46d2-85e3-f59f72109a55">

`many-cubes --no-frustum-culling`, this branch:
<img width="1064" alt="Screenshot 2024-03-12 180011"
src="https://github.com/bevyengine/bevy/assets/157897/0899f036-6075-44c5-a972-44d95895f46c">

You can see that `batch_and_prepare_binned_render_phase` is a much
smaller fraction of the time. Zooming in on that function, with yellow
being this branch and red being `main`, we see:

<img width="1064" alt="Screenshot 2024-03-12 175832"
src="https://github.com/bevyengine/bevy/assets/157897/0dfc8d3f-49f4-496e-8825-a66e64d356d0">

The binning happens in `queue_material_meshes`. Again with yellow being
this branch and red being `main`:
<img width="1064" alt="Screenshot 2024-03-12 175755"
src="https://github.com/bevyengine/bevy/assets/157897/b9b20dc1-11c8-400c-a6cc-1c2e09c1bb96">

We can see that there is a small regression in `queue_material_meshes`
performance, but it's not nearly enough to outweigh the large gains in
`batch_and_prepare_binned_render_phase`.

---------

Co-authored-by: James Liu <contact@jamessliu.com>
2024-03-30 02:55:02 +00:00
s-puig
7363268ea8
Fix ambiguities causing a crash (#12780)
# Objective

- Disabling some plugins causes a crash due to ambiguities relying in
feature flags and not checking if both plugins are enabled causing code
like this to crash:

`app.add_plugins(DefaultPlugins.build().disable::<AnimationPlugin>())`

## Solution

- Check if plugins were added before ambiguities.
- Move bevy_gizmos ambiguities from bevy_internal to bevy_gizmos since
they already depend on them.
2024-03-29 16:00:13 +00:00
Jacques Schutte
4508077297
Move FloatOrd into bevy_math (#12732)
# Objective

- Fixes #12712

## Solution

- Move the `float_ord.rs` file to `bevy_math`
- Change any `bevy_utils::FloatOrd` statements to `bevy_math::FloatOrd`

---

## Changelog

- Moved `FloatOrd` from `bevy_utils` to `bevy_math`

## Migration Guide

- References to `bevy_utils::FloatOrd` should be changed to
`bevy_math::FloatOrd`
2024-03-27 18:30:11 +00:00
James Liu
56bcbb0975
Forbid unsafe in most crates in the engine (#12684)
# Objective
Resolves #3824. `unsafe` code should be the exception, not the norm in
Rust. It's obviously needed for various use cases as it's interfacing
with platforms and essentially running the borrow checker at runtime in
the ECS, but the touted benefits of Bevy is that we are able to heavily
leverage Rust's safety, and we should be holding ourselves accountable
to that by minimizing our unsafe footprint.

## Solution
Deny `unsafe_code` workspace wide. Add explicit exceptions for the
following crates, and forbid it in almost all of the others.

* bevy_ecs - Obvious given how much unsafe is needed to achieve
performant results
* bevy_ptr - Works with raw pointers, even more low level than bevy_ecs.
 * bevy_render - due to needing to integrate with wgpu
 * bevy_window - due to needing to integrate with raw_window_handle
* bevy_utils - Several unsafe utilities used by bevy_ecs. Ideally moved
into bevy_ecs instead of made publicly usable.
 * bevy_reflect - Required for the unsafe type casting it's doing.
 * bevy_transform - for the parallel transform propagation
 * bevy_gizmos  - For the SystemParam impls it has.
* bevy_assets - To support reflection. Might not be required, not 100%
sure yet.
* bevy_mikktspace - due to being a conversion from a C library. Pending
safe rewrite.
* bevy_dynamic_plugin - Inherently unsafe due to the dynamic loading
nature.

Several uses of unsafe were rewritten, as they did not need to be using
them:

* bevy_text - a case of `Option::unchecked` could be rewritten as a
normal for loop and match instead of an iterator.
* bevy_color - the Pod/Zeroable implementations were replaceable with
bytemuck's derive macros.
2024-03-27 03:30:08 +00:00
mamekoro
cb9789bc35
Remove unnecessary executable flags from Rust source files (#12707)
# Objective
I found that some .rs files are unnecessarily executable.

Rust source files may start with a shebang-like statement `#!`, so let's
make sure they are not executable just in case.

Here is the result of the `find` commend that lists executable .rs files
as of main branch `86bd648`.
```console
$ find -name \*.rs -type f -executable
./crates/bevy_gizmos/src/lib.rs
./crates/bevy_tasks/src/lib.rs
./crates/bevy_time/src/lib.rs
./crates/bevy_transform/src/lib.rs
./src/lib.rs
```

It appears that the permissions of those files were originally 644, but
were unexpectedly changed to 755 by commit
52e3f2007b.

## Solution
Make them not executable by using this command;
`find -name \*.rs -type f -executable -exec chmod --verbose a-x -- {}
\+`
2024-03-25 20:03:55 +00:00
Lynn
97a5059535
Gizmo line styles (#12394)
# Objective

- Adds line styles to bevy gizmos, suggestion of #9400 
- Currently solid and dotted lines are implemented but this can easily
be extended to support dashed lines as well if that is wanted.

## Solution

- Adds the enum `GizmoLineStyle` and uses it in each `GizmoConfig` to
configure the style of the line.
- Each "dot" in a dotted line has the same width and height as the
`line_width` of the corresponding line.

---

## Changelog

- Added `GizmoLineStyle` to `bevy_gizmos`
- Added a `line_style: GizmoLineStyle ` attribute to `GizmoConfig`
- Updated the `lines.wgsl` shader and the pipelines accordingly.

## Migration Guide

- Any manually created `GizmoConfig` must now include the `line_style`
attribute

## Additional information
Some pretty pictures :)

This is the 3d_gizmos example with/without `line_perspective`:
<img width="1440" alt="Screenshot 2024-03-09 at 23 25 53"
src="https://github.com/bevyengine/bevy/assets/62256001/b1b97311-e78d-4de3-8dfe-9e48a35bb27d">
<img width="1440" alt="Screenshot 2024-03-09 at 23 25 39"
src="https://github.com/bevyengine/bevy/assets/62256001/50ee8ecb-5290-484d-ba36-7fd028374f7f">

And the 2d example:
<img width="1440" alt="Screenshot 2024-03-09 at 23 25 06"
src="https://github.com/bevyengine/bevy/assets/62256001/4452168f-d605-4333-bfa5-5461d268b132">

---------

Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
2024-03-25 19:10:45 +00:00
James Liu
f096ad4155
Set the logo and favicon for all of Bevy's published crates (#12696)
# Objective
Currently the built docs only shows the logo and favicon for the top
level `bevy` crate. This makes views like
https://docs.rs/bevy_ecs/latest/bevy_ecs/ look potentially unrelated to
the project at first glance.

## Solution
Reproduce the docs attributes for every crate that Bevy publishes.

Ideally this would be done with some workspace level Cargo.toml control,
but AFAICT, such support does not exist.
2024-03-25 18:52:50 +00:00
Ame
72c51cdab9
Make feature(doc_auto_cfg) work (#12642)
# Objective

- In #12366 `![cfg_attr(docsrs, feature(doc_auto_cfg))] `was added. But
to apply it it needs `--cfg=docsrs` in rustdoc-args.


## Solution

- Apply `--cfg=docsrs` to all crates and CI.

I also added `[package.metadata.docs.rs]` to all crates to avoid adding
code behind a feature and forget adding the metadata.

Before:

![Screenshot 2024-03-22 at 00 51
57](https://github.com/bevyengine/bevy/assets/104745335/6a9dfdaa-8710-4784-852b-5f9b74e3522c)

After:
![Screenshot 2024-03-22 at 00 51
32](https://github.com/bevyengine/bevy/assets/104745335/c5bd6d8e-8ddb-45b3-b844-5ecf9f88961c)
2024-03-23 02:22:52 +00:00