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>
# 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)
# 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
# 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
# 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>
# 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>
# 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`.
# 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>
# 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.
# 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.
# 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>
# 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.
# 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(...)`
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.
# 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
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
# 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>
# 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>
# 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.
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`.
# 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.
# 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.
# 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.
# 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.
# 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.
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>
# 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>.`
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>
# 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.
# 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`
# 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.
# 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 -- {}
\+`
# 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>
# 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.
# Objective
- Adds 3d grids, suggestion of #9400
## Solution
- Added 3d grids (grids spanning all three dimensions, not flat grids)
to bevy_gizmos
---
## Changelog
- `gizmos.grid(...)` and `gizmos.grid_2d(...)` now return a
`GridBuilder2d`.
- Added `gizmos.grid_3d(...)` which returns a `GridBuilder3d`.
- The difference between them is basically only that `GridBuilder3d`
exposes some methods for configuring the z axis while the 2d version
doesn't.
- Allowed for drawing the outer edges along a specific axis by calling
`.outer_edges_x()`, etc. on the builder.
## Additional information
Please note that I have not added the 3d grid to any example as not to
clutter them.
Here is an image of what the 3d grid looks like:
<img width="1440" alt="Screenshot 2024-03-12 at 02 19 55"
src="https://github.com/bevyengine/bevy/assets/62256001/4cd3b7de-cf2c-4f05-8a79-920a4dd804b8">
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Adds gizmo line joints, suggestion of #9400
## Solution
- Adds `line_joints: GizmoLineJoint` to `GizmoConfig`. Currently the
following values are supported:
- `GizmoLineJoint::None`: does not draw line joints, same behaviour as
previously
- `GizmoLineJoint::Bevel`: draws a single triangle between the lines
- `GizmoLineJoint::Miter` / 'spiky joints': draws two triangles between
the lines extending them until they meet at a (miter) point.
- NOTE: for very small angles between the lines, which happens
frequently in 3d, the miter point will be very far away from the point
at which the lines meet.
- `GizmoLineJoint::Round(resolution)`: Draw a circle arc between the
lines. The circle is a triangle fan of `resolution` triangles.
---
## Changelog
- Added `GizmoLineJoint`, use that in `GizmoConfig` and added necessary
pipelines and draw commands.
- Added a new `line_joints.wgsl` shader containing three vertex shaders
`vertex_bevel`, `vertex_miter` and `vertex_round` as well as a basic
`fragment` shader.
## Migration Guide
Any manually created `GizmoConfig`s must now set the `.line_joints`
field.
## Known issues
- The way we currently create basic closed shapes like rectangles,
circles, triangles or really any closed 2d shape means that one of the
corners will not be drawn with joints, although that would probably be
expected. (see the triangle in the 2d image)
- This could be somewhat mitigated by introducing line caps or fixed by
adding another segment overlapping the first of the strip. (Maybe in a
followup PR?)
- 3d shapes can look 'off' with line joints (especially bevel) because
wherever 3 or more lines meet one of them may stick out beyond the joint
drawn between the other 2.
- Adding additional lines so that there is a joint between every line at
a corner would fix this but would probably be too computationally
expensive.
- Miter joints are 'unreasonably long' for very small angles between the
lines (the angle is the angle between the lines in screen space). This
is technically correct but distracting and does not feel right,
especially in 3d contexts. I think limiting the length of the miter to
the point at which the lines meet might be a good idea.
- The joints may be drawn with a different gizmo in-between them and
their corresponding lines in 2d. Some sort of z-ordering would probably
be good here, but I believe this may be out of scope for this PR.
## Additional information
Some pretty images :)
<img width="1175" alt="Screenshot 2024-03-02 at 04 53 50"
src="https://github.com/bevyengine/bevy/assets/62256001/58df7e63-9376-4430-8871-32adba0cb53b">
- Note that the top vertex does not have a joint drawn.
<img width="1440" alt="Screenshot 2024-03-02 at 05 03 55"
src="https://github.com/bevyengine/bevy/assets/62256001/137a00cf-cbd4-48c2-a46f-4b47492d4fd9">
Now for a weird video:
https://github.com/bevyengine/bevy/assets/62256001/93026f48-f1d6-46fe-9163-5ab548a3fce4
- The black lines shooting out from the cube are miter joints that get
very long because the lines between which they are drawn are (almost)
collinear in screen space.
---------
Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
# Objective
Rotating vectors is a very common task. It is required for a variety of
things both within Bevy itself and in many third party plugins, for
example all over physics and collision detection, and for things like
Bevy's bounding volumes and several gizmo implementations.
For 3D, we can do this using a `Quat`, but for 2D, we do not have a
clear and efficient option. `Mat2` can be used for rotating vectors if
created using `Mat2::from_angle`, but this is not obvious to many users,
it doesn't have many rotation helpers, and the type does not give any
guarantees that it represents a valid rotation.
We should have a proper type for 2D rotations. In addition to allowing
for potential optimization, it would allow us to have a consistent and
explicitly documented representation used throughout the engine, i.e.
counterclockwise and in radians.
## Representation
The mathematical formula for rotating a 2D vector is the following:
```
new_x = x * cos - y * sin
new_y = x * sin + y * cos
```
Here, `sin` and `cos` are the sine and cosine of the rotation angle.
Computing these every time when a vector needs to be rotated can be
expensive, so the rotation shouldn't be just an `f32` angle. Instead, it
is often more efficient to represent the rotation using the sine and
cosine of the angle instead of storing the angle itself. This can be
freely passed around and reused without unnecessary computations.
The two options are either a 2x2 rotation matrix or a unit complex
number where the cosine is the real part and the sine is the imaginary
part. These are equivalent for the most part, but the unit complex
representation is a bit more memory efficient (two `f32`s instead of
four), so I chose that. This is like Nalgebra's
[`UnitComplex`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.UnitComplex.html)
type, which can be used for the
[`Rotation2`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.Rotation2.html)
type.
## Implementation
Add a `Rotation2d` type represented as a unit complex number:
```rust
/// A counterclockwise 2D rotation in radians.
///
/// The rotation angle is wrapped to be within the `]-pi, pi]` range.
pub struct Rotation2d {
/// The cosine of the rotation angle in radians.
///
/// This is the real part of the unit complex number representing the rotation.
pub cos: f32,
/// The sine of the rotation angle in radians.
///
/// This is the imaginary part of the unit complex number representing the rotation.
pub sin: f32,
}
```
Using it is similar to using `Quat`, but in 2D:
```rust
let rotation = Rotation2d::radians(PI / 2.0);
// Rotate vector (also works on Direction2d!)
assert_eq!(rotation * Vec2::X, Vec2::Y);
// Get angle as degrees
assert_eq!(rotation.as_degrees(), 90.0);
// Getting sin and cos is free
let (sin, cos) = rotation.sin_cos();
// "Subtract" rotations
let rotation2 = Rotation2d::FRAC_PI_4; // there are constants!
let diff = rotation * rotation2.inverse();
assert_eq!(diff.as_radians(), PI / 4.0);
// This is equivalent to the above
assert_eq!(rotation2.angle_between(rotation), PI / 4.0);
// Lerp
let rotation1 = Rotation2d::IDENTITY;
let rotation2 = Rotation2d::FRAC_PI_2;
let result = rotation1.lerp(rotation2, 0.5);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_4);
// Slerp
let rotation1 = Rotation2d::FRAC_PI_4);
let rotation2 = Rotation2d::degrees(-180.0); // we can use degrees too!
let result = rotation1.slerp(rotation2, 1.0 / 3.0);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_2);
```
There's also a `From<f32>` implementation for `Rotation2d`, which means
that methods can still accept radians as floats if the argument uses
`impl Into<Rotation2d>`. This means that adding `Rotation2d` shouldn't
even be a breaking change.
---
## Changelog
- Added `Rotation2d`
- Bounding volume methods now take an `impl Into<Rotation2d>`
- Gizmo methods with rotation now take an `impl Into<Rotation2d>`
## Future use cases
- Collision detection (a type like this is quite essential considering
how common vector rotations are)
- `Transform` helpers (e.g. return a 2D rotation about the Z axis from a
`Transform`)
- The rotation used for `Transform2d` (#8268)
- More gizmos, maybe meshes... everything in 2D that uses rotation
---------
Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Co-authored-by: Robert Walter <robwalter96@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
# Objective
Fix missing `TextBundle` (and many others) which are present in the main
crate as default features but optional in the sub-crate. See:
- https://docs.rs/bevy/0.13.0/bevy/ui/node_bundles/index.html
- https://docs.rs/bevy_ui/0.13.0/bevy_ui/node_bundles/index.html
~~There are probably other instances in other crates that I could track
down, but maybe "all-features = true" should be used by default in all
sub-crates? Not sure.~~ (There were many.) I only noticed this because
rust-analyzer's "open docs" features takes me to the sub-crate, not the
main one.
## Solution
Add "all-features = true" to docs.rs metadata for crates that use
features.
## Changelog
### Changed
- Unified features documented on docs.rs between main crate and
sub-crates