# Objective
The `Cone` primitive should support meshing.
## Solution
Implement meshing for the `Cone` primitive. The default cone has a
height of 1 and a base radius of 0.5, and is centered at the origin.
An issue with cone meshes is that the tip does not really have a normal
that works, even with duplicated vertices. This PR uses only a single
vertex for the tip, with a normal of zero; this results in an "invalid"
normal that gets ignored by the fragment shader. This seems to be the
only approach we have for perfectly smooth cones. For discussion on the
topic, see #10298 and #5891.
Another thing to note is that the cone uses polar coordinates for the
UVs:
<img
src="https://github.com/bevyengine/bevy/assets/57632562/e101ded9-110a-4ac4-a98d-f1e4d740a24a"
alt="cone" width="400" />
This way, textures are applied as if looking at the cone from above:
<img
src="https://github.com/bevyengine/bevy/assets/57632562/8dea00f1-a283-4bc4-9676-91e8d4adb07a"
alt="texture" width="200" />
<img
src="https://github.com/bevyengine/bevy/assets/57632562/d9d1b5e6-a8ba-4690-b599-904dd85777a1"
alt="cone" width="200" />
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/12597
The current tracing customization option (the `update_subscriber` field)
was basically unusable because it provides a `dyn Subscriber` and most
layers require a `Subscriber` that also implements `for<'a>
LookupSpan<'a, Data=Data<'a>>`, so it was impossible to add a layer on
top of the `dyn Subscriber`.
This PR provides an alternative way of adding additional tracing layers
to the LogPlugin by instead creating an `Option<Layer>`.
This is enough for most situations because `Option<Layer>` and
`Vec<Layer>` both implement `Layer`.
## Solution
- Replace the `update_subscriber` field of `LogPlugin` with a
`custom_layer` field which is function pointer returning an
`Option<BoxedLayer>`
- Update the examples to showcase that this works:
- with multiple additional layers
- with Layers that were previously problematic, such as
`bevy::log::tracing_subscriber::fmt::layer().with_file(true)` (mentioned
in the issue)
Note that in the example this results in duplicate logs, since we have
our own layer on top of the default `fmt_layer` added in the LogPlugin;
maybe in the future we might want to provide a single one? Or to let the
user customize the default `fmt_layer` ? I still think this change is an
improvement upon the previous solution, which was basically broken.
---
## Changelog
> This section is optional. If this was a trivial fix, or has no
externally-visible impact, you can delete this section.
- The `LogPlugin`'s `update_subscriber` field has been replaced with
`custom_layer` to allow the user to flexibly add a `tracing::Layer` to
the layer stack
## Migration Guide
- The `LogPlugin`'s `update_subscriber` field has been replaced with
`custom_layer`
---------
Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
# Objective
Fixes#13097 and other issues preventing the motion blur example from
working on wasm
## Solution
- Use a vec2 for padding
- Fix error initializing the `MotionBlur` struct on wasm+webgl2
- Disable MSAA on wasm+webgl2
- Fix `GlobalsUniform` padding getting added on the shader side for
webgpu builds
## Notes
The motion blur example now runs, but with artifacts. In addition to the
obvious black artifacts, the motion blur or dithering seem to just look
worse in a way I can't really describe. That may be expected.
```
AdapterInfo { name: "ANGLE (Apple, ANGLE Metal Renderer: Apple M1 Max, Unspecified Version)", vendor: 4203, device: 0, device_type: IntegratedGpu, driver: "", driver_info: "", backend: Gl }
```
<img width="1276" alt="Screenshot 2024-04-25 at 6 51 21 AM"
src="https://github.com/bevyengine/bevy/assets/200550/65401d4f-92fe-454b-9dbc-a2d89d3ad963">
# Objective
Extracts the state mechanisms into a new crate called "bevy_state".
This comes with a few goals:
- state wasn't really an inherent machinery of the ecs system, and so
keeping it within bevy_ecs felt forced
- by mixing it in with bevy_ecs, the maintainability of our more robust
state system was significantly compromised
moving state into a new crate makes it easier to encapsulate as it's own
feature, and easier to read and understand since it's no longer a
single, massive file.
## Solution
move the state-related elements from bevy_ecs to a new crate
## Testing
- Did you test these changes? If so, how? all the automated tests
migrated and passed, ran the pre-existing examples without changes to
validate.
---
## Migration Guide
Since bevy_state is now gated behind the `bevy_state` feature, projects
that use state but don't use the `default-features` will need to add
that feature flag.
Since it is no longer part of bevy_ecs, projects that use bevy_ecs
directly will need to manually pull in `bevy_state`, trigger the
StateTransition schedule, and handle any of the elements that bevy_app
currently sets up.
---------
Co-authored-by: Kristoffer Søholm <k.soeholm@gmail.com>
# Objective
Since `align` was introduced, it has been reworked to allow the input of
`Dir3` instead of `Vec3`, and we also introduced random sampling for
points on a sphere and then for `Dir3`. Previously, this example rolled
its own random generation, but it doesn't need to any more.
## Solution
Refactor the 'align' example to use `Dir3` instead of `Vec3`, using the
`bevy_math` API for random directions.
Switched the return type from `Vec3` to `Dir3` for directional axis
methods within the `GlobalTransform` component.
## Migration Guide
The `GlobalTransform` component's directional axis methods (e.g.,
`right()`, `left()`, `up()`, `down()`, `back()`, `forward()`) have been
updated from returning `Vec3` to `Dir3`.
Clearcoat is a separate material layer that represents a thin
translucent layer of a material. Examples include (from the [Filament
spec]) car paint, soda cans, and lacquered wood. This commit implements
support for clearcoat following the Filament and Khronos specifications,
marking the beginnings of support for multiple PBR layers in Bevy.
The [`KHR_materials_clearcoat`] specification describes the clearcoat
support in glTF. In Blender, applying a clearcoat to the Principled BSDF
node causes the clearcoat settings to be exported via this extension. As
of this commit, Bevy parses and reads the extension data when present in
glTF. Note that the `gltf` crate has no support for
`KHR_materials_clearcoat`; this patch therefore implements the JSON
semantics manually.
Clearcoat is integrated with `StandardMaterial`, but the code is behind
a series of `#ifdef`s that only activate when clearcoat is present.
Additionally, the `pbr_feature_layer_material_textures` Cargo feature
must be active in order to enable support for clearcoat factor maps,
clearcoat roughness maps, and clearcoat normal maps. This approach
mirrors the same pattern used by the existing transmission feature and
exists to avoid running out of texture bindings on platforms like WebGL
and WebGPU. Note that constant clearcoat factors and roughness values
*are* supported in the browser; only the relatively-less-common maps are
disabled on those platforms.
This patch refactors the lighting code in `StandardMaterial`
significantly in order to better support multiple layers in a natural
way. That code was due for a refactor in any case, so this is a nice
improvement.
A new demo, `clearcoat`, has been added. It's based on [the
corresponding three.js demo], but all the assets (aside from the skybox
and environment map) are my original work.
[Filament spec]:
https://google.github.io/filament/Filament.html#materialsystem/clearcoatmodel
[`KHR_materials_clearcoat`]:
https://github.com/KhronosGroup/glTF/blob/main/extensions/2.0/Khronos/KHR_materials_clearcoat/README.md
[the corresponding three.js demo]:
https://threejs.org/examples/webgl_materials_physical_clearcoat.html
![Screenshot 2024-04-19
101143](https://github.com/bevyengine/bevy/assets/157897/3444bcb5-5c20-490c-b0ad-53759bd47ae2)
![Screenshot 2024-04-19
102054](https://github.com/bevyengine/bevy/assets/157897/6e953944-75b8-49ef-bc71-97b0a53b3a27)
## Changelog
### Added
* `StandardMaterial` now supports a clearcoat layer, which represents a
thin translucent layer over an underlying material.
* The glTF loader now supports the `KHR_materials_clearcoat` extension,
representing materials with clearcoat layers.
## Migration Guide
* The lighting functions in the `pbr_lighting` WGSL module now have
clearcoat parameters, if `STANDARD_MATERIAL_CLEARCOAT` is defined.
* The `R` reflection vector parameter has been removed from some
lighting functions, as it was unused.
# Objective
- In PR #12882 I added a new example which contained a comment with an
unfinished and cut off sentence. This wasn't caught until after the PR
was merged.
- This simply finishes that comment.
## Solution
- Finished the incomplete comment.
## Testing
- This is simply a comment change so no testing needed other than
reading it.
# Objective
Dynamic types can be tricky to understand and work with in bevy_reflect.
There should be an example that shows what they are and how they're
used.
## Solution
Add a `Dynamic Types` reflection example.
I'm planning to go through the reflection examples, adding new ones and
updating old ones. And I think this walkthrough style tends to work
best. Due to the amount of text and associated explanation, it might fit
better in a dedicated reflection chapter of the WIP Bevy Book. However,
I think it might be valuable to have some public-facing tutorials for
these concepts.
Let me know if there any thoughts or critiques with the example— both in
content and this overall structure!
## Testing
To test these changes, you can run the example locally:
```
cargo run --example dynamic_types
```
---
## Changelog
- Add `Dynamic Types` reflection example
# Objective
The `custom_loop` example didn't replicate the `app.finish` /
`app.cleanup` calls from the default runner; I discovered this when
trying to troubleshoot why my application with a custom loop wasn't
calling its plugin finalizers, and realised that the upstream example
that I'd referenced didn't have the relevant calls.
## Solution
Added the missing calls, replicating what the default runner does:
d390420093/crates/bevy_app/src/app.rs (L895-L896)
## Testing
I've confirmed that adding these two calls to my application fixed the
issue I was encountering. I haven't tested it within the example itself
as it's relatively straightforward and I didn't want to pollute the
example with a plugin using a finalizer.
# Objective
- Add auto exposure/eye adaptation to the bevy render pipeline.
- Support features that users might expect from other engines:
- Metering masks
- Compensation curves
- Smooth exposure transitions
This PR is based on an implementation I already built for a personal
project before https://github.com/bevyengine/bevy/pull/8809 was
submitted, so I wasn't able to adopt that PR in the proper way. I've
still drawn inspiration from it, so @fintelia should be credited as
well.
## Solution
An auto exposure compute shader builds a 64 bin histogram of the scene's
luminance, and then adjusts the exposure based on that histogram. Using
a histogram allows the system to ignore outliers like shadows and
specular highlights, and it allows to give more weight to certain areas
based on a mask.
---
## Changelog
- Added: AutoExposure plugin that allows to adjust a camera's exposure
based on it's scene's luminance.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
If the current example is used as is, the `button_pressed` system will
run every update.
Update the example so that it is a more ready to use for people
## Solution
Rewrote most of it.
Another solution would be to just minimally fix the problems
```Rust
.add_systems(Startup, (count_entities, setup).chain())
```
and
```Rust
fn evaluate_callbacks(query: Query<(Entity, &Callback), With<Triggered>>, mut commands: Commands) {
for (entity, callback) in query.iter() {
commands.run_system(callback.0);
commands.entity(entity).remove::<Triggered>();
}
}
```
## Testing
- Did you test these changes? If so, how?
Ran the example and pressed A / B on the keyboard
---
Implement visibility ranges, also known as hierarchical levels of detail
(HLODs).
This commit introduces a new component, `VisibilityRange`, which allows
developers to specify camera distances in which meshes are to be shown
and hidden. Hiding meshes happens early in the rendering pipeline, so
this feature can be used for level of detail optimization. Additionally,
this feature is properly evaluated per-view, so different views can show
different levels of detail.
This feature differs from proper mesh LODs, which can be implemented
later. Engines generally implement true mesh LODs later in the pipeline;
they're typically more efficient than HLODs with GPU-driven rendering.
However, mesh LODs are more limited than HLODs, because they require the
lower levels of detail to be meshes with the same vertex layout and
shader (and perhaps the same material) as the original mesh. Games often
want to use objects other than meshes to replace distant models, such as
*octahedral imposters* or *billboard imposters*.
The reason why the feature is called *hierarchical level of detail* is
that HLODs can replace multiple meshes with a single mesh when the
camera is far away. This can be useful for reducing drawcall count. Note
that `VisibilityRange` doesn't automatically propagate down to children;
it must be placed on every mesh.
Crossfading between different levels of detail is supported, using the
standard 4x4 ordered dithering pattern from [1]. The shader code to
compute the dithering patterns should be well-optimized. The dithering
code is only active when visibility ranges are in use for the mesh in
question, so that we don't lose early Z.
Cascaded shadow maps show the HLOD level of the view they're associated
with. Point light and spot light shadow maps, which have no CSMs,
display all HLOD levels that are visible in any view. To support this
efficiently and avoid doing visibility checks multiple times, we
precalculate all visible HLOD levels for each entity with a
`VisibilityRange` during the `check_visibility_range` system.
A new example, `visibility_range`, has been added to the tree, as well
as a new low-poly version of the flight helmet model to go with it. It
demonstrates use of the visibility range feature to provide levels of
detail.
[1]: https://en.wikipedia.org/wiki/Ordered_dithering#Threshold_map
[^1]: Unreal doesn't have a feature that exactly corresponds to
visibility ranges, but Unreal's HLOD system serves roughly the same
purpose.
## Changelog
### Added
* A new `VisibilityRange` component is available to conditionally enable
entity visibility at camera distances, with optional crossfade support.
This can be used to implement different levels of detail (LODs).
## Screenshots
High-poly model:
![Screenshot 2024-04-09
185541](https://github.com/bevyengine/bevy/assets/157897/7e8be017-7187-4471-8866-974e2d8f2623)
Low-poly model up close:
![Screenshot 2024-04-09
185546](https://github.com/bevyengine/bevy/assets/157897/429603fe-6bb7-4246-8b4e-b4888fd1d3a0)
Crossfading between the two:
![Screenshot 2024-04-09
185604](https://github.com/bevyengine/bevy/assets/157897/86d0d543-f8f3-49ec-8fe5-caa4d0784fd4)
---------
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
# Objective
- I've been using the `texture_binding_array` example as a base to use
multiple textures in meshes in my program
- I only realised once I was deep in render code that these helpers
existed to create layouts
- I wish I knew the existed earlier because the alternative (filling in
every struct field) is so much more verbose
## Solution
- Use `BindGroupLayoutEntries::with_indices` to teach users that the
helper exists
- Also fix typo which should be `texture_2d`.
## Alternatives considered
- Just leave it as is to teach users about every single struct field
- However, leaving as is leaves users writing roughly 29 lines versus
roughly 2 lines for 2 entries and I'd prefer the 2 line approach
## Testing
Ran the example locally and compared before and after.
Before:
<img width="1280" alt="image"
src="https://github.com/bevyengine/bevy/assets/135186256/f5897210-2560-4110-b92b-85497be9023c">
After:
<img width="1279" alt="image"
src="https://github.com/bevyengine/bevy/assets/135186256/8d13a939-b1ce-4a49-a9da-0b1779c8cb6a">
Co-authored-by: mgi388 <>
# Objective
- #12755 introduced the need to download a file to run an example
- This means the example fails to run in CI without downloading that
file
## Solution
- Add a new metadata to examples "setup" that provides setup
instructions
- Replace the URL in the meshlet example to one that can actually be
downloaded
- example-showcase execute the setup before running an example
# Objective
- Simplifies/clarifies the winit loop.
- Fixes#12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
## Summary/Description
This PR extends states to allow support for a wider variety of state
types and patterns, by providing 3 distinct types of state:
- Standard [`States`] can only be changed by manually setting the
[`NextState<S>`] resource. These states are the baseline on which the
other state types are built, and can be used on their own for many
simple patterns. See the [state
example](https://github.com/bevyengine/bevy/blob/latest/examples/ecs/state.rs)
for a simple use case - these are the states that existed so far in
Bevy.
- [`SubStates`] are children of other states - they can be changed
manually using [`NextState<S>`], but are removed from the [`World`] if
the source states aren't in the right state. See the [sub_states
example](https://github.com/lee-orr/bevy/blob/derived_state/examples/ecs/sub_states.rs)
for a simple use case based on the derive macro, or read the trait docs
for more complex scenarios.
- [`ComputedStates`] are fully derived from other states - they provide
a [`compute`](ComputedStates::compute) method that takes in the source
states and returns their derived value. They are particularly useful for
situations where a simplified view of the source states is necessary -
such as having an `InAMenu` computed state derived from a source state
that defines multiple distinct menus. See the [computed state
example](https://github.com/lee-orr/bevy/blob/derived_state/examples/ecs/computed_states.rscomputed_states.rs)
to see a sampling of uses for these states.
# Objective
This PR is another attempt at allowing Bevy to better handle complex
state objects in a manner that doesn't rely on strict equality. While my
previous attempts (https://github.com/bevyengine/bevy/pull/10088 and
https://github.com/bevyengine/bevy/pull/9957) relied on complex matching
capacities at the point of adding a system to application, this one
instead relies on deterministically deriving simple states from more
complex ones.
As a result, it does not require any special macros, nor does it change
any other interactions with the state system once you define and add
your derived state. It also maintains a degree of distinction between
`State` and just normal application state - your derivations have to end
up being discreet pre-determined values, meaning there is less of a
risk/temptation to place a significant amount of logic and data within a
given state.
### Addition - Sub States
closes#9942
After some conversation with Maintainers & SMEs, a significant concern
was that people might attempt to use this feature as if it were
sub-states, and find themselves unable to use it appropriately. Since
`ComputedState` is mainly a state matching feature, while `SubStates`
are more of a state mutation related feature - but one that is easy to
add with the help of the machinery introduced by `ComputedState`, it was
added here as well. The relevant discussion is here:
https://discord.com/channels/691052431525675048/1200556329803186316
## Solution
closes#11358
The solution is to create a new type of state - one implementing
`ComputedStates` - which is deterministically tied to one or more other
states. Implementors write a function to transform the source states
into the computed state, and it gets triggered whenever one of the
source states changes.
In addition, we added the `FreelyMutableState` trait , which is
implemented as part of the derive macro for `States`. This allows us to
limit use of `NextState<S>` to states that are actually mutable,
preventing mis-use of `ComputedStates`.
---
## Changelog
- Added `ComputedStates` trait
- Added `FreelyMutableState` trait
- Converted `NextState` resource to an Enum, with `Unchanged` and
`Pending`
- Added `App::add_computed_state::<S: ComputedStates>()`, to allow for
easily adding derived states to an App.
- Moved the `StateTransition` schedule label from `bevy_app` to
`bevy_ecs` - but maintained the export in `bevy_app` for continuity.
- Modified the process for updating states. Instead of just having an
`apply_state_transition` system that can be added anywhere, we now have
a multi-stage process that has to run within the `StateTransition`
label. First, all the state changes are calculated - manual transitions
rely on `apply_state_transition`, while computed transitions run their
computation process before both call `internal_apply_state_transition`
to apply the transition, send out the transition event, trigger
dependent states, and record which exit/transition/enter schedules need
to occur. Once all the states have been updated, the transition
schedules are called - first the exit schedules, then transition
schedules and finally enter schedules.
- Added `SubStates` trait
- Adjusted `apply_state_transition` to be a no-op if the `State<S>`
resource doesn't exist
## Migration Guide
If the user accessed the NextState resource's value directly or created
them from scratch they will need to adjust to use the new enum variants:
- if they created a `NextState(Some(S))` - they should now use
`NextState::Pending(S)`
- if they created a `NextState(None)` -they should now use
`NextState::Unchanged`
- if they matched on the `NextState` value, they would need to make the
adjustments above
If the user manually utilized `apply_state_transition`, they should
instead use systems that trigger the `StateTransition` schedule.
---
## Future Work
There is still some future potential work in the area, but I wanted to
keep these potential features and changes separate to keep the scope
here contained, and keep the core of it easy to understand and use.
However, I do want to note some of these things, both as inspiration to
others and an illustration of what this PR could unlock.
- `NextState::Remove` - Now that the `State` related mechanisms all
utilize options (#11417), it's fairly easy to add support for explicit
state removal. And while `ComputedStates` can add and remove themselves,
right now `FreelyMutableState`s can't be removed from within the state
system. While it existed originally in this PR, it is a different
question with a separate scope and usability concerns - so having it as
it's own future PR seems like the best approach. This feature currently
lives in a separate branch in my fork, and the differences between it
and this PR can be seen here: https://github.com/lee-orr/bevy/pull/5
- `NextState::ReEnter` - this would allow you to trigger exit & entry
systems for the current state type. We can potentially also add a
`NextState::ReEnterRecirsive` to also re-trigger any states that depend
on the current one.
- More mechanisms for `State` updates - This PR would finally make
states that aren't a set of exclusive Enums useful, and with that comes
the question of setting state more effectively. Right now, to update a
state you either need to fully create the new state, or include the
`Res<Option<State<S>>>` resource in your system, clone the state, mutate
it, and then use `NextState.set(my_mutated_state)` to make it the
pending next state. There are a few other potential methods that could
be implemented in future PRs:
- Inverse Compute States - these would essentially be compute states
that have an additional (manually defined) function that can be used to
nudge the source states so that they result in the computed states
having a given value. For example, you could use set the `IsPaused`
state, and it would attempt to pause or unpause the game by modifying
the `AppState` as needed.
- Closure-based state modification - this would involve adding a
`NextState.modify(f: impl Fn(Option<S> -> Option<S>)` method, and then
you can pass in closures or function pointers to adjust the state as
needed.
- Message-based state modification - this would involve either creating
states that can respond to specific messages, similar to Elm or Redux.
These could either use the `NextState` mechanism or the Event mechanism.
- ~`SubStates` - which are essentially a hybrid of computed and manual
states. In the simplest (and most likely) version, they would work by
having a computed element that determines whether the state should
exist, and if it should has the capacity to add a new version in, but
then any changes to it's content would be freely mutated.~ this feature
is now part of this PR. See above.
- Lastly, since states are getting more complex there might be value in
moving them out of `bevy_ecs` and into their own crate, or at least out
of the `schedule` module into a `states` module. #11087
As mentioned, all these future work elements are TBD and are explicitly
not part of this PR - I just wanted to provide them as potential
explorations for the future.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Marcel Champagne <voiceofmarcel@gmail.com>
Co-authored-by: MiniaczQ <xnetroidpl@gmail.com>
This commit expands Bevy's existing tonemapping feature to a complete
set of filmic color grading tools, matching those of engines like Unity,
Unreal, and Godot. The following features are supported:
* White point adjustment. This is inspired by Unity's implementation of
the feature, but simplified and optimized. *Temperature* and *tint*
control the adjustments to the *x* and *y* chromaticity values of [CIE
1931]. Following Unity, the adjustments are made relative to the [D65
standard illuminant] in the [LMS color space].
* Hue rotation. This simply converts the RGB value to [HSV], alters the
hue, and converts back.
* Color correction. This allows the *gamma*, *gain*, and *lift* values
to be adjusted according to the standard [ASC CDL combined function].
* Separate color correction for shadows, midtones, and highlights.
Blender's source code was used as a reference for the implementation of
this. The midtone ranges can be adjusted by the user. To avoid abrupt
color changes, a small crossfade is used between the different sections
of the image, again following Blender's formulas.
A new example, `color_grading`, has been added, offering a GUI to change
all the color grading settings. It uses the same test scene as the
existing `tonemapping` example, which has been factored out into a
shared glTF scene.
[CIE 1931]: https://en.wikipedia.org/wiki/CIE_1931_color_space
[D65 standard illuminant]:
https://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D
[LMS color space]: https://en.wikipedia.org/wiki/LMS_color_space
[HSV]: https://en.wikipedia.org/wiki/HSL_and_HSV
[ASC CDL combined function]:
https://en.wikipedia.org/wiki/ASC_CDL#Combined_Function
## Changelog
### Added
* Many new filmic color grading options have been added to the
`ColorGrading` component.
## Migration Guide
* `ColorGrading::gamma` and `ColorGrading::pre_saturation` are now set
separately for the `shadows`, `midtones`, and `highlights` sections. You
can migrate code with the `ColorGrading::all_sections` and
`ColorGrading::all_sections_mut` functions, which access and/or update
all sections at once.
* `ColorGrading::post_saturation` and `ColorGrading::exposure` are now
fields of `ColorGrading::global`.
## Screenshots
![Screenshot 2024-04-27
143144](https://github.com/bevyengine/bevy/assets/157897/c1de5894-917d-4101-b5c9-e644d141a941)
![Screenshot 2024-04-27
143216](https://github.com/bevyengine/bevy/assets/157897/da393c8a-d747-42f5-b47c-6465044c788d)
# Objective
- Enables support for `Display::Block`
- Enables support for `Overflow::Hidden`
- Allows for cleaner integration with text, image and other content
layout.
- Unblocks https://github.com/bevyengine/bevy/pull/8104
- Unlocks the possibility of Bevy creating a custom layout tree over
which Taffy operates.
- Enables #8808 / #10193 to remove a Mutex around the font system.
## Todo
- [x] ~Fix rendering of text/images to account for padding/border on
nodes (should size/position to content box rather than border box)~ In
order get this into a mergeable state this PR instead zeroes out
padding/border when syncing leaf node styles into Taffy to preserve the
existing behaviour. https://github.com/bevyengine/bevy/issues/6879 can
be fixed in a followup PR.
## Solution
- Update the version of Taffy
- Update code to work with the new version
Note: Taffy 0.4 has not yet been released. This PR is being created in
advance of the release to ensure that there are no blockers to upgrading
once the release occurs.
---
## Changelog
- Bevy now supports the `Display::Block` and `Overflow::Hidden` styles.
# Objective
- Partially resolves#12639.
## Solution
- Deprecate `ReceivedCharacter`.
- Replace `ReceivedCharacter` with `KeyboardInput` in the relevant
examples.
## Migration Guide
- `ReceivedCharacter` is now deprecated, use `KeyboardInput` instead.
- Before:
```rust
fn listen_characters(events: EventReader<ReceivedCharacter>) {
for event in events.read() {
info!("{}", event.char);
}
}
```
After:
```rust
fn listen_characters(events: EventReader<KeyboardInput>) {
for event in events.read() {
// Only check for characters when the key is pressed.
if event.state == ButtonState::Released {
continue;
}
// Note that some keys such as `Space` and `Tab` won't be detected as
before.
// Instead, check for them with `Key::Space` and `Key::Tab`.
if let Key::Character(character) = &event.logical_key {
info!("{}", character);
}
}
}
```
---------
Co-authored-by: Mike <mike.hsu@gmail.com>
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`.
Keeping track of explicit visibility per cluster between frames does not
work with LODs, and leads to worse culling (using the final depth buffer
from the previous frame is more accurate).
Instead, we need to generate a second depth pyramid after the second
raster pass, and then use that in the first culling pass in the next
frame to test if a cluster would have been visible last frame or not.
As part of these changes, the write_index_buffer pass has been folded
into the culling pass for a large performance gain, and to avoid
tracking a lot of extra state that would be needed between passes.
Prepass previous model/view stuff was adapted to work with meshlets as
well.
Also fixed a bug with materials, and other misc improvements.
---------
Co-authored-by: François <mockersf@gmail.com>
Co-authored-by: atlas dostal <rodol@rivalrebels.com>
Co-authored-by: vero <email@atlasdostal.com>
Co-authored-by: Patrick Walton <pcwalton@mimiga.net>
Co-authored-by: Robert Swain <robert.swain@gmail.com>
# Objective
- The [`version`] field in `Cargo.toml` is optional for crates not
published on <https://crates.io>.
- We have several `publish = false` tools in this repository that still
have a version field, even when it's not useful.
[`version`]:
https://doc.rust-lang.org/cargo/reference/manifest.html#the-version-field
## Solution
- Remove the [`version`] field for all crates where `publish = false`.
- Update the description on a few crates and remove extra newlines as
well.
# Objective
Fixes#11476
## Solution
Give the pipeline its own "mesh2d instances hashmap."
Pretty sure this is a good fix, but I am not super familiar with this
code so a rendering expert should take a look.
> your fix in the pull request works brilliantly for me too.
> -- _Discord user who pointed out bug_
https://github.com/bevyengine/bevy/assets/2632925/e046205e-3317-47c3-9959-fc94c529f7e0
# Objective
- Adds per-object motion blur to the core 3d pipeline. This is a common
effect used in games and other simulations.
- Partially resolves#4710
## Solution
- This is a post-process effect that uses the depth and motion vector
buffers to estimate per-object motion blur. The implementation is
combined from knowledge from multiple papers and articles. The approach
itself, and the shader are quite simple. Most of the effort was in
wiring up the bevy rendering plumbing, and properly specializing for HDR
and MSAA.
- To work with MSAA, the MULTISAMPLED_SHADING wgpu capability is
required. I've extracted this code from #9000. This is because the
prepass buffers are multisampled, and require accessing with
`textureLoad` as opposed to the widely compatible `textureSample`.
- Added an example to demonstrate the effect of motion blur parameters.
## Future Improvements
- While this approach does have limitations, it's one of the most
commonly used, and is much better than camera motion blur, which does
not consider object velocity. For example, this implementation allows a
dolly to track an object, and that object will remain unblurred while
the background is blurred. The biggest issue with this implementation is
that blur is constrained to the boundaries of objects which results in
hard edges. There are solutions to this by either dilating the object or
the motion vector buffer, or by taking a different approach such as
https://casual-effects.com/research/McGuire2012Blur/index.html
- I'm using a noise PRNG function to jitter samples. This could be
replaced with a blue noise texture lookup or similar, however after
playing with the parameters, it gives quite nice results with 4 samples,
and is significantly better than the artifacts generated when not
jittering.
---
## Changelog
- Added: per-object motion blur. This can be enabled and configured by
adding the `MotionBlurBundle` to a camera entity.
---------
Co-authored-by: Torstein Grindvik <52322338+torsteingrindvik@users.noreply.github.com>
# Objective
- animating a sprite in response to an event is a [common beginner
problem](https://www.reddit.com/r/bevy/comments/13xx4v7/sprite_animation_in_bevy/)
## Solution
- provide a simple example to show how to animate a sprite in response
to an event
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
Clarify the comment about the camera's coordinate system in
`examples/3d/generate_custom_mesh.rs` by explicitly stating which axes
point where.
Fixes#13018
## Solution
Copy the wording from #13012 into the example.
# Objective
Closes#13017.
## Solution
- Make `AppExit` a enum with a `Success` and `Error` variant.
- Make `App::run()` return a `AppExit` if it ever returns.
- Make app runners return a `AppExit` to signal if they encountered a
error.
---
## Changelog
### Added
- [`App::should_exit`](https://example.org/)
- [`AppExit`](https://docs.rs/bevy/latest/bevy/app/struct.AppExit.html)
to the `bevy` and `bevy_app` preludes,
### Changed
- [`AppExit`](https://docs.rs/bevy/latest/bevy/app/struct.AppExit.html)
is now a enum with 2 variants (`Success` and `Error`).
- The app's [runner
function](https://docs.rs/bevy/latest/bevy/app/struct.App.html#method.set_runner)
now has to return a `AppExit`.
-
[`App::run()`](https://docs.rs/bevy/latest/bevy/app/struct.App.html#method.run)
now also returns the `AppExit` produced by the runner function.
## Migration Guide
- Replace all usages of
[`AppExit`](https://docs.rs/bevy/latest/bevy/app/struct.AppExit.html)
with `AppExit::Success` or `AppExit::Failure`.
- Any custom app runners now need to return a `AppExit`. We suggest you
return a `AppExit::Error` if any `AppExit` raised was a Error. You can
use the new [`App::should_exit`](https://example.org/) method.
- If not exiting from `main` any other way. You should return the
`AppExit` from `App::run()` so the app correctly returns a error code if
anything fails e.g.
```rust
fn main() -> AppExit {
App::new()
//Your setup here...
.run()
}
```
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Allow parallel iteration over events, resolve#10766
## Solution
- Add `EventParIter` which works similarly to `QueryParIter`,
implementing a `for_each{_with_id}` operator.
I chose to not mirror `EventIteratorWithId` and instead implement both
operations on a single struct.
- Reuse `BatchingStrategy` from `QueryParIter`
## Changelog
- `EventReader` now supports parallel event iteration using
`par_read().for_each(|event| ...)`.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
# Objective
- The docs says the WireframeColor is supposed to override the default
global color but it doesn't.
## Solution
- Use WireframeColor to override global color like docs said it was
supposed to do.
- Updated the example to document this feature
- I also took the opportunity to clean up the code a bit
Fixes#13032
# Objective
Fixes#12900
## Solution
Added comment to example indicating that additional audio formats are
supported when the feature is added.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
# Objective
When learning about creating meshes in bevy using this example I
couldn't tell which coordinate system bevy uses, which caused confusion
and having to look it up else where.
## Solution
Add a comment that says what coordinate system bevy uses.
# Objective
- Fixes#12976
## Solution
This one is a doozy.
- Run `cargo +beta clippy --workspace --all-targets --all-features` and
fix all issues
- This includes:
- Moving inner attributes to be outer attributes, when the item in
question has both inner and outer attributes
- Use `ptr::from_ref` in more scenarios
- Extend the valid idents list used by `clippy:doc_markdown` with more
names
- Use `Clone::clone_from` when possible
- Remove redundant `ron` import
- Add backticks to **so many** identifiers and items
- I'm sorry whoever has to review this
---
## Changelog
- Added links to more identifiers in documentation.
[Alpha to coverage] (A2C) replaces alpha blending with a
hardware-specific multisample coverage mask when multisample
antialiasing is in use. It's a simple form of [order-independent
transparency] that relies on MSAA. ["Anti-aliased Alpha Test: The
Esoteric Alpha To Coverage"] is a good summary of the motivation for and
best practices relating to A2C.
This commit implements alpha to coverage support as a new variant for
`AlphaMode`. You can supply `AlphaMode::AlphaToCoverage` as the
`alpha_mode` field in `StandardMaterial` to use it. When in use, the
standard material shader automatically applies the texture filtering
method from ["Anti-aliased Alpha Test: The Esoteric Alpha To Coverage"].
Objects with alpha-to-coverage materials are binned in the opaque pass,
as they're fully order-independent.
The `transparency_3d` example has been updated to feature an object with
alpha to coverage. Happily, the example was already using MSAA.
This is part of #2223, as far as I can tell.
[Alpha to coverage]: https://en.wikipedia.org/wiki/Alpha_to_coverage
[order-independent transparency]:
https://en.wikipedia.org/wiki/Order-independent_transparency
["Anti-aliased Alpha Test: The Esoteric Alpha To Coverage"]:
https://bgolus.medium.com/anti-aliased-alpha-test-the-esoteric-alpha-to-coverage-8b177335ae4f
---
## Changelog
### Added
* The `AlphaMode` enum now supports `AlphaToCoverage`, to provide
limited order-independent transparency when multisample antialiasing is
in use.
# Objective
- Fix some doc warnings
- Add doc-scrape-examples to all examples
Moved from #12692
I run `cargo +nightly doc --workspace --all-features --no-deps
-Zunstable-options -Zrustdoc-scrape-examples`
<details>
```
warning: public documentation for `GzAssetLoaderError` links to private item `GzAssetLoader`
--> examples/asset/asset_decompression.rs:24:47
|
24 | /// Possible errors that can be produced by [`GzAssetLoader`]
| ^^^^^^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
warning: `bevy` (example "asset_decompression") generated 1 warning
warning: unresolved link to `shape::Quad`
--> examples/2d/mesh2d.rs:3:15
|
3 | //! [`Quad`]: shape::Quad
| ^^^^^^^^^^^ no item named `shape` in scope
|
= note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
warning: `bevy` (example "mesh2d") generated 1 warning
warning: unresolved link to `WorldQuery`
--> examples/ecs/custom_query_param.rs:1:49
|
1 | //! This example illustrates the usage of the [`WorldQuery`] derive macro, which allows
| ^^^^^^^^^^ no item named `WorldQuery` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
= note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
warning: `bevy` (example "custom_query_param") generated 1 warning
warning: unresolved link to `shape::Quad`
--> examples/2d/mesh2d_vertex_color_texture.rs:4:15
|
4 | //! [`Quad`]: shape::Quad
| ^^^^^^^^^^^ no item named `shape` in scope
|
= note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
warning: `bevy` (example "mesh2d_vertex_color_texture") generated 1 warning
warning: public documentation for `TextPlugin` links to private item `CoolText`
--> examples/asset/processing/asset_processing.rs:48:9
|
48 | /// * [`CoolText`]: a custom RON text format that supports dependencies and embedded dependencies
| ^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
warning: public documentation for `TextPlugin` links to private item `Text`
--> examples/asset/processing/asset_processing.rs:49:9
|
49 | /// * [`Text`]: a "normal" plain text file
| ^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
warning: public documentation for `TextPlugin` links to private item `CoolText`
--> examples/asset/processing/asset_processing.rs:51:57
|
51 | /// It also defines an asset processor that will load [`CoolText`], resolve embedded dependenc...
| ^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
warning: `bevy` (example "asset_processing") generated 3 warnings
warning: public documentation for `CustomAssetLoaderError` links to private item `CustomAssetLoader`
--> examples/asset/custom_asset.rs:20:47
|
20 | /// Possible errors that can be produced by [`CustomAssetLoader`]
| ^^^^^^^^^^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
warning: public documentation for `BlobAssetLoaderError` links to private item `CustomAssetLoader`
--> examples/asset/custom_asset.rs:61:47
|
61 | /// Possible errors that can be produced by [`CustomAssetLoader`]
| ^^^^^^^^^^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
```
```
warning: `bevy` (example "mesh2d") generated 1 warning
warning: public documentation for `log_layers_ecs` links to private item `update_subscriber`
--> examples/app/log_layers_ecs.rs:6:18
|
6 | //! Inside the [`update_subscriber`] function we will create a [`mpsc::Sender`] and a [`mpsc::R...
| ^^^^^^^^^^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
= note: `#[warn(rustdoc::private_intra_doc_links)]` on by default
warning: unresolved link to `AdvancedLayer`
--> examples/app/log_layers_ecs.rs:7:72
|
7 | ... will go into the [`AdvancedLayer`] and the [`Receiver`](mpsc::Receiver) will
| ^^^^^^^^^^^^^ no item named `AdvancedLayer` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
= note: `#[warn(rustdoc::broken_intra_doc_links)]` on by default
warning: unresolved link to `LogEvents`
--> examples/app/log_layers_ecs.rs:8:42
|
8 | //! go into a non-send resource called [`LogEvents`] (It has to be non-send because [`Receiver`...
| ^^^^^^^^^ no item named `LogEvents` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: public documentation for `log_layers_ecs` links to private item `transfer_log_events`
--> examples/app/log_layers_ecs.rs:9:30
|
9 | //! From there we will use [`transfer_log_events`] to transfer log events from [`LogEvents`] to...
| ^^^^^^^^^^^^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
warning: unresolved link to `LogEvents`
--> examples/app/log_layers_ecs.rs:9:82
|
9 | ...nsfer log events from [`LogEvents`] to an ECS event called [`LogEvent`].
| ^^^^^^^^^ no item named `LogEvents` in scope
|
= help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
warning: public documentation for `log_layers_ecs` links to private item `LogEvent`
--> examples/app/log_layers_ecs.rs:9:119
|
9 | ...nts`] to an ECS event called [`LogEvent`].
| ^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
warning: public documentation for `log_layers_ecs` links to private item `LogEvent`
--> examples/app/log_layers_ecs.rs:11:49
|
11 | //! Finally, after all that we can access the [`LogEvent`] event from our systems and use it.
| ^^^^^^^^ this item is private
|
= note: this link will resolve properly if you pass `--document-private-items`
```
<details/>
This commit splits `VisibleEntities::entities` into four separate lists:
one for lights, one for 2D meshes, one for 3D meshes, and one for UI
elements. This allows `queue_material_meshes` and similar methods to
avoid examining entities that are obviously irrelevant. In particular,
this separation helps scenes with many skinned meshes, as the individual
bones are considered visible entities but have no rendered appearance.
Internally, `VisibleEntities::entities` is a `HashMap` from the `TypeId`
representing a `QueryFilter` to the appropriate `Entity` list. I had to
do this because `VisibleEntities` is located within an upstream crate
from the crates that provide lights (`bevy_pbr`) and 2D meshes
(`bevy_sprite`). As an added benefit, this setup allows apps to provide
their own types of renderable components, by simply adding a specialized
`check_visibility` to the schedule.
This provides a 16.23% end-to-end speedup on `many_foxes` with 10,000
foxes (24.06 ms/frame to 20.70 ms/frame).
## Migration guide
* `check_visibility` and `VisibleEntities` now store the four types of
renderable entities--2D meshes, 3D meshes, lights, and UI
elements--separately. If your custom rendering code examines
`VisibleEntities`, it will now need to specify which type of entity it's
interested in using the `WithMesh2d`, `WithMesh`, `WithLight`, and
`WithNode` types respectively. If your app introduces a new type of
renderable entity, you'll need to add an explicit call to
`check_visibility` to the schedule to accommodate your new component or
components.
## Analysis
`many_foxes`, 10,000 foxes: `main`:
![Screenshot 2024-03-31
114444](https://github.com/bevyengine/bevy/assets/157897/16ecb2ff-6e04-46c0-a4b0-b2fde2084bad)
`many_foxes`, 10,000 foxes, this branch:
![Screenshot 2024-03-31
114256](https://github.com/bevyengine/bevy/assets/157897/94dedae4-bd00-45b2-9aaf-dfc237004ddb)
`queue_material_meshes` (yellow = this branch, red = `main`):
![Screenshot 2024-03-31
114637](https://github.com/bevyengine/bevy/assets/157897/f90912bd-45bd-42c4-bd74-57d98a0f036e)
`queue_shadows` (yellow = this branch, red = `main`):
![Screenshot 2024-03-31
114607](https://github.com/bevyengine/bevy/assets/157897/6ce693e3-20c0-4234-8ec9-a6f191299e2d)
I ported the two existing PCF techniques to the cubemap domain as best I
could. Generally, the technique is to create a 2D orthonormal basis
using Gram-Schmidt normalization, then apply the technique over that
basis. The results look fine, though the shadow bias often needs
adjusting.
For comparison, Unity uses a 4-tap pattern for PCF on point lights of
(1, 1, 1), (-1, -1, 1), (-1, 1, -1), (1, -1, -1). I tried this but
didn't like the look, so I went with the design above, which ports the
2D techniques to the 3D domain. There's surprisingly little material on
point light PCF.
I've gone through every example using point lights and verified that the
shadow maps look fine, adjusting biases as necessary.
Fixes#3628.
---
## Changelog
### Added
* Shadows from point lights now support percentage-closer filtering
(PCF), and as a result look less aliased.
### Changed
* `ShadowFilteringMethod::Castano13` and
`ShadowFilteringMethod::Jimenez14` have been renamed to
`ShadowFilteringMethod::Gaussian` and `ShadowFilteringMethod::Temporal`
respectively.
## Migration Guide
* `ShadowFilteringMethod::Castano13` and
`ShadowFilteringMethod::Jimenez14` have been renamed to
`ShadowFilteringMethod::Gaussian` and `ShadowFilteringMethod::Temporal`
respectively.
Currently, `MeshUniform`s are rather large: 160 bytes. They're also
somewhat expensive to compute, because they involve taking the inverse
of a 3x4 matrix. Finally, if a mesh is present in multiple views, that
mesh will have a separate `MeshUniform` for each and every view, which
is wasteful.
This commit fixes these issues by introducing the concept of a *mesh
input uniform* and adding a *mesh uniform building* compute shader pass.
The `MeshInputUniform` is simply the minimum amount of data needed for
the GPU to compute the full `MeshUniform`. Most of this data is just the
transform and is therefore only 64 bytes. `MeshInputUniform`s are
computed during the *extraction* phase, much like skins are today, in
order to avoid needlessly copying transforms around on CPU. (In fact,
the render app has been changed to only store the translation of each
mesh; it no longer cares about any other part of the transform, which is
stored only on the GPU and the main world.) Before rendering, the
`build_mesh_uniforms` pass runs to expand the `MeshInputUniform`s to the
full `MeshUniform`.
The mesh uniform building pass does the following, all on GPU:
1. Copy the appropriate fields of the `MeshInputUniform` to the
`MeshUniform` slot. If a single mesh is present in multiple views, this
effectively duplicates it into each view.
2. Compute the inverse transpose of the model transform, used for
transforming normals.
3. If applicable, copy the mesh's transform from the previous frame for
TAA. To support this, we double-buffer the `MeshInputUniform`s over two
frames and swap the buffers each frame. The `MeshInputUniform`s for the
current frame contain the index of that mesh's `MeshInputUniform` for
the previous frame.
This commit produces wins in virtually every CPU part of the pipeline:
`extract_meshes`, `queue_material_meshes`,
`batch_and_prepare_render_phase`, and especially
`write_batched_instance_buffer` are all faster. Shrinking the amount of
CPU data that has to be shuffled around speeds up the entire rendering
process.
| Benchmark | This branch | `main` | Speedup |
|------------------------|-------------|---------|---------|
| `many_cubes -nfc` | 17.259 | 24.529 | 42.12% |
| `many_cubes -nfc -vpi` | 302.116 | 312.123 | 3.31% |
| `many_foxes` | 3.227 | 3.515 | 8.92% |
Because mesh uniform building requires compute shader, and WebGL 2 has
no compute shader, the existing CPU mesh uniform building code has been
left as-is. Many types now have both CPU mesh uniform building and GPU
mesh uniform building modes. Developers can opt into the old CPU mesh
uniform building by setting the `use_gpu_uniform_builder` option on
`PbrPlugin` to `false`.
Below are graphs of the CPU portions of `many-cubes
--no-frustum-culling`. Yellow is this branch, red is `main`.
`extract_meshes`:
![Screenshot 2024-04-02
124842](https://github.com/bevyengine/bevy/assets/157897/a6748ea4-dd05-47b6-9254-45d07d33cb10)
It's notable that we get a small win even though we're now writing to a
GPU buffer.
`queue_material_meshes`:
![Screenshot 2024-04-02
124911](https://github.com/bevyengine/bevy/assets/157897/ecb44d78-65dc-448d-ba85-2de91aa2ad94)
There's a bit of a regression here; not sure what's causing it. In any
case it's very outweighed by the other gains.
`batch_and_prepare_render_phase`:
![Screenshot 2024-04-02
125123](https://github.com/bevyengine/bevy/assets/157897/4e20fc86-f9dd-4e5c-8623-837e4258f435)
There's a huge win here, enough to make batching basically drop off the
profile.
`write_batched_instance_buffer`:
![Screenshot 2024-04-02
125237](https://github.com/bevyengine/bevy/assets/157897/401a5c32-9dc1-4991-996d-eb1cac6014b2)
There's a massive improvement here, as expected. Note that a lot of it
simply comes from the fact that `MeshInputUniform` is `Pod`. (This isn't
a maintainability problem in my view because `MeshInputUniform` is so
simple: just 16 tightly-packed words.)
## Changelog
### Added
* Per-mesh instance data is now generated on GPU with a compute shader
instead of CPU, resulting in rendering performance improvements on
platforms where compute shaders are supported.
## Migration guide
* Custom render phases now need multiple systems beyond just
`batch_and_prepare_render_phase`. Code that was previously creating
custom render phases should now add a `BinnedRenderPhasePlugin` or
`SortedRenderPhasePlugin` as appropriate instead of directly adding
`batch_and_prepare_render_phase`.
# 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.
Allows the user to select a scene to load, then a loading screen is
shown until all assets are loaded, and pipelines compiled.
# Objective
- Fixes#12654
## Solution
- Add desired assets to be monitored to a list.
- While there are assets that are not fully loaded, show a loading
screen.
- Once all assets are loaded, and pipelines compiled, show the scene
that was loaded.
# Objective
- Example `compute_shader_game_of_life` is random and not following the
rules of the game of life: at each steps, it randomly reads some pixel
of the current step and some of the previous step instead of only from
the previous step
- Fixes#9353
## Solution
- Adopted from #9678
- Added a switch of the texture displayed every frame otherwise the game
of life looks wrong
- Added a way to display the texture bigger so that I could manually
check everything was right
---------
Co-authored-by: Sludge <96552222+SludgePhD@users.noreply.github.com>
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
# Objective
- Fixes#12411
- Add an example demonstrating the usage of asset meta files.
## Solution
- Add a new example displaying a basic scene of three pixelated images
- Apply a .meta file to one of the assets setting Nearest filtering
- Use AssetServer::load_with_settings on the last one as another way to
achieve the same effect
- The result is one blurry image and two crisp images demonstrating a
common scenario in which changing settings are useful.
# Objective
- It's pretty common for users to want to read data back from the gpu
and into the main world
## Solution
- Add a simple example that shows how to read data back from the gpu and
send it to the main world using a channel.
- The example is largely based on this wgpu example but adapted to bevy
-
fb305b85f6/examples/src/repeated_compute/mod.rs
---------
Co-authored-by: stormy <120167078+stowmyy@users.noreply.github.com>
Co-authored-by: Torstein Grindvik <52322338+torsteingrindvik@users.noreply.github.com>
# Objective
- There is a little mistake in a line comment.
## Solution
- Fixed the comment to correctly describe what happens in the documented
calculation.
# Objective
Fix#11931
## Solution
- Make stepping a non-default feature
- Adjust documentation and examples
- In particular, make the breakout example not show the stepping prompt
if compiled without the feature (shows a log message instead)
---
## Changelog
- Removed `bevy_debug_stepping` from default features
## Migration Guide
The system-by-system stepping feature is now disabled by default; to use
it, enable the `bevy_debug_stepping` feature explicitly:
```toml
[dependencies]
bevy = { version = "0.14", features = ["bevy_debug_stepping"] }
```
Code using
[`Stepping`](https://docs.rs/bevy/latest/bevy/ecs/schedule/struct.Stepping.html)
will still compile with the feature disabled, but will print a runtime
error message to the console if the application attempts to enable
stepping.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
- As @james7132 said [on
Discord](https://discord.com/channels/691052431525675048/692572690833473578/1224626740773523536),
the `close_on_esc` system is forcing `bevy_window` to depend on
`bevy_input`.
- `close_on_esc` is not likely to be used in production, so it arguably
does not have a place in `bevy_window`.
## Solution
- As suggested by @afonsolage, move `close_on_esc` into
`bevy_dev_tools`.
- Add an example to the documentation too.
- Remove `bevy_window`'s dependency on `bevy_input`.
- Add `bevy_reflect`'s `smol_str` feature to `bevy_window` because it
was implicitly depended upon with `bevy_input` before it was removed.
- Remove any usage of `close_on_esc` from the examples.
- `bevy_dev_tools` is not enabled by default. I personally find it
frustrating to run examples with additional features, so I opted to
remove it entirely.
- This is up for discussion if you have an alternate solution.
---
## Changelog
- Moved `bevy_window::close_on_esc` to `bevy_dev_tools::close_on_esc`.
- Removed usage of `bevy_dev_tools::close_on_esc` from all examples.
## Migration Guide
`bevy_window::close_on_esc` has been moved to
`bevy_dev_tools::close_on_esc`. You will first need to enable
`bevy_dev_tools` as a feature in your `Cargo.toml`:
```toml
[dependencies]
bevy = { version = "0.14", features = ["bevy_dev_tools"] }
```
Finally, modify any imports to use `bevy_dev_tools` instead:
```rust
// Old:
// use bevy:🪟:close_on_esc;
// New:
use bevy::dev_tools::close_on_esc;
App::new()
.add_systems(Update, close_on_esc)
// ...
.run();
```
# Objective
- Enable stressing of more of the material mesh entity draw code paths
## Solution
- Support generation of a number of different mesh assets from the
built-in primitives, and select randomly from them. This breaks batches
based on different meshes.
- Support disabling automatic batching. This skips the batching cost at
the expense of stressing render pass draw command encoding.
- Support enabling directional light cascaded shadow mapping - this is
commonly a big source of slow down in normal scenes.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
This commit makes the following optimizations:
## `MeshPipelineKey`/`BaseMeshPipelineKey` split
`MeshPipelineKey` has been split into `BaseMeshPipelineKey`, which lives
in `bevy_render` and `MeshPipelineKey`, which lives in `bevy_pbr`.
Conceptually, `BaseMeshPipelineKey` is a superclass of
`MeshPipelineKey`. For `BaseMeshPipelineKey`, the bits start at the
highest (most significant) bit and grow downward toward the lowest bit;
for `MeshPipelineKey`, the bits start at the lowest bit and grow upward
toward the highest bit. This prevents them from colliding.
The goal of this is to avoid having to reassemble bits of the pipeline
key for every mesh every frame. Instead, we can just use a bitwise or
operation to combine the pieces that make up a `MeshPipelineKey`.
## `specialize_slow`
Previously, all of `specialize()` was marked as `#[inline]`. This
bloated `queue_material_meshes` unnecessarily, as a large chunk of it
ended up being a slow path that was rarely hit. This commit refactors
the function to move the slow path to `specialize_slow()`.
Together, these two changes shave about 5% off `queue_material_meshes`:
![Screenshot 2024-03-29
130002](https://github.com/bevyengine/bevy/assets/157897/a7e5a994-a807-4328-b314-9003429dcdd2)
## Migration Guide
- The `primitive_topology` field on `GpuMesh` is now an accessor method:
`GpuMesh::primitive_topology()`.
- For performance reasons, `MeshPipelineKey` has been split into
`BaseMeshPipelineKey`, which lives in `bevy_render`, and
`MeshPipelineKey`, which lives in `bevy_pbr`. These two should be
combined with bitwise-or to produce the final `MeshPipelineKey`.
# Objective
- There are several redundant imports in the tests and examples that are
not caught by CI because additional flags need to be passed.
## Solution
- Run `cargo check --workspace --tests` and `cargo check --workspace
--examples`, then fix all warnings.
- Add `test-check` to CI, which will be run in the check-compiles job.
This should catch future warnings for tests. Examples are already
checked, but I'm not yet sure why they weren't caught.
## Discussion
- Should the `--tests` and `--examples` flags be added to CI, so this is
caught in the future?
- If so, #12818 will need to be merged first. It was also a warning
raised by checking the examples, but I chose to split off into a
separate PR.
---------
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
- Since #12453, `DeterministicRenderingConfig` doesn't do anything
## Solution
- Remove it
---
## Migration Guide
- Removed `DeterministicRenderingConfig`. There shouldn't be any z
fighting anymore in the rendering even without setting
`stable_sort_z_fighting`
# Objective
- The `ImePreedit` component from
[`text_input`](50699ecf76/examples/input/text_input.rs (L126-L127))
appears to be unused.
- This was found by running `cargo check --workspace --examples`,
originally as part of #12817.
## Solution
- Remove it :)
# 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>.`
# Objective
- `examples/shader/post_processing.rs` is a shader example that works
for 3d
- I recently tried to update this example to get it to work on 2d but
failed to do so
- Then I created a discord help thread to help me figure this out.
[here's the link to the
thread](https://discordapp.com/channels/691052431525675048/1221819669116354723).
## Solution
- The solution is to replace all instances of 3d structures with their
respective 2d counterparts
## Changelog
- Added a small comment that explains how to get the example to work on
2d
#### Please do suggest changes if any
---------
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
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>
Created soundtrack example, fade-in and fade-out features, added new
assets, and updated credits.
# Objective
- Fixes#12651
## Solution
- Created a resource to hold the track list.
- The audio assets are then loaded by the asset server and added to the
track list.
- Once the game is in a specific state, an `AudioBundle` is spawned and
plays the appropriate track.
- The audio volume starts at zero and is then incremented gradually
until it reaches full volume.
- Once the game state changes, the current track fades out, and a new
one fades in at the same time, offering a relatively seamless
transition.
- Once a track is completely faded out, it is despawned from the app.
- Game state changes are simulated through a `Timer` for simplicity.
- Track change system is only run if there is a change in the
`GameState` resource.
- All tracks are used according to their respective licenses.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Wireframes are currently supported for 3D meshes using the
`WireframePlugin` in `bevy_pbr`. This PR adds the same functionality for
2D meshes.
Closes#5881.
## Solution
Since there's no easy way to share material implementations between 2D,
3D, and UI, this is mostly a straight copy and rename from the original
plugin into `bevy_sprite`.
<img width="1392" alt="image"
src="https://github.com/bevyengine/bevy/assets/3961616/7aca156f-448a-4c7e-89b8-0a72c5919769">
---
## Changelog
- Added `Wireframe2dPlugin` and related types to support 2D wireframes.
- Added an example to demonstrate how to use 2D wireframes
---------
Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
# Objective
- Example `mesh2d_manual` crashes in wasm/webgl2, as reported in
https://github.com/bevyengine/bevy-website/issues/1123#issuecomment-2019479670
```
wgpu error: Validation Error
Caused by:
In a RenderPass
note: encoder = `<CommandBuffer-(0, 1, Gl)>`
In a set_push_constant command
Provided push constant is for stage(s) ShaderStages(VERTEX), however the pipeline layout has no push constant range for the stage(s) ShaderStages(VERTEX)
```
## Solution
- Properly declare the push constant as in
4508077297/crates/bevy_sprite/src/mesh2d/mesh.rs (L514-L524)
# Objective
Previously, the `Point` trait, which abstracts all of the operations of
a real vector space, was sitting in the submodule of `bevy_math` for
cubic splines. However, the trait has broader applications than merely
cubic splines, and we should use it when possible to avoid code
duplication when performing vector operations.
## Solution
`Point` has been moved into a new submodule in `bevy_math` named
`common_traits`. Furthermore, it has been renamed to `VectorSpace`,
which is more descriptive, and an additional trait `NormedVectorSpace`
has been introduced to expand the API to cover situations involving
geometry in addition to algebra. Additionally, `VectorSpace` itself now
requires a `ZERO` constant and `Neg`. It also supports a `lerp` function
as an automatic trait method.
Here is what that looks like:
```rust
/// A type that supports the mathematical operations of a real vector space, irrespective of dimension.
/// In particular, this means that the implementing type supports:
/// - Scalar multiplication and division on the right by elements of `f32`
/// - Negation
/// - Addition and subtraction
/// - Zero
///
/// Within the limitations of floating point arithmetic, all the following are required to hold:
/// - (Associativity of addition) For all `u, v, w: Self`, `(u + v) + w == u + (v + w)`.
/// - (Commutativity of addition) For all `u, v: Self`, `u + v == v + u`.
/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`.
/// - (Additive inverse) For all `v: Self`, `v - v == v + (-v) == Self::ZERO`.
/// - (Compatibility of multiplication) For all `a, b: f32`, `v: Self`, `v * (a * b) == (v * a) * b`.
/// - (Multiplicative identity) For all `v: Self`, `v * 1.0 == v`.
/// - (Distributivity for vector addition) For all `a: f32`, `u, v: Self`, `(u + v) * a == u * a + v * a`.
/// - (Distributivity for scalar addition) For all `a, b: f32`, `v: Self`, `v * (a + b) == v * a + v * b`.
///
/// Note that, because implementing types use floating point arithmetic, they are not required to actually
/// implement `PartialEq` or `Eq`.
pub trait VectorSpace:
Mul<f32, Output = Self>
+ Div<f32, Output = Self>
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Neg
+ Default
+ Debug
+ Clone
+ Copy
{
/// The zero vector, which is the identity of addition for the vector space type.
const ZERO: Self;
/// Perform vector space linear interpolation between this element and another, based
/// on the parameter `t`. When `t` is `0`, `self` is recovered. When `t` is `1`, `rhs`
/// is recovered.
///
/// Note that the value of `t` is not clamped by this function, so interpolating outside
/// of the interval `[0,1]` is allowed.
#[inline]
fn lerp(&self, rhs: Self, t: f32) -> Self {
*self * (1. - t) + rhs * t
}
}
```
```rust
/// A type that supports the operations of a normed vector space; i.e. a norm operation in addition
/// to those of [`VectorSpace`]. Specifically, the implementor must guarantee that the following
/// relationships hold, within the limitations of floating point arithmetic:
/// - (Nonnegativity) For all `v: Self`, `v.norm() >= 0.0`.
/// - (Positive definiteness) For all `v: Self`, `v.norm() == 0.0` implies `v == Self::ZERO`.
/// - (Absolute homogeneity) For all `c: f32`, `v: Self`, `(v * c).norm() == v.norm() * c.abs()`.
/// - (Triangle inequality) For all `v, w: Self`, `(v + w).norm() <= v.norm() + w.norm()`.
///
/// Note that, because implementing types use floating point arithmetic, they are not required to actually
/// implement `PartialEq` or `Eq`.
pub trait NormedVectorSpace: VectorSpace {
/// The size of this element. The return value should always be nonnegative.
fn norm(self) -> f32;
/// The squared norm of this element. Computing this is often faster than computing
/// [`NormedVectorSpace::norm`].
#[inline]
fn norm_squared(self) -> f32 {
self.norm() * self.norm()
}
/// The distance between this element and another, as determined by the norm.
#[inline]
fn distance(self, rhs: Self) -> f32 {
(rhs - self).norm()
}
/// The squared distance between this element and another, as determined by the norm. Note that
/// this is often faster to compute in practice than [`NormedVectorSpace::distance`].
#[inline]
fn distance_squared(self, rhs: Self) -> f32 {
(rhs - self).norm_squared()
}
}
```
Furthermore, this PR also demonstrates the use of the
`NormedVectorSpace` combined API to implement `ShapeSample` for
`Triangle2d` and `Triangle3d` simultaneously. Such deduplication is one
of the drivers for developing these APIs.
---
## Changelog
- `Point` from `cubic_splines` becomes `VectorSpace`, exported as
`bevy::math::VectorSpace`.
- `VectorSpace` requires `Neg` and `VectorSpace::ZERO` in addition to
its existing prerequisites.
- Introduced public traits `bevy::math::NormedVectorSpace` for generic
geometry tasks involving vectors.
- Implemented `ShapeSample` for `Triangle2d` and `Triangle3d`.
## Migration Guide
Since `Point` no longer exists, any projects using it must switch to
`bevy::math::VectorSpace`. Additionally, third-party implementations of
this trait now require the `Neg` trait; the constant `VectorSpace::ZERO`
must be provided as well.
---
## Discussion
### Design considerations
Originally, the `NormedVectorSpace::norm` method was part of a separate
trait `Normed`. However, I think that was probably too broad and, more
importantly, the semantics of having it in `NormedVectorSpace` are much
clearer.
As it currently stands, the API exposed here is pretty minimal, and
there is definitely a lot more that we could do, but there are more
questions to answer along the way. As a silly example, we could
implement `NormedVectorSpace::length` as an alias for
`NormedVectorSpace::norm`, but this overlaps with methods in all of the
glam types, so we would want to make sure that the implementations are
effectively identical (for what it's worth, I think they are already).
### Future directions
One example of something that could belong in the `NormedVectorSpace`
API is normalization. Actually, such a thing previously existed on this
branch before I decided to shelve it because of concerns with namespace
collision. It looked like this:
```rust
/// This element, but normalized to norm 1 if possible. Returns an error when the reciprocal of
/// the element's norm is not finite.
#[inline]
#[must_use]
fn normalize(&self) -> Result<Self, NonNormalizableError> {
let reciprocal = 1.0 / self.norm();
if reciprocal.is_finite() {
Ok(*self * reciprocal)
} else {
Err(NonNormalizableError { reciprocal })
}
}
/// An error indicating that an element of a [`NormedVectorSpace`] was non-normalizable due to having
/// non-finite norm-reciprocal.
#[derive(Debug, Error)]
#[error("Element with norm reciprocal {reciprocal} cannot be normalized")]
pub struct NonNormalizableError {
reciprocal: f32
}
```
With this kind of thing in hand, it might be worth considering
eventually making the passage from vectors to directions fully generic
by employing a wrapper type. (Of course, for our concrete types, we
would leave the existing names in place as aliases.) That is, something
like:
```rust
pub struct NormOne<T>
where T: NormedVectorSpace { //... }
```
Utterly separately, the reason that I implemented `ShapeSample` for
`Triangle2d`/`Triangle3d` was to prototype uniform sampling of abstract
meshes, so that's also a future direction.
---------
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
Adopted from and closes https://github.com/bevyengine/bevy/pull/9914 by
@djeedai
# Objective
Fix the use of `TypeRegistry` instead of `TypeRegistryArc` in dynamic
scene and its serializer.
Rename `DynamicScene::serialize_ron()` into `serialize()` to highlight
the fact this is not about serializing to RON specifically, but rather
about serializing to the official Bevy scene format (`.scn` /
`.scn.ron`) which the `SceneLoader` can deserialize (and which happens
to be based in RON, but that not the object here). Also make the link
with the documentation of `SceneLoader` so users understand the full
serializing cycle of a Bevy dynamic scene.
Document `SceneSerializer` with an example showing how to serialize to a
custom format (here: RON), which is easily transposed to serializing
into any other format.
Fixes#9520
## Changelog
### Changed
* `SceneSerializer` and all related serializing helper types now take a
`&TypeRegistry` instead of a `&TypeRegistryArc`. ([SceneSerializer
needlessly uses specifically
&TypeRegistryArc #9520](https://github.com/bevyengine/bevy/issues/9520))
* `DynamicScene::serialize_ron()` was renamed to `serialize()`.
## Migration Guide
* `SceneSerializer` and all related serializing helper types now take a
`&TypeRegistry` instead of a `&TypeRegistryArc`. You can upgrade by
getting the former from the latter with `TypeRegistryArc::read()`,
_e.g._
```diff
let registry_arc: TypeRegistryArc = [...];
- let serializer = SceneSerializer(&scene, ®istry_arc);
+ let registry = registry_arc.read();
+ let serializer = SceneSerializer(&scene, ®istry);
```
* Rename `DynamicScene::serialize_ron()` to `serialize()`.
---------
Co-authored-by: Jerome Humbert <djeedai@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
Co-authored-by: James Liu <contact@jamessliu.com>
# 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
We have `ReflectSerializer` and `TypedReflectSerializer`. The former is
the one users will most often use since the latter takes a bit more
effort to deserialize.
However, our deserializers are named `UntypedReflectDeserializer` and
`TypedReflectDeserializer`. There is no obvious indication that
`UntypedReflectDeserializer` must be used with `ReflectSerializer` since
the names don't quite match up.
## Solution
Rename `UntypedReflectDeserializer` back to `ReflectDeserializer`
(initially changed as part of #5723).
Also update the docs for both deserializers (as they were pretty out of
date) and include doc examples.
I also updated the docs for the serializers, too, just so that
everything is consistent.
---
## Changelog
- Renamed `UntypedReflectDeserializer` to `ReflectDeserializer`
- Updated docs for `ReflectDeserializer`, `TypedReflectDeserializer`,
`ReflectSerializer`, and `TypedReflectSerializer`
## Migration Guide
`UntypedReflectDeserializer` has been renamed to `ReflectDeserializer`.
Usages will need to be updated accordingly.
```diff
- let reflect_deserializer = UntypedReflectDeserializer::new(®istry);
+ let reflect_deserializer = ReflectDeserializer::new(®istry);
```
# Objective
- Be more explicit in the name of the module for the ui debug overlay
- Avoid confusion and possible overlap with new overlays
## Solution
- Rename `debug_overlay` to `ui_debug_overlay`
# 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>
Fixes#12600
## Solution
Removed Into<AssetId<T>> for Handle<T> as proposed in Issue
conversation, fixed dependent code
## Migration guide
If you use passing Handle by value as AssetId, you should pass reference
or call .id() method on it
Before (0.13):
`assets.insert(handle, value);`
After (0.14):
`assets.insert(&handle, value);`
or
`assets.insert(handle.id(), value);`
# Objective
Fixes issue #12613 - the RNG used in examples is _deterministic_, but
its implementation is not _portable_ across platforms. We want to switch
to using a portable RNG that does not vary across platforms, to ensure
certain examples play out the same way every time.
## Solution
Replace all occurences of `rand::rngs::StdRng` with
`rand_chacha::ChaCha8Rng`, as recommended in issue #12613
---
## Changelog
- Add `rand_chacha` as a new dependency (controversial?)
- Replace all occurences of `rand::rngs::StdRng` with
`rand_chacha::ChaCha8Rng`
# Objective
- Implements maths and `Animatable` for `Srgba` as suggested
[here](https://github.com/bevyengine/bevy/issues/12617#issuecomment-2013494774).
## Solution
- Implements `Animatable` and maths for `Srgba` just like their
implemented for other colors.
---
## Changelog
- Updated the example to mention `Srgba`.
## Migration Guide
- The previously existing implementation of mul/div for `Srgba` did not
modify `alpha` but these operations do modify `alpha` now. Users need to
be aware of this change.
# Objective
- went through bounding_2d example with a fine-toothed comb and found
two small issues
## Solution
- pulled "draw a small filled-in circle" logic into a function
- removed impotent addition of aabb / circle origin (identically
`Vec2(0.0, 0.0)`)
# Objective
Fixes#12200 .
## Solution
I added a Hue Trait with the rotate_hue method to enable hue rotation.
Additionally, I modified the implementation of animations in the
animated_material sample.
---
## Changelog
- Added a `Hue` trait to `bevy_color/src/color_ops.rs`.
- Added the `Hue` trait implementation to `Hsla`, `Hsva`, `Hwba`,
`Lcha`, and `Oklcha`.
- Updated animated_material sample.
## Migration Guide
Users of Oklcha need to change their usage to use the with_hue method
instead of the with_h method.
---------
Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Fixes#12202
## Solution
- Implements `Animatable` for all color types implementing arithmetic
operations.
- the colors returned by `Animatable`s methods are already clamped.
- Adds a `color_animation.rs` example.
- Implements the `*Assign` operators for color types that already had
the corresponding operators. This is just a 'nice to have' and I am
happy to remove this if it's not wanted.
---
## Changelog
- `bevy_animation` now depends on `bevy_color`.
- `LinearRgba`, `Laba`, `Oklaba` and `Xyza` implement `Animatable`.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
# Objective
- A new example `rounded_borders` was introduced in #12500, similar to
the `borders` example, but containing labels to describe each border,
leaving inconsistency between the examples.
## Solution
- Update the `borders` example to be consistent with `rounded_borders`.
Co-authored-by: François Mockers <mockersf@gmail.com>
# Objective
- Currently the fps_overlay affects any other ui node spawned. This
should not happen
## Solution
- Use position absolute and a ZIndex of `i32::MAX - 32`
- I also modified the example a little bit to center it correctly. It
only worked previously because the overlay was pushing it down. I also
took the opportunity to simplify the text spawning code a little bit.
# Objective
Implements border radius for UI nodes. Adopted from #8973, but excludes
shadows.
## Solution
- Add a component `BorderRadius` which contains a radius value for each
corner of the UI node.
- Use a fragment shader to generate the rounded corners using a signed
distance function.
<img width="50%"
src="https://github.com/bevyengine/bevy/assets/26204416/16b2ba95-e274-4ce7-adb2-34cc41a776a5"></img>
## Changelog
- `BorderRadius`: New component that holds the border radius values.
- `NodeBundle` & `ButtonBundle`: Added a `border_radius: BorderRadius`
field.
- `extract_uinode_borders`: Stripped down, most of the work is done in
the shader now. Borders are no longer assembled from multiple rects,
instead the shader uses a signed distance function to draw the border.
- `UiVertex`: Added size, border and radius fields.
- `UiPipeline`: Added three vertex attributes to the vertex buffer
layout, to accept the UI node's size, border thickness and border
radius.
- Examples: Added rounded corners to the UI element in the `button`
example, and a `rounded_borders` example.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Zachary Harrold <zac@harrold.com.au>
Co-authored-by: Pablo Reinhardt <126117294+pablo-lua@users.noreply.github.com>
# Objective
- This is an adopted version of #10420
- The objective is to help debugging the Ui layout tree with helpful
outlines, that can be easily enabled/disabled
## Solution
- Like #10420, the solution is using the bevy_gizmos in outlining the
nodes
---
## Changelog
### Added
- Added debug_overlay mod to `bevy_dev_tools`
- Added bevy_ui_debug feature to `bevy_dev_tools`
## How to use
- The user must use `bevy_dev_tools` feature in TOML
- The user must use the plugin UiDebugPlugin, that can be found on
`bevy::dev_tools::debug_overlay`
- Finally, to enable the function, the user must set
`UiDebugOptions::enabled` to true
Someone can easily toggle the function with something like:
```rust
fn toggle_overlay(input: Res<ButtonInput<KeyCode>>, options: ResMut<UiDebugOptions>) {
if input.just_pressed(KeyCode::Space) {
// The toggle method will enable if disabled and disable if enabled
options.toggle();
}
}
```
Note that this feature can be disabled from dev_tools, as its in fact
behind a default feature there, being the feature bevy_ui_debug.
# Limitations
Currently, due to limitations with gizmos itself, it's not possible to
support this feature to more the one window, so this tool is limited to
the primary window only.
# Showcase
![image](https://github.com/bevyengine/bevy/assets/126117294/ce9d70e6-0a57-4fa9-9753-ff5a9d82c009)
Ui example with debug_overlay enabled
![image](https://github.com/bevyengine/bevy/assets/126117294/e945015c-5bab-4d7f-9273-472aabaf25a9)
And disabled
---------
Co-authored-by: Nicola Papale <nico@nicopap.ch>
Co-authored-by: Pablo Reinhardt <pabloreinhardt@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Simplify implementing some asset traits without Box::pin(async move{})
shenanigans.
Fixes (in part) https://github.com/bevyengine/bevy/issues/11308
## Solution
Use async-fn in traits when possible in all traits. Traits with return
position impl trait are not object safe however, and as AssetReader and
AssetWriter are both used with dynamic dispatch, you need a Boxed
version of these futures anyway.
In the future, Rust is [adding
](https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html)proc
macros to generate these traits automatically, and at some point in the
future dyn traits should 'just work'. Until then.... this seemed liked
the right approach given more ErasedXXX already exist, but, no clue if
there's plans here! Especially since these are public now, it's a bit of
an unfortunate API, and means this is a breaking change.
In theory this saves some performance when these traits are used with
static dispatch, but, seems like most code paths go through dynamic
dispatch, which boxes anyway.
I also suspect a bunch of the lifetime annotations on these function
could be simplified now as the BoxedFuture was often the only thing
returned which needed a lifetime annotation, but I'm not touching that
for now as traits + lifetimes can be so tricky.
This is a revival of
[pull/11362](https://github.com/bevyengine/bevy/pull/11362) after a
spectacular merge f*ckup, with updates to the latest Bevy. Just to recap
some discussion:
- Overall this seems like a win for code quality, especially when
implementing these traits, but a loss for having to deal with ErasedXXX
variants.
- `ConditionalSend` was the preferred name for the trait that might be
Send, to deal with wasm platforms.
- When reviewing be sure to disable whitespace difference, as that's 95%
of the PR.
## Changelog
- AssetReader, AssetWriter, AssetLoader, AssetSaver and Process now use
async-fn in traits rather than boxed futures.
## Migration Guide
- Custom implementations of AssetReader, AssetWriter, AssetLoader,
AssetSaver and Process should switch to async fn rather than returning a
bevy_utils::BoxedFuture.
- Simultaniously, to use dynamic dispatch on these traits you should
instead use dyn ErasedXXX.
# Objective
I was wondering why the `lighting` example was still looking quite
different lately (specifically, the intensity of the green light on the
cube) and noticed that we had one more color change I didn't catch
before.
Prior to the `bevy_color` port, `PINK` was actually "deep pink" from the
css4 spec.
`palettes::css::PINK` is now correctly a lighter pink color defined by
the same spec.
```rust
// Bevy 0.13
pub const PINK: Color = Color::rgb(1.0, 0.08, 0.58);
// Bevy 0.14-dev
pub const PINK: Srgba = Srgba::new(1.0, 0.753, 0.796, 1.0);
pub const DEEP_PINK: Srgba = Srgba::new(1.0, 0.078, 0.576, 1.0);
```
## Solution
Change usages of `css::PINK` to `DEEP_PINK` to restore the examples to
their former colors.
# Objective
- Make example alien_cake_addict deterministic so that it's easier to
check for regression
## Solution
- Use a seeded random
---------
Co-authored-by: Rob Parrett <robparrett@gmail.com>
# Objective
- in example `axes`, the axes are sometime one frame late to follow
their mesh
## Solution
- System `move_cubes` modify the transforms, and `draw_axes` query them
for the axes
- if their order is not specified, it will be random and sometimes axes
are drawn before transforms are updated
- order systems
# Objective
- Improve the code quality of the breakout example
- As a newcomer to `bevy` I was pointed to the breakout example after
the "Getting Started" tutorial
- I'm making this PR because it had a few wrong comments + some
inconsistency in used patterns
## Solution
- Remove references to `wall` in all the collision code as it also
handles bricks and the paddle
- Use the newtype pattern with `bevy::prelude::Deref` for resources
- It was already used for `Velocity` before this PR
- `Scoreboard` is a resource only containing `score`, so it's simpler as
a newtype `Score` resource
- `CollisionSound` is already a newtype, so might as well unify the
access pattern for it
- Added docstrings for `WallLocation::position` and `WallLocation::size`
to explain what they represent
# Objective
- Closes#11793
- Introduces a general API for aligning local coordinates of Transforms
with given vectors.
## Solution
- We introduce `Transform::align`, which allows a rotation to be
specified by four pieces of alignment data, as explained by the
documentation:
````rust
/// Rotates this [`Transform`] so that the `main_axis` vector, reinterpreted in local coordinates, points
/// in the given `main_direction`, while `secondary_axis` points towards `secondary_direction`.
///
/// For example, if a spaceship model has its nose pointing in the X-direction in its own local coordinates
/// and its dorsal fin pointing in the Y-direction, then `align(Vec3::X, v, Vec3::Y, w)` will make the spaceship's
/// nose point in the direction of `v`, while the dorsal fin does its best to point in the direction `w`.
///
/// More precisely, the [`Transform::rotation`] produced will be such that:
/// * applying it to `main_axis` results in `main_direction`
/// * applying it to `secondary_axis` produces a vector that lies in the half-plane generated by `main_direction` and
/// `secondary_direction` (with positive contribution by `secondary_direction`)
///
/// [`Transform::look_to`] is recovered, for instance, when `main_axis` is `Vec3::NEG_Z` (the [`Transform::forward`]
/// direction in the default orientation) and `secondary_axis` is `Vec3::Y` (the [`Transform::up`] direction in the default
/// orientation). (Failure cases may differ somewhat.)
///
/// In some cases a rotation cannot be constructed. Another axis will be picked in those cases:
/// * if `main_axis` or `main_direction` is zero, `Vec3::X` takes its place
/// * if `secondary_axis` or `secondary_direction` is zero, `Vec3::Y` takes its place
/// * if `main_axis` is parallel with `secondary_axis` or `main_direction` is parallel with `secondary_direction`,
/// a rotation is constructed which takes `main_axis` to `main_direction` along a great circle, ignoring the secondary
/// counterparts
///
/// Example
/// ```
/// # use bevy_math::{Vec3, Quat};
/// # use bevy_transform::components::Transform;
/// let mut t1 = Transform::IDENTITY;
/// let mut t2 = Transform::IDENTITY;
/// t1.align(Vec3::ZERO, Vec3::Z, Vec3::ZERO, Vec3::X);
/// t2.align(Vec3::X, Vec3::Z, Vec3::Y, Vec3::X);
/// assert_eq!(t1.rotation, t2.rotation);
///
/// t1.align(Vec3::X, Vec3::Z, Vec3::X, Vec3::Y);
/// assert_eq!(t1.rotation, Quat::from_rotation_arc(Vec3::X, Vec3::Z));
/// ```
pub fn align(
&mut self,
main_axis: Vec3,
main_direction: Vec3,
secondary_axis: Vec3,
secondary_direction: Vec3,
) { //... }
````
- We introduce `Transform::aligned_by`, the returning-Self version of
`align`:
````rust
pub fn aligned_by(
mut self,
main_axis: Vec3,
main_direction: Vec3,
secondary_axis: Vec3,
secondary_direction: Vec3,
) -> Self { //... }
````
- We introduce an example (examples/transforms/align.rs) that shows the
usage of this API. It is likely to be mathier than most other
`Transform` APIs, so when run, the example demonstrates what the API
does in space:
<img width="1440" alt="Screenshot 2024-03-12 at 11 01 19 AM"
src="https://github.com/bevyengine/bevy/assets/2975848/884b3cc3-cbd9-48ae-8f8c-49a677c59dfe">
---
## Changelog
- Added methods `align`, `aligned_by` to `Transform`.
- Added transforms/align.rs to examples.
---
## Discussion
### On the form of `align`
The original issue linked above suggests an API similar to that of the
existing `Transform::look_to` method:
````rust
pub fn align_to(&mut self, direction: Vec3, up: Vec3) { //... }
````
Not allowing an input axis of some sort that is to be aligned with
`direction` would not really solve the problem in the issue, since the
user could easily be in a scenario where they have to compose with
another rotation on their own (undesirable). This leads to something
like:
````rust
pub fn align_to(&mut self, axis: Vec3, direction: Vec3, up: Vec3) { //... }
````
However, this still has two problems:
- If the vector that the user wants to align is parallel to the Y-axis,
then the API basically does not work (we cannot fully specify a
rotation)
- More generally, it does not give the user the freedom to specify which
direction is to be treated as the local "up" direction, so it fails as a
general alignment API
Specifying both leads us to the present situation, with two local axis
inputs (`main_axis` and `secondary_axis`) and two target directions
(`main_direction` and `secondary_direction`). This might seem a little
cumbersome for general use, but for the time being I stand by the
decision not to expand further without prompting from users. I'll expand
on this below.
### Additional APIs?
Presently, this PR introduces only `align` and `aligned_by`. Other
potentially useful bundles of API surface arrange into a few different
categories:
1. Inferring direction from position, a la `Transform::look_at`, which
might look something like this:
````rust
pub fn align_at(&mut self, axis: Vec3, target: Vec3, up: Vec3) {
self.align(axis, target - self.translation, Vec3::Y, up);
}
````
(This is simple but still runs into issues when the user wants to point
the local Y-axis somewhere.)
2. Filling in some data for the user for common use-cases; e.g.:
````rust
pub fn align_x(&mut self, direction: Vec3, up: Vec3) {
self.align(Vec3::X, direction, Vec3::Y, up);
}
````
(Here, use of the `up` vector doesn't lose any generality, but it might
be less convenient to specify than something else. This does naturally
leave open the question of what `align_y` would look like if we provided
it.)
Morally speaking, I do think that the `up` business is more pertinent
when the intention is to work with cameras, which the `look_at` and
`look_to` APIs seem to cover pretty well. If that's the case, then I'm
not sure what the ideal shape for these API functions would be, since it
seems like a lot of input would have to be baked into the function
definitions. For some cases, this might not be the end of the world:
````rust
pub fn align_x_z(&mut self, direction: Vec3, weak_direction: Vec3) {
self.align(Vec3::X, direction, Vec3::Z, weak_direction);
}
````
(However, this is not symmetrical in x and z, so you'd still need six
API functions just to support the standard positive coordinate axes, and
if you support negative axes then things really start to balloon.)
The reasons that these are not actually produced in this PR are as
follows:
1. Without prompting from actual users in the wild, it is unknown to me
whether these additional APIs would actually see a lot of use. Extending
these to our users in the future would be trivial if we see there is a
demand for something specific from the above-mentioned categories.
2. As discussed above, there are so many permutations of these that
could be provided that trying to do so looks like it risks unduly
ballooning the API surface for this feature.
3. Finally, and most importantly, creating these helper functions in
user-space is trivial, since they all just involve specializing `align`
to particular inputs; e.g.:
````rust
fn align_ship(ship_transform: &mut Transform, nose_direction: Vec3, dorsal_direction: Vec3) {
ship_transform.align(Ship::NOSE, nose_direction, Ship::DORSAL, dorsal_direction);
}
````
With that in mind, I would prefer instead to focus on making the
documentation and examples for a thin API as clear as possible, so that
users can get a grip on the tool and specialize it for their own needs
when they feel the desire to do so.
### `Dir3`?
As in the case of `Transform::look_to` and `Transform::look_at`, the
inputs to this function are, morally speaking, *directions* rather than
vectors (actually, if we're being pedantic, the input is *really really*
a pair of orthonormal frames), so it's worth asking whether we should
really be using `Dir3` as inputs instead of `Vec3`. I opted for `Vec3`
for the following reasons:
1. Specifying a `Dir3` in user-space is just more annoying than
providing a `Vec3`. Even in the most basic cases (e.g. providing a
vector literal), you still have to do error handling or call an unsafe
unwrap in your function invocations.
2. The existing API mentioned above uses `Vec3`, so we are just adhering
to the same thing.
Of course, the use of `Vec3` has its own downsides; it can be argued
that the replacement of zero-vectors with fixed ones (which we do in
`Transform::align` as well as `Transform::look_to`) more-or-less amounts
to failing silently.
### Future steps
The question of additional APIs was addressed above. For me, the main
thing here to handle more immediately is actually just upstreaming this
API (or something similar and slightly mathier) to `glam::Quat`. The
reason that this would be desirable for users is that this API currently
only works with `Transform`s even though all it's actually doing is
specifying a rotation. Upstreaming to `glam::Quat`, properly done, could
buy a lot basically for free, since a number of `Transform` methods take
a rotation as an input. Using these together would require a little bit
of mathematical savvy, but it opens up some good things (e.g.
`Transform::rotate_around`).