# Objective
The Tracy profiling docs were confusing and overwhelming to some for a
number of reasons:
- only mentioning that you can capture through the UI in a single
sentence quite a bit down
- interspersed installation, version-matching and usage instructions
- lack of clear steps
- lack of separation between topics
## Solution
I've added a Quickstart which guides people through using the Tracy UI
to capture, including some more installation instructions for various
platforms (unofficial macos/linux binary builds, link to repology
packages list).
Additionally, I've created the following sub-titles (sub-headers?)
- `Finding the correct tracy version`
- `Commandline capture (less overhead)`, which is where most of the
previous instructions ended up
- `Using the Tracy UI`, for the basic usage guide with screenshots
Rendered version:
https://github.com/laundmo/bevy/blob/improve-tracy-profiling-docs/docs/profiling.md#tracy-profiler
# Objective
This PR refactors the `FreeCam` controller to improve its modularity and
flexibility. Happy to adjust based on feedback or suggestions!
Fixes#21456
## Solution
* **Splits the `FreeCam` system into two components**:
* `FreeCam`: Stores the **configuration** of the camera controller,
including key bindings, movement speeds, and sensitivity. This struct is
immutable during runtime, ensuring that the core settings stay
consistent.
* `FreeCamState`: Manages the **dynamic runtime state** of the camera,
such as the current pitch, yaw, velocity, and speed multiplier. This
component allows for real-time adjustments to camera behavior without
altering the original settings.
* **Improves the example for debugging and testing**:
A simplified example (`free_cam_simple`) has been introduced, allowing
for easy testing and showcasing of the new FreeCam controller system.
* **Fixes the bug with translation speed**:
As noted in #21483, the camera’s translation speed would "stick" after
excessive scrolling. This bug was still present in the
`free_cam_controller` example. Following the approach suggested in
#21486, the bug has been resolved in the new `free_cam_simple` example
(I did not yet verify the existing ones).
* **Clarifies documentation**:
Documentation has been updated to reflect the new structure, clearly
describing the roles of both `FreeCam` (static settings) and
`FreeCamState` (dynamic state).
## Testing
* For testing, I added a simple example `free_cam_simple` as a POC (this
can be removed later if no longer needed).
* Run with: `cargo run --example free_cam_simple --features="free_cam"`
---------
Co-authored-by: syszery <syszery@users.noreply.github.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Implements scaffolding for a 2D pan camera controller.
Fixes#21468
## Solution
- Introduced a `PanCam` component with settings for panning, zooming,
and rotation via keyboard input, following the design of the existing
`FreeCam`.
- Added a `PanCamPlugin` to register the controller system.
- Implemented keyboard-based panning and rotation.
## TODOs
- Movement is currently world-axis aligned.
- TODO: Consider movement relative to camera rotation.
- Zooming support is scaffolded with config fields but not yet
implemented.
## Testing
Unfortunately, I was unable to fully test this implementation due to
issues running graphical output with GPU acceleration under WSL.
As a result, zoom behavior and rotation effects remain TODOs, and the
whole code could not be fully verified.
Once I resolve the GPU passthrough issues, I plan to complete and test
the remaining features (with a more meaningful example).
---
I'm happy to hear any suggestions or feedback in the meantime!
---------
Co-authored-by: syszery <syszery@users.noreply.github.com>
Co-authored-by: Janis <130913856+janis-bhm@users.noreply.github.com>
# Objective
- Fixes#21551.
- Fixes#20688.
## Solution
- Insert slab_index instead of slot_index into free_slabs.
## Testing
Ran the repro in #20688 and it works!
# Objective
- `bevy_asset` needs better testing.
- It is useful to know how many load tasks the asset server launched.
For example, #12756 is difficult to test because we are literally
looking for whether another load **doesn't** happen.
## Solution
- Add an `AssetServerStats` struct.
- Increment the number of loads whenever we start a load.
## Testing
- Updated several tests to also assert about the number of expected
loads.
- The testing here is not exhaustive, but should cover the common cases.
- I will be looking into more testing in the future.
# Objective
- We use npm for tests on wasm and on mobile
- Dependencies haven't been updated in... a long time
## Solution
- Update them
## Testing
- I ran both in local and it worked
# Objective
- Fixes https://github.com/bevyengine/bevy/issues/16277
- The maintainers have already removed some annoying logs like the probe
one, but the format crates are still incredibly chatty
- Fixes https://github.com/bevyengine/bevy/issues/14904
- That's a completely benign warning that is annoying for Linux users
## Solution
- Improve the default filter
## Testing
- Tested in a standalone project (Foxtrot)
# Objective
- make gizmos render agnostic
## Solution
- split crate
## Testing
- ci and a few examples
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
There have been problems with `MeshAllocator` and
`MaterialBindGroupAllocator` losing track of asset changes, then it
would be nice to have an automated way of checking if the number of
allocations is growing uncontrollably.
## Solution
Create diagnostics that collect measurements of allocations from
`MeshAllocator` and `MaterialBindGroupAllocator`, and number of render
assets present
## Showcase
```rust
app.add_plugins(DefaultPlugins)
.add_plugins((
MeshAllocatorDiagnosticPlugin,
MaterialAllocatorDiagnosticPlugin::<StandardMaterial>::default(),
RenderAssetDiagnosticPlugin::<RenderMesh>::new(" render meshes"),
RenderAssetDiagnosticPlugin::<GpuImage>::new(" gpu images"),
// ImageMaterial is the name of the manual material used on the `manual_material` example
ErasedRenderAssetDiagnosticPlugin::<ImageMaterial>::new(" image materials"),
));
```
If you also have `LogDiagnosticsPlugin`, the output looks something like
this:
```
INFO bevy_diagnostic: mesh_allocator_allocations : 4.000000 meshes (avg 4.000000 meshes)
INFO bevy_diagnostic: mesh_allocator_slabs : 4.000000 slabs (avg 4.000000 slabs)
INFO bevy_diagnostic: mesh_allocator_slabs_size : 4194360.000000 bytes (avg 4194360.000000 bytes)
INFO bevy_diagnostic: material_allocator_allocations/bevy_pbr::pbr_material::StandardMaterial: 14.000000 materials (avg 14.000000 materials)
INFO bevy_diagnostic: material_allocator_slabs/bevy_pbr::pbr_material::StandardMaterial : 1.000000 slabs (avg 1.000000 slabs)
INFO bevy_diagnostic: material_allocator_slabs_size/bevy_pbr::pbr_material::StandardMaterial : 576.000000 bytes (avg 576.000000 bytes)
INFO bevy_diagnostic: render_asset/bevy_render::mesh::RenderMesh : 5.000000 render meshes (avg 5.000000 render meshes)
INFO bevy_diagnostic: render_asset/bevy_render::texture::gpu_image::GpuImage : 10.000000 gpu images (avg 10.000000 gpu images)
INFO bevy_diagnostic: erased_render_asset/manual_material::ImageMaterial : 2.000000 image materials (avg 2.000000 image materials)
```
# Objective
Fixes#21528 causing the main branch to not build when not using default
features
## Solution
Added explicit dependencies on morph feature for bevy_mesh and
bevy_render for bevy_pbr
## Testing
Now builds successfully on my machine using
> cargo build --no-default-features --features
std,x11,bevy_winit,bevy_state,bevy_window,bevy_pbr,bevy_sprite,bevy_text,bevy_core_pipeline,bevy_picking,bevy_animation,png,zstd_rust,tonemapping_luts,ktx2
# Objective
- alternative to #21502
- also undoes #20890
- does not regress #19205
- fixes#21489 and #21479
## Solution
the fix i originally made was wrong. the reason it worked was because it
failed the conditional and did not clip the lines in some cases where
the original bug was exhibited. the condition was correct before, it
turns out, but the clipping logic is wrong: an epsilon is added, with a
comment saying it is to avoid falsely culling the vertex due to floating
point imprecision leaving it just barely in front of the near plane.
However, i do not see why an epsilon should be needed here, or why this
should be avoided: triangle primitives are regularly intersecting the
clipping plane, that is standard order of business. The entire primitive
is not discarded if only part of it is clipped, instead only the visible
pixels are rasterized.
## Testing
- original bug test case by Antony looks right
- both grid test cases look right
- gizmos examples look right
Fixes#18904.
See also:
- https://github.com/gfx-rs/wgpu/issues/4394
- https://github.com/gfx-rs/wgpu/pull/7339
# A Debugging Story
In the above issue, the defect can be reproduced by running the
`3d_scene` example with an Intel adapter on Vulkan and observing the
following output:
<img width="1924" height="1126" alt="image"
src="https://github.com/user-attachments/assets/c6a82873-7afc-4901-a812-dca46951b082"
/>
## 1. Indirect Draw Args
The first thing to check is what's being passed to
`vkCmdDrawIndexedIndirectCount` in `main_opaque_pass_3d`. What we see is
a little bizarre:
<img width="895" height="130" alt="image"
src="https://github.com/user-attachments/assets/675cc55d-e377-4e77-81f2-9b2720ccb188"
/>
We should see two separate meshes here for the circular base and the
cube, but instead we see 3 items, two of which are identical with
exception of their `first_instance` id.
## 2. Reversed work item ordering
Trying to debug what could possibly be wrong with the shader input lead
to observing the `PreprocessWorkItem` buffer that gets passed to mesh
preprocessing. Here, there was a very conspicuous difference between
when things would work and when they would break:
```sh
// Working
work_items[0] = {input_index: 0, output_index: 0}
work_items[1] = {input_index: 1, output_index: 1}
// Broken
work_items[0] = {input_index: 1, output_index: 0}
work_items[1] = {input_index: 0, output_index: 1}
```
This was very conspicuous and likely due to ECS query instability.
However, the code looked like it should be robust enough to handle work
items in any order. Further, this works just fine on Nvidia, so the
ordering itself is clearly not the issue.
## 3. Memory ordering?
My first assumption was that this must be some kind of weirdness with
memory ordering or some other race only observable on Intel. This led me
to the following write:
```wgsl
// If we're the first mesh instance in this batch, write the index of our
// `MeshInput` into the appropriate slot so that the indirect parameters
// building shader can access it.
if (instance_index == 0u || work_items[instance_index - 1].output_or_indirect_parameters_index != indirect_parameters_index) {
indirect_parameters_gpu_metadata[indirect_parameters_index].mesh_index = input_index;
}
```
Even though the logic looks totally fine and shouldn't require any
synchronization, I tried making the write atomic, which didn't seem to
help at all. My next step was to try to remove the condition and just
unconditionally write. This could lead to some weirdness in the event of
batch size N > 1, but I just wanted to see what happened. And,... it
solved the bug?
## 4. SPIR-V de-compilation
This made no sense to me why this would fix things, so I decided to
decompile the shader and see what was going on, and found the following:
```c
bool _247 = _236 == 0;
uint _248 = _236 - 1;
uint* _249 = &_221[_248].output_or_indirect_parameters_index;
uint _250 = *_249;
bool _251 = _250 != _246;
bool _252 = _247 || _251;
if(_252) {
uint* _256 = &_227[_246].mesh_index;
*_256 = _244;
}
```
This looks wrong. The final condition `_247 || _251` doesn't seem right.
Checking and confirming, [`||` in WGSL is supposed to short
circuit](https://www.w3.org/TR/WGSL/#logical-expr). Instead, here, we
unconditionally read from
`&_221[_248].output_or_indirect_parameters_index;` AKA
`work_items[instance_index - 1]`. In the event `instance_index` is 0
that means we are OOB. Uh oh!!
## 5. Vendor differences
I'm not sure why this UB have any effect on Nvidia. But we can walk
through the entire bug:
On the first thread in the workgroup where `instance_index` is 0, we
will *always* OOB read, which on Intel seems to cause the thread to
terminate or otherwise return garbage that makes the condition fail or
something else weird. *However*, in the event that the first work item's
input/output index is *supposed* to be 0, everything happens to just
work, since the zero-initialized memory of the GPU metadata is by chance
correct. Thus, the bug only appears when things are sorted funny and a
batch set with a non-zero input index appears at the front of the work
items. Yikes!
The fix is to make sure that we only read from the prior input when we
are not the first item.
# Objective
Fixes#21329 - The naming of the `clear_children` function could be
misunderstood, so we suggest to rename it.
The current `clear_children` function could be understood to despawn the
children, which it does not do. To emphasize the difference between
`clear` and `despawn`, we can rename `clear` to `detach`. So we arrive
at the final naming of `despawn` and `detach`.
## Solution
To improve this, we could rename `clear_children` to `detach_children`
and all other `clear`/`remove` functions too. I also suggest to rename
all `remove_child*` functions for the same reason.
This renaming resulted in a confict because two methods now had the same
name:
- `detach_children(self)`, previously `clear_children`
- `detach_children(self, children: &[Entity])`, previously
`remove_children`
To solve this, I propose we rename the former to `detach_all_children`.
This was chosen because it has the least impact, considering that all
methods do take a slice of children, except this one.
Changing the `insert_*` and `add_*` functions should be discussed. I
think there is less potential for confusion, because they require you to
pass an existing entity. Therefore it should be clear that this does not
spawn anything.
Note: The function `ui_surface.try_remove_children` has not been
renamed.
## Testing
Currently running the tests, but there are unrelated compile errors in
wgpu-hal blocking me (I am on windows).
For this reason, this is a draft pull request. Feel free to provide
feedback already, while I am trying to make the tests run.
## Discussion
As proposed in this PR, this would be a breaking change and will likely
affect a large number of downstream projects directly. If you think this
should be handled differently, via a `#[deprecated]` flag, I can rework
the code to do that.
Is there no documentation to update? The repo yielded no more search
results than this.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes https://github.com/bevyengine/bevy/issues/21261
## Solution
Changes:
- Detect events directly on radio buttons,
- Make RadioGroup optional,
- ValueChange events are triggered on checked radio button and
RadioGroup.
This makes radio button behavior:
- similar to other widgets, where we can observe triggered change
directly on widget,
- radio button widget can function separately,
- modular, users can decide if they want to use RadioGroup or want to
roll out their own solution.
Current behavior in examples doesn't change with this PR.
## Testing
Tested using existing examples. See `feathers` example, behavior doesn't
change.
Additionally, tested in bevy_immediate where widget consistency is
useful.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
- Make the problem with #21269 more concrete.
## Solution
- Add a test to show that loaders during processing can read processed
assets.
- Add an ignored test to show that loaders during processing cannot
currently read source assets.
- This also tests that nested asset loads during processing actually
works.
## Testing
- Oops! All tests!
PR #20993 attempted to fix a crash that would occur with the following
sequence of events:
1. An entity's material changes from type A to type B. (The material
*type* must change, not just the material asset.)
2. The `extract_entities_needs_specialization<B>` system runs and adds a
new specialization change tick to the entity.
3. The `extract_entities_needs_specialization<A>` system runs and
removes the specialization change tick.
4. We crash in rendering because no specialization change tick was
present for the entity.
Unfortunately, that PR used the presence of the entity in
`RenderMaterialInstances` to detect whether the entity is safe to delete
from the specialization change tick table. This is incorrect for meshes
that change material types while not visible, because only visible
meshes are present in `RenderMaterialInstances`. So the above race can
still occur if the mesh changes materials while off-screen, which will
lead to a crash when the mesh becomes visible.
This PR fixes the issue by dividing the process of adding new
specialization ticks and the process of removing old specialization
ticks into two systems. First, all specialization ticks for all
materials are updated; alongside that, we store the *material instance
tick*, which is a tick that's updated once per frame. After that, we run
`sweep_entities_needing_specialization`, which traverses the
`RemovedComponents` list for each material and prunes dead entities from
the table if and only if their material instance ticks haven't changed
since the last frame. This ensures that the above race can't happen,
regardless of whether the meshes are present in
`RenderMaterialInstances`.
Having to have two separate specialization ticks, one being the standard
Bevy system tick and one being a special material instance tick that's
updated once per frame, is unfortunate, but it seemed to me like the
least bad option. We should be able to get rid of all of this when we
have untyped materials.
# Objective
- Add initial support for indirect specular lighting (reflections) to
Solari's realtime renderer
## Solution
- A new pass is added called `specular_gi`
- For rough materials, we reuse the path from [diffuse] ReSTIR GI, and
just shade using the specular BRDF
- For smooth materials, we trace a new path with up to 3 bounces,
terminating in the world cache once we've hit a rough enough surface
- DLSS-RR guide buffers now use correct diffuse and specular albedos
## Future
* Specular motion vectors for DLSS-RR guiding are not yet implemented. I
think I want to leave this for a future PR. For now they're hardcoded to
zero.
* Reflections can reveal the world cache
* General quality is not great, there's probably some heuristics we can
tune to reduce the noise, but at least it's a baseline to start with.
## Showcase
Before
<img width="2564" height="1500" alt="image"
src="https://github.com/user-attachments/assets/07839d09-4692-40ff-8b25-f7e1e9787a7e"
/>
After
<img width="2564" height="1500" alt="image"
src="https://github.com/user-attachments/assets/79772fbc-dca5-4170-bed7-73fe0e3e182a"
/>
---------
Co-authored-by: SparkyPotato <noob.sparkypotato@gmail.com>
# Objective
- This is sort of a step towards #19024.
- This is a step towards #11266.
Context: The AssetServer **never** deals with Uuid assets anyway. We
always allocate asset indices, and asset UUIDs are not handled properly
(dependencies on UUID assets are never loaded, so their dependents won't
ever be notified).
## Solution
- Create `ErasedAssetIndex` as a replacement for `UntypedAssetId`.
- Use `ErasedAssetIndex` or `AssetIndex` where relevant within the
`AssetServer`.
# Objective
I've been having panics in situations where:
- I despawn a UI Root Node in PostUpdate
- I don't have any system order dependency between my PostUpdate system
and `UiSystems::Prepare`, so there was no sync point between the two
Therefore the order of operations was:
- My system runs and queues a command to despawn a root node
- The UI system runs and tries to insert `Propagate` on my root node
- CommandExecutions:
- my command to despawn the root node is executed
- the command to insert Propagate is executed, causing a panics
This means that any attempt to despawn a Root node in PostUpdate will
probably cause these kinds of panics.
## Solution
Replace the command with `try_insert` so that if the Root Node is
despawned we don't try to add a Propagate component on it.
## Testing
This fixed the issue in my repo
# Objective
- There was a TODO to make this type actually a trait.
- #21409 introduced a test flake on WIndows (since the transaction log
file may not have been fully released by the time the next test ran),
and made tests create the `crates/bevy_asset/imported_assets/log` file.
## Solution
- Create two traits: `ProcessorTransactionLogFactory` and
`ProcessorTransactionLog`. The former creates the latter.
- Rewrite the test helper for asset processing to use a fake transaction
log that doesn't do anything.
- Note: pretty much the entire implementation was just reformatted into
the trait.
- Note: these transaction log methods are returning `BevyError` instead
of something like `std::io::Error`.
## Testing
- I ran the asset tests on repeat for a while (including with #21433
where the flake was first seen and I was able to reproduce fairly
quickly). No issues!
Note: we could make a release notes for the fact that users can make
their own transaction logs, but this feature is primarily for unit
testing. Maybe a user could make a more robust transaction log, but it's
really not clear that it would be important for anyone.
# Objective
Fixes#21482
## Solution
Before exiting the system when the controller is disabled, check if
either of the cursor grab flags are set and ungrab any windows if so.
Note: I think it's a bit strange that the camera un-grabs every window,
not just the one with focus, but I've just copied this behaviour from
further down in the function. In this case, it might be more correct to
do this anyway, since the controller might be disabled when the
respective window isn't focused.
## Testing
I used #21477 to test this
## Objective
Users of the `bevy` crate currently live one of two lifestyles:
1. Use all of Bevy's default features, potentially compiling many
features you don't need or don't want. If there is a feature you _cannot
have_ in your app, you must move on to option (2)
2. Disable Bevy's default features, and compose the complete list of
features yourself.
Living in the world of (2) is an exercise in frustration, as the list of
required features to accomplish a given task changes regularly across
releases as we add and change features. This is an _expert level_ task
that requires intimate knowledge of engine internals to get right. Even
I, Bevy's lead developer, would struggle here. To the point that I would
never voluntarily choose to disable Bevy's default features.
Most games/apps are 2D-only, 3D-only, or UI-only and don't require the
full set of features. We cannot currently in good conscience recommend
that those developers live in the "no default features" world. That is a
fast track to pain, suffering, and perhaps a quick exit from the Bevy
ecosystem.
The same problem exists for developers that want to build their own Bevy
renderer or replace Bevy UI with their own framework. Once again, we
_cannot_ recommend that those developers manage every Bevy feature
themselves.
Fixes: #21369
Alternative to: #20741#21236
## Solution
Define a "standalone" set of features that enable Bevy developers to
disable default features, then opt in to the funtionality they want. The
"default" `bevy` feature set is now just:
```toml
default = ["2d", "3d", "ui"]
```
This enables developers to select only the features they need. For
example, a UI-only app would look like this:
```toml
bevy = { version = "0.17", default-features = false, features = [ "ui" ] }
```
"2d", "3d", and "ui" each contain the "full" Bevy experience for that
domain. This also includes:
- `default_platform`: the default "platform support" features (see docs)
- `default_app`: the default "app framework" features (see docs)
For developers that do not want the default bevy render / platform / app
functionality, this breaks down further into:
- `common_api`: common / core backend-less user-facing Bevy render api
- `2d_api`: common / core backend-less user-facing Bevy 2d api
- `3d_api`: common / core backend-less user-facing Bevy 3d api
- `ui_api`: common / core backend-less user-facing Bevy ui api
(and many others)
I've also added the `dev` feature to this PR, which enables the
recommended "dev only" features like dynamic linking, asset watching /
hot reloading, and dev / debug tools. Including dynamic linking is a bit
controversial here given that it doesn't work everywhere. But I'd like
to aggressively push people into the dynamic linking workflow wherever
possible, as developing without it is signficantly worse. And removing a
single `dev` feature is a much simpler release workflow.
---------
Co-authored-by: atlv <email@atlasdostal.com>
# Objective
This introduces a generalised 2d `Ring` shape for any underlying
primitive (i.e. what an `Annulus` is to a `Circle`). This allows us to
have "hollow" shapes or "outlines". `Ring` is also extrudable. It is
assumed that the inner and outer meshes have the same number of
vertices.
```rs
let capsule_ring = Ring::new(Capsule2d::new(50.0, 100.0), Capsule2d::new(45.0, 100.0));
let hexagon_ring = Ring::new(RegularPolygon::new(50.0, 6), RegularPolygon::new(45.0, 6)); // note vertex count must match
```
## Solution
There is a new generic primitive `Ring`, which takes as input any
`Primitive2d`, with two instances of that shape: the outer and the inner
(or hollow).
The mesh for a `RingMeshBuilder` is constructed by concatenating the
vertices of the outer and inner meshes, then walking the perimeter to
join corresponding vertices like so:
<img width="513" height="509" alt="image"
src="https://github.com/user-attachments/assets/2cecb458-3b59-44fb-858b-1beffecd1e57"
/>
```
# outer vertices, then inner vertices
positions = [
0 1 2 3 4
0' 1' 2' 3' 4'
]
# pairs of triangles
indices = [
0 1 0' 0' 1 1'
1 2 1' 1' 2 2'
2 3 2' 2' 3 3'
3 4 3' 3' 4 4'
4 0 4' 4' 0 0'
]
```
Examples of generated meshes:
<img width="398" height="351" alt="image"
src="https://github.com/user-attachments/assets/348bbd91-9f4e-4040-bfa5-d508a4308c10"
/>
<img width="472" height="376" alt="image"
src="https://github.com/user-attachments/assets/dbaf894e-6f7f-4b79-af3e-69516da85898"
/>
<img width="388" height="357" alt="image"
src="https://github.com/user-attachments/assets/cb9881e5-4518-4743-b8de-5816b632f36f"
/>
<img width="449" height="402" alt="image"
src="https://github.com/user-attachments/assets/7d2022c9-b8cf-4b4b-bb09-cbe4fe49fb89"
/>
## Testing
I've tested these changes by updating the `2d_shapes`, `3d_shapes` and
`custom_primitives` examples.
It could potentially benefit from unit tests.
---
## Showcase
<img width="1282" height="752" alt="image"
src="https://github.com/user-attachments/assets/edab9dbf-1093-43c7-9804-8e5c8a830573"
/>
_Rings of 2d primitives (bottom row)_
<img width="1282" height="752" alt="image"
src="https://github.com/user-attachments/assets/fbeed7f9-42bb-432c-bce9-cfeca87d70af"
/>
_Extrusions of rings of extrudable primitives (back row)_
---
## Follow-up work
I've only realised this from looking at Extrudable, but because I used
the mesh positions but it does assume the positions are well-ordered
around the perimeter. Extrudable instead uses the notion of a perimeter
(via indices so it doesn't matter what order the mesh positions are in),
a follow-up may be to do something similar for Ring. An alternative idea
may be to compute the perimeter first as directly a list of Vec2
positions (maybe a Perimeter trait), then construct any needed meshes
from that.
This potentially makes `Annulus` redundant as it is equivalent to a
`Ring<Circle>`. One thing of note is that `Extrusion<Annulus>` is
textured differently from `Extrusion<Ring<Circle>>`.
Another idea is to have a way to construct `PrimitiveTopology::LineList`
meshes from Primitive shapes (which may have a similar effect as
creating a Ring).
# Objective
Fixes#8906#8906 reports that the `reflect` attribute silently fails when using the
`#[reflect[...]]` syntax. I wasn't able to reproduce that issue, so it
was likely resolved in a prior change. This pull request addresses only
the syntax issue.
## Solution
Validate the `Meta::List` delimiter in reflect macro to allow only
`MacroDelimiter::Paren`
## Testing
- Did you test these changes? If so, how?
I run `cargo check --example reflection_types`
- Are there any parts that need more testing?
No
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Run `cargo check --example reflection_types`
Then modify the reflection_types example by changing:
```
#[reflect(Hash, PartialEq, Clone)]
pub struct E {
x: usize,
}
```
to
```
#[reflect[Hash, PartialEq, Clone]]
pub struct E {
x: usize,
}
```
then run `cargo check --example reflection_types` again it should now
fail with this error:
```
error: `#[reflect = "..."]` must use parenthesis `(` and `)`
```
# Objective
Addresses #21467.
## Solution
Adds the "free_cam_controller" example, that contains a simple scene
with a camera controlled by the FreeCamPlugin. the code explains how to
change the settings in the FreeCam component and the example provides
bindings to change sensitivity and friction live.
## Testing
`cargo run --example free_cam_controller --features="free_cam"`
As this is my first contribution to the project, please let me know
about any problems.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
The `solari` example does not compile when run with the
required-features following #20215.
## Solution
Require the new free_cam feature.
## Testing
`cargo build --example solari --features="bevy_solari https free_cam"`
# Objective
- Example feathers is hidden, maybe because its experimental
- Other examples are using the experimental feathers feature and are not
hidden
## Solution
- un hide the feathers example
I would like this to be part of the next 0.17 patch, feathers is part of
the release notes, it's a bit sad to not be able to show the example on
the website
# Objective
- Fixes#21455
- Change the behavior of freecam to use smooth nudge instead of an
exponential, per-frame fall off
## Solution
- As written, the freecam's velocity decays by half every loop.
- Instead, I used smooth_nudge, which takes the time difference into
account so that its behavior isn't depended on the fixed main loop's hz.
- The freecam plugin took a f32 that defaulted to 0.5, and was written
so lower numbers would have faster decay. In smooth nudge terms, you
could describe this as 64 log 2 at the fixed time step of 64 hz, which
is a decay rate of around 44.3.
- I used 40.0 as this seems like an easily understandable default.
- This is a breaking change because now higher numbers (instead of lower
numbers) supplied to `friction`, will increase the decay rate. However,
all of the examples that use freecamplugin relied on the default()
friction value, and it was only recently added, so I think this is okay.
## Testing
- I tested this change in the examples that use freecam;
---
# Objective
As pointed out by @BigWingBeat in
https://github.com/bevyengine/bevy/pull/20215#issuecomment-3099726369
the default mouse sensitivity of the free_cam controller is crazy high.
## Solution
Divide the sensitivity value by 5. 10 was too much, but 5 feels about
right for a "careful and controlled scene editor".
## Testing
`cargo run --example 3d_gizmos --features="free_cam"`
# Objective
As noted in
https://github.com/bevyengine/bevy/pull/20215#issuecomment-3099068564 by
@BigWingBeat, the conversion factor used in the free cam camera
controller code that was added in #11921 arbitrary and untested.
This is a problem that users have stumbled across elsewhere, including
in #21140 and myself when writing leafwing-input-manager!
## Solution
1. Define a constant with the correct conversion factor, at least as
reported in #21140. This goes in `bevy_input` as it's broadly useful.
2. Use that constant in bevy_camera_controller::free_cam.
3. Approximately scale the default value on the camera controller to
compensate.
## Testing
We use this controller in a number of our examples. I chose `3d_gizmos`,
which worked just about the same before and after. The scroll wheel
controls your "walking speed".
# Objective
Moving the camera around is really important to validate that our scenes
are rendered correctly.
Bevy engine devs currently do this via a fairly cursed "library example"
which includes a basic freecam controller (which is technically distinct
from a flycam apparently). This has three problems:
1. Oh god why are we taking pseudo-dependencies on other examples.
2. Something like this would be useful for debugging for users.
3. Something like this would be useful for the editor and other tooling.
## Solution
Create a new `bevy_camera_controllers` crate, and move the existing
freecam implementation into it, nearly verbatim.
This cleans up some ugly tech debt in how we do this, makes it easier to
add a camera controller to other examples, and also gives us a scaffold
for future camera controllers.
This PR has been marked `X-Blessed`, as I went over this plan with @cart
in a [meeting on
2025-06-23](https://discord.com/channels/691052431525675048/692572690833473578/1386847828923519038),
and we both agreed that this was the right first step.
## Testing
I've tested the examples that rely on this camera controller: they work
just like before.
## Notes for reviewers
- I don't intend to land this in Bevy 0.17: the existing example code is
not high enough quality for me to be happy shipping this
- we're also soft feature-frozen; I was just in the mood to do this
today
- this PR has some minimal cleanup: just enough naming and docs work to
make this code not an active liability. Any more will risk derailing
this PR and making it harder to review
- I've opted to expose top-level feature flags for the various camera
controllers. This is a bit noisy, but it was the only sensible way I
could see to both have "no camera controllers by default" and "still
easy to use these controllers in examples"
- this will not be the only camera controller in this crate, or the Bevy
Editor
- this is not the place to discuss "what should the default camera
controller for the Bevy Editor be"
- if you think this crate, or this particular move is the wrong strategy
for some other reason though, please do speak up :)
- my personal (unblessed) hope is that we continue to add camera
controllers to this crate as needed for various first-party tooling. I
will probably largely push-back on adding camera controllers that we do
not actively use to this crate, since I don't think they make great
libraries in general (much better to copy-paste)
## TODO
- [x] add release note. I'm waiting until after Bevy 0.17 ships to do
this
- [x] update the examples/README.md file. I was lazy and didn't want to
constantly resolve merge conflicts on that while this PR sits
- [x] change to singular crate name
## Future work
- split apart the giant camera controller component
- make keybinding better, either with or without a real input manager
solution
- split apart the system to make it more modular
- make the system handle fixed timesteps better
- use the camera controller in more examples for debugging
- add more camera controllers!
---------
Co-authored-by: atlv <email@atlasdostal.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
## Objective
Closes#21349
Provides an ergonomic way to create a `Handle<A>` from a `Uuid` at
runtime.
## Solution
Implements the `From<Uuid>` trait for `Handle<A>`, allowing users to
write:
```rust
let uuid = Uuid::new_v4();
let handle: Handle<Image> = uuid.into();
```
Instead of the current verbose approach:
```rust
let handle = Handle::<Image>::Uuid(uuid, PhantomData);
```
## Testing
- Added comprehensive test `from_uuid` that verifies:
- Conversion from `Uuid` to `Handle<A>` works correctly
- The resulting handle is a UUID variant
- The handle ID matches the input UUID
- Both `.into()` and explicit `From::from()` work
- All existing handle tests continue to pass
- Clippy and formatting checks pass
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective
- The previous state had the loader task send a single
`InternalAssetEvent::Loaded` for every root asset **and** each of its
subassets. The `handle_internal_asset_events` system reads these events
one at a time. This means these two threads are racing. So it's possible
to see some of the subassets loaded without the root asset being loaded
in a frame, and then have to wait an additional frame to see the
remaining subassets and root asset loaded.
## Solution
- Instead of recursively sending the subassets inside the loader task,
just send the `LoadedAsset` in its entirety.
- Do the recursion when processing the loaded asset. Since we're doing
this in the system, the entire loaded asset will be processed in a
single frame.
- This also reduces contention of the channel.
## Testing
- None. This is kinda a "fake issue". In order to see it, handling a
loaded asset in `handle_internal_asset_events` needs to finish the last
received subasset before the loader task sends the root asset. This is
probably pretty unlikely, but could in theory cause flaky tests.